From 8c20d7894151439b1cfb06660cf8594604a48fa2 Mon Sep 17 00:00:00 2001 From: Andreas Schultz Date: Fri, 5 Feb 2016 17:38:49 +0100 Subject: [PATCH] remove dos style newlines --- conf/ac.conf | 180 +- conf/wtp.conf | 294 +- src/ac/ac_80211_json.c | 940 ++--- src/ac/ac_80211_json_addwlan.c | 82 +- src/ac/ac_80211_json_addwlan.h | 16 +- src/ac/ac_80211_json_antenna.c | 218 +- src/ac/ac_80211_json_antenna.h | 16 +- src/ac/ac_80211_json_assignbssid.c | 82 +- src/ac/ac_80211_json_assignbssid.h | 16 +- src/ac/ac_80211_json_deletewlan.c | 82 +- src/ac/ac_80211_json_deletewlan.h | 16 +- src/ac/ac_80211_json_directsequencecontrol.c | 176 +- src/ac/ac_80211_json_directsequencecontrol.h | 16 +- src/ac/ac_80211_json_ie.c | 78 +- src/ac/ac_80211_json_ie.h | 16 +- src/ac/ac_80211_json_macoperation.c | 236 +- src/ac/ac_80211_json_macoperation.h | 16 +- src/ac/ac_80211_json_miccountermeasures.c | 82 +- src/ac/ac_80211_json_miccountermeasures.h | 16 +- src/ac/ac_80211_json_multidomaincapability.c | 176 +- src/ac/ac_80211_json_multidomaincapability.h | 16 +- src/ac/ac_80211_json_ofdmcontrol.c | 176 +- src/ac/ac_80211_json_ofdmcontrol.h | 16 +- src/ac/ac_80211_json_rateset.c | 162 +- src/ac/ac_80211_json_rateset.h | 16 +- src/ac/ac_80211_json_rsnaerrorreport.c | 82 +- src/ac/ac_80211_json_rsnaerrorreport.h | 16 +- src/ac/ac_80211_json_statistics.c | 82 +- src/ac/ac_80211_json_statistics.h | 16 +- src/ac/ac_80211_json_supportedrates.c | 162 +- src/ac/ac_80211_json_supportedrates.h | 16 +- src/ac/ac_80211_json_txpower.c | 136 +- src/ac/ac_80211_json_txpower.h | 16 +- src/ac/ac_80211_json_txpowerlevel.c | 162 +- src/ac/ac_80211_json_txpowerlevel.h | 16 +- src/ac/ac_80211_json_updatewlan.c | 82 +- src/ac/ac_80211_json_updatewlan.h | 16 +- src/ac/ac_80211_json_wtpqos.c | 158 +- src/ac/ac_80211_json_wtpqos.h | 16 +- src/ac/ac_80211_json_wtpradioconf.c | 256 +- src/ac/ac_80211_json_wtpradioconf.h | 16 +- src/ac/ac_80211_json_wtpradiofailalarm.c | 158 +- src/ac/ac_80211_json_wtpradiofailalarm.h | 16 +- src/ac/ac_80211_json_wtpradioinformation.c | 136 +- src/ac/ac_80211_json_wtpradioinformation.h | 16 +- src/ac/ac_backend.c | 1794 ++++----- src/ac/ac_backend.h | 44 +- src/ac/ac_ieee80211_data.c | 918 ++--- src/ac/ac_json.h | 184 +- src/ac/ac_kmod.c | 1406 +++---- src/ac/ac_kmod.h | 142 +- src/ac/ac_soap.c | 1736 ++++----- src/ac/ac_soap.h | 228 +- src/ac/ac_wlans.c | 976 ++--- src/ac/ac_wlans.h | 256 +- src/ac/kmod/Makefile | 36 +- src/ac/kmod/capwap.c | 1578 ++++---- src/ac/kmod/capwap.h | 248 +- src/ac/kmod/capwap_private.c | 2084 +++++----- src/ac/kmod/capwap_private.h | 134 +- src/ac/kmod/capwap_rfc.h | 374 +- src/ac/kmod/config.h | 26 +- src/ac/kmod/iface.c | 600 +-- src/ac/kmod/iface.h | 54 +- src/ac/kmod/main.c | 64 +- src/ac/kmod/netlinkapp.c | 1222 +++--- src/ac/kmod/netlinkapp.h | 30 +- src/ac/kmod/nlsmartcapwap.h | 146 +- src/ac/kmod/socket.c | 454 +-- src/ac/kmod/socket.h | 70 +- src/ac/kmod/station.c | 314 +- src/ac/kmod/station.h | 116 +- src/common/binding/ieee80211/ieee80211.c | 1458 +++---- src/common/binding/ieee80211/ieee80211.h | 1212 +++--- src/common/capwap_hash.c | 1110 +++--- src/common/capwap_hash.h | 108 +- src/common/capwap_rfc.h | 472 +-- src/common/capwap_socket.c | 776 ++-- src/common/capwap_socket.h | 60 +- src/common/capwap_timeout.c | 684 ++-- src/common/capwap_timeout.h | 98 +- src/wtp/binding/ieee80211/netlink_link.c | 310 +- src/wtp/binding/ieee80211/netlink_link.h | 118 +- src/wtp/binding/ieee80211/wifi_drivers.c | 3672 +++++++++--------- src/wtp/binding/ieee80211/wifi_drivers.h | 872 ++--- src/wtp/binding/ieee80211/wifi_nl80211.c | 3510 ++++++++--------- src/wtp/binding/ieee80211/wifi_nl80211.h | 90 +- src/wtp/kmod/capwap.c | 1578 ++++---- src/wtp/kmod/capwap.h | 248 +- src/wtp/kmod/capwap_private.c | 550 +-- src/wtp/kmod/capwap_private.h | 54 +- src/wtp/kmod/capwap_rfc.h | 374 +- src/wtp/kmod/config.h | 26 +- src/wtp/kmod/netlinkapp.c | 1606 ++++---- src/wtp/kmod/netlinkapp.h | 38 +- src/wtp/kmod/nlsmartcapwap.h | 132 +- src/wtp/kmod/socket.c | 454 +-- src/wtp/kmod/socket.h | 70 +- src/wtp/wtp_element_helper.c | 130 +- src/wtp/wtp_kmod.c | 1182 +++--- src/wtp/wtp_kmod.h | 130 +- src/wtp/wtp_radio.c | 1578 ++++---- src/wtp/wtp_radio.h | 180 +- webservice/smartcapwap.wsdl | 652 ++-- 104 files changed, 21740 insertions(+), 21740 deletions(-) diff --git a/conf/ac.conf b/conf/ac.conf index 2d265d0..041a189 100755 --- a/conf/ac.conf +++ b/conf/ac.conf @@ -1,90 +1,90 @@ -# AC configuration file - -version = "1.0"; - -application: { - standalone = true; - - name = "ac 1"; - - binding = [ - "802.11" - ]; - - descriptor: { - maxstations = 20; - maxwtp = 10; - - security: { - presharedkey = false; - x509 = false; - }; - - rmacfiled: { - supported = false; - }; - - dtlspolicy: { - cleardatachannel = true; - dtlsdatachannel = true; - }; - - info = ( - { idvendor = 12345; type = "hardware"; value = "1.0"; }, - { idvendor = 33457; type = "software"; value = "2.0"; } - ); - }; - - ecn = "limited"; - - timer: { - discovery = 20; - echorequest = 30; - decrypterrorreport = 120; - idletimeout = 320; - }; - - wtpfallback = true; - - dtls: { - enable = true; - - type = "x509"; - - presharedkey: { - hint = "esempio"; - identity = "prova"; - pskkey = "123456"; - }; - - x509: { - calist = "/etc/capwap/ca.crt"; - certificate = "/etc/capwap/ac.crt"; - privatekey = "/etc/capwap/ac.key"; - }; - }; - - network: { - #binding = "eth1"; - #listen = ""; - transport = "udp"; - mtu = 1400; - }; -}; - -backend: { - id = "1"; - version = "1.0"; - server: ( - { url = "http://127.0.0.1/csoap.php"; } - #{ url = "https://127.0.0.1/csoap.php"; x509: { calist = "/etc/capwap/casoap.crt"; certificate = "/etc/capwap/clientsoap.crt"; privatekey = "/etc/capwap/clientsoap.key"; }; } - ); -}; - -logging: { - enable = true; - level = "debug"; - output = ( - { mode = "stdout"; } - ); -}; +# AC configuration file + +version = "1.0"; + +application: { + standalone = true; + + name = "ac 1"; + + binding = [ + "802.11" + ]; + + descriptor: { + maxstations = 20; + maxwtp = 10; + + security: { + presharedkey = false; + x509 = false; + }; + + rmacfiled: { + supported = false; + }; + + dtlspolicy: { + cleardatachannel = true; + dtlsdatachannel = true; + }; + + info = ( + { idvendor = 12345; type = "hardware"; value = "1.0"; }, + { idvendor = 33457; type = "software"; value = "2.0"; } + ); + }; + + ecn = "limited"; + + timer: { + discovery = 20; + echorequest = 30; + decrypterrorreport = 120; + idletimeout = 320; + }; + + wtpfallback = true; + + dtls: { + enable = true; + + type = "x509"; + + presharedkey: { + hint = "esempio"; + identity = "prova"; + pskkey = "123456"; + }; + + x509: { + calist = "/etc/capwap/ca.crt"; + certificate = "/etc/capwap/ac.crt"; + privatekey = "/etc/capwap/ac.key"; + }; + }; + + network: { + #binding = "eth1"; + #listen = ""; + transport = "udp"; + mtu = 1400; + }; +}; + +backend: { + id = "1"; + version = "1.0"; + server: ( + { url = "http://127.0.0.1/csoap.php"; } + #{ url = "https://127.0.0.1/csoap.php"; x509: { calist = "/etc/capwap/casoap.crt"; certificate = "/etc/capwap/clientsoap.crt"; privatekey = "/etc/capwap/clientsoap.key"; }; } + ); +}; + +logging: { + enable = true; + level = "debug"; + output = ( + { mode = "stdout"; } + ); +}; diff --git a/conf/wtp.conf b/conf/wtp.conf index 32d5e28..8748c79 100755 --- a/conf/wtp.conf +++ b/conf/wtp.conf @@ -1,147 +1,147 @@ -# WTP configuration file - -version = "1.0"; - -application: { - standalone = true; - - name = "wtp 1"; - - location = "Ufficio"; - - binding = "802.11"; - - tunnelmode: { - nativeframe = false; - ethframe = false; - localbridging = true; - }; - - mactype = "localmac"; - - boardinfo: { - idvendor = 123456; - - element = ( - { name = "model"; value = "1.0"; }, - { name = "serial"; value = "2.0"; }, - { name = "id"; value = "3.0"; }, - { name = "revision"; value = "4.0"; }, - { name = "macaddress"; type = "interface"; value = "eth1"; } - ); - }; - - descriptor: { - encryption = [ - "802.11_AES", - "802.11_TKIP" - ]; - - info = ( - { idvendor = 23456; type = "hardware"; value = "abcde"; }, - { idvendor = 33457; type = "software"; value = "fghil"; }, - { idvendor = 43458; type = "boot"; value = "mnopq"; }, - { idvendor = 53459; type = "other"; value = "qwert"; } - ); - }; - - ecn = "limited"; - - timer: { - statistics = 120; - }; - - dtls: { - enable = true; - - dtlspolicy: { - cleardatachannel = true; - dtlsdatachannel = true; - }; - - type = "x509"; - - presharedkey: { - identity = "prova"; - pskkey = "123456"; - }; - - x509: { - calist = "/etc/capwap/ca.crt"; - certificate = "/etc/capwap/wtp.crt"; - privatekey = "/etc/capwap/wtp.key"; - }; - }; - - wlan: { - prefix = "ap"; - }; - - radio = ( - { - device = "phy0"; - enabled = true; - driver = "nl80211"; - mode = "g"; - country = "IT"; - outdoor = false; - rtsthreshold = 2347; - shortretry = 7; - longretry = 4; - shortpreamble = true; - fragmentationthreshold = 2346; - txmsdulifetime = 512; - rxmsdulifetime = 512; - maxbssid = 1; - bssprefixname = "ap"; - dtimperiod = 1; - beaconperiod = 100; - antenna = { - diversity = false; - combiner = "omni"; - selection = [ "internal" ]; - }; - multidomaincapability = { - firstchannel = 1; - numberchannels = 11; - maxtxpower = 100; - }; - supportedrates = [ - 12, 18, 24, 36, 48, 72, 96, 108 - ]; - txpower = { - current = 100; - supported = [ 100 ]; - }; - } - ); - - network: { - #binding = "eth1"; - #listen = ""; - #port = 0; - transport = "udp"; - mtu = 1400; - }; - - acdiscovery: { - search = true; - host = [ - "127.0.0.1" - ]; - }; - - acprefered: { - host = [ - "127.0.0.1" - ]; - }; -}; - -logging: { - enable = true; - level = "debug"; - output = ( - { mode = "stdout"; } - ); -}; +# WTP configuration file + +version = "1.0"; + +application: { + standalone = true; + + name = "wtp 1"; + + location = "Ufficio"; + + binding = "802.11"; + + tunnelmode: { + nativeframe = false; + ethframe = false; + localbridging = true; + }; + + mactype = "localmac"; + + boardinfo: { + idvendor = 123456; + + element = ( + { name = "model"; value = "1.0"; }, + { name = "serial"; value = "2.0"; }, + { name = "id"; value = "3.0"; }, + { name = "revision"; value = "4.0"; }, + { name = "macaddress"; type = "interface"; value = "eth1"; } + ); + }; + + descriptor: { + encryption = [ + "802.11_AES", + "802.11_TKIP" + ]; + + info = ( + { idvendor = 23456; type = "hardware"; value = "abcde"; }, + { idvendor = 33457; type = "software"; value = "fghil"; }, + { idvendor = 43458; type = "boot"; value = "mnopq"; }, + { idvendor = 53459; type = "other"; value = "qwert"; } + ); + }; + + ecn = "limited"; + + timer: { + statistics = 120; + }; + + dtls: { + enable = true; + + dtlspolicy: { + cleardatachannel = true; + dtlsdatachannel = true; + }; + + type = "x509"; + + presharedkey: { + identity = "prova"; + pskkey = "123456"; + }; + + x509: { + calist = "/etc/capwap/ca.crt"; + certificate = "/etc/capwap/wtp.crt"; + privatekey = "/etc/capwap/wtp.key"; + }; + }; + + wlan: { + prefix = "ap"; + }; + + radio = ( + { + device = "phy0"; + enabled = true; + driver = "nl80211"; + mode = "g"; + country = "IT"; + outdoor = false; + rtsthreshold = 2347; + shortretry = 7; + longretry = 4; + shortpreamble = true; + fragmentationthreshold = 2346; + txmsdulifetime = 512; + rxmsdulifetime = 512; + maxbssid = 1; + bssprefixname = "ap"; + dtimperiod = 1; + beaconperiod = 100; + antenna = { + diversity = false; + combiner = "omni"; + selection = [ "internal" ]; + }; + multidomaincapability = { + firstchannel = 1; + numberchannels = 11; + maxtxpower = 100; + }; + supportedrates = [ + 12, 18, 24, 36, 48, 72, 96, 108 + ]; + txpower = { + current = 100; + supported = [ 100 ]; + }; + } + ); + + network: { + #binding = "eth1"; + #listen = ""; + #port = 0; + transport = "udp"; + mtu = 1400; + }; + + acdiscovery: { + search = true; + host = [ + "127.0.0.1" + ]; + }; + + acprefered: { + host = [ + "127.0.0.1" + ]; + }; +}; + +logging: { + enable = true; + level = "debug"; + output = ( + { mode = "stdout"; } + ); +}; diff --git a/src/ac/ac_80211_json.c b/src/ac/ac_80211_json.c index 2dbc846..d24faf0 100644 --- a/src/ac/ac_80211_json.c +++ b/src/ac/ac_80211_json.c @@ -1,470 +1,470 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static struct ac_json_ieee80211_ops* ac_json_80211_message_elements[] = { - /* CAPWAP_ELEMENT_80211_ADD_WLAN */ &ac_json_80211_addwlan_ops, - /* CAPWAP_ELEMENT_80211_ANTENNA */ &ac_json_80211_antenna_ops, - /* CAPWAP_ELEMENT_80211_ASSIGN_BSSID */ &ac_json_80211_assignbssid_ops, - /* CAPWAP_ELEMENT_80211_DELETE_WLAN */ &ac_json_80211_deletewlan_ops, - /* CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL */ &ac_json_80211_directsequencecontrol_ops, - /* CAPWAP_ELEMENT_80211_IE */ &ac_json_80211_ie_ops, - /* CAPWAP_ELEMENT_80211_MACOPERATION */ &ac_json_80211_macoperation_ops, - /* CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES */ &ac_json_80211_miccountermeasures_ops, - /* CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY */ &ac_json_80211_multidomaincapability_ops, - /* CAPWAP_ELEMENT_80211_OFDMCONTROL */ &ac_json_80211_ofdmcontrol_ops, - /* CAPWAP_ELEMENT_80211_RATESET */ &ac_json_80211_rateset_ops, - /* CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT */ &ac_json_80211_rsnaerrorreport_ops, - /* CAPWAP_ELEMENT_80211_STATION */ NULL, - /* CAPWAP_ELEMENT_80211_STATION_QOS_PROFILE */ NULL, - /* CAPWAP_ELEMENT_80211_STATION_SESSION_KEY_PROFILE */ NULL, - /* CAPWAP_ELEMENT_80211_STATISTICS */ &ac_json_80211_statistics_ops, - /* CAPWAP_ELEMENT_80211_SUPPORTEDRATES */ &ac_json_80211_supportedrates_ops, - /* CAPWAP_ELEMENT_80211_TXPOWER */ &ac_json_80211_txpower_ops, - /* CAPWAP_ELEMENT_80211_TXPOWERLEVEL */ &ac_json_80211_txpowerlevel_ops, - /* CAPWAP_ELEMENT_80211_UPDATE_STATION_QOS */ NULL, - /* CAPWAP_ELEMENT_80211_UPDATE_WLAN */ &ac_json_80211_updatewlan_ops, - /* CAPWAP_ELEMENT_80211_WTP_QOS */ &ac_json_80211_wtpqos_ops, - /* CAPWAP_ELEMENT_80211_WTP_RADIO_CONF */ &ac_json_80211_wtpradioconf_ops, - /* CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM */ &ac_json_80211_wtpradiofailalarm_ops, - /* CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION */ &ac_json_80211_wtpradioinformation_ops -}; - -/* */ -static struct ac_json_ieee80211_ops* ac_json_80211_getops_by_capwaptype(uint16_t type) { - int i; - - for (i = 0; i < CAPWAP_80211_MESSAGE_ELEMENTS_COUNT; i++) { - if (ac_json_80211_message_elements[i] && (ac_json_80211_message_elements[i]->type == type)) { - return ac_json_80211_message_elements[i]; - } - } - - return NULL; -} - -/* */ -static struct ac_json_ieee80211_ops* ac_json_80211_getops_by_jsontype(char* type) { - int i; - - for (i = 0; i < CAPWAP_80211_MESSAGE_ELEMENTS_COUNT; i++) { - if (ac_json_80211_message_elements[i] && !strcmp(ac_json_80211_message_elements[i]->json_type, type)) { - return ac_json_80211_message_elements[i]; - } - } - - return NULL; -} - -/* */ -void ac_json_ieee80211_init(struct ac_json_ieee80211_wtpradio* wtpradio) { - ASSERT(wtpradio != NULL); - - memset(wtpradio, 0, sizeof(struct ac_json_ieee80211_wtpradio)); -} - -/* */ -void ac_json_ieee80211_free(struct ac_json_ieee80211_wtpradio* wtpradio) { - int i, j; - - ASSERT(wtpradio != NULL); - - for (i = 0; i < RADIOID_MAX_COUNT; i++) { - struct ac_json_ieee80211_item* item = &wtpradio->items[i]; - - if (item->valid) { - if (item->addwlan) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ADD_WLAN)->free_message_element(item->addwlan); - } - - if (item->antenna) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ANTENNA)->free_message_element(item->antenna); - } - - if (item->assignbssid) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ASSIGN_BSSID)->free_message_element(item->assignbssid); - } - - if (item->deletewlan) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DELETE_WLAN)->free_message_element(item->deletewlan); - } - - if (item->directsequencecontrol) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL)->free_message_element(item->directsequencecontrol); - } - - if (item->iearray) { - struct capwap_message_elements_ops* ieops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_IE); - - for (j = 0; j < item->iearray->count; j++) { - ieops->free_message_element(*(struct capwap_80211_ie_element**)capwap_array_get_item_pointer(item->iearray, j)); - } - - capwap_array_free(item->iearray); - } - - if (item->macoperation) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MACOPERATION)->free_message_element(item->macoperation); - } - - if (item->miccountermeasures) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES)->free_message_element(item->miccountermeasures); - } - - if (item->multidomaincapability) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY)->free_message_element(item->multidomaincapability); - } - - if (item->ofdmcontrol) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_OFDMCONTROL)->free_message_element(item->ofdmcontrol); - } - - if (item->rateset) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RATESET)->free_message_element(item->rateset); - } - - if (item->rsnaerrorreport) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT)->free_message_element(item->rsnaerrorreport); - } - - if (item->statistics) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_STATISTICS)->free_message_element(item->statistics); - } - - if (item->supportedrates) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_SUPPORTEDRATES)->free_message_element(item->supportedrates); - } - - if (item->txpower) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWER)->free_message_element(item->txpower); - } - - if (item->txpowerlevel) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWERLEVEL)->free_message_element(item->txpowerlevel); - } - - if (item->updatewlan) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_UPDATE_WLAN)->free_message_element(item->updatewlan); - } - - if (item->wtpqos) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_QOS)->free_message_element(item->wtpqos); - } - - if (item->wtpradioconf) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_CONF)->free_message_element(item->wtpradioconf); - } - - if (item->wtpradiofailalarm) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM)->free_message_element(item->wtpradiofailalarm); - } - - if (item->wtpradioinformation) { - capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)->free_message_element(item->wtpradioinformation); - } - } - } -} - -/* */ -int ac_json_ieee80211_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, uint16_t type, void* data, int overwrite) { - struct ac_json_ieee80211_ops* ops; - - ASSERT(wtpradio != NULL); - ASSERT(IS_80211_MESSAGE_ELEMENTS(type)); - ASSERT(data != NULL); - - /* */ - ops = ac_json_80211_getops_by_capwaptype(type); - if (!ops) { - return 0; - } - - return ops->add_message_element(wtpradio, data, overwrite); -} - -/* */ -int ac_json_ieee80211_parsingmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_message_element_itemlist* messageelement) { - int i; - - ASSERT(wtpradio != NULL); - ASSERT(messageelement != NULL); - ASSERT(IS_80211_MESSAGE_ELEMENTS(messageelement->type)); - - if (messageelement->category == CAPWAP_MESSAGE_ELEMENT_SINGLE) { - if (!ac_json_ieee80211_addmessageelement(wtpradio, messageelement->type, messageelement->data, 0)) { - return 0; - } - } else if (messageelement->category == CAPWAP_MESSAGE_ELEMENT_ARRAY) { - struct capwap_array* items = (struct capwap_array*)messageelement->data; - - for (i = 0; i < items->count; i++) { - if (!ac_json_ieee80211_addmessageelement(wtpradio, messageelement->type, *(void**)capwap_array_get_item_pointer(items, i), 0)) { - return 0; - } - } - } else { - return 0; - } - - return 1; -} - -/* */ -int ac_json_ieee80211_parsingjson(struct ac_json_ieee80211_wtpradio* wtpradio, struct json_object* jsonroot) { - int i; - int length; - - ASSERT(wtpradio != NULL); - ASSERT(jsonroot != NULL); - - if (json_object_get_type(jsonroot) != json_type_array) { - return 0; - } - - /* */ - length = json_object_array_length(jsonroot); - for (i = 0; i < length; i++) { - struct json_object* jsonitem; - struct json_object* jsonradio = json_object_array_get_idx(jsonroot, i); - - /* Get RadioID */ - jsonitem = compat_json_object_object_get(jsonradio, "RadioID"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - int radioid = json_object_get_int(jsonitem); - if (IS_VALID_RADIOID(radioid)) { - struct lh_entry* entry; - - /* Parsing every entry */ - for(entry = json_object_get_object(jsonradio)->head; entry != NULL; entry = entry->next) { - struct ac_json_ieee80211_ops* ops = ac_json_80211_getops_by_jsontype((char*)entry->k); /* Retrieve JSON handler */ - if (ops) { - void* data = ops->create_message_element((struct json_object*)entry->v, radioid); - if (data) { - /* Message element complete */ - ac_json_ieee80211_addmessageelement(wtpradio, ops->type, data, 1); - - /* Free resource */ - capwap_get_message_element_ops(ops->type)->free_message_element(data); - } - } - } - } - } - } - - return 1; -} - -/* */ -struct json_object* ac_json_ieee80211_getjson(struct ac_json_ieee80211_wtpradio* wtpradio) { - int i; - struct json_object* jsonarray; - struct json_object* jsonitems; - - ASSERT(wtpradio != NULL); - - jsonarray = json_object_new_array(); - for (i = 0; i < RADIOID_MAX_COUNT; i++) { - struct ac_json_ieee80211_item* item = &wtpradio->items[i]; - - if (!item->valid) { - continue; - } - - /* */ - jsonitems = json_object_new_object(); - - /* Radio Id */ - json_object_object_add(jsonitems, "RadioID", json_object_new_int(i + 1)); - - if (item->addwlan) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_ADD_WLAN)->create_json(jsonitems, item->addwlan); - } - - if (item->antenna) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_ANTENNA)->create_json(jsonitems, item->antenna); - } - - if (item->assignbssid) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_ASSIGN_BSSID)->create_json(jsonitems, item->assignbssid); - } - - if (item->deletewlan) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_DELETE_WLAN)->create_json(jsonitems, item->deletewlan); - } - - if (item->directsequencecontrol) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL)->create_json(jsonitems, item->directsequencecontrol); - } - - if (item->iearray) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_IE)->create_json(jsonitems, item->iearray); - } - - if (item->macoperation) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_MACOPERATION)->create_json(jsonitems, item->macoperation); - } - - if (item->miccountermeasures) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES)->create_json(jsonitems, item->miccountermeasures); - } - - if (item->multidomaincapability) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY)->create_json(jsonitems, item->multidomaincapability); - } - - if (item->ofdmcontrol) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_OFDMCONTROL)->create_json(jsonitems, item->ofdmcontrol); - } - - if (item->rateset) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_RATESET)->create_json(jsonitems, item->rateset); - } - - if (item->rsnaerrorreport) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT)->create_json(jsonitems, item->rsnaerrorreport); - } - - if (item->statistics) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_STATISTICS)->create_json(jsonitems, item->statistics); - } - - if (item->supportedrates) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_SUPPORTEDRATES)->create_json(jsonitems, item->supportedrates); - } - - if (item->txpower) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_TXPOWER)->create_json(jsonitems, item->txpower); - } - - if (item->txpowerlevel) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_TXPOWERLEVEL)->create_json(jsonitems, item->txpowerlevel); - } - - if (item->updatewlan) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_UPDATE_WLAN)->create_json(jsonitems, item->updatewlan); - } - - if (item->wtpqos) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTP_QOS)->create_json(jsonitems, item->wtpqos); - } - - if (item->wtpradioconf) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTP_RADIO_CONF)->create_json(jsonitems, item->wtpradioconf); - } - - if (item->wtpradiofailalarm) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM)->create_json(jsonitems, item->wtpradiofailalarm); - } - - if (item->wtpradioinformation) { - ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)->create_json(jsonitems, item->wtpradioinformation); - } - - /* */ - json_object_array_add(jsonarray, jsonitems); - } - - return jsonarray; -} - -/* */ -void ac_json_ieee80211_buildpacket(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_packet_txmng* txmngpacket) { - int i, j; - - ASSERT(wtpradio != NULL); - ASSERT(txmngpacket != NULL); - - for (i = 0; i < RADIOID_MAX_COUNT; i++) { - struct ac_json_ieee80211_item* item = &wtpradio->items[i]; - - if (item->valid) { - if (item->addwlan) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ADD_WLAN, item->addwlan); - } - - if (item->antenna) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ANTENNA, item->antenna); - } - - if (item->assignbssid) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ASSIGN_BSSID, item->assignbssid); - } - - if (item->deletewlan) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_DELETE_WLAN, item->deletewlan); - } - - if (item->directsequencecontrol) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL, item->directsequencecontrol); - } - - if (item->iearray) { - for (j = 0; j < item->iearray->count; j++) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_IE, *(struct capwap_80211_ie_element**)capwap_array_get_item_pointer(item->iearray, j)); - } - } - - if (item->macoperation) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_MACOPERATION, item->macoperation); - } - - if (item->miccountermeasures) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES, item->miccountermeasures); - } - - if (item->multidomaincapability) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY, item->multidomaincapability); - } - - if (item->ofdmcontrol) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_OFDMCONTROL, item->ofdmcontrol); - } - - if (item->rateset) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_RATESET, item->rateset); - } - - if (item->rsnaerrorreport) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT, item->rsnaerrorreport); - } - - if (item->statistics) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_STATISTICS, item->statistics); - } - - if (item->supportedrates) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_SUPPORTEDRATES, item->supportedrates); - } - - if (item->txpower) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_TXPOWER, item->txpower); - } - - if (item->txpowerlevel) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_TXPOWERLEVEL, item->txpowerlevel); - } - - if (item->updatewlan) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_UPDATE_WLAN, item->updatewlan); - } - - if (item->wtpqos) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTP_QOS, item->wtpqos); - } - - if (item->wtpradioconf) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTP_RADIO_CONF, item->wtpradioconf); - } - - if (item->wtpradiofailalarm) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM, item->wtpradiofailalarm); - } - - if (item->wtpradioinformation) { - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION, item->wtpradioinformation); - } - } - } -} +#include "ac.h" +#include "ac_json.h" + +/* */ +static struct ac_json_ieee80211_ops* ac_json_80211_message_elements[] = { + /* CAPWAP_ELEMENT_80211_ADD_WLAN */ &ac_json_80211_addwlan_ops, + /* CAPWAP_ELEMENT_80211_ANTENNA */ &ac_json_80211_antenna_ops, + /* CAPWAP_ELEMENT_80211_ASSIGN_BSSID */ &ac_json_80211_assignbssid_ops, + /* CAPWAP_ELEMENT_80211_DELETE_WLAN */ &ac_json_80211_deletewlan_ops, + /* CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL */ &ac_json_80211_directsequencecontrol_ops, + /* CAPWAP_ELEMENT_80211_IE */ &ac_json_80211_ie_ops, + /* CAPWAP_ELEMENT_80211_MACOPERATION */ &ac_json_80211_macoperation_ops, + /* CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES */ &ac_json_80211_miccountermeasures_ops, + /* CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY */ &ac_json_80211_multidomaincapability_ops, + /* CAPWAP_ELEMENT_80211_OFDMCONTROL */ &ac_json_80211_ofdmcontrol_ops, + /* CAPWAP_ELEMENT_80211_RATESET */ &ac_json_80211_rateset_ops, + /* CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT */ &ac_json_80211_rsnaerrorreport_ops, + /* CAPWAP_ELEMENT_80211_STATION */ NULL, + /* CAPWAP_ELEMENT_80211_STATION_QOS_PROFILE */ NULL, + /* CAPWAP_ELEMENT_80211_STATION_SESSION_KEY_PROFILE */ NULL, + /* CAPWAP_ELEMENT_80211_STATISTICS */ &ac_json_80211_statistics_ops, + /* CAPWAP_ELEMENT_80211_SUPPORTEDRATES */ &ac_json_80211_supportedrates_ops, + /* CAPWAP_ELEMENT_80211_TXPOWER */ &ac_json_80211_txpower_ops, + /* CAPWAP_ELEMENT_80211_TXPOWERLEVEL */ &ac_json_80211_txpowerlevel_ops, + /* CAPWAP_ELEMENT_80211_UPDATE_STATION_QOS */ NULL, + /* CAPWAP_ELEMENT_80211_UPDATE_WLAN */ &ac_json_80211_updatewlan_ops, + /* CAPWAP_ELEMENT_80211_WTP_QOS */ &ac_json_80211_wtpqos_ops, + /* CAPWAP_ELEMENT_80211_WTP_RADIO_CONF */ &ac_json_80211_wtpradioconf_ops, + /* CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM */ &ac_json_80211_wtpradiofailalarm_ops, + /* CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION */ &ac_json_80211_wtpradioinformation_ops +}; + +/* */ +static struct ac_json_ieee80211_ops* ac_json_80211_getops_by_capwaptype(uint16_t type) { + int i; + + for (i = 0; i < CAPWAP_80211_MESSAGE_ELEMENTS_COUNT; i++) { + if (ac_json_80211_message_elements[i] && (ac_json_80211_message_elements[i]->type == type)) { + return ac_json_80211_message_elements[i]; + } + } + + return NULL; +} + +/* */ +static struct ac_json_ieee80211_ops* ac_json_80211_getops_by_jsontype(char* type) { + int i; + + for (i = 0; i < CAPWAP_80211_MESSAGE_ELEMENTS_COUNT; i++) { + if (ac_json_80211_message_elements[i] && !strcmp(ac_json_80211_message_elements[i]->json_type, type)) { + return ac_json_80211_message_elements[i]; + } + } + + return NULL; +} + +/* */ +void ac_json_ieee80211_init(struct ac_json_ieee80211_wtpradio* wtpradio) { + ASSERT(wtpradio != NULL); + + memset(wtpradio, 0, sizeof(struct ac_json_ieee80211_wtpradio)); +} + +/* */ +void ac_json_ieee80211_free(struct ac_json_ieee80211_wtpradio* wtpradio) { + int i, j; + + ASSERT(wtpradio != NULL); + + for (i = 0; i < RADIOID_MAX_COUNT; i++) { + struct ac_json_ieee80211_item* item = &wtpradio->items[i]; + + if (item->valid) { + if (item->addwlan) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ADD_WLAN)->free_message_element(item->addwlan); + } + + if (item->antenna) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ANTENNA)->free_message_element(item->antenna); + } + + if (item->assignbssid) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ASSIGN_BSSID)->free_message_element(item->assignbssid); + } + + if (item->deletewlan) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DELETE_WLAN)->free_message_element(item->deletewlan); + } + + if (item->directsequencecontrol) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL)->free_message_element(item->directsequencecontrol); + } + + if (item->iearray) { + struct capwap_message_elements_ops* ieops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_IE); + + for (j = 0; j < item->iearray->count; j++) { + ieops->free_message_element(*(struct capwap_80211_ie_element**)capwap_array_get_item_pointer(item->iearray, j)); + } + + capwap_array_free(item->iearray); + } + + if (item->macoperation) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MACOPERATION)->free_message_element(item->macoperation); + } + + if (item->miccountermeasures) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES)->free_message_element(item->miccountermeasures); + } + + if (item->multidomaincapability) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY)->free_message_element(item->multidomaincapability); + } + + if (item->ofdmcontrol) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_OFDMCONTROL)->free_message_element(item->ofdmcontrol); + } + + if (item->rateset) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RATESET)->free_message_element(item->rateset); + } + + if (item->rsnaerrorreport) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT)->free_message_element(item->rsnaerrorreport); + } + + if (item->statistics) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_STATISTICS)->free_message_element(item->statistics); + } + + if (item->supportedrates) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_SUPPORTEDRATES)->free_message_element(item->supportedrates); + } + + if (item->txpower) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWER)->free_message_element(item->txpower); + } + + if (item->txpowerlevel) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWERLEVEL)->free_message_element(item->txpowerlevel); + } + + if (item->updatewlan) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_UPDATE_WLAN)->free_message_element(item->updatewlan); + } + + if (item->wtpqos) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_QOS)->free_message_element(item->wtpqos); + } + + if (item->wtpradioconf) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_CONF)->free_message_element(item->wtpradioconf); + } + + if (item->wtpradiofailalarm) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM)->free_message_element(item->wtpradiofailalarm); + } + + if (item->wtpradioinformation) { + capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)->free_message_element(item->wtpradioinformation); + } + } + } +} + +/* */ +int ac_json_ieee80211_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, uint16_t type, void* data, int overwrite) { + struct ac_json_ieee80211_ops* ops; + + ASSERT(wtpradio != NULL); + ASSERT(IS_80211_MESSAGE_ELEMENTS(type)); + ASSERT(data != NULL); + + /* */ + ops = ac_json_80211_getops_by_capwaptype(type); + if (!ops) { + return 0; + } + + return ops->add_message_element(wtpradio, data, overwrite); +} + +/* */ +int ac_json_ieee80211_parsingmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_message_element_itemlist* messageelement) { + int i; + + ASSERT(wtpradio != NULL); + ASSERT(messageelement != NULL); + ASSERT(IS_80211_MESSAGE_ELEMENTS(messageelement->type)); + + if (messageelement->category == CAPWAP_MESSAGE_ELEMENT_SINGLE) { + if (!ac_json_ieee80211_addmessageelement(wtpradio, messageelement->type, messageelement->data, 0)) { + return 0; + } + } else if (messageelement->category == CAPWAP_MESSAGE_ELEMENT_ARRAY) { + struct capwap_array* items = (struct capwap_array*)messageelement->data; + + for (i = 0; i < items->count; i++) { + if (!ac_json_ieee80211_addmessageelement(wtpradio, messageelement->type, *(void**)capwap_array_get_item_pointer(items, i), 0)) { + return 0; + } + } + } else { + return 0; + } + + return 1; +} + +/* */ +int ac_json_ieee80211_parsingjson(struct ac_json_ieee80211_wtpradio* wtpradio, struct json_object* jsonroot) { + int i; + int length; + + ASSERT(wtpradio != NULL); + ASSERT(jsonroot != NULL); + + if (json_object_get_type(jsonroot) != json_type_array) { + return 0; + } + + /* */ + length = json_object_array_length(jsonroot); + for (i = 0; i < length; i++) { + struct json_object* jsonitem; + struct json_object* jsonradio = json_object_array_get_idx(jsonroot, i); + + /* Get RadioID */ + jsonitem = compat_json_object_object_get(jsonradio, "RadioID"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + int radioid = json_object_get_int(jsonitem); + if (IS_VALID_RADIOID(radioid)) { + struct lh_entry* entry; + + /* Parsing every entry */ + for(entry = json_object_get_object(jsonradio)->head; entry != NULL; entry = entry->next) { + struct ac_json_ieee80211_ops* ops = ac_json_80211_getops_by_jsontype((char*)entry->k); /* Retrieve JSON handler */ + if (ops) { + void* data = ops->create_message_element((struct json_object*)entry->v, radioid); + if (data) { + /* Message element complete */ + ac_json_ieee80211_addmessageelement(wtpradio, ops->type, data, 1); + + /* Free resource */ + capwap_get_message_element_ops(ops->type)->free_message_element(data); + } + } + } + } + } + } + + return 1; +} + +/* */ +struct json_object* ac_json_ieee80211_getjson(struct ac_json_ieee80211_wtpradio* wtpradio) { + int i; + struct json_object* jsonarray; + struct json_object* jsonitems; + + ASSERT(wtpradio != NULL); + + jsonarray = json_object_new_array(); + for (i = 0; i < RADIOID_MAX_COUNT; i++) { + struct ac_json_ieee80211_item* item = &wtpradio->items[i]; + + if (!item->valid) { + continue; + } + + /* */ + jsonitems = json_object_new_object(); + + /* Radio Id */ + json_object_object_add(jsonitems, "RadioID", json_object_new_int(i + 1)); + + if (item->addwlan) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_ADD_WLAN)->create_json(jsonitems, item->addwlan); + } + + if (item->antenna) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_ANTENNA)->create_json(jsonitems, item->antenna); + } + + if (item->assignbssid) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_ASSIGN_BSSID)->create_json(jsonitems, item->assignbssid); + } + + if (item->deletewlan) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_DELETE_WLAN)->create_json(jsonitems, item->deletewlan); + } + + if (item->directsequencecontrol) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL)->create_json(jsonitems, item->directsequencecontrol); + } + + if (item->iearray) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_IE)->create_json(jsonitems, item->iearray); + } + + if (item->macoperation) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_MACOPERATION)->create_json(jsonitems, item->macoperation); + } + + if (item->miccountermeasures) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES)->create_json(jsonitems, item->miccountermeasures); + } + + if (item->multidomaincapability) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY)->create_json(jsonitems, item->multidomaincapability); + } + + if (item->ofdmcontrol) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_OFDMCONTROL)->create_json(jsonitems, item->ofdmcontrol); + } + + if (item->rateset) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_RATESET)->create_json(jsonitems, item->rateset); + } + + if (item->rsnaerrorreport) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT)->create_json(jsonitems, item->rsnaerrorreport); + } + + if (item->statistics) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_STATISTICS)->create_json(jsonitems, item->statistics); + } + + if (item->supportedrates) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_SUPPORTEDRATES)->create_json(jsonitems, item->supportedrates); + } + + if (item->txpower) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_TXPOWER)->create_json(jsonitems, item->txpower); + } + + if (item->txpowerlevel) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_TXPOWERLEVEL)->create_json(jsonitems, item->txpowerlevel); + } + + if (item->updatewlan) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_UPDATE_WLAN)->create_json(jsonitems, item->updatewlan); + } + + if (item->wtpqos) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTP_QOS)->create_json(jsonitems, item->wtpqos); + } + + if (item->wtpradioconf) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTP_RADIO_CONF)->create_json(jsonitems, item->wtpradioconf); + } + + if (item->wtpradiofailalarm) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM)->create_json(jsonitems, item->wtpradiofailalarm); + } + + if (item->wtpradioinformation) { + ac_json_80211_getops_by_capwaptype(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION)->create_json(jsonitems, item->wtpradioinformation); + } + + /* */ + json_object_array_add(jsonarray, jsonitems); + } + + return jsonarray; +} + +/* */ +void ac_json_ieee80211_buildpacket(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_packet_txmng* txmngpacket) { + int i, j; + + ASSERT(wtpradio != NULL); + ASSERT(txmngpacket != NULL); + + for (i = 0; i < RADIOID_MAX_COUNT; i++) { + struct ac_json_ieee80211_item* item = &wtpradio->items[i]; + + if (item->valid) { + if (item->addwlan) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ADD_WLAN, item->addwlan); + } + + if (item->antenna) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ANTENNA, item->antenna); + } + + if (item->assignbssid) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_ASSIGN_BSSID, item->assignbssid); + } + + if (item->deletewlan) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_DELETE_WLAN, item->deletewlan); + } + + if (item->directsequencecontrol) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL, item->directsequencecontrol); + } + + if (item->iearray) { + for (j = 0; j < item->iearray->count; j++) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_IE, *(struct capwap_80211_ie_element**)capwap_array_get_item_pointer(item->iearray, j)); + } + } + + if (item->macoperation) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_MACOPERATION, item->macoperation); + } + + if (item->miccountermeasures) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES, item->miccountermeasures); + } + + if (item->multidomaincapability) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY, item->multidomaincapability); + } + + if (item->ofdmcontrol) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_OFDMCONTROL, item->ofdmcontrol); + } + + if (item->rateset) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_RATESET, item->rateset); + } + + if (item->rsnaerrorreport) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT, item->rsnaerrorreport); + } + + if (item->statistics) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_STATISTICS, item->statistics); + } + + if (item->supportedrates) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_SUPPORTEDRATES, item->supportedrates); + } + + if (item->txpower) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_TXPOWER, item->txpower); + } + + if (item->txpowerlevel) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_TXPOWERLEVEL, item->txpowerlevel); + } + + if (item->updatewlan) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_UPDATE_WLAN, item->updatewlan); + } + + if (item->wtpqos) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTP_QOS, item->wtpqos); + } + + if (item->wtpradioconf) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTP_RADIO_CONF, item->wtpradioconf); + } + + if (item->wtpradiofailalarm) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM, item->wtpradiofailalarm); + } + + if (item->wtpradioinformation) { + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION, item->wtpradioinformation); + } + } + } +} diff --git a/src/ac/ac_80211_json_addwlan.c b/src/ac/ac_80211_json_addwlan.c index 22a251f..87d655b 100644 --- a/src/ac/ac_80211_json_addwlan.c +++ b/src/ac/ac_80211_json_addwlan.c @@ -1,41 +1,41 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_addwlan_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_addwlan_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_addwlan_element* addwlan = (struct capwap_80211_addwlan_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[addwlan->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ADD_WLAN); - - if (item->addwlan) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->addwlan); - } - - item->valid = 1; - item->addwlan = (struct capwap_80211_addwlan_element*)ops->clone_message_element(addwlan); - - return 1; -} - -/* */ -static void ac_json_80211_addwlan_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_addwlan_ops = { - .type = CAPWAP_ELEMENT_80211_ADD_WLAN, - .json_type = "IEEE80211AddWLAN", - .create_message_element = ac_json_80211_addwlan_createmessageelement, - .add_message_element = ac_json_80211_addwlan_addmessageelement, - .create_json = ac_json_80211_addwlan_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_addwlan_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_addwlan_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_addwlan_element* addwlan = (struct capwap_80211_addwlan_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[addwlan->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ADD_WLAN); + + if (item->addwlan) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->addwlan); + } + + item->valid = 1; + item->addwlan = (struct capwap_80211_addwlan_element*)ops->clone_message_element(addwlan); + + return 1; +} + +/* */ +static void ac_json_80211_addwlan_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_addwlan_ops = { + .type = CAPWAP_ELEMENT_80211_ADD_WLAN, + .json_type = "IEEE80211AddWLAN", + .create_message_element = ac_json_80211_addwlan_createmessageelement, + .add_message_element = ac_json_80211_addwlan_addmessageelement, + .create_json = ac_json_80211_addwlan_createjson +}; diff --git a/src/ac/ac_80211_json_addwlan.h b/src/ac/ac_80211_json_addwlan.h index 89171fd..3e32440 100644 --- a/src/ac/ac_80211_json_addwlan.h +++ b/src/ac/ac_80211_json_addwlan.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_ADDWLAN_HEADER__ -#define __AC_JSON_80211_ADDWLAN_HEADER__ - -#include "capwap_element_80211_addwlan.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_addwlan_ops; - -#endif /* __AC_JSON_80211_ADDWLAN_HEADER__ */ +#ifndef __AC_JSON_80211_ADDWLAN_HEADER__ +#define __AC_JSON_80211_ADDWLAN_HEADER__ + +#include "capwap_element_80211_addwlan.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_addwlan_ops; + +#endif /* __AC_JSON_80211_ADDWLAN_HEADER__ */ diff --git a/src/ac/ac_80211_json_antenna.c b/src/ac/ac_80211_json_antenna.c index 4e41c4c..57b0e7f 100644 --- a/src/ac/ac_80211_json_antenna.c +++ b/src/ac/ac_80211_json_antenna.c @@ -1,109 +1,109 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211Antenna: { - Diversity: [bool], - Combiner: [int], - AntennaSelection: [ - [int] - ] -} -*/ - -/* */ -static void* ac_json_80211_antenna_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_antenna_element* antenna; - - antenna = (struct capwap_80211_antenna_element*)capwap_alloc(sizeof(struct capwap_80211_antenna_element)); - memset(antenna, 0, sizeof(struct capwap_80211_antenna_element)); - antenna->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "Diversity"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_boolean)) { - antenna->diversity = (json_object_get_boolean(jsonitem) ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE); - } else { - capwap_free(antenna); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "Combiner"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - antenna->combiner = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(antenna); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "AntennaSelection"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_array)) { - int i; - int length; - - antenna->selections = capwap_array_create(sizeof(uint8_t), 0, 1); - - length = json_object_array_length(jsonitem); - for (i = 0; i < length; i++) { - struct json_object* jsonvalue = json_object_array_get_idx(jsonitem, i); - if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { - uint8_t* value = (uint8_t*)capwap_array_get_item_pointer(antenna->selections, antenna->selections->count); - *value = (uint8_t)json_object_get_int(jsonvalue); - } - } - } else { - capwap_free(antenna); - return NULL; - } - - return antenna; -} - -/* */ -static int ac_json_80211_antenna_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_antenna_element* antenna = (struct capwap_80211_antenna_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[antenna->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ANTENNA); - - if (item->antenna) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->antenna); - } - - item->valid = 1; - item->antenna = (struct capwap_80211_antenna_element*)ops->clone_message_element(antenna); - - return 1; -} - -/* */ -static void ac_json_80211_antenna_createjson(struct json_object* jsonparent, void* data) { - int i; - struct json_object* jsonantenna; - struct json_object* jsonitem; - struct capwap_80211_antenna_element* antenna = (struct capwap_80211_antenna_element*)data; - - jsonantenna = json_object_new_array(); - for (i = 0; i < antenna->selections->count; i++) { - json_object_array_add(jsonantenna, json_object_new_int((int)*(uint8_t*)capwap_array_get_item_pointer(antenna->selections, i))); - } - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "Diversity", json_object_new_boolean((antenna->diversity == CAPWAP_ANTENNA_DIVERSITY_ENABLE) ? 1 : 0)); - json_object_object_add(jsonitem, "Combiner", json_object_new_int((int)antenna->combiner)); - json_object_object_add(jsonitem, "AntennaSelection", jsonantenna); - json_object_object_add(jsonparent, "IEEE80211Antenna", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_antenna_ops = { - .type = CAPWAP_ELEMENT_80211_ANTENNA, - .json_type = "IEEE80211Antenna", - .create_message_element = ac_json_80211_antenna_createmessageelement, - .add_message_element = ac_json_80211_antenna_addmessageelement, - .create_json = ac_json_80211_antenna_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211Antenna: { + Diversity: [bool], + Combiner: [int], + AntennaSelection: [ + [int] + ] +} +*/ + +/* */ +static void* ac_json_80211_antenna_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_antenna_element* antenna; + + antenna = (struct capwap_80211_antenna_element*)capwap_alloc(sizeof(struct capwap_80211_antenna_element)); + memset(antenna, 0, sizeof(struct capwap_80211_antenna_element)); + antenna->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "Diversity"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_boolean)) { + antenna->diversity = (json_object_get_boolean(jsonitem) ? CAPWAP_ANTENNA_DIVERSITY_ENABLE : CAPWAP_ANTENNA_DIVERSITY_DISABLE); + } else { + capwap_free(antenna); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "Combiner"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + antenna->combiner = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(antenna); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "AntennaSelection"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_array)) { + int i; + int length; + + antenna->selections = capwap_array_create(sizeof(uint8_t), 0, 1); + + length = json_object_array_length(jsonitem); + for (i = 0; i < length; i++) { + struct json_object* jsonvalue = json_object_array_get_idx(jsonitem, i); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { + uint8_t* value = (uint8_t*)capwap_array_get_item_pointer(antenna->selections, antenna->selections->count); + *value = (uint8_t)json_object_get_int(jsonvalue); + } + } + } else { + capwap_free(antenna); + return NULL; + } + + return antenna; +} + +/* */ +static int ac_json_80211_antenna_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_antenna_element* antenna = (struct capwap_80211_antenna_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[antenna->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ANTENNA); + + if (item->antenna) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->antenna); + } + + item->valid = 1; + item->antenna = (struct capwap_80211_antenna_element*)ops->clone_message_element(antenna); + + return 1; +} + +/* */ +static void ac_json_80211_antenna_createjson(struct json_object* jsonparent, void* data) { + int i; + struct json_object* jsonantenna; + struct json_object* jsonitem; + struct capwap_80211_antenna_element* antenna = (struct capwap_80211_antenna_element*)data; + + jsonantenna = json_object_new_array(); + for (i = 0; i < antenna->selections->count; i++) { + json_object_array_add(jsonantenna, json_object_new_int((int)*(uint8_t*)capwap_array_get_item_pointer(antenna->selections, i))); + } + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "Diversity", json_object_new_boolean((antenna->diversity == CAPWAP_ANTENNA_DIVERSITY_ENABLE) ? 1 : 0)); + json_object_object_add(jsonitem, "Combiner", json_object_new_int((int)antenna->combiner)); + json_object_object_add(jsonitem, "AntennaSelection", jsonantenna); + json_object_object_add(jsonparent, "IEEE80211Antenna", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_antenna_ops = { + .type = CAPWAP_ELEMENT_80211_ANTENNA, + .json_type = "IEEE80211Antenna", + .create_message_element = ac_json_80211_antenna_createmessageelement, + .add_message_element = ac_json_80211_antenna_addmessageelement, + .create_json = ac_json_80211_antenna_createjson +}; diff --git a/src/ac/ac_80211_json_antenna.h b/src/ac/ac_80211_json_antenna.h index ce6c072..8ace14f 100644 --- a/src/ac/ac_80211_json_antenna.h +++ b/src/ac/ac_80211_json_antenna.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_ANTENNA_HEADER__ -#define __AC_JSON_80211_ANTENNA_HEADER__ - -#include "capwap_element_80211_antenna.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_antenna_ops; - -#endif /* __AC_JSON_80211_ANTENNA_HEADER__ */ +#ifndef __AC_JSON_80211_ANTENNA_HEADER__ +#define __AC_JSON_80211_ANTENNA_HEADER__ + +#include "capwap_element_80211_antenna.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_antenna_ops; + +#endif /* __AC_JSON_80211_ANTENNA_HEADER__ */ diff --git a/src/ac/ac_80211_json_assignbssid.c b/src/ac/ac_80211_json_assignbssid.c index c35c2a5..035769e 100644 --- a/src/ac/ac_80211_json_assignbssid.c +++ b/src/ac/ac_80211_json_assignbssid.c @@ -1,41 +1,41 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_assignbssid_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_assignbssid_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_assignbssid_element* assignbssid = (struct capwap_80211_assignbssid_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[assignbssid->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ASSIGN_BSSID); - - if (item->assignbssid) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->assignbssid); - } - - item->valid = 1; - item->assignbssid = (struct capwap_80211_assignbssid_element*)ops->clone_message_element(assignbssid); - - return 1; -} - -/* */ -static void ac_json_80211_assignbssid_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_assignbssid_ops = { - .type = CAPWAP_ELEMENT_80211_ASSIGN_BSSID, - .json_type = "IEEE80211AssignBSSID", - .create_message_element = ac_json_80211_assignbssid_createmessageelement, - .add_message_element = ac_json_80211_assignbssid_addmessageelement, - .create_json = ac_json_80211_assignbssid_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_assignbssid_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_assignbssid_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_assignbssid_element* assignbssid = (struct capwap_80211_assignbssid_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[assignbssid->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_ASSIGN_BSSID); + + if (item->assignbssid) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->assignbssid); + } + + item->valid = 1; + item->assignbssid = (struct capwap_80211_assignbssid_element*)ops->clone_message_element(assignbssid); + + return 1; +} + +/* */ +static void ac_json_80211_assignbssid_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_assignbssid_ops = { + .type = CAPWAP_ELEMENT_80211_ASSIGN_BSSID, + .json_type = "IEEE80211AssignBSSID", + .create_message_element = ac_json_80211_assignbssid_createmessageelement, + .add_message_element = ac_json_80211_assignbssid_addmessageelement, + .create_json = ac_json_80211_assignbssid_createjson +}; diff --git a/src/ac/ac_80211_json_assignbssid.h b/src/ac/ac_80211_json_assignbssid.h index 0e4593f..ff5fd35 100644 --- a/src/ac/ac_80211_json_assignbssid.h +++ b/src/ac/ac_80211_json_assignbssid.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_ASSIGNBSSID_HEADER__ -#define __AC_JSON_80211_ASSIGNBSSID_HEADER__ - -#include "capwap_element_80211_assignbssid.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_assignbssid_ops; - -#endif /* __AC_JSON_80211_ASSIGNBSSID_HEADER__ */ +#ifndef __AC_JSON_80211_ASSIGNBSSID_HEADER__ +#define __AC_JSON_80211_ASSIGNBSSID_HEADER__ + +#include "capwap_element_80211_assignbssid.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_assignbssid_ops; + +#endif /* __AC_JSON_80211_ASSIGNBSSID_HEADER__ */ diff --git a/src/ac/ac_80211_json_deletewlan.c b/src/ac/ac_80211_json_deletewlan.c index cbf9513..7a32b4f 100644 --- a/src/ac/ac_80211_json_deletewlan.c +++ b/src/ac/ac_80211_json_deletewlan.c @@ -1,41 +1,41 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_deletewlan_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_deletewlan_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_deletewlan_element* deletewlan = (struct capwap_80211_deletewlan_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[deletewlan->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DELETE_WLAN); - - if (item->deletewlan) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->deletewlan); - } - - item->valid = 1; - item->deletewlan = (struct capwap_80211_deletewlan_element*)ops->clone_message_element(deletewlan); - - return 1; -} - -/* */ -static void ac_json_80211_deletewlan_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_deletewlan_ops = { - .type = CAPWAP_ELEMENT_80211_DELETE_WLAN, - .json_type = "IEEE80211DeleteWLAN", - .create_message_element = ac_json_80211_deletewlan_createmessageelement, - .add_message_element = ac_json_80211_deletewlan_addmessageelement, - .create_json = ac_json_80211_deletewlan_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_deletewlan_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_deletewlan_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_deletewlan_element* deletewlan = (struct capwap_80211_deletewlan_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[deletewlan->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DELETE_WLAN); + + if (item->deletewlan) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->deletewlan); + } + + item->valid = 1; + item->deletewlan = (struct capwap_80211_deletewlan_element*)ops->clone_message_element(deletewlan); + + return 1; +} + +/* */ +static void ac_json_80211_deletewlan_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_deletewlan_ops = { + .type = CAPWAP_ELEMENT_80211_DELETE_WLAN, + .json_type = "IEEE80211DeleteWLAN", + .create_message_element = ac_json_80211_deletewlan_createmessageelement, + .add_message_element = ac_json_80211_deletewlan_addmessageelement, + .create_json = ac_json_80211_deletewlan_createjson +}; diff --git a/src/ac/ac_80211_json_deletewlan.h b/src/ac/ac_80211_json_deletewlan.h index e549573..2851f62 100644 --- a/src/ac/ac_80211_json_deletewlan.h +++ b/src/ac/ac_80211_json_deletewlan.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_DELETEWLAN_HEADER__ -#define __AC_JSON_80211_DELETEWLAN_HEADER__ - -#include "capwap_element_80211_deletewlan.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_deletewlan_ops; - -#endif /* __AC_JSON_80211_DELETEWLAN_HEADER__ */ +#ifndef __AC_JSON_80211_DELETEWLAN_HEADER__ +#define __AC_JSON_80211_DELETEWLAN_HEADER__ + +#include "capwap_element_80211_deletewlan.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_deletewlan_ops; + +#endif /* __AC_JSON_80211_DELETEWLAN_HEADER__ */ diff --git a/src/ac/ac_80211_json_directsequencecontrol.c b/src/ac/ac_80211_json_directsequencecontrol.c index e0da566..85c8a3b 100644 --- a/src/ac/ac_80211_json_directsequencecontrol.c +++ b/src/ac/ac_80211_json_directsequencecontrol.c @@ -1,88 +1,88 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211DirectSequenceControl: { - CurrentChan: [int], - CurrentCCA: [int], - EnergyDetectThreshold: [int] -} -*/ - -/* */ -static void* ac_json_80211_directsequencecontrol_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_directsequencecontrol_element* directsequencecontrol; - - directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)capwap_alloc(sizeof(struct capwap_80211_directsequencecontrol_element)); - memset(directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); - directsequencecontrol->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - directsequencecontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(directsequencecontrol); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "CurrentCCA"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - directsequencecontrol->currentcca = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(directsequencecontrol); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "EnergyDetectThreshold"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - directsequencecontrol->enerydetectthreshold = (uint32_t)json_object_get_int(jsonitem); - } else { - capwap_free(directsequencecontrol); - return NULL; - } - - return directsequencecontrol; -} - -/* */ -static int ac_json_80211_directsequencecontrol_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_directsequencecontrol_element* directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[directsequencecontrol->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL); - - if (item->directsequencecontrol) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->directsequencecontrol); - } - - item->valid = 1; - item->directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)ops->clone_message_element(directsequencecontrol); - - return 1; -} - -/* */ -static void ac_json_80211_directsequencecontrol_createjson(struct json_object* jsonparent, void* data) { - struct json_object* jsonitem; - struct capwap_80211_directsequencecontrol_element* directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "CurrentChan", json_object_new_int((int)directsequencecontrol->currentchannel)); - json_object_object_add(jsonitem, "CurrentCCA", json_object_new_int((int)directsequencecontrol->currentcca)); - json_object_object_add(jsonitem, "EnergyDetectThreshold", json_object_new_int((int)directsequencecontrol->enerydetectthreshold)); - json_object_object_add(jsonparent, "IEEE80211DirectSequenceControl", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_directsequencecontrol_ops = { - .type = CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL, - .json_type = "IEEE80211DirectSequenceControl", - .create_message_element = ac_json_80211_directsequencecontrol_createmessageelement, - .add_message_element = ac_json_80211_directsequencecontrol_addmessageelement, - .create_json = ac_json_80211_directsequencecontrol_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211DirectSequenceControl: { + CurrentChan: [int], + CurrentCCA: [int], + EnergyDetectThreshold: [int] +} +*/ + +/* */ +static void* ac_json_80211_directsequencecontrol_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_directsequencecontrol_element* directsequencecontrol; + + directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)capwap_alloc(sizeof(struct capwap_80211_directsequencecontrol_element)); + memset(directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); + directsequencecontrol->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + directsequencecontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(directsequencecontrol); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "CurrentCCA"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + directsequencecontrol->currentcca = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(directsequencecontrol); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "EnergyDetectThreshold"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + directsequencecontrol->enerydetectthreshold = (uint32_t)json_object_get_int(jsonitem); + } else { + capwap_free(directsequencecontrol); + return NULL; + } + + return directsequencecontrol; +} + +/* */ +static int ac_json_80211_directsequencecontrol_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_directsequencecontrol_element* directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[directsequencecontrol->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL); + + if (item->directsequencecontrol) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->directsequencecontrol); + } + + item->valid = 1; + item->directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)ops->clone_message_element(directsequencecontrol); + + return 1; +} + +/* */ +static void ac_json_80211_directsequencecontrol_createjson(struct json_object* jsonparent, void* data) { + struct json_object* jsonitem; + struct capwap_80211_directsequencecontrol_element* directsequencecontrol = (struct capwap_80211_directsequencecontrol_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "CurrentChan", json_object_new_int((int)directsequencecontrol->currentchannel)); + json_object_object_add(jsonitem, "CurrentCCA", json_object_new_int((int)directsequencecontrol->currentcca)); + json_object_object_add(jsonitem, "EnergyDetectThreshold", json_object_new_int((int)directsequencecontrol->enerydetectthreshold)); + json_object_object_add(jsonparent, "IEEE80211DirectSequenceControl", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_directsequencecontrol_ops = { + .type = CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL, + .json_type = "IEEE80211DirectSequenceControl", + .create_message_element = ac_json_80211_directsequencecontrol_createmessageelement, + .add_message_element = ac_json_80211_directsequencecontrol_addmessageelement, + .create_json = ac_json_80211_directsequencecontrol_createjson +}; diff --git a/src/ac/ac_80211_json_directsequencecontrol.h b/src/ac/ac_80211_json_directsequencecontrol.h index baa5544..3eccb24 100644 --- a/src/ac/ac_80211_json_directsequencecontrol.h +++ b/src/ac/ac_80211_json_directsequencecontrol.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_DIRECTSEQUENCECONTROL_HEADER__ -#define __AC_JSON_80211_DIRECTSEQUENCECONTROL_HEADER__ - -#include "capwap_element_80211_directsequencecontrol.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_directsequencecontrol_ops; - -#endif /* __AC_JSON_80211_DIRECTSEQUENCECONTROL_HEADER__ */ +#ifndef __AC_JSON_80211_DIRECTSEQUENCECONTROL_HEADER__ +#define __AC_JSON_80211_DIRECTSEQUENCECONTROL_HEADER__ + +#include "capwap_element_80211_directsequencecontrol.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_directsequencecontrol_ops; + +#endif /* __AC_JSON_80211_DIRECTSEQUENCECONTROL_HEADER__ */ diff --git a/src/ac/ac_80211_json_ie.c b/src/ac/ac_80211_json_ie.c index b84e58d..87afa09 100644 --- a/src/ac/ac_80211_json_ie.c +++ b/src/ac/ac_80211_json_ie.c @@ -1,39 +1,39 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_ie_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_ie_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_ie_element** ieclone; - struct capwap_80211_ie_element* ie = (struct capwap_80211_ie_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[ie->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_IE); - - if (!item->iearray) { - item->iearray = capwap_array_create(sizeof(struct capwap_80211_ie_element*), 0, 0); - } - - item->valid = 1; - ieclone = (struct capwap_80211_ie_element**)capwap_array_get_item_pointer(item->iearray, item->iearray->count); - *ieclone = (struct capwap_80211_ie_element*)ops->clone_message_element(ie); - - return 1; -} - -/* */ -static void ac_json_80211_ie_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_ie_ops = { - .type = CAPWAP_ELEMENT_80211_IE, - .json_type = "IEEE80211IE", - .create_message_element = ac_json_80211_ie_createmessageelement, - .add_message_element = ac_json_80211_ie_addmessageelement, - .create_json = ac_json_80211_ie_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_ie_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_ie_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_ie_element** ieclone; + struct capwap_80211_ie_element* ie = (struct capwap_80211_ie_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[ie->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_IE); + + if (!item->iearray) { + item->iearray = capwap_array_create(sizeof(struct capwap_80211_ie_element*), 0, 0); + } + + item->valid = 1; + ieclone = (struct capwap_80211_ie_element**)capwap_array_get_item_pointer(item->iearray, item->iearray->count); + *ieclone = (struct capwap_80211_ie_element*)ops->clone_message_element(ie); + + return 1; +} + +/* */ +static void ac_json_80211_ie_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_ie_ops = { + .type = CAPWAP_ELEMENT_80211_IE, + .json_type = "IEEE80211IE", + .create_message_element = ac_json_80211_ie_createmessageelement, + .add_message_element = ac_json_80211_ie_addmessageelement, + .create_json = ac_json_80211_ie_createjson +}; diff --git a/src/ac/ac_80211_json_ie.h b/src/ac/ac_80211_json_ie.h index 74acd45..8853fb3 100644 --- a/src/ac/ac_80211_json_ie.h +++ b/src/ac/ac_80211_json_ie.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_IE_HEADER__ -#define __AC_JSON_80211_IE_HEADER__ - -#include "capwap_element_80211_ie.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_ie_ops; - -#endif /* __AC_JSON_80211_IE_HEADER__ */ +#ifndef __AC_JSON_80211_IE_HEADER__ +#define __AC_JSON_80211_IE_HEADER__ + +#include "capwap_element_80211_ie.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_ie_ops; + +#endif /* __AC_JSON_80211_IE_HEADER__ */ diff --git a/src/ac/ac_80211_json_macoperation.c b/src/ac/ac_80211_json_macoperation.c index 2d58f6c..d34db2e 100644 --- a/src/ac/ac_80211_json_macoperation.c +++ b/src/ac/ac_80211_json_macoperation.c @@ -1,118 +1,118 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211MACOperation: { - RTSThreshold: [int], - ShortRetry: [int], - LongRetry: [int], - FragmentationThreshold: [int], - TxMSDULifetime: [int], - RxMSDULifetime: [int] -} -*/ - -/* */ -static void* ac_json_80211_macoperation_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_macoperation_element* macoperation; - - macoperation = (struct capwap_80211_macoperation_element*)capwap_alloc(sizeof(struct capwap_80211_macoperation_element)); - memset(macoperation, 0, sizeof(struct capwap_80211_macoperation_element)); - macoperation->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "RTSThreshold"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - macoperation->rtsthreshold = (uint16_t)json_object_get_int(jsonitem); - } else { - capwap_free(macoperation); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "ShortRetry"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - macoperation->shortretry = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(macoperation); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "LongRetry"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - macoperation->longretry = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(macoperation); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "FragmentationThreshold"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - macoperation->fragthreshold = (uint16_t)json_object_get_int(jsonitem); - } else { - capwap_free(macoperation); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "TxMSDULifetime"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - macoperation->txmsdulifetime = (uint32_t)json_object_get_int(jsonitem); - } else { - capwap_free(macoperation); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "RxMSDULifetime"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - macoperation->rxmsdulifetime = (uint32_t)json_object_get_int(jsonitem); - } else { - capwap_free(macoperation); - return NULL; - } - - return macoperation; -} - -/* */ -static int ac_json_80211_macoperation_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_macoperation_element* macoperation = (struct capwap_80211_macoperation_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[macoperation->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MACOPERATION); - - if (item->macoperation) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->macoperation); - } - - item->valid = 1; - item->macoperation = (struct capwap_80211_macoperation_element*)ops->clone_message_element(macoperation); - - return 1; -} - -/* */ -static void ac_json_80211_macoperation_createjson(struct json_object* jsonparent, void* data) { - struct json_object* jsonitem; - struct capwap_80211_macoperation_element* macoperation = (struct capwap_80211_macoperation_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "RTSThreshold", json_object_new_int((int)macoperation->rtsthreshold)); - json_object_object_add(jsonitem, "ShortRetry", json_object_new_int((int)macoperation->shortretry)); - json_object_object_add(jsonitem, "LongRetry", json_object_new_int((int)macoperation->longretry)); - json_object_object_add(jsonitem, "FragmentationThreshold", json_object_new_int((int)macoperation->fragthreshold)); - json_object_object_add(jsonitem, "TxMSDULifetime", json_object_new_int((int)macoperation->txmsdulifetime)); - json_object_object_add(jsonitem, "RxMSDULifetime", json_object_new_int((int)macoperation->rxmsdulifetime)); - json_object_object_add(jsonparent, "IEEE80211MACOperation", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_macoperation_ops = { - .type = CAPWAP_ELEMENT_80211_MACOPERATION, - .json_type = "IEEE80211MACOperation", - .create_message_element = ac_json_80211_macoperation_createmessageelement, - .add_message_element = ac_json_80211_macoperation_addmessageelement, - .create_json = ac_json_80211_macoperation_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211MACOperation: { + RTSThreshold: [int], + ShortRetry: [int], + LongRetry: [int], + FragmentationThreshold: [int], + TxMSDULifetime: [int], + RxMSDULifetime: [int] +} +*/ + +/* */ +static void* ac_json_80211_macoperation_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_macoperation_element* macoperation; + + macoperation = (struct capwap_80211_macoperation_element*)capwap_alloc(sizeof(struct capwap_80211_macoperation_element)); + memset(macoperation, 0, sizeof(struct capwap_80211_macoperation_element)); + macoperation->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "RTSThreshold"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + macoperation->rtsthreshold = (uint16_t)json_object_get_int(jsonitem); + } else { + capwap_free(macoperation); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "ShortRetry"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + macoperation->shortretry = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(macoperation); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "LongRetry"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + macoperation->longretry = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(macoperation); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "FragmentationThreshold"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + macoperation->fragthreshold = (uint16_t)json_object_get_int(jsonitem); + } else { + capwap_free(macoperation); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "TxMSDULifetime"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + macoperation->txmsdulifetime = (uint32_t)json_object_get_int(jsonitem); + } else { + capwap_free(macoperation); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "RxMSDULifetime"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + macoperation->rxmsdulifetime = (uint32_t)json_object_get_int(jsonitem); + } else { + capwap_free(macoperation); + return NULL; + } + + return macoperation; +} + +/* */ +static int ac_json_80211_macoperation_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_macoperation_element* macoperation = (struct capwap_80211_macoperation_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[macoperation->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MACOPERATION); + + if (item->macoperation) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->macoperation); + } + + item->valid = 1; + item->macoperation = (struct capwap_80211_macoperation_element*)ops->clone_message_element(macoperation); + + return 1; +} + +/* */ +static void ac_json_80211_macoperation_createjson(struct json_object* jsonparent, void* data) { + struct json_object* jsonitem; + struct capwap_80211_macoperation_element* macoperation = (struct capwap_80211_macoperation_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "RTSThreshold", json_object_new_int((int)macoperation->rtsthreshold)); + json_object_object_add(jsonitem, "ShortRetry", json_object_new_int((int)macoperation->shortretry)); + json_object_object_add(jsonitem, "LongRetry", json_object_new_int((int)macoperation->longretry)); + json_object_object_add(jsonitem, "FragmentationThreshold", json_object_new_int((int)macoperation->fragthreshold)); + json_object_object_add(jsonitem, "TxMSDULifetime", json_object_new_int((int)macoperation->txmsdulifetime)); + json_object_object_add(jsonitem, "RxMSDULifetime", json_object_new_int((int)macoperation->rxmsdulifetime)); + json_object_object_add(jsonparent, "IEEE80211MACOperation", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_macoperation_ops = { + .type = CAPWAP_ELEMENT_80211_MACOPERATION, + .json_type = "IEEE80211MACOperation", + .create_message_element = ac_json_80211_macoperation_createmessageelement, + .add_message_element = ac_json_80211_macoperation_addmessageelement, + .create_json = ac_json_80211_macoperation_createjson +}; diff --git a/src/ac/ac_80211_json_macoperation.h b/src/ac/ac_80211_json_macoperation.h index b7410e5..6a3f004 100644 --- a/src/ac/ac_80211_json_macoperation.h +++ b/src/ac/ac_80211_json_macoperation.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_MACOPERATION_HEADER__ -#define __AC_JSON_80211_MACOPERATION_HEADER__ - -#include "capwap_element_80211_macoperation.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_macoperation_ops; - -#endif /* __AC_JSON_80211_MACOPERATION_HEADER__ */ +#ifndef __AC_JSON_80211_MACOPERATION_HEADER__ +#define __AC_JSON_80211_MACOPERATION_HEADER__ + +#include "capwap_element_80211_macoperation.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_macoperation_ops; + +#endif /* __AC_JSON_80211_MACOPERATION_HEADER__ */ diff --git a/src/ac/ac_80211_json_miccountermeasures.c b/src/ac/ac_80211_json_miccountermeasures.c index 5c15f83..15ec6ac 100644 --- a/src/ac/ac_80211_json_miccountermeasures.c +++ b/src/ac/ac_80211_json_miccountermeasures.c @@ -1,41 +1,41 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_miccountermeasures_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_miccountermeasures_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_miccountermeasures_element* miccountermeasures = (struct capwap_80211_miccountermeasures_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[miccountermeasures->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES); - - if (item->miccountermeasures) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->miccountermeasures); - } - - item->valid = 1; - item->miccountermeasures = (struct capwap_80211_miccountermeasures_element*)ops->clone_message_element(miccountermeasures); - - return 1; -} - -/* */ -static void ac_json_80211_miccountermeasures_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_miccountermeasures_ops = { - .type = CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES, - .json_type = "IEEE80211MicCounterMeasures", - .create_message_element = ac_json_80211_miccountermeasures_createmessageelement, - .add_message_element = ac_json_80211_miccountermeasures_addmessageelement, - .create_json = ac_json_80211_miccountermeasures_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_miccountermeasures_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_miccountermeasures_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_miccountermeasures_element* miccountermeasures = (struct capwap_80211_miccountermeasures_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[miccountermeasures->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES); + + if (item->miccountermeasures) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->miccountermeasures); + } + + item->valid = 1; + item->miccountermeasures = (struct capwap_80211_miccountermeasures_element*)ops->clone_message_element(miccountermeasures); + + return 1; +} + +/* */ +static void ac_json_80211_miccountermeasures_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_miccountermeasures_ops = { + .type = CAPWAP_ELEMENT_80211_MIC_COUNTERMEASURES, + .json_type = "IEEE80211MicCounterMeasures", + .create_message_element = ac_json_80211_miccountermeasures_createmessageelement, + .add_message_element = ac_json_80211_miccountermeasures_addmessageelement, + .create_json = ac_json_80211_miccountermeasures_createjson +}; diff --git a/src/ac/ac_80211_json_miccountermeasures.h b/src/ac/ac_80211_json_miccountermeasures.h index 95d8f62..4f189ef 100644 --- a/src/ac/ac_80211_json_miccountermeasures.h +++ b/src/ac/ac_80211_json_miccountermeasures.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_MICCOUNTERMEASURES_HEADER__ -#define __AC_JSON_80211_MICCOUNTERMEASURES_HEADER__ - -#include "capwap_element_80211_miccountermeasures.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_miccountermeasures_ops; - -#endif /* __AC_JSON_80211_MICCOUNTERMEASURES_HEADER__ */ +#ifndef __AC_JSON_80211_MICCOUNTERMEASURES_HEADER__ +#define __AC_JSON_80211_MICCOUNTERMEASURES_HEADER__ + +#include "capwap_element_80211_miccountermeasures.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_miccountermeasures_ops; + +#endif /* __AC_JSON_80211_MICCOUNTERMEASURES_HEADER__ */ diff --git a/src/ac/ac_80211_json_multidomaincapability.c b/src/ac/ac_80211_json_multidomaincapability.c index 641d505..024331c 100644 --- a/src/ac/ac_80211_json_multidomaincapability.c +++ b/src/ac/ac_80211_json_multidomaincapability.c @@ -1,88 +1,88 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211MultiDomainCapability: { - FirstChannel: [int], - NumberChannels: [int], - MaxTxPowerLevel: [int] -} -*/ - -/* */ -static void* ac_json_80211_multidomaincapability_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_multidomaincapability_element* multidomaincapability; - - multidomaincapability = (struct capwap_80211_multidomaincapability_element*)capwap_alloc(sizeof(struct capwap_80211_multidomaincapability_element)); - memset(multidomaincapability, 0, sizeof(struct capwap_80211_multidomaincapability_element)); - multidomaincapability->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "FirstChannel"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - multidomaincapability->firstchannel = (uint16_t)json_object_get_int(jsonitem); - } else { - capwap_free(multidomaincapability); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "NumberChannels"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - multidomaincapability->numberchannels = (uint16_t)json_object_get_int(jsonitem); - } else { - capwap_free(multidomaincapability); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "MaxTxPowerLevel"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - multidomaincapability->maxtxpowerlevel = (uint16_t)json_object_get_int(jsonitem); - } else { - capwap_free(multidomaincapability); - return NULL; - } - - return multidomaincapability; -} - -/* */ -static int ac_json_80211_multidomaincapability_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_multidomaincapability_element* multidomaincapability = (struct capwap_80211_multidomaincapability_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[multidomaincapability->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY); - - if (item->multidomaincapability) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->multidomaincapability); - } - - item->valid = 1; - item->multidomaincapability = (struct capwap_80211_multidomaincapability_element*)ops->clone_message_element(multidomaincapability); - - return 1; -} - -/* */ -static void ac_json_80211_multidomaincapability_createjson(struct json_object* jsonparent, void* data) { - struct json_object* jsonitem; - struct capwap_80211_multidomaincapability_element* multidomaincapability = (struct capwap_80211_multidomaincapability_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "FirstChannel", json_object_new_int((int)multidomaincapability->firstchannel)); - json_object_object_add(jsonitem, "NumberChannels", json_object_new_int((int)multidomaincapability->numberchannels)); - json_object_object_add(jsonitem, "MaxTxPowerLevel", json_object_new_int((int)multidomaincapability->maxtxpowerlevel)); - json_object_object_add(jsonparent, "IEEE80211MultiDomainCapability", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_multidomaincapability_ops = { - .type = CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY, - .json_type = "IEEE80211MultiDomainCapability", - .create_message_element = ac_json_80211_multidomaincapability_createmessageelement, - .add_message_element = ac_json_80211_multidomaincapability_addmessageelement, - .create_json = ac_json_80211_multidomaincapability_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211MultiDomainCapability: { + FirstChannel: [int], + NumberChannels: [int], + MaxTxPowerLevel: [int] +} +*/ + +/* */ +static void* ac_json_80211_multidomaincapability_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_multidomaincapability_element* multidomaincapability; + + multidomaincapability = (struct capwap_80211_multidomaincapability_element*)capwap_alloc(sizeof(struct capwap_80211_multidomaincapability_element)); + memset(multidomaincapability, 0, sizeof(struct capwap_80211_multidomaincapability_element)); + multidomaincapability->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "FirstChannel"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + multidomaincapability->firstchannel = (uint16_t)json_object_get_int(jsonitem); + } else { + capwap_free(multidomaincapability); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "NumberChannels"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + multidomaincapability->numberchannels = (uint16_t)json_object_get_int(jsonitem); + } else { + capwap_free(multidomaincapability); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "MaxTxPowerLevel"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + multidomaincapability->maxtxpowerlevel = (uint16_t)json_object_get_int(jsonitem); + } else { + capwap_free(multidomaincapability); + return NULL; + } + + return multidomaincapability; +} + +/* */ +static int ac_json_80211_multidomaincapability_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_multidomaincapability_element* multidomaincapability = (struct capwap_80211_multidomaincapability_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[multidomaincapability->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY); + + if (item->multidomaincapability) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->multidomaincapability); + } + + item->valid = 1; + item->multidomaincapability = (struct capwap_80211_multidomaincapability_element*)ops->clone_message_element(multidomaincapability); + + return 1; +} + +/* */ +static void ac_json_80211_multidomaincapability_createjson(struct json_object* jsonparent, void* data) { + struct json_object* jsonitem; + struct capwap_80211_multidomaincapability_element* multidomaincapability = (struct capwap_80211_multidomaincapability_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "FirstChannel", json_object_new_int((int)multidomaincapability->firstchannel)); + json_object_object_add(jsonitem, "NumberChannels", json_object_new_int((int)multidomaincapability->numberchannels)); + json_object_object_add(jsonitem, "MaxTxPowerLevel", json_object_new_int((int)multidomaincapability->maxtxpowerlevel)); + json_object_object_add(jsonparent, "IEEE80211MultiDomainCapability", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_multidomaincapability_ops = { + .type = CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY, + .json_type = "IEEE80211MultiDomainCapability", + .create_message_element = ac_json_80211_multidomaincapability_createmessageelement, + .add_message_element = ac_json_80211_multidomaincapability_addmessageelement, + .create_json = ac_json_80211_multidomaincapability_createjson +}; diff --git a/src/ac/ac_80211_json_multidomaincapability.h b/src/ac/ac_80211_json_multidomaincapability.h index 7d90e19..269d8b8 100644 --- a/src/ac/ac_80211_json_multidomaincapability.h +++ b/src/ac/ac_80211_json_multidomaincapability.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_MULTIDOMAINCAPABILITY_HEADER__ -#define __AC_JSON_80211_MULTIDOMAINCAPABILITY_HEADER__ - -#include "capwap_element_80211_multidomaincapability.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_multidomaincapability_ops; - -#endif /* __AC_JSON_80211_MULTIDOMAINCAPABILITY_HEADER__ */ +#ifndef __AC_JSON_80211_MULTIDOMAINCAPABILITY_HEADER__ +#define __AC_JSON_80211_MULTIDOMAINCAPABILITY_HEADER__ + +#include "capwap_element_80211_multidomaincapability.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_multidomaincapability_ops; + +#endif /* __AC_JSON_80211_MULTIDOMAINCAPABILITY_HEADER__ */ diff --git a/src/ac/ac_80211_json_ofdmcontrol.c b/src/ac/ac_80211_json_ofdmcontrol.c index ebf81ad..e2ee376 100644 --- a/src/ac/ac_80211_json_ofdmcontrol.c +++ b/src/ac/ac_80211_json_ofdmcontrol.c @@ -1,88 +1,88 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211OFDMControl: { - CurrentChan: [int], - BandSupport: [int], - TIThreshold: [int] -} -*/ - -/* */ -static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_ofdmcontrol_element* ofdmcontrol; - - ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)capwap_alloc(sizeof(struct capwap_80211_ofdmcontrol_element)); - memset(ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); - ofdmcontrol->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - ofdmcontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(ofdmcontrol); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "BandSupport"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - ofdmcontrol->bandsupport = (uint8_t)json_object_get_int(jsonitem) & CAPWAP_OFDMCONTROL_BAND_MASK; - } else { - capwap_free(ofdmcontrol); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "TIThreshold"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - ofdmcontrol->tithreshold = (uint32_t)json_object_get_int(jsonitem); - } else { - capwap_free(ofdmcontrol); - return NULL; - } - - return ofdmcontrol; -} - -/* */ -static int ac_json_80211_ofdmcontrol_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_ofdmcontrol_element* ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[ofdmcontrol->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_OFDMCONTROL); - - if (item->ofdmcontrol) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->ofdmcontrol); - } - - item->valid = 1; - item->ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)ops->clone_message_element(ofdmcontrol); - - return 1; -} - -/* */ -static void ac_json_80211_ofdmcontrol_createjson(struct json_object* jsonparent, void* data) { - struct json_object* jsonitem; - struct capwap_80211_ofdmcontrol_element* ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "CurrentChan", json_object_new_int((int)ofdmcontrol->currentchannel)); - json_object_object_add(jsonitem, "BandSupport", json_object_new_int((int)ofdmcontrol->bandsupport)); - json_object_object_add(jsonitem, "TIThreshold", json_object_new_int((int)ofdmcontrol->tithreshold)); - json_object_object_add(jsonparent, "IEEE80211OFDMControl", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_ofdmcontrol_ops = { - .type = CAPWAP_ELEMENT_80211_OFDMCONTROL, - .json_type = "IEEE80211OFDMControl", - .create_message_element = ac_json_80211_ofdmcontrol_createmessageelement, - .add_message_element = ac_json_80211_ofdmcontrol_addmessageelement, - .create_json = ac_json_80211_ofdmcontrol_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211OFDMControl: { + CurrentChan: [int], + BandSupport: [int], + TIThreshold: [int] +} +*/ + +/* */ +static void* ac_json_80211_ofdmcontrol_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_ofdmcontrol_element* ofdmcontrol; + + ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)capwap_alloc(sizeof(struct capwap_80211_ofdmcontrol_element)); + memset(ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); + ofdmcontrol->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "CurrentChan"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + ofdmcontrol->currentchannel = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(ofdmcontrol); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "BandSupport"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + ofdmcontrol->bandsupport = (uint8_t)json_object_get_int(jsonitem) & CAPWAP_OFDMCONTROL_BAND_MASK; + } else { + capwap_free(ofdmcontrol); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "TIThreshold"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + ofdmcontrol->tithreshold = (uint32_t)json_object_get_int(jsonitem); + } else { + capwap_free(ofdmcontrol); + return NULL; + } + + return ofdmcontrol; +} + +/* */ +static int ac_json_80211_ofdmcontrol_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_ofdmcontrol_element* ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[ofdmcontrol->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_OFDMCONTROL); + + if (item->ofdmcontrol) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->ofdmcontrol); + } + + item->valid = 1; + item->ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)ops->clone_message_element(ofdmcontrol); + + return 1; +} + +/* */ +static void ac_json_80211_ofdmcontrol_createjson(struct json_object* jsonparent, void* data) { + struct json_object* jsonitem; + struct capwap_80211_ofdmcontrol_element* ofdmcontrol = (struct capwap_80211_ofdmcontrol_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "CurrentChan", json_object_new_int((int)ofdmcontrol->currentchannel)); + json_object_object_add(jsonitem, "BandSupport", json_object_new_int((int)ofdmcontrol->bandsupport)); + json_object_object_add(jsonitem, "TIThreshold", json_object_new_int((int)ofdmcontrol->tithreshold)); + json_object_object_add(jsonparent, "IEEE80211OFDMControl", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_ofdmcontrol_ops = { + .type = CAPWAP_ELEMENT_80211_OFDMCONTROL, + .json_type = "IEEE80211OFDMControl", + .create_message_element = ac_json_80211_ofdmcontrol_createmessageelement, + .add_message_element = ac_json_80211_ofdmcontrol_addmessageelement, + .create_json = ac_json_80211_ofdmcontrol_createjson +}; diff --git a/src/ac/ac_80211_json_ofdmcontrol.h b/src/ac/ac_80211_json_ofdmcontrol.h index fb3a149..fcf95cf 100644 --- a/src/ac/ac_80211_json_ofdmcontrol.h +++ b/src/ac/ac_80211_json_ofdmcontrol.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_OFDMCONTROL_HEADER__ -#define __AC_JSON_80211_OFDMCONTROL_HEADER__ - -#include "capwap_element_80211_ofdmcontrol.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_ofdmcontrol_ops; - -#endif /* __AC_JSON_80211_OFDMCONTROL_HEADER__ */ +#ifndef __AC_JSON_80211_OFDMCONTROL_HEADER__ +#define __AC_JSON_80211_OFDMCONTROL_HEADER__ + +#include "capwap_element_80211_ofdmcontrol.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_ofdmcontrol_ops; + +#endif /* __AC_JSON_80211_OFDMCONTROL_HEADER__ */ diff --git a/src/ac/ac_80211_json_rateset.c b/src/ac/ac_80211_json_rateset.c index 45fcbd6..3f2ada4 100644 --- a/src/ac/ac_80211_json_rateset.c +++ b/src/ac/ac_80211_json_rateset.c @@ -1,81 +1,81 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211Rateset: [ - [int] -] -*/ - -/* */ -static void* ac_json_80211_rateset_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - int i; - int length; - struct capwap_80211_rateset_element* rateset; - - if (json_object_get_type(jsonparent) != json_type_array) { - return NULL; - } - - length = json_object_array_length(jsonparent); - if ((length < CAPWAP_RATESET_MINLENGTH) || (length > CAPWAP_RATESET_MAXLENGTH)) { - return NULL; - } - - rateset = (struct capwap_80211_rateset_element*)capwap_alloc(sizeof(struct capwap_80211_rateset_element)); - memset(rateset, 0, sizeof(struct capwap_80211_rateset_element)); - rateset->radioid = radioid; - - for (i = 0; i < length; i++) { - struct json_object* jsonvalue = json_object_array_get_idx(jsonparent, i); - if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { - rateset->ratesetcount++; - rateset->rateset[i] = (uint8_t)json_object_get_int(jsonvalue); - } - } - - return rateset; -} - -/* */ -static int ac_json_80211_rateset_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_rateset_element* rateset = (struct capwap_80211_rateset_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[rateset->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RATESET); - - if (item->rateset) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->rateset); - } - - item->valid = 1; - item->rateset = (struct capwap_80211_rateset_element*)ops->clone_message_element(rateset); - - return 1; -} - -/* */ -static void ac_json_80211_rateset_createjson(struct json_object* jsonparent, void* data) { - int i; - struct json_object* jsonrates; - struct capwap_80211_rateset_element* rateset = (struct capwap_80211_rateset_element*)data; - - jsonrates = json_object_new_array(); - for (i = 0; i < rateset->ratesetcount; i++) { - json_object_array_add(jsonrates, json_object_new_int((int)rateset->rateset[i])); - } - - json_object_object_add(jsonparent, "IEEE80211Rateset", jsonrates); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_rateset_ops = { - .type = CAPWAP_ELEMENT_80211_RATESET, - .json_type = "IEEE80211Rateset", - .create_message_element = ac_json_80211_rateset_createmessageelement, - .add_message_element = ac_json_80211_rateset_addmessageelement, - .create_json = ac_json_80211_rateset_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211Rateset: [ + [int] +] +*/ + +/* */ +static void* ac_json_80211_rateset_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + int i; + int length; + struct capwap_80211_rateset_element* rateset; + + if (json_object_get_type(jsonparent) != json_type_array) { + return NULL; + } + + length = json_object_array_length(jsonparent); + if ((length < CAPWAP_RATESET_MINLENGTH) || (length > CAPWAP_RATESET_MAXLENGTH)) { + return NULL; + } + + rateset = (struct capwap_80211_rateset_element*)capwap_alloc(sizeof(struct capwap_80211_rateset_element)); + memset(rateset, 0, sizeof(struct capwap_80211_rateset_element)); + rateset->radioid = radioid; + + for (i = 0; i < length; i++) { + struct json_object* jsonvalue = json_object_array_get_idx(jsonparent, i); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { + rateset->ratesetcount++; + rateset->rateset[i] = (uint8_t)json_object_get_int(jsonvalue); + } + } + + return rateset; +} + +/* */ +static int ac_json_80211_rateset_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_rateset_element* rateset = (struct capwap_80211_rateset_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[rateset->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RATESET); + + if (item->rateset) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->rateset); + } + + item->valid = 1; + item->rateset = (struct capwap_80211_rateset_element*)ops->clone_message_element(rateset); + + return 1; +} + +/* */ +static void ac_json_80211_rateset_createjson(struct json_object* jsonparent, void* data) { + int i; + struct json_object* jsonrates; + struct capwap_80211_rateset_element* rateset = (struct capwap_80211_rateset_element*)data; + + jsonrates = json_object_new_array(); + for (i = 0; i < rateset->ratesetcount; i++) { + json_object_array_add(jsonrates, json_object_new_int((int)rateset->rateset[i])); + } + + json_object_object_add(jsonparent, "IEEE80211Rateset", jsonrates); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_rateset_ops = { + .type = CAPWAP_ELEMENT_80211_RATESET, + .json_type = "IEEE80211Rateset", + .create_message_element = ac_json_80211_rateset_createmessageelement, + .add_message_element = ac_json_80211_rateset_addmessageelement, + .create_json = ac_json_80211_rateset_createjson +}; diff --git a/src/ac/ac_80211_json_rateset.h b/src/ac/ac_80211_json_rateset.h index 5d3b22e..df9bcf5 100644 --- a/src/ac/ac_80211_json_rateset.h +++ b/src/ac/ac_80211_json_rateset.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_RATESET_HEADER__ -#define __AC_JSON_80211_RATESET_HEADER__ - -#include "capwap_element_80211_rateset.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_rateset_ops; - -#endif /* __AC_JSON_80211_RATESET_HEADER__ */ +#ifndef __AC_JSON_80211_RATESET_HEADER__ +#define __AC_JSON_80211_RATESET_HEADER__ + +#include "capwap_element_80211_rateset.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_rateset_ops; + +#endif /* __AC_JSON_80211_RATESET_HEADER__ */ diff --git a/src/ac/ac_80211_json_rsnaerrorreport.c b/src/ac/ac_80211_json_rsnaerrorreport.c index 4e98c6b..19a784b 100644 --- a/src/ac/ac_80211_json_rsnaerrorreport.c +++ b/src/ac/ac_80211_json_rsnaerrorreport.c @@ -1,41 +1,41 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_rsnaerrorreport_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_rsnaerrorreport_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_rsnaerrorreport_element* rsnaerrorreport = (struct capwap_80211_rsnaerrorreport_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[rsnaerrorreport->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT); - - if (item->rsnaerrorreport) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->rsnaerrorreport); - } - - item->valid = 1; - item->rsnaerrorreport = (struct capwap_80211_rsnaerrorreport_element*)ops->clone_message_element(rsnaerrorreport); - - return 1; -} - -/* */ -static void ac_json_80211_rsnaerrorreport_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_rsnaerrorreport_ops = { - .type = CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT, - .json_type = "IEEE80211RSNAErrorReport", - .create_message_element = ac_json_80211_rsnaerrorreport_createmessageelement, - .add_message_element = ac_json_80211_rsnaerrorreport_addmessageelement, - .create_json = ac_json_80211_rsnaerrorreport_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_rsnaerrorreport_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_rsnaerrorreport_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_rsnaerrorreport_element* rsnaerrorreport = (struct capwap_80211_rsnaerrorreport_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[rsnaerrorreport->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT); + + if (item->rsnaerrorreport) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->rsnaerrorreport); + } + + item->valid = 1; + item->rsnaerrorreport = (struct capwap_80211_rsnaerrorreport_element*)ops->clone_message_element(rsnaerrorreport); + + return 1; +} + +/* */ +static void ac_json_80211_rsnaerrorreport_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_rsnaerrorreport_ops = { + .type = CAPWAP_ELEMENT_80211_RSNA_ERROR_REPORT, + .json_type = "IEEE80211RSNAErrorReport", + .create_message_element = ac_json_80211_rsnaerrorreport_createmessageelement, + .add_message_element = ac_json_80211_rsnaerrorreport_addmessageelement, + .create_json = ac_json_80211_rsnaerrorreport_createjson +}; diff --git a/src/ac/ac_80211_json_rsnaerrorreport.h b/src/ac/ac_80211_json_rsnaerrorreport.h index 15e1d52..f82d30b 100644 --- a/src/ac/ac_80211_json_rsnaerrorreport.h +++ b/src/ac/ac_80211_json_rsnaerrorreport.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_RSNAERRORREPORT_HEADER__ -#define __AC_JSON_80211_RSNAERRORREPORT_HEADER__ - -#include "capwap_element_80211_rsnaerrorreport.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_rsnaerrorreport_ops; - -#endif /* __AC_JSON_80211_RSNAERRORREPORT_HEADER__ */ +#ifndef __AC_JSON_80211_RSNAERRORREPORT_HEADER__ +#define __AC_JSON_80211_RSNAERRORREPORT_HEADER__ + +#include "capwap_element_80211_rsnaerrorreport.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_rsnaerrorreport_ops; + +#endif /* __AC_JSON_80211_RSNAERRORREPORT_HEADER__ */ diff --git a/src/ac/ac_80211_json_statistics.c b/src/ac/ac_80211_json_statistics.c index d5b2baa..0f37626 100644 --- a/src/ac/ac_80211_json_statistics.c +++ b/src/ac/ac_80211_json_statistics.c @@ -1,41 +1,41 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_statistics_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_statistics_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_statistics_element* statistics = (struct capwap_80211_statistics_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[statistics->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_STATISTICS); - - if (item->statistics) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->statistics); - } - - item->valid = 1; - item->statistics = (struct capwap_80211_statistics_element*)ops->clone_message_element(statistics); - - return 1; -} - -/* */ -static void ac_json_80211_statistics_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_statistics_ops = { - .type = CAPWAP_ELEMENT_80211_STATISTICS, - .json_type = "IEEE80211Statistics", - .create_message_element = ac_json_80211_statistics_createmessageelement, - .add_message_element = ac_json_80211_statistics_addmessageelement, - .create_json = ac_json_80211_statistics_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_statistics_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_statistics_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_statistics_element* statistics = (struct capwap_80211_statistics_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[statistics->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_STATISTICS); + + if (item->statistics) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->statistics); + } + + item->valid = 1; + item->statistics = (struct capwap_80211_statistics_element*)ops->clone_message_element(statistics); + + return 1; +} + +/* */ +static void ac_json_80211_statistics_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_statistics_ops = { + .type = CAPWAP_ELEMENT_80211_STATISTICS, + .json_type = "IEEE80211Statistics", + .create_message_element = ac_json_80211_statistics_createmessageelement, + .add_message_element = ac_json_80211_statistics_addmessageelement, + .create_json = ac_json_80211_statistics_createjson +}; diff --git a/src/ac/ac_80211_json_statistics.h b/src/ac/ac_80211_json_statistics.h index 120dcdb..29b220d 100644 --- a/src/ac/ac_80211_json_statistics.h +++ b/src/ac/ac_80211_json_statistics.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_STATISTICS_HEADER__ -#define __AC_JSON_80211_STATISTICS_HEADER__ - -#include "capwap_element_80211_statistics.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_statistics_ops; - -#endif /* __AC_JSON_80211_STATISTICS_HEADER__ */ +#ifndef __AC_JSON_80211_STATISTICS_HEADER__ +#define __AC_JSON_80211_STATISTICS_HEADER__ + +#include "capwap_element_80211_statistics.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_statistics_ops; + +#endif /* __AC_JSON_80211_STATISTICS_HEADER__ */ diff --git a/src/ac/ac_80211_json_supportedrates.c b/src/ac/ac_80211_json_supportedrates.c index 7e494d2..4fd87cc 100644 --- a/src/ac/ac_80211_json_supportedrates.c +++ b/src/ac/ac_80211_json_supportedrates.c @@ -1,81 +1,81 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211SupportedRates: [ - [int] -] -*/ - -/* */ -static void* ac_json_80211_supportedrates_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - int i; - int length; - struct capwap_80211_supportedrates_element* supportedrates; - - if (json_object_get_type(jsonparent) != json_type_array) { - return NULL; - } - - length = json_object_array_length(jsonparent); - if ((length < CAPWAP_SUPPORTEDRATES_MINLENGTH) || (length > CAPWAP_SUPPORTEDRATES_MAXLENGTH)) { - return NULL; - } - - supportedrates = (struct capwap_80211_supportedrates_element*)capwap_alloc(sizeof(struct capwap_80211_supportedrates_element)); - memset(supportedrates, 0, sizeof(struct capwap_80211_supportedrates_element)); - supportedrates->radioid = radioid; - - for (i = 0; i < length; i++) { - struct json_object* jsonvalue = json_object_array_get_idx(jsonparent, i); - if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { - supportedrates->supportedratescount++; - supportedrates->supportedrates[i] = (uint8_t)json_object_get_int(jsonvalue); - } - } - - return supportedrates; -} - -/* */ -static int ac_json_80211_supportedrates_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_supportedrates_element* supportedrates = (struct capwap_80211_supportedrates_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[supportedrates->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_SUPPORTEDRATES); - - if (item->supportedrates) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->supportedrates); - } - - item->valid = 1; - item->supportedrates = (struct capwap_80211_supportedrates_element*)ops->clone_message_element(supportedrates); - - return 1; -} - -/* */ -static void ac_json_80211_supportedrates_createjson(struct json_object* jsonparent, void* data) { - int i; - struct json_object* jsonrates; - struct capwap_80211_supportedrates_element* supportedrates = (struct capwap_80211_supportedrates_element*)data; - - jsonrates = json_object_new_array(); - for (i = 0; i < supportedrates->supportedratescount; i++) { - json_object_array_add(jsonrates, json_object_new_int((int)supportedrates->supportedrates[i])); - } - - json_object_object_add(jsonparent, "IEEE80211SupportedRates", jsonrates); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_supportedrates_ops = { - .type = CAPWAP_ELEMENT_80211_SUPPORTEDRATES, - .json_type = "IEEE80211SupportedRates", - .create_message_element = ac_json_80211_supportedrates_createmessageelement, - .add_message_element = ac_json_80211_supportedrates_addmessageelement, - .create_json = ac_json_80211_supportedrates_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211SupportedRates: [ + [int] +] +*/ + +/* */ +static void* ac_json_80211_supportedrates_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + int i; + int length; + struct capwap_80211_supportedrates_element* supportedrates; + + if (json_object_get_type(jsonparent) != json_type_array) { + return NULL; + } + + length = json_object_array_length(jsonparent); + if ((length < CAPWAP_SUPPORTEDRATES_MINLENGTH) || (length > CAPWAP_SUPPORTEDRATES_MAXLENGTH)) { + return NULL; + } + + supportedrates = (struct capwap_80211_supportedrates_element*)capwap_alloc(sizeof(struct capwap_80211_supportedrates_element)); + memset(supportedrates, 0, sizeof(struct capwap_80211_supportedrates_element)); + supportedrates->radioid = radioid; + + for (i = 0; i < length; i++) { + struct json_object* jsonvalue = json_object_array_get_idx(jsonparent, i); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { + supportedrates->supportedratescount++; + supportedrates->supportedrates[i] = (uint8_t)json_object_get_int(jsonvalue); + } + } + + return supportedrates; +} + +/* */ +static int ac_json_80211_supportedrates_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_supportedrates_element* supportedrates = (struct capwap_80211_supportedrates_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[supportedrates->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_SUPPORTEDRATES); + + if (item->supportedrates) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->supportedrates); + } + + item->valid = 1; + item->supportedrates = (struct capwap_80211_supportedrates_element*)ops->clone_message_element(supportedrates); + + return 1; +} + +/* */ +static void ac_json_80211_supportedrates_createjson(struct json_object* jsonparent, void* data) { + int i; + struct json_object* jsonrates; + struct capwap_80211_supportedrates_element* supportedrates = (struct capwap_80211_supportedrates_element*)data; + + jsonrates = json_object_new_array(); + for (i = 0; i < supportedrates->supportedratescount; i++) { + json_object_array_add(jsonrates, json_object_new_int((int)supportedrates->supportedrates[i])); + } + + json_object_object_add(jsonparent, "IEEE80211SupportedRates", jsonrates); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_supportedrates_ops = { + .type = CAPWAP_ELEMENT_80211_SUPPORTEDRATES, + .json_type = "IEEE80211SupportedRates", + .create_message_element = ac_json_80211_supportedrates_createmessageelement, + .add_message_element = ac_json_80211_supportedrates_addmessageelement, + .create_json = ac_json_80211_supportedrates_createjson +}; diff --git a/src/ac/ac_80211_json_supportedrates.h b/src/ac/ac_80211_json_supportedrates.h index f4d0470..c9c2b15 100644 --- a/src/ac/ac_80211_json_supportedrates.h +++ b/src/ac/ac_80211_json_supportedrates.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_SUPPORTEDRATES_HEADER__ -#define __AC_JSON_80211_SUPPORTEDRATES_HEADER__ - -#include "capwap_element_80211_supportedrates.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_supportedrates_ops; - -#endif /* __AC_JSON_80211_SUPPORTEDRATES_HEADER__ */ +#ifndef __AC_JSON_80211_SUPPORTEDRATES_HEADER__ +#define __AC_JSON_80211_SUPPORTEDRATES_HEADER__ + +#include "capwap_element_80211_supportedrates.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_supportedrates_ops; + +#endif /* __AC_JSON_80211_SUPPORTEDRATES_HEADER__ */ diff --git a/src/ac/ac_80211_json_txpower.c b/src/ac/ac_80211_json_txpower.c index ebff98d..986f55d 100644 --- a/src/ac/ac_80211_json_txpower.c +++ b/src/ac/ac_80211_json_txpower.c @@ -1,68 +1,68 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211TxPower: { - CurrentTxPower: [int] -} -*/ - -/* */ -static void* ac_json_80211_txpower_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_txpower_element* txpower; - - txpower = (struct capwap_80211_txpower_element*)capwap_alloc(sizeof(struct capwap_80211_txpower_element)); - memset(txpower, 0, sizeof(struct capwap_80211_txpower_element)); - txpower->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "CurrentTxPower"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - txpower->currenttxpower = (uint16_t)json_object_get_int(jsonitem); - } else { - capwap_free(txpower); - return NULL; - } - - return txpower; -} - -/* */ -static int ac_json_80211_txpower_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_txpower_element* txpower = (struct capwap_80211_txpower_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[txpower->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWER); - - if (item->txpower) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->txpower); - } - - item->valid = 1; - item->txpower = (struct capwap_80211_txpower_element*)ops->clone_message_element(txpower); - - return 1; -} - -/* */ -static void ac_json_80211_txpower_createjson(struct json_object* jsonparent, void* data) { - struct json_object* jsonitem; - struct capwap_80211_txpower_element* txpower = (struct capwap_80211_txpower_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "CurrentTxPower", json_object_new_int((int)txpower->currenttxpower)); - json_object_object_add(jsonparent, "IEEE80211TxPower", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_txpower_ops = { - .type = CAPWAP_ELEMENT_80211_TXPOWER, - .json_type = "IEEE80211TxPower", - .create_message_element = ac_json_80211_txpower_createmessageelement, - .add_message_element = ac_json_80211_txpower_addmessageelement, - .create_json = ac_json_80211_txpower_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211TxPower: { + CurrentTxPower: [int] +} +*/ + +/* */ +static void* ac_json_80211_txpower_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_txpower_element* txpower; + + txpower = (struct capwap_80211_txpower_element*)capwap_alloc(sizeof(struct capwap_80211_txpower_element)); + memset(txpower, 0, sizeof(struct capwap_80211_txpower_element)); + txpower->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "CurrentTxPower"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + txpower->currenttxpower = (uint16_t)json_object_get_int(jsonitem); + } else { + capwap_free(txpower); + return NULL; + } + + return txpower; +} + +/* */ +static int ac_json_80211_txpower_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_txpower_element* txpower = (struct capwap_80211_txpower_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[txpower->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWER); + + if (item->txpower) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->txpower); + } + + item->valid = 1; + item->txpower = (struct capwap_80211_txpower_element*)ops->clone_message_element(txpower); + + return 1; +} + +/* */ +static void ac_json_80211_txpower_createjson(struct json_object* jsonparent, void* data) { + struct json_object* jsonitem; + struct capwap_80211_txpower_element* txpower = (struct capwap_80211_txpower_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "CurrentTxPower", json_object_new_int((int)txpower->currenttxpower)); + json_object_object_add(jsonparent, "IEEE80211TxPower", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_txpower_ops = { + .type = CAPWAP_ELEMENT_80211_TXPOWER, + .json_type = "IEEE80211TxPower", + .create_message_element = ac_json_80211_txpower_createmessageelement, + .add_message_element = ac_json_80211_txpower_addmessageelement, + .create_json = ac_json_80211_txpower_createjson +}; diff --git a/src/ac/ac_80211_json_txpower.h b/src/ac/ac_80211_json_txpower.h index 8a5a49a..5e38b13 100644 --- a/src/ac/ac_80211_json_txpower.h +++ b/src/ac/ac_80211_json_txpower.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_TXPOWER_HEADER__ -#define __AC_JSON_80211_TXPOWER_HEADER__ - -#include "capwap_element_80211_txpower.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_txpower_ops; - -#endif /* __AC_JSON_80211_TXPOWER_HEADER__ */ +#ifndef __AC_JSON_80211_TXPOWER_HEADER__ +#define __AC_JSON_80211_TXPOWER_HEADER__ + +#include "capwap_element_80211_txpower.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_txpower_ops; + +#endif /* __AC_JSON_80211_TXPOWER_HEADER__ */ diff --git a/src/ac/ac_80211_json_txpowerlevel.c b/src/ac/ac_80211_json_txpowerlevel.c index 5af0dd7..cfcd9b3 100644 --- a/src/ac/ac_80211_json_txpowerlevel.c +++ b/src/ac/ac_80211_json_txpowerlevel.c @@ -1,81 +1,81 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211TXPowerLevel: [ - [int] -] -*/ - -/* */ -static void* ac_json_80211_txpowerlevel_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - int i; - int length; - struct capwap_80211_txpowerlevel_element* txpowerlevel; - - if (json_object_get_type(jsonparent) != json_type_array) { - return NULL; - } - - length = json_object_array_length(jsonparent); - if (length > CAPWAP_TXPOWERLEVEL_MAXLENGTH) { - return NULL; - } - - txpowerlevel = (struct capwap_80211_txpowerlevel_element*)capwap_alloc(sizeof(struct capwap_80211_txpowerlevel_element)); - memset(txpowerlevel, 0, sizeof(struct capwap_80211_txpowerlevel_element)); - txpowerlevel->radioid = radioid; - - for (i = 0; i < length; i++) { - struct json_object* jsonvalue = json_object_array_get_idx(jsonparent, i); - if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { - txpowerlevel->numlevels++; - txpowerlevel->powerlevel[i] = (uint16_t)json_object_get_int(jsonvalue); - } - } - - return txpowerlevel; -} - -/* */ -static int ac_json_80211_txpowerlevel_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_txpowerlevel_element* txpowerlevel = (struct capwap_80211_txpowerlevel_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[txpowerlevel->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWERLEVEL); - - if (item->txpowerlevel) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->txpowerlevel); - } - - item->valid = 1; - item->txpowerlevel = (struct capwap_80211_txpowerlevel_element*)ops->clone_message_element(txpowerlevel); - - return 1; -} - -/* */ -static void ac_json_80211_txpowerlevel_createjson(struct json_object* jsonparent, void* data) { - int i; - struct json_object* jsontxpower; - struct capwap_80211_txpowerlevel_element* txpowerlevel = (struct capwap_80211_txpowerlevel_element*)data; - - jsontxpower = json_object_new_array(); - for (i = 0; i < txpowerlevel->numlevels; i++) { - json_object_array_add(jsontxpower, json_object_new_int((int)txpowerlevel->powerlevel[i])); - } - - json_object_object_add(jsonparent, "IEEE80211TXPowerLevel", jsontxpower); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_txpowerlevel_ops = { - .type = CAPWAP_ELEMENT_80211_TXPOWERLEVEL, - .json_type = "IEEE80211TXPowerLevel", - .create_message_element = ac_json_80211_txpowerlevel_createmessageelement, - .add_message_element = ac_json_80211_txpowerlevel_addmessageelement, - .create_json = ac_json_80211_txpowerlevel_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211TXPowerLevel: [ + [int] +] +*/ + +/* */ +static void* ac_json_80211_txpowerlevel_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + int i; + int length; + struct capwap_80211_txpowerlevel_element* txpowerlevel; + + if (json_object_get_type(jsonparent) != json_type_array) { + return NULL; + } + + length = json_object_array_length(jsonparent); + if (length > CAPWAP_TXPOWERLEVEL_MAXLENGTH) { + return NULL; + } + + txpowerlevel = (struct capwap_80211_txpowerlevel_element*)capwap_alloc(sizeof(struct capwap_80211_txpowerlevel_element)); + memset(txpowerlevel, 0, sizeof(struct capwap_80211_txpowerlevel_element)); + txpowerlevel->radioid = radioid; + + for (i = 0; i < length; i++) { + struct json_object* jsonvalue = json_object_array_get_idx(jsonparent, i); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_int)) { + txpowerlevel->numlevels++; + txpowerlevel->powerlevel[i] = (uint16_t)json_object_get_int(jsonvalue); + } + } + + return txpowerlevel; +} + +/* */ +static int ac_json_80211_txpowerlevel_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_txpowerlevel_element* txpowerlevel = (struct capwap_80211_txpowerlevel_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[txpowerlevel->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_TXPOWERLEVEL); + + if (item->txpowerlevel) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->txpowerlevel); + } + + item->valid = 1; + item->txpowerlevel = (struct capwap_80211_txpowerlevel_element*)ops->clone_message_element(txpowerlevel); + + return 1; +} + +/* */ +static void ac_json_80211_txpowerlevel_createjson(struct json_object* jsonparent, void* data) { + int i; + struct json_object* jsontxpower; + struct capwap_80211_txpowerlevel_element* txpowerlevel = (struct capwap_80211_txpowerlevel_element*)data; + + jsontxpower = json_object_new_array(); + for (i = 0; i < txpowerlevel->numlevels; i++) { + json_object_array_add(jsontxpower, json_object_new_int((int)txpowerlevel->powerlevel[i])); + } + + json_object_object_add(jsonparent, "IEEE80211TXPowerLevel", jsontxpower); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_txpowerlevel_ops = { + .type = CAPWAP_ELEMENT_80211_TXPOWERLEVEL, + .json_type = "IEEE80211TXPowerLevel", + .create_message_element = ac_json_80211_txpowerlevel_createmessageelement, + .add_message_element = ac_json_80211_txpowerlevel_addmessageelement, + .create_json = ac_json_80211_txpowerlevel_createjson +}; diff --git a/src/ac/ac_80211_json_txpowerlevel.h b/src/ac/ac_80211_json_txpowerlevel.h index d3c2f30..38c332b 100644 --- a/src/ac/ac_80211_json_txpowerlevel.h +++ b/src/ac/ac_80211_json_txpowerlevel.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_TXPOWERLEVEL_HEADER__ -#define __AC_JSON_80211_TXPOWERLEVEL_HEADER__ - -#include "capwap_element_80211_txpowerlevel.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_txpowerlevel_ops; - -#endif /* __AC_JSON_80211_TXPOWERLEVEL_HEADER__ */ +#ifndef __AC_JSON_80211_TXPOWERLEVEL_HEADER__ +#define __AC_JSON_80211_TXPOWERLEVEL_HEADER__ + +#include "capwap_element_80211_txpowerlevel.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_txpowerlevel_ops; + +#endif /* __AC_JSON_80211_TXPOWERLEVEL_HEADER__ */ diff --git a/src/ac/ac_80211_json_updatewlan.c b/src/ac/ac_80211_json_updatewlan.c index b66bdb8..7c98647 100644 --- a/src/ac/ac_80211_json_updatewlan.c +++ b/src/ac/ac_80211_json_updatewlan.c @@ -1,41 +1,41 @@ -#include "ac.h" -#include "ac_json.h" - -/* */ -static void* ac_json_80211_updatewlan_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_updatewlan_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_updatewlan_element* updatewlan = (struct capwap_80211_updatewlan_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[updatewlan->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_UPDATE_WLAN); - - if (item->updatewlan) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->updatewlan); - } - - item->valid = 1; - item->updatewlan = (struct capwap_80211_updatewlan_element*)ops->clone_message_element(updatewlan); - - return 1; -} - -/* */ -static void ac_json_80211_updatewlan_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_updatewlan_ops = { - .type = CAPWAP_ELEMENT_80211_UPDATE_WLAN, - .json_type = "IEEE80211UpdateWLAN", - .create_message_element = ac_json_80211_updatewlan_createmessageelement, - .add_message_element = ac_json_80211_updatewlan_addmessageelement, - .create_json = ac_json_80211_updatewlan_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* */ +static void* ac_json_80211_updatewlan_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_updatewlan_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_updatewlan_element* updatewlan = (struct capwap_80211_updatewlan_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[updatewlan->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_UPDATE_WLAN); + + if (item->updatewlan) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->updatewlan); + } + + item->valid = 1; + item->updatewlan = (struct capwap_80211_updatewlan_element*)ops->clone_message_element(updatewlan); + + return 1; +} + +/* */ +static void ac_json_80211_updatewlan_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_updatewlan_ops = { + .type = CAPWAP_ELEMENT_80211_UPDATE_WLAN, + .json_type = "IEEE80211UpdateWLAN", + .create_message_element = ac_json_80211_updatewlan_createmessageelement, + .add_message_element = ac_json_80211_updatewlan_addmessageelement, + .create_json = ac_json_80211_updatewlan_createjson +}; diff --git a/src/ac/ac_80211_json_updatewlan.h b/src/ac/ac_80211_json_updatewlan.h index 9ed23a0..76586b1 100644 --- a/src/ac/ac_80211_json_updatewlan.h +++ b/src/ac/ac_80211_json_updatewlan.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_UPDATEWLAN_HEADER__ -#define __AC_JSON_80211_UPDATEWLAN_HEADER__ - -#include "capwap_element_80211_updatewlan.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_updatewlan_ops; - -#endif /* __AC_JSON_80211_UPDATEWLAN_HEADER__ */ +#ifndef __AC_JSON_80211_UPDATEWLAN_HEADER__ +#define __AC_JSON_80211_UPDATEWLAN_HEADER__ + +#include "capwap_element_80211_updatewlan.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_updatewlan_ops; + +#endif /* __AC_JSON_80211_UPDATEWLAN_HEADER__ */ diff --git a/src/ac/ac_80211_json_wtpqos.c b/src/ac/ac_80211_json_wtpqos.c index 3350f41..961bb66 100644 --- a/src/ac/ac_80211_json_wtpqos.c +++ b/src/ac/ac_80211_json_wtpqos.c @@ -1,79 +1,79 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211WTPQoS: { - TaggingPolicy: [int], - Voice: { - QueueDepth: [int], - CWMin: [int], - CWMax: [int], - AIFS: [int], - Priority8021p: [int], - DSCP: [int] - } - Video: { - QueueDepth: [int], - CWMin: [int], - CWMax: [int], - AIFS: [int], - Priority8021p: [int], - DSCP: [int] - } - BestEffort: { - QueueDepth: [int], - CWMin: [int], - CWMax: [int], - AIFS: [int], - Priority8021p: [int], - DSCP: [int] - } - Background: { - QueueDepth: [int], - CWMin: [int], - CWMax: [int], - AIFS: [int], - Priority8021p: [int], - DSCP: [int] - } -} -*/ - -/* */ -static void* ac_json_80211_wtpqos_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - return NULL; /* TODO */ -} - -/* */ -static int ac_json_80211_wtpqos_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_wtpqos_element* wtpqos = (struct capwap_80211_wtpqos_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[wtpqos->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_QOS); - - if (item->wtpqos) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->wtpqos); - } - - item->valid = 1; - item->wtpqos = (struct capwap_80211_wtpqos_element*)ops->clone_message_element(wtpqos); - - return 1; -} - -/* */ -static void ac_json_80211_wtpqos_createjson(struct json_object* jsonparent, void* data) { - /* TODO */ -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_wtpqos_ops = { - .type = CAPWAP_ELEMENT_80211_WTP_QOS, - .json_type = "IEEE80211WTPQoS", - .create_message_element = ac_json_80211_wtpqos_createmessageelement, - .add_message_element = ac_json_80211_wtpqos_addmessageelement, - .create_json = ac_json_80211_wtpqos_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211WTPQoS: { + TaggingPolicy: [int], + Voice: { + QueueDepth: [int], + CWMin: [int], + CWMax: [int], + AIFS: [int], + Priority8021p: [int], + DSCP: [int] + } + Video: { + QueueDepth: [int], + CWMin: [int], + CWMax: [int], + AIFS: [int], + Priority8021p: [int], + DSCP: [int] + } + BestEffort: { + QueueDepth: [int], + CWMin: [int], + CWMax: [int], + AIFS: [int], + Priority8021p: [int], + DSCP: [int] + } + Background: { + QueueDepth: [int], + CWMin: [int], + CWMax: [int], + AIFS: [int], + Priority8021p: [int], + DSCP: [int] + } +} +*/ + +/* */ +static void* ac_json_80211_wtpqos_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + return NULL; /* TODO */ +} + +/* */ +static int ac_json_80211_wtpqos_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_wtpqos_element* wtpqos = (struct capwap_80211_wtpqos_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[wtpqos->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_QOS); + + if (item->wtpqos) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->wtpqos); + } + + item->valid = 1; + item->wtpqos = (struct capwap_80211_wtpqos_element*)ops->clone_message_element(wtpqos); + + return 1; +} + +/* */ +static void ac_json_80211_wtpqos_createjson(struct json_object* jsonparent, void* data) { + /* TODO */ +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_wtpqos_ops = { + .type = CAPWAP_ELEMENT_80211_WTP_QOS, + .json_type = "IEEE80211WTPQoS", + .create_message_element = ac_json_80211_wtpqos_createmessageelement, + .add_message_element = ac_json_80211_wtpqos_addmessageelement, + .create_json = ac_json_80211_wtpqos_createjson +}; diff --git a/src/ac/ac_80211_json_wtpqos.h b/src/ac/ac_80211_json_wtpqos.h index 2191299..2758513 100644 --- a/src/ac/ac_80211_json_wtpqos.h +++ b/src/ac/ac_80211_json_wtpqos.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_WTPQOS_HEADER__ -#define __AC_JSON_80211_WTPQOS_HEADER__ - -#include "capwap_element_80211_wtpqos.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_wtpqos_ops; - -#endif /* __AC_JSON_80211_WTPQOS_HEADER__ */ +#ifndef __AC_JSON_80211_WTPQOS_HEADER__ +#define __AC_JSON_80211_WTPQOS_HEADER__ + +#include "capwap_element_80211_wtpqos.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_wtpqos_ops; + +#endif /* __AC_JSON_80211_WTPQOS_HEADER__ */ diff --git a/src/ac/ac_80211_json_wtpradioconf.c b/src/ac/ac_80211_json_wtpradioconf.c index b242b39..f974910 100644 --- a/src/ac/ac_80211_json_wtpradioconf.c +++ b/src/ac/ac_80211_json_wtpradioconf.c @@ -1,128 +1,128 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211WTPRadioConfiguration: { - ShortPreamble: [int], - NumBSSIDs: [int], - DTIMPeriod: [int], - BSSID: [string], - BeaconPeriod: [int], - CountryString: [string] -} -*/ - -/* */ -static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_wtpradioconf_element* wtpradioconf; - - wtpradioconf = (struct capwap_80211_wtpradioconf_element*)capwap_alloc(sizeof(struct capwap_80211_wtpradioconf_element)); - memset(wtpradioconf, 0, sizeof(struct capwap_80211_wtpradioconf_element)); - wtpradioconf->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "ShortPreamble"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - wtpradioconf->shortpreamble = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(wtpradioconf); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "NumBSSIDs"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - wtpradioconf->maxbssid = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(wtpradioconf); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "DTIMPeriod"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - wtpradioconf->dtimperiod = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(wtpradioconf); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "BSSID"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { - if (!capwap_scanf_macaddress((unsigned char*)wtpradioconf->bssid, json_object_get_string(jsonitem), MACADDRESS_EUI48_LENGTH)) { - capwap_free(wtpradioconf); - return NULL; - } - } else { - capwap_free(wtpradioconf); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "BeaconPeriod"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - wtpradioconf->beaconperiod = (uint16_t)json_object_get_int(jsonitem); - } else { - capwap_free(wtpradioconf); - return NULL; - } - - jsonitem = compat_json_object_object_get(jsonparent, "CountryString"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { - const char* country = json_object_get_string(jsonitem); - if (strlen(country) == (CAPWAP_WTP_RADIO_CONF_COUNTRY_LENGTH - 1)) { - strcpy((char*)wtpradioconf->country, country); - } else { - capwap_free(wtpradioconf); - return NULL; - } - } else { - capwap_free(wtpradioconf); - return NULL; - } - - return wtpradioconf; -} - -/* */ -static int ac_json_80211_wtpradioconf_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_wtpradioconf_element* wtpradioconf = (struct capwap_80211_wtpradioconf_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[wtpradioconf->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_CONF); - - if (item->wtpradioconf) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->wtpradioconf); - } - - item->valid = 1; - item->wtpradioconf = (struct capwap_80211_wtpradioconf_element*)ops->clone_message_element(wtpradioconf); - - return 1; -} - -/* */ -static void ac_json_80211_wtpradioconf_createjson(struct json_object* jsonparent, void* data) { - char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; - struct json_object* jsonitem; - struct capwap_80211_wtpradioconf_element* wtpradioconf = (struct capwap_80211_wtpradioconf_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "ShortPreamble", json_object_new_int((int)wtpradioconf->shortpreamble)); - json_object_object_add(jsonitem, "NumBSSIDs", json_object_new_int((int)wtpradioconf->maxbssid)); - json_object_object_add(jsonitem, "DTIMPeriod", json_object_new_int((int)wtpradioconf->dtimperiod)); - json_object_object_add(jsonitem, "BSSID", json_object_new_string(capwap_printf_macaddress(buffer, wtpradioconf->bssid, MACADDRESS_EUI48_LENGTH))); - json_object_object_add(jsonitem, "BeaconPeriod", json_object_new_int((int)wtpradioconf->beaconperiod)); - json_object_object_add(jsonitem, "CountryString", json_object_new_string((char*)wtpradioconf->country)); - json_object_object_add(jsonparent, "IEEE80211WTPRadioConfiguration", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_wtpradioconf_ops = { - .type = CAPWAP_ELEMENT_80211_WTP_RADIO_CONF, - .json_type = "IEEE80211WTPRadioConfiguration", - .create_message_element = ac_json_80211_wtpradioconf_createmessageelement, - .add_message_element = ac_json_80211_wtpradioconf_addmessageelement, - .create_json = ac_json_80211_wtpradioconf_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211WTPRadioConfiguration: { + ShortPreamble: [int], + NumBSSIDs: [int], + DTIMPeriod: [int], + BSSID: [string], + BeaconPeriod: [int], + CountryString: [string] +} +*/ + +/* */ +static void* ac_json_80211_wtpradioconf_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_wtpradioconf_element* wtpradioconf; + + wtpradioconf = (struct capwap_80211_wtpradioconf_element*)capwap_alloc(sizeof(struct capwap_80211_wtpradioconf_element)); + memset(wtpradioconf, 0, sizeof(struct capwap_80211_wtpradioconf_element)); + wtpradioconf->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "ShortPreamble"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + wtpradioconf->shortpreamble = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(wtpradioconf); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "NumBSSIDs"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + wtpradioconf->maxbssid = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(wtpradioconf); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "DTIMPeriod"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + wtpradioconf->dtimperiod = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(wtpradioconf); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "BSSID"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { + if (!capwap_scanf_macaddress((unsigned char*)wtpradioconf->bssid, json_object_get_string(jsonitem), MACADDRESS_EUI48_LENGTH)) { + capwap_free(wtpradioconf); + return NULL; + } + } else { + capwap_free(wtpradioconf); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "BeaconPeriod"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + wtpradioconf->beaconperiod = (uint16_t)json_object_get_int(jsonitem); + } else { + capwap_free(wtpradioconf); + return NULL; + } + + jsonitem = compat_json_object_object_get(jsonparent, "CountryString"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_string)) { + const char* country = json_object_get_string(jsonitem); + if (strlen(country) == (CAPWAP_WTP_RADIO_CONF_COUNTRY_LENGTH - 1)) { + strcpy((char*)wtpradioconf->country, country); + } else { + capwap_free(wtpradioconf); + return NULL; + } + } else { + capwap_free(wtpradioconf); + return NULL; + } + + return wtpradioconf; +} + +/* */ +static int ac_json_80211_wtpradioconf_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_wtpradioconf_element* wtpradioconf = (struct capwap_80211_wtpradioconf_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[wtpradioconf->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_CONF); + + if (item->wtpradioconf) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->wtpradioconf); + } + + item->valid = 1; + item->wtpradioconf = (struct capwap_80211_wtpradioconf_element*)ops->clone_message_element(wtpradioconf); + + return 1; +} + +/* */ +static void ac_json_80211_wtpradioconf_createjson(struct json_object* jsonparent, void* data) { + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; + struct json_object* jsonitem; + struct capwap_80211_wtpradioconf_element* wtpradioconf = (struct capwap_80211_wtpradioconf_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "ShortPreamble", json_object_new_int((int)wtpradioconf->shortpreamble)); + json_object_object_add(jsonitem, "NumBSSIDs", json_object_new_int((int)wtpradioconf->maxbssid)); + json_object_object_add(jsonitem, "DTIMPeriod", json_object_new_int((int)wtpradioconf->dtimperiod)); + json_object_object_add(jsonitem, "BSSID", json_object_new_string(capwap_printf_macaddress(buffer, wtpradioconf->bssid, MACADDRESS_EUI48_LENGTH))); + json_object_object_add(jsonitem, "BeaconPeriod", json_object_new_int((int)wtpradioconf->beaconperiod)); + json_object_object_add(jsonitem, "CountryString", json_object_new_string((char*)wtpradioconf->country)); + json_object_object_add(jsonparent, "IEEE80211WTPRadioConfiguration", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_wtpradioconf_ops = { + .type = CAPWAP_ELEMENT_80211_WTP_RADIO_CONF, + .json_type = "IEEE80211WTPRadioConfiguration", + .create_message_element = ac_json_80211_wtpradioconf_createmessageelement, + .add_message_element = ac_json_80211_wtpradioconf_addmessageelement, + .create_json = ac_json_80211_wtpradioconf_createjson +}; diff --git a/src/ac/ac_80211_json_wtpradioconf.h b/src/ac/ac_80211_json_wtpradioconf.h index cd96f68..00a7d75 100644 --- a/src/ac/ac_80211_json_wtpradioconf.h +++ b/src/ac/ac_80211_json_wtpradioconf.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_WTPRADIOCONF_HEADER__ -#define __AC_JSON_80211_WTPRADIOCONF_HEADER__ - -#include "capwap_element_80211_wtpradioconf.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_wtpradioconf_ops; - -#endif /* __AC_JSON_80211_WTPRADIOCONF_HEADER__ */ +#ifndef __AC_JSON_80211_WTPRADIOCONF_HEADER__ +#define __AC_JSON_80211_WTPRADIOCONF_HEADER__ + +#include "capwap_element_80211_wtpradioconf.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_wtpradioconf_ops; + +#endif /* __AC_JSON_80211_WTPRADIOCONF_HEADER__ */ diff --git a/src/ac/ac_80211_json_wtpradiofailalarm.c b/src/ac/ac_80211_json_wtpradiofailalarm.c index c409cdd..3a42d6f 100644 --- a/src/ac/ac_80211_json_wtpradiofailalarm.c +++ b/src/ac/ac_80211_json_wtpradiofailalarm.c @@ -1,79 +1,79 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211WTPRadioFailAlarm: { - Type: [int], - Status: [int] -} -*/ - -/* */ -static void* ac_json_80211_wtpradiofailalarm_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm; - - wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)capwap_alloc(sizeof(struct capwap_80211_wtpradiofailalarm_element)); - memset(wtpradiofailalarm, 0, sizeof(struct capwap_80211_wtpradiofailalarm_element)); - wtpradiofailalarm->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "Type"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - wtpradiofailalarm->type = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(wtpradiofailalarm); - return NULL; - } - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "Status"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - wtpradiofailalarm->status = (uint8_t)json_object_get_int(jsonitem); - } else { - capwap_free(wtpradiofailalarm); - return NULL; - } - - return wtpradiofailalarm; -} - -/* */ -static int ac_json_80211_wtpradiofailalarm_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[wtpradiofailalarm->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM); - - if (item->wtpradiofailalarm) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->wtpradiofailalarm); - } - - item->valid = 1; - item->wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)ops->clone_message_element(wtpradiofailalarm); - - return 1; -} - -/* */ -static void ac_json_80211_wtpradiofailalarm_createjson(struct json_object* jsonparent, void* data) { - struct json_object* jsonitem; - struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "Type", json_object_new_int((int)wtpradiofailalarm->type)); - json_object_object_add(jsonitem, "Status", json_object_new_int((int)wtpradiofailalarm->status)); - json_object_object_add(jsonparent, "IEEE80211WTPRadioFailAlarm", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_wtpradiofailalarm_ops = { - .type = CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM, - .json_type = "IEEE80211WTPRadioFailAlarm", - .create_message_element = ac_json_80211_wtpradiofailalarm_createmessageelement, - .add_message_element = ac_json_80211_wtpradiofailalarm_addmessageelement, - .create_json = ac_json_80211_wtpradiofailalarm_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211WTPRadioFailAlarm: { + Type: [int], + Status: [int] +} +*/ + +/* */ +static void* ac_json_80211_wtpradiofailalarm_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm; + + wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)capwap_alloc(sizeof(struct capwap_80211_wtpradiofailalarm_element)); + memset(wtpradiofailalarm, 0, sizeof(struct capwap_80211_wtpradiofailalarm_element)); + wtpradiofailalarm->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "Type"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + wtpradiofailalarm->type = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(wtpradiofailalarm); + return NULL; + } + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "Status"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + wtpradiofailalarm->status = (uint8_t)json_object_get_int(jsonitem); + } else { + capwap_free(wtpradiofailalarm); + return NULL; + } + + return wtpradiofailalarm; +} + +/* */ +static int ac_json_80211_wtpradiofailalarm_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[wtpradiofailalarm->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM); + + if (item->wtpradiofailalarm) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->wtpradiofailalarm); + } + + item->valid = 1; + item->wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)ops->clone_message_element(wtpradiofailalarm); + + return 1; +} + +/* */ +static void ac_json_80211_wtpradiofailalarm_createjson(struct json_object* jsonparent, void* data) { + struct json_object* jsonitem; + struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm = (struct capwap_80211_wtpradiofailalarm_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "Type", json_object_new_int((int)wtpradiofailalarm->type)); + json_object_object_add(jsonitem, "Status", json_object_new_int((int)wtpradiofailalarm->status)); + json_object_object_add(jsonparent, "IEEE80211WTPRadioFailAlarm", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_wtpradiofailalarm_ops = { + .type = CAPWAP_ELEMENT_80211_WTP_RADIO_FAIL_ALARM, + .json_type = "IEEE80211WTPRadioFailAlarm", + .create_message_element = ac_json_80211_wtpradiofailalarm_createmessageelement, + .add_message_element = ac_json_80211_wtpradiofailalarm_addmessageelement, + .create_json = ac_json_80211_wtpradiofailalarm_createjson +}; diff --git a/src/ac/ac_80211_json_wtpradiofailalarm.h b/src/ac/ac_80211_json_wtpradiofailalarm.h index e25342f..8f454d3 100644 --- a/src/ac/ac_80211_json_wtpradiofailalarm.h +++ b/src/ac/ac_80211_json_wtpradiofailalarm.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_WTPRADIOFAILALARM_HEADER__ -#define __AC_JSON_80211_WTPRADIOFAILALARM_HEADER__ - -#include "capwap_element_80211_wtpradiofailalarm.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_wtpradiofailalarm_ops; - -#endif /* __AC_JSON_80211_WTPRADIOFAILALARM_HEADER__ */ +#ifndef __AC_JSON_80211_WTPRADIOFAILALARM_HEADER__ +#define __AC_JSON_80211_WTPRADIOFAILALARM_HEADER__ + +#include "capwap_element_80211_wtpradiofailalarm.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_wtpradiofailalarm_ops; + +#endif /* __AC_JSON_80211_WTPRADIOFAILALARM_HEADER__ */ diff --git a/src/ac/ac_80211_json_wtpradioinformation.c b/src/ac/ac_80211_json_wtpradioinformation.c index 65c0daa..7fbe9e0 100644 --- a/src/ac/ac_80211_json_wtpradioinformation.c +++ b/src/ac/ac_80211_json_wtpradioinformation.c @@ -1,68 +1,68 @@ -#include "ac.h" -#include "ac_json.h" - -/* -IEEE80211WTPRadioInformation: { - Mode: [int] -} -*/ - -/* */ -static void* ac_json_80211_wtpradioinformation_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { - struct json_object* jsonitem; - struct capwap_80211_wtpradioinformation_element* wtpradioinformation; - - wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)capwap_alloc(sizeof(struct capwap_80211_wtpradioinformation_element)); - memset(wtpradioinformation, 0, sizeof(struct capwap_80211_wtpradioinformation_element)); - wtpradioinformation->radioid = radioid; - - /* */ - jsonitem = compat_json_object_object_get(jsonparent, "Mode"); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { - wtpradioinformation->radiotype = (uint32_t)json_object_get_int(jsonitem) & CAPWAP_RADIO_TYPE_MASK; - } else { - capwap_free(wtpradioinformation); - return NULL; - } - - return wtpradioinformation; -} - -/* */ -static int ac_json_80211_wtpradioinformation_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { - struct capwap_80211_wtpradioinformation_element* wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)data; - struct ac_json_ieee80211_item* item = &wtpradio->items[wtpradioinformation->radioid - 1]; - struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION); - - if (item->wtpradioinformation) { - if (!overwrite) { - return 0; - } - - ops->free_message_element(item->wtpradioinformation); - } - - item->valid = 1; - item->wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)ops->clone_message_element(wtpradioinformation); - - return 1; -} - -/* */ -static void ac_json_80211_wtpradioinformation_createjson(struct json_object* jsonparent, void* data) { - struct json_object* jsonitem; - struct capwap_80211_wtpradioinformation_element* wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)data; - - jsonitem = json_object_new_object(); - json_object_object_add(jsonitem, "Mode", json_object_new_int((int)wtpradioinformation->radiotype)); - json_object_object_add(jsonparent, "IEEE80211WTPRadioInformation", jsonitem); -} - -/* */ -struct ac_json_ieee80211_ops ac_json_80211_wtpradioinformation_ops = { - .type = CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION, - .json_type = "IEEE80211WTPRadioInformation", - .create_message_element = ac_json_80211_wtpradioinformation_createmessageelement, - .add_message_element = ac_json_80211_wtpradioinformation_addmessageelement, - .create_json = ac_json_80211_wtpradioinformation_createjson -}; +#include "ac.h" +#include "ac_json.h" + +/* +IEEE80211WTPRadioInformation: { + Mode: [int] +} +*/ + +/* */ +static void* ac_json_80211_wtpradioinformation_createmessageelement(struct json_object* jsonparent, uint16_t radioid) { + struct json_object* jsonitem; + struct capwap_80211_wtpradioinformation_element* wtpradioinformation; + + wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)capwap_alloc(sizeof(struct capwap_80211_wtpradioinformation_element)); + memset(wtpradioinformation, 0, sizeof(struct capwap_80211_wtpradioinformation_element)); + wtpradioinformation->radioid = radioid; + + /* */ + jsonitem = compat_json_object_object_get(jsonparent, "Mode"); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_int)) { + wtpradioinformation->radiotype = (uint32_t)json_object_get_int(jsonitem) & CAPWAP_RADIO_TYPE_MASK; + } else { + capwap_free(wtpradioinformation); + return NULL; + } + + return wtpradioinformation; +} + +/* */ +static int ac_json_80211_wtpradioinformation_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite) { + struct capwap_80211_wtpradioinformation_element* wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)data; + struct ac_json_ieee80211_item* item = &wtpradio->items[wtpradioinformation->radioid - 1]; + struct capwap_message_elements_ops* ops = capwap_get_message_element_ops(CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION); + + if (item->wtpradioinformation) { + if (!overwrite) { + return 0; + } + + ops->free_message_element(item->wtpradioinformation); + } + + item->valid = 1; + item->wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)ops->clone_message_element(wtpradioinformation); + + return 1; +} + +/* */ +static void ac_json_80211_wtpradioinformation_createjson(struct json_object* jsonparent, void* data) { + struct json_object* jsonitem; + struct capwap_80211_wtpradioinformation_element* wtpradioinformation = (struct capwap_80211_wtpradioinformation_element*)data; + + jsonitem = json_object_new_object(); + json_object_object_add(jsonitem, "Mode", json_object_new_int((int)wtpradioinformation->radiotype)); + json_object_object_add(jsonparent, "IEEE80211WTPRadioInformation", jsonitem); +} + +/* */ +struct ac_json_ieee80211_ops ac_json_80211_wtpradioinformation_ops = { + .type = CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION, + .json_type = "IEEE80211WTPRadioInformation", + .create_message_element = ac_json_80211_wtpradioinformation_createmessageelement, + .add_message_element = ac_json_80211_wtpradioinformation_addmessageelement, + .create_json = ac_json_80211_wtpradioinformation_createjson +}; diff --git a/src/ac/ac_80211_json_wtpradioinformation.h b/src/ac/ac_80211_json_wtpradioinformation.h index af4cd4f..68d2be2 100644 --- a/src/ac/ac_80211_json_wtpradioinformation.h +++ b/src/ac/ac_80211_json_wtpradioinformation.h @@ -1,8 +1,8 @@ -#ifndef __AC_JSON_80211_WTPRADIOINFORMATION_HEADER__ -#define __AC_JSON_80211_WTPRADIOINFORMATION_HEADER__ - -#include "capwap_element_80211_wtpradioinformation.h" - -extern struct ac_json_ieee80211_ops ac_json_80211_wtpradioinformation_ops; - -#endif /* __AC_JSON_80211_WTPRADIOINFORMATION_HEADER__ */ +#ifndef __AC_JSON_80211_WTPRADIOINFORMATION_HEADER__ +#define __AC_JSON_80211_WTPRADIOINFORMATION_HEADER__ + +#include "capwap_element_80211_wtpradioinformation.h" + +extern struct ac_json_ieee80211_ops ac_json_80211_wtpradioinformation_ops; + +#endif /* __AC_JSON_80211_WTPRADIOINFORMATION_HEADER__ */ diff --git a/src/ac/ac_backend.c b/src/ac/ac_backend.c index bdc257f..2ee0bc5 100644 --- a/src/ac/ac_backend.c +++ b/src/ac/ac_backend.c @@ -1,897 +1,897 @@ -#include "ac.h" -#include "capwap_dfa.h" -#include "ac_backend.h" -#include "ac_soap.h" -#include "ac_session.h" - -/* */ -#define AC_BACKEND_WAIT_TIMEOUT 10000 -#define SOAP_PROTOCOL_RESPONSE_WAIT_EVENT_TIMEOUT 70000 - -/* */ -struct ac_backend_t { - pthread_t threadid; - int endthread; - - capwap_event_t wait; - capwap_lock_t lock; - capwap_lock_t backendlock; - - /* Backend Soap */ - int activebackend; - int backendstatus; - int errorjoinbackend; - - /* Session */ - char* backendsessionid; - - /* Soap Request */ - struct ac_http_soap_request* soaprequest; -}; - -static struct ac_backend_t g_ac_backend; - -/* */ -static struct ac_http_soap_server* ac_backend_get_server(void) { - return *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); -} - -/* */ -static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct json_object* jsonparams) { - int result = -1; - struct ac_session_t* session; - struct json_object* jsonwtpid; - - /* Params CloseWTPSession Action - { - WTPId: [string] - } - */ - - /* WTPId */ - jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId"); - if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { - return -1; - } - - /* Get session */ - session = ac_search_session_from_wtpid(json_object_get_string(jsonwtpid)); - if (session) { - struct ac_session_notify_event_t notify; - - /* Notify Request to Complete Event */ - strcpy(notify.idevent, idevent); - notify.action = NOTIFY_ACTION_CHANGE_STATE; - notify.session_state = CAPWAP_DEAD_STATE; - ac_session_send_action(session, AC_SESSION_ACTION_NOTIFY_EVENT, 0, (void*)¬ify, sizeof(struct ac_session_notify_event_t)); - - /* Async close session */ - capwap_logging_debug("Receive close wtp session for WTP %s", session->wtpid); - ac_session_send_action(session, AC_SESSION_ACTION_CLOSE, 0, NULL, 0); - - /* */ - ac_session_release_reference(session); - result = 0; - } - - return result; -} - -/* */ -static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_object* jsonparams) { - int result = -1; - struct ac_session_t* session; - struct json_object* jsonwtpid; - struct json_object* jsonimage; - struct json_object* jsonvendor; - struct json_object* jsondata; - - /* Params ResetWTP Action - { - WTPId: [string], - ImageIdentifier: { - Vendor: [int], - Data: [string] - } - } - */ - - /* WTPId */ - jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId"); - if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { - return -1; - } - - /* ImageIdentifier */ - jsonimage = compat_json_object_object_get(jsonparams, "ImageIdentifier"); - if (!jsonimage || (json_object_get_type(jsonimage) != json_type_object)) { - return -1; - } - - jsonvendor = compat_json_object_object_get(jsonimage, "Vendor"); - jsondata = compat_json_object_object_get(jsonimage, "Data"); - if (!jsonvendor || !jsondata || (json_object_get_type(jsonvendor) != json_type_int) || (json_object_get_type(jsondata) != json_type_string)) { - return -1; - } - - /* Get session */ - session = ac_search_session_from_wtpid(json_object_get_string(jsonwtpid)); - if (session) { - const char* name = json_object_get_string(jsondata); - if (name && *name) { - int length; - struct ac_notify_reset_t* reset; - struct ac_session_notify_event_t notify; - - /* Notification data */ - length = sizeof(struct ac_notify_reset_t) + strlen(name) + 1; - reset = (struct ac_notify_reset_t*)capwap_alloc(length); - - /* */ - reset->vendor = (uint32_t)json_object_get_int(jsonvendor); - strcpy((char*)reset->name, name); - - /* Notify Request to Complete Event */ - strcpy(notify.idevent, idevent); - notify.action = NOTIFY_ACTION_CHANGE_STATE; - notify.session_state = CAPWAP_DEAD_STATE; - ac_session_send_action(session, AC_SESSION_ACTION_NOTIFY_EVENT, 0, (void*)¬ify, sizeof(struct ac_session_notify_event_t)); - - /* Notify Action */ - capwap_logging_debug("Receive reset request for WTP %s", session->wtpid); - ac_session_send_action(session, AC_SESSION_ACTION_RESET_WTP, 0, (void*)reset, length); - result = 0; - - /* */ - capwap_free(reset); - } - - ac_session_release_reference(session); - } - - return result; -} - -/* */ -static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_object* jsonparams) { - int result = -1; - struct ac_session_t* session; - struct json_object* jsonwtpid; - struct json_object* jsonradioid; - struct json_object* jsonwlanid; - struct json_object* jsoncapability; - struct json_object* jsonqos; - struct json_object* jsonauthtype; - struct json_object* jsonmacmode; - struct json_object* jsontunnelmode; - struct json_object* jsonhidessid; - struct json_object* jsonssid; - const char* ssid; - - /* Params AddWLAN Action - { - WTPID: [string], - RadioID: [int], - WLANID: [int], - Capability: [int], - Key: { - TODO - }, - DefaultQoS: [int], - AuthType: [int], - MACMode: [int], - TunnelMode: [int], - SuppressSSID: [bool], - SSID: [string], - IE: { - TODO - } - } - */ - - /* WTPID */ - jsonwtpid = compat_json_object_object_get(jsonparams, "WTPID"); - if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { - return -1; - } - - /* RadioID */ - jsonradioid = compat_json_object_object_get(jsonparams, "RadioID"); - if (!jsonradioid || (json_object_get_type(jsonradioid) != json_type_int)) { - return -1; - } - - /* WLANID */ - jsonwlanid = compat_json_object_object_get(jsonparams, "WLANID"); - if (!jsonwlanid || (json_object_get_type(jsonwlanid) != json_type_int)) { - return -1; - } - - /* Capability */ - jsoncapability = compat_json_object_object_get(jsonparams, "Capability"); - if (!jsoncapability || (json_object_get_type(jsoncapability) != json_type_int)) { - return -1; - } - - /* Key */ - /* TODO */ - - /* DefaultQoS */ - jsonqos = compat_json_object_object_get(jsonparams, "DefaultQoS"); - if (!jsonqos || (json_object_get_type(jsonqos) != json_type_int)) { - return -1; - } - - /* AuthType */ - jsonauthtype = compat_json_object_object_get(jsonparams, "AuthType"); - if (!jsonauthtype || (json_object_get_type(jsonauthtype) != json_type_int)) { - return -1; - } - - /* MACMode */ - jsonmacmode = compat_json_object_object_get(jsonparams, "MACMode"); - if (!jsonmacmode || (json_object_get_type(jsonmacmode) != json_type_int)) { - return -1; - } - - /* TunnelMode */ - jsontunnelmode = compat_json_object_object_get(jsonparams, "TunnelMode"); - if (!jsontunnelmode || (json_object_get_type(jsontunnelmode) != json_type_int)) { - return -1; - } - - /* SuppressSSID */ - jsonhidessid = compat_json_object_object_get(jsonparams, "SuppressSSID"); - if (!jsonhidessid || (json_object_get_type(jsonhidessid) != json_type_boolean)) { - return -1; - } - - /* SSID */ - jsonssid = compat_json_object_object_get(jsonparams, "SSID"); - if (jsonssid && (json_object_get_type(jsonssid) == json_type_string)) { - ssid = json_object_get_string(jsonssid); - if (strlen(ssid) > CAPWAP_ADD_WLAN_SSID_LENGTH) { - return -1; - } - } else { - return -1; - } - - /* IE */ - /* TODO */ - - /* Get session */ - session = ac_search_session_from_wtpid(json_object_get_string(jsonwtpid)); - if (session) { - int length; - struct ac_notify_addwlan_t* addwlan; - struct ac_session_notify_event_t notify; - - /* Notification data */ - length = sizeof(struct ac_notify_addwlan_t); - addwlan = (struct ac_notify_addwlan_t*)capwap_alloc(length); - - /* */ - addwlan->radioid = (uint8_t)json_object_get_int(jsonradioid); - addwlan->wlanid = (uint8_t)json_object_get_int(jsonwlanid); - addwlan->capability = (uint16_t)json_object_get_int(jsoncapability); - addwlan->qos = (uint8_t)json_object_get_int(jsonqos); - addwlan->authmode = (uint8_t)json_object_get_int(jsonauthtype); - addwlan->macmode = (uint8_t)json_object_get_int(jsonmacmode); - addwlan->tunnelmode = (uint8_t)json_object_get_int(jsontunnelmode); - addwlan->suppressssid = (uint8_t)(json_object_get_boolean(jsonhidessid) ? 1 : 0); - strcpy(addwlan->ssid, ssid); - - /* Notify Request to Complete Event */ - strcpy(notify.idevent, idevent); - notify.action = NOTIFY_ACTION_RECEIVE_RESPONSE_CONTROLMESSAGE; - notify.ctrlmsg_type = CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE; - ac_session_send_action(session, AC_SESSION_ACTION_NOTIFY_EVENT, 0, (void*)¬ify, sizeof(struct ac_session_notify_event_t)); - - /* Notify Action */ - capwap_logging_debug("Receive AddWLAN request for WTP %s with SSID: %s", session->wtpid, addwlan->ssid); - ac_session_send_action(session, AC_SESSION_ACTION_ADDWLAN, 0, (void*)addwlan, length); - - /* */ - ac_session_release_reference(session); - capwap_free(addwlan); - result = 0; - } - - return result; -} - -/* */ -static int ac_backend_parsing_updatewlan_event(const char* idevent, struct json_object* jsonparams) { - int result = -1; - - return result; -} - -/* */ -static int ac_backend_parsing_deletewlan_event(const char* idevent, struct json_object* jsonparams) { - int result = -1; - - return result; -} - -/* */ -static int ac_backend_soap_update_event(const char* idevent, int status) { - int result = 0; - char buffer[256]; - struct ac_soap_request* request = NULL; - struct ac_http_soap_server* server; - - ASSERT(g_ac_backend.soaprequest == NULL); - ASSERT(g_ac_backend.backendsessionid != NULL); - - /* Get HTTP Soap Server */ - server = ac_backend_get_server(); - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Build Soap Request */ - if (!g_ac_backend.endthread) { - request = ac_soapclient_create_request("updateBackendEvent", SOAP_NAMESPACE_URI); - if (request) { - ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); - ac_soapclient_add_param(request, "xs:string", "idevent", idevent); - ac_soapclient_add_param(request, "xs:int", "status", capwap_itoa(status, buffer)); - g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); - } - } - - capwap_lock_exit(&g_ac_backend.lock); - - /* */ - if (!g_ac_backend.soaprequest) { - if (request) { - ac_soapclient_free_request(request); - } - - return 0; - } - - /* Send Request & Recv Response */ - if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { - struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); - if (response) { - ac_soapclient_free_response(response); - } - } - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Free resource */ - ac_soapclient_close_request(g_ac_backend.soaprequest, 1); - g_ac_backend.soaprequest = NULL; - - capwap_lock_exit(&g_ac_backend.lock); - - return result; -} - -/* */ -static int ac_backend_soap_getconfiguration(void) { - int result = -1; - struct ac_soap_request* request = NULL; - struct ac_http_soap_server* server; - struct json_object* jsonroot = NULL; - - ASSERT(g_ac_backend.soaprequest == NULL); - ASSERT(g_ac_backend.backendsessionid != NULL); - - /* Get HTTP Soap Server */ - server = ac_backend_get_server(); - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Build Soap Request */ - if (!g_ac_backend.endthread) { - request = ac_soapclient_create_request("getConfiguration", SOAP_NAMESPACE_URI); - if (request) { - ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); - g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); - } - } - - capwap_lock_exit(&g_ac_backend.lock); - - /* */ - if (!g_ac_backend.soaprequest) { - if (request) { - ac_soapclient_free_request(request); - } - - return -1; - } - - /* Send Request & Recv Response */ - if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { - struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); - if (response) { - /* Get Configuration result */ - jsonroot = ac_soapclient_parse_json_response(response); - ac_soapclient_free_response(response); - } - } - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Free resource */ - ac_soapclient_close_request(g_ac_backend.soaprequest, 1); - g_ac_backend.soaprequest = NULL; - - capwap_lock_exit(&g_ac_backend.lock); - - /* Send JSON command to primary thread */ - if (jsonroot) { - result = ac_msgqueue_update_configuration(jsonroot); - if (result) { - json_object_put(jsonroot); - } - } - - return result; -} - -/* */ -static int ac_backend_soap_join(int forcereset) { - struct ac_soap_request* request = NULL; - struct ac_http_soap_server* server; - - ASSERT(g_ac_backend.soaprequest == NULL); - ASSERT(g_ac_backend.backendsessionid == NULL); - - /* Get HTTP Soap Server */ - server = ac_backend_get_server(); - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Build Soap Request */ - if (!g_ac_backend.endthread) { - request = ac_soapclient_create_request("joinBackend", SOAP_NAMESPACE_URI); - if (request) { - ac_soapclient_add_param(request, "xs:string", "idac", g_ac.backendacid); - ac_soapclient_add_param(request, "xs:string", "version", g_ac.backendversion); - ac_soapclient_add_param(request, "xs:boolean", "forcereset", (forcereset ? "true" : "false")); - g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); - } - } - - capwap_lock_exit(&g_ac_backend.lock); - - /* */ - if (!g_ac_backend.soaprequest) { - if (request) { - ac_soapclient_free_request(request); - } - - return -1; - } - - /* Send Request & Recv Response */ - if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { - struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); - if (response) { - /* Get join result */ - if ((response->responsecode == HTTP_RESULT_OK) && response->xmlResponseReturn) { - xmlChar* xmlResult = xmlNodeGetContent(response->xmlResponseReturn); - if (xmlStrlen(xmlResult)) { - g_ac_backend.backendsessionid = capwap_duplicate_string((const char*)xmlResult); - } - - xmlFree(xmlResult); - } - - /* */ - ac_soapclient_free_response(response); - } - } - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Free resource */ - ac_soapclient_close_request(g_ac_backend.soaprequest, 1); - g_ac_backend.soaprequest = NULL; - - capwap_lock_exit(&g_ac_backend.lock); - - /* Retrieve AC configuration */ - if (g_ac_backend.backendsessionid && forcereset) { - if (ac_backend_soap_getconfiguration()) { - capwap_logging_error("Unable to get AC configuration from Backend Server"); - capwap_free(g_ac_backend.backendsessionid); - g_ac_backend.backendsessionid = NULL; - } - } - - return (g_ac_backend.backendsessionid ? 0 : -1); -} - -/* */ -static int ac_backend_parsing_event(struct json_object* jsonitem) { - int result = -1; - struct json_object* jsonvalue; - - ASSERT(jsonitem != NULL); - - /* Receive event into JSON result - { - EventID: [int], - Action: [string], - Params: { - - } - } - */ - - /* Get EventID */ - jsonvalue = compat_json_object_object_get(jsonitem, "EventID"); - if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) { - const char* idevent = json_object_get_string(jsonvalue); - - /* Get Action */ - jsonvalue = compat_json_object_object_get(jsonitem, "Action"); - if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) { - const char* action = json_object_get_string(jsonvalue); - if (action) { - jsonvalue = compat_json_object_object_get(jsonitem, "Params"); - if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) { - /* Parsing params according to the action */ - if (!strcmp(action, "CloseWTPSession")) { - result = ac_backend_parsing_closewtpsession_event(idevent, jsonvalue); - } else if (!strcmp(action, "ResetWTP")) { - result = ac_backend_parsing_resetwtp_event(idevent, jsonvalue); - } else if (!strcmp(action, "AddWLAN")) { - result = ac_backend_parsing_addwlan_event(idevent, jsonvalue); - } else if (!strcmp(action, "UpdateWLAN")) { - result = ac_backend_parsing_updatewlan_event(idevent, jsonvalue); - } else if (!strcmp(action, "DeleteWLAN")) { - result = ac_backend_parsing_deletewlan_event(idevent, jsonvalue); - } - - /* Notify result action */ - ac_backend_soap_update_event(idevent, (!result ? SOAP_EVENT_STATUS_RUNNING : SOAP_EVENT_STATUS_GENERIC_ERROR)); - } - } - } - } - - return result; -} - -/* */ -static int ac_backend_soap_waitevent(void) { - int result = -1; - struct ac_soap_request* request = NULL; - struct ac_http_soap_server* server; - struct json_object* jsonroot = NULL; - - ASSERT(g_ac_backend.soaprequest == NULL); - ASSERT(g_ac_backend.backendsessionid != NULL); - - /* Get HTTP Soap Server */ - server = ac_backend_get_server(); - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Build Soap Request */ - if (!g_ac_backend.endthread) { - request = ac_soapclient_create_request("waitBackendEvent", SOAP_NAMESPACE_URI); - if (request) { - ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); - g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); - - /* Change result timeout */ - g_ac_backend.soaprequest->responsetimeout = SOAP_PROTOCOL_RESPONSE_WAIT_EVENT_TIMEOUT; - } - } - - capwap_lock_exit(&g_ac_backend.lock); - - /* */ - if (!g_ac_backend.soaprequest) { - if (request) { - ac_soapclient_free_request(request); - } - - return -1; - } - - /* Send Request & Recv Response */ - if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { - struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); - if (response) { - /* Wait event result */ - jsonroot = ac_soapclient_parse_json_response(response); - ac_soapclient_free_response(response); - } - } - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Free resource */ - ac_soapclient_close_request(g_ac_backend.soaprequest, 1); - g_ac_backend.soaprequest = NULL; - - capwap_lock_exit(&g_ac_backend.lock); - - /* Parsing JSON command after close event request */ - if (jsonroot) { - if (json_object_get_type(jsonroot) == json_type_array) { - int i; - int length; - - /* Parsing every message into JSON result */ - length = json_object_array_length(jsonroot); - if (!length) { - result = 0; - } else { - for (i = 0; i < length; i++) { - struct json_object* jsonitem = json_object_array_get_idx(jsonroot, i); - if (jsonitem && (json_object_get_type(jsonitem) == json_type_object)) { - result = ac_backend_parsing_event(jsonitem); - if (result) { - break; - } - } - } - } - } - - /* Free JSON */ - json_object_put(jsonroot); - } - - return result; -} - -/* */ -static void ac_backend_soap_leave(void) { - struct ac_soap_request* request; - struct ac_http_soap_server* server; - - ASSERT(g_ac_backend.soaprequest == NULL); - - /* */ - if (!g_ac_backend.backendstatus || !g_ac_backend.backendsessionid) { - return; - } - - /* Get HTTP Soap Server */ - server = ac_backend_get_server(); - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Build Soap Request */ - request = ac_soapclient_create_request("leaveBackend", SOAP_NAMESPACE_URI); - if (request) { - ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); - g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); - } - - capwap_lock_exit(&g_ac_backend.lock); - - /* */ - if (!g_ac_backend.soaprequest) { - if (request) { - ac_soapclient_free_request(request); - } - - return; - } - - /* Send Request & Recv Response */ - if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { - struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); - if (response) { - ac_soapclient_free_response(response); - } - } - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - /* Free resource */ - ac_soapclient_close_request(g_ac_backend.soaprequest, 1); - g_ac_backend.soaprequest = NULL; - - capwap_lock_exit(&g_ac_backend.lock); -} - -/* */ -static void ac_backend_run(void) { - int connected = 0; - int forcereset = 1; - - capwap_lock_enter(&g_ac_backend.backendlock); - - while (!g_ac_backend.endthread) { - if (connected) { - if (ac_backend_soap_waitevent()) { - if (g_ac_backend.endthread) { - break; - } - - /* Connection error, change Backend Server */ - connected = 0; - capwap_logging_debug("Lost connection with Backend Server"); - capwap_lock_enter(&g_ac_backend.backendlock); - - /* Lost session id */ - capwap_free(g_ac_backend.backendsessionid); - g_ac_backend.backendsessionid = NULL; - - /* Change backend */ - g_ac_backend.activebackend = (g_ac_backend.activebackend + 1) % g_ac.availablebackends->count; - } - } else { - /* Join with a Backend Server */ - if (!ac_backend_soap_join(forcereset)) { - capwap_logging_debug("Joined with Backend Server"); - - /* Join Complete */ - connected = 1; - forcereset = 0; - g_ac_backend.backendstatus = 1; - g_ac_backend.errorjoinbackend = 0; - capwap_lock_exit(&g_ac_backend.backendlock); - } else { - /* Change Backend Server */ - g_ac_backend.activebackend = (g_ac_backend.activebackend + 1) % g_ac.availablebackends->count; - g_ac_backend.errorjoinbackend++; - - /* Wait timeout before continue */ - if (g_ac_backend.errorjoinbackend >= g_ac.availablebackends->count) { - capwap_logging_debug("Unable to join with Backend Server"); - - /* */ - forcereset = 1; - g_ac_backend.backendstatus = 0; - g_ac_backend.errorjoinbackend = 0; - - capwap_lock_exit(&g_ac_backend.backendlock); - - /* Close all sessions */ - ac_msgqueue_close_allsessions(); - - /* Wait before retry join to backend server */ - capwap_event_wait_timeout(&g_ac_backend.wait, AC_BACKEND_WAIT_TIMEOUT); - - capwap_lock_enter(&g_ac_backend.backendlock); - } - } - } - } - - /* Leave Backend */ - ac_backend_soap_leave(); - g_ac_backend.backendstatus = 0; - - /* */ - if (g_ac_backend.backendsessionid) { - capwap_free(g_ac_backend.backendsessionid); - g_ac_backend.backendsessionid = NULL; - } - - /* */ - if (!connected) { - capwap_lock_exit(&g_ac_backend.backendlock); - } -} - -/* */ -static void* ac_backend_thread(void* param) { - capwap_logging_debug("Backend start"); - ac_backend_run(); - capwap_logging_debug("Backend stop"); - - /* Thread exit */ - pthread_exit(NULL); - return NULL; -} - -/* */ -int ac_backend_isconnect(void) { - return (g_ac_backend.backendstatus ? 1 : 0); -} - -/* */ -struct ac_http_soap_request* ac_backend_createrequest_with_session(char* method, char* uri) { - struct ac_http_soap_server* server; - struct ac_soap_request* request; - struct ac_http_soap_request* soaprequest = NULL; - - /* Get active connection only if Backend Management Thread is not trying to connect with a Backend Server */ - capwap_lock_enter(&g_ac_backend.backendlock); - - if (ac_backend_isconnect()) { - server = ac_backend_get_server(); - - /* Build Soap Request */ - request = ac_soapclient_create_request(method, SOAP_NAMESPACE_URI); - if (request) { - soaprequest = ac_soapclient_prepare_request(request, server); - if (soaprequest) { - ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); - } else { - ac_soapclient_free_request(request); - } - } - } - - capwap_lock_exit(&g_ac_backend.backendlock); - - return soaprequest; -} - -/* */ -int ac_backend_start(void) { - int result; - - memset(&g_ac_backend, 0, sizeof(struct ac_backend_t)); - - /* */ - if (!g_ac.backendacid) { - capwap_logging_error("AC Backend ID isn't set"); - return 0; - } else if (!g_ac.backendversion) { - capwap_logging_error("Backend Protocol Version isn't set"); - return 0; - } else if (!g_ac.availablebackends->count) { - capwap_logging_error("List of available backends is empty"); - return 0; - } - - /* Init */ - capwap_lock_init(&g_ac_backend.lock); - capwap_lock_init(&g_ac_backend.backendlock); - capwap_event_init(&g_ac_backend.wait); - - /* Create thread */ - result = pthread_create(&g_ac_backend.threadid, NULL, ac_backend_thread, NULL); - if (result) { - capwap_logging_debug("Unable create backend thread"); - return 0; - } - - return 1; -} - -/* */ -void ac_backend_stop(void) { - void* dummy; - - g_ac_backend.endthread = 1; - - /* Critical section */ - capwap_lock_enter(&g_ac_backend.lock); - - if (g_ac_backend.soaprequest) { - ac_soapclient_shutdown_request(g_ac_backend.soaprequest); - } - - /* */ - capwap_lock_exit(&g_ac_backend.lock); - capwap_event_signal(&g_ac_backend.wait); - - /* Wait close thread */ - pthread_join(g_ac_backend.threadid, &dummy); -} - -/* */ -void ac_backend_free(void) { - capwap_event_destroy(&g_ac_backend.wait); - capwap_lock_destroy(&g_ac_backend.lock); - capwap_lock_destroy(&g_ac_backend.backendlock); -} +#include "ac.h" +#include "capwap_dfa.h" +#include "ac_backend.h" +#include "ac_soap.h" +#include "ac_session.h" + +/* */ +#define AC_BACKEND_WAIT_TIMEOUT 10000 +#define SOAP_PROTOCOL_RESPONSE_WAIT_EVENT_TIMEOUT 70000 + +/* */ +struct ac_backend_t { + pthread_t threadid; + int endthread; + + capwap_event_t wait; + capwap_lock_t lock; + capwap_lock_t backendlock; + + /* Backend Soap */ + int activebackend; + int backendstatus; + int errorjoinbackend; + + /* Session */ + char* backendsessionid; + + /* Soap Request */ + struct ac_http_soap_request* soaprequest; +}; + +static struct ac_backend_t g_ac_backend; + +/* */ +static struct ac_http_soap_server* ac_backend_get_server(void) { + return *(struct ac_http_soap_server**)capwap_array_get_item_pointer(g_ac.availablebackends, g_ac_backend.activebackend); +} + +/* */ +static int ac_backend_parsing_closewtpsession_event(const char* idevent, struct json_object* jsonparams) { + int result = -1; + struct ac_session_t* session; + struct json_object* jsonwtpid; + + /* Params CloseWTPSession Action + { + WTPId: [string] + } + */ + + /* WTPId */ + jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId"); + if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { + return -1; + } + + /* Get session */ + session = ac_search_session_from_wtpid(json_object_get_string(jsonwtpid)); + if (session) { + struct ac_session_notify_event_t notify; + + /* Notify Request to Complete Event */ + strcpy(notify.idevent, idevent); + notify.action = NOTIFY_ACTION_CHANGE_STATE; + notify.session_state = CAPWAP_DEAD_STATE; + ac_session_send_action(session, AC_SESSION_ACTION_NOTIFY_EVENT, 0, (void*)¬ify, sizeof(struct ac_session_notify_event_t)); + + /* Async close session */ + capwap_logging_debug("Receive close wtp session for WTP %s", session->wtpid); + ac_session_send_action(session, AC_SESSION_ACTION_CLOSE, 0, NULL, 0); + + /* */ + ac_session_release_reference(session); + result = 0; + } + + return result; +} + +/* */ +static int ac_backend_parsing_resetwtp_event(const char* idevent, struct json_object* jsonparams) { + int result = -1; + struct ac_session_t* session; + struct json_object* jsonwtpid; + struct json_object* jsonimage; + struct json_object* jsonvendor; + struct json_object* jsondata; + + /* Params ResetWTP Action + { + WTPId: [string], + ImageIdentifier: { + Vendor: [int], + Data: [string] + } + } + */ + + /* WTPId */ + jsonwtpid = compat_json_object_object_get(jsonparams, "WTPId"); + if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { + return -1; + } + + /* ImageIdentifier */ + jsonimage = compat_json_object_object_get(jsonparams, "ImageIdentifier"); + if (!jsonimage || (json_object_get_type(jsonimage) != json_type_object)) { + return -1; + } + + jsonvendor = compat_json_object_object_get(jsonimage, "Vendor"); + jsondata = compat_json_object_object_get(jsonimage, "Data"); + if (!jsonvendor || !jsondata || (json_object_get_type(jsonvendor) != json_type_int) || (json_object_get_type(jsondata) != json_type_string)) { + return -1; + } + + /* Get session */ + session = ac_search_session_from_wtpid(json_object_get_string(jsonwtpid)); + if (session) { + const char* name = json_object_get_string(jsondata); + if (name && *name) { + int length; + struct ac_notify_reset_t* reset; + struct ac_session_notify_event_t notify; + + /* Notification data */ + length = sizeof(struct ac_notify_reset_t) + strlen(name) + 1; + reset = (struct ac_notify_reset_t*)capwap_alloc(length); + + /* */ + reset->vendor = (uint32_t)json_object_get_int(jsonvendor); + strcpy((char*)reset->name, name); + + /* Notify Request to Complete Event */ + strcpy(notify.idevent, idevent); + notify.action = NOTIFY_ACTION_CHANGE_STATE; + notify.session_state = CAPWAP_DEAD_STATE; + ac_session_send_action(session, AC_SESSION_ACTION_NOTIFY_EVENT, 0, (void*)¬ify, sizeof(struct ac_session_notify_event_t)); + + /* Notify Action */ + capwap_logging_debug("Receive reset request for WTP %s", session->wtpid); + ac_session_send_action(session, AC_SESSION_ACTION_RESET_WTP, 0, (void*)reset, length); + result = 0; + + /* */ + capwap_free(reset); + } + + ac_session_release_reference(session); + } + + return result; +} + +/* */ +static int ac_backend_parsing_addwlan_event(const char* idevent, struct json_object* jsonparams) { + int result = -1; + struct ac_session_t* session; + struct json_object* jsonwtpid; + struct json_object* jsonradioid; + struct json_object* jsonwlanid; + struct json_object* jsoncapability; + struct json_object* jsonqos; + struct json_object* jsonauthtype; + struct json_object* jsonmacmode; + struct json_object* jsontunnelmode; + struct json_object* jsonhidessid; + struct json_object* jsonssid; + const char* ssid; + + /* Params AddWLAN Action + { + WTPID: [string], + RadioID: [int], + WLANID: [int], + Capability: [int], + Key: { + TODO + }, + DefaultQoS: [int], + AuthType: [int], + MACMode: [int], + TunnelMode: [int], + SuppressSSID: [bool], + SSID: [string], + IE: { + TODO + } + } + */ + + /* WTPID */ + jsonwtpid = compat_json_object_object_get(jsonparams, "WTPID"); + if (!jsonwtpid || (json_object_get_type(jsonwtpid) != json_type_string)) { + return -1; + } + + /* RadioID */ + jsonradioid = compat_json_object_object_get(jsonparams, "RadioID"); + if (!jsonradioid || (json_object_get_type(jsonradioid) != json_type_int)) { + return -1; + } + + /* WLANID */ + jsonwlanid = compat_json_object_object_get(jsonparams, "WLANID"); + if (!jsonwlanid || (json_object_get_type(jsonwlanid) != json_type_int)) { + return -1; + } + + /* Capability */ + jsoncapability = compat_json_object_object_get(jsonparams, "Capability"); + if (!jsoncapability || (json_object_get_type(jsoncapability) != json_type_int)) { + return -1; + } + + /* Key */ + /* TODO */ + + /* DefaultQoS */ + jsonqos = compat_json_object_object_get(jsonparams, "DefaultQoS"); + if (!jsonqos || (json_object_get_type(jsonqos) != json_type_int)) { + return -1; + } + + /* AuthType */ + jsonauthtype = compat_json_object_object_get(jsonparams, "AuthType"); + if (!jsonauthtype || (json_object_get_type(jsonauthtype) != json_type_int)) { + return -1; + } + + /* MACMode */ + jsonmacmode = compat_json_object_object_get(jsonparams, "MACMode"); + if (!jsonmacmode || (json_object_get_type(jsonmacmode) != json_type_int)) { + return -1; + } + + /* TunnelMode */ + jsontunnelmode = compat_json_object_object_get(jsonparams, "TunnelMode"); + if (!jsontunnelmode || (json_object_get_type(jsontunnelmode) != json_type_int)) { + return -1; + } + + /* SuppressSSID */ + jsonhidessid = compat_json_object_object_get(jsonparams, "SuppressSSID"); + if (!jsonhidessid || (json_object_get_type(jsonhidessid) != json_type_boolean)) { + return -1; + } + + /* SSID */ + jsonssid = compat_json_object_object_get(jsonparams, "SSID"); + if (jsonssid && (json_object_get_type(jsonssid) == json_type_string)) { + ssid = json_object_get_string(jsonssid); + if (strlen(ssid) > CAPWAP_ADD_WLAN_SSID_LENGTH) { + return -1; + } + } else { + return -1; + } + + /* IE */ + /* TODO */ + + /* Get session */ + session = ac_search_session_from_wtpid(json_object_get_string(jsonwtpid)); + if (session) { + int length; + struct ac_notify_addwlan_t* addwlan; + struct ac_session_notify_event_t notify; + + /* Notification data */ + length = sizeof(struct ac_notify_addwlan_t); + addwlan = (struct ac_notify_addwlan_t*)capwap_alloc(length); + + /* */ + addwlan->radioid = (uint8_t)json_object_get_int(jsonradioid); + addwlan->wlanid = (uint8_t)json_object_get_int(jsonwlanid); + addwlan->capability = (uint16_t)json_object_get_int(jsoncapability); + addwlan->qos = (uint8_t)json_object_get_int(jsonqos); + addwlan->authmode = (uint8_t)json_object_get_int(jsonauthtype); + addwlan->macmode = (uint8_t)json_object_get_int(jsonmacmode); + addwlan->tunnelmode = (uint8_t)json_object_get_int(jsontunnelmode); + addwlan->suppressssid = (uint8_t)(json_object_get_boolean(jsonhidessid) ? 1 : 0); + strcpy(addwlan->ssid, ssid); + + /* Notify Request to Complete Event */ + strcpy(notify.idevent, idevent); + notify.action = NOTIFY_ACTION_RECEIVE_RESPONSE_CONTROLMESSAGE; + notify.ctrlmsg_type = CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE; + ac_session_send_action(session, AC_SESSION_ACTION_NOTIFY_EVENT, 0, (void*)¬ify, sizeof(struct ac_session_notify_event_t)); + + /* Notify Action */ + capwap_logging_debug("Receive AddWLAN request for WTP %s with SSID: %s", session->wtpid, addwlan->ssid); + ac_session_send_action(session, AC_SESSION_ACTION_ADDWLAN, 0, (void*)addwlan, length); + + /* */ + ac_session_release_reference(session); + capwap_free(addwlan); + result = 0; + } + + return result; +} + +/* */ +static int ac_backend_parsing_updatewlan_event(const char* idevent, struct json_object* jsonparams) { + int result = -1; + + return result; +} + +/* */ +static int ac_backend_parsing_deletewlan_event(const char* idevent, struct json_object* jsonparams) { + int result = -1; + + return result; +} + +/* */ +static int ac_backend_soap_update_event(const char* idevent, int status) { + int result = 0; + char buffer[256]; + struct ac_soap_request* request = NULL; + struct ac_http_soap_server* server; + + ASSERT(g_ac_backend.soaprequest == NULL); + ASSERT(g_ac_backend.backendsessionid != NULL); + + /* Get HTTP Soap Server */ + server = ac_backend_get_server(); + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Build Soap Request */ + if (!g_ac_backend.endthread) { + request = ac_soapclient_create_request("updateBackendEvent", SOAP_NAMESPACE_URI); + if (request) { + ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); + ac_soapclient_add_param(request, "xs:string", "idevent", idevent); + ac_soapclient_add_param(request, "xs:int", "status", capwap_itoa(status, buffer)); + g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); + } + } + + capwap_lock_exit(&g_ac_backend.lock); + + /* */ + if (!g_ac_backend.soaprequest) { + if (request) { + ac_soapclient_free_request(request); + } + + return 0; + } + + /* Send Request & Recv Response */ + if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { + struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); + if (response) { + ac_soapclient_free_response(response); + } + } + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Free resource */ + ac_soapclient_close_request(g_ac_backend.soaprequest, 1); + g_ac_backend.soaprequest = NULL; + + capwap_lock_exit(&g_ac_backend.lock); + + return result; +} + +/* */ +static int ac_backend_soap_getconfiguration(void) { + int result = -1; + struct ac_soap_request* request = NULL; + struct ac_http_soap_server* server; + struct json_object* jsonroot = NULL; + + ASSERT(g_ac_backend.soaprequest == NULL); + ASSERT(g_ac_backend.backendsessionid != NULL); + + /* Get HTTP Soap Server */ + server = ac_backend_get_server(); + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Build Soap Request */ + if (!g_ac_backend.endthread) { + request = ac_soapclient_create_request("getConfiguration", SOAP_NAMESPACE_URI); + if (request) { + ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); + g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); + } + } + + capwap_lock_exit(&g_ac_backend.lock); + + /* */ + if (!g_ac_backend.soaprequest) { + if (request) { + ac_soapclient_free_request(request); + } + + return -1; + } + + /* Send Request & Recv Response */ + if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { + struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); + if (response) { + /* Get Configuration result */ + jsonroot = ac_soapclient_parse_json_response(response); + ac_soapclient_free_response(response); + } + } + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Free resource */ + ac_soapclient_close_request(g_ac_backend.soaprequest, 1); + g_ac_backend.soaprequest = NULL; + + capwap_lock_exit(&g_ac_backend.lock); + + /* Send JSON command to primary thread */ + if (jsonroot) { + result = ac_msgqueue_update_configuration(jsonroot); + if (result) { + json_object_put(jsonroot); + } + } + + return result; +} + +/* */ +static int ac_backend_soap_join(int forcereset) { + struct ac_soap_request* request = NULL; + struct ac_http_soap_server* server; + + ASSERT(g_ac_backend.soaprequest == NULL); + ASSERT(g_ac_backend.backendsessionid == NULL); + + /* Get HTTP Soap Server */ + server = ac_backend_get_server(); + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Build Soap Request */ + if (!g_ac_backend.endthread) { + request = ac_soapclient_create_request("joinBackend", SOAP_NAMESPACE_URI); + if (request) { + ac_soapclient_add_param(request, "xs:string", "idac", g_ac.backendacid); + ac_soapclient_add_param(request, "xs:string", "version", g_ac.backendversion); + ac_soapclient_add_param(request, "xs:boolean", "forcereset", (forcereset ? "true" : "false")); + g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); + } + } + + capwap_lock_exit(&g_ac_backend.lock); + + /* */ + if (!g_ac_backend.soaprequest) { + if (request) { + ac_soapclient_free_request(request); + } + + return -1; + } + + /* Send Request & Recv Response */ + if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { + struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); + if (response) { + /* Get join result */ + if ((response->responsecode == HTTP_RESULT_OK) && response->xmlResponseReturn) { + xmlChar* xmlResult = xmlNodeGetContent(response->xmlResponseReturn); + if (xmlStrlen(xmlResult)) { + g_ac_backend.backendsessionid = capwap_duplicate_string((const char*)xmlResult); + } + + xmlFree(xmlResult); + } + + /* */ + ac_soapclient_free_response(response); + } + } + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Free resource */ + ac_soapclient_close_request(g_ac_backend.soaprequest, 1); + g_ac_backend.soaprequest = NULL; + + capwap_lock_exit(&g_ac_backend.lock); + + /* Retrieve AC configuration */ + if (g_ac_backend.backendsessionid && forcereset) { + if (ac_backend_soap_getconfiguration()) { + capwap_logging_error("Unable to get AC configuration from Backend Server"); + capwap_free(g_ac_backend.backendsessionid); + g_ac_backend.backendsessionid = NULL; + } + } + + return (g_ac_backend.backendsessionid ? 0 : -1); +} + +/* */ +static int ac_backend_parsing_event(struct json_object* jsonitem) { + int result = -1; + struct json_object* jsonvalue; + + ASSERT(jsonitem != NULL); + + /* Receive event into JSON result + { + EventID: [int], + Action: [string], + Params: { + + } + } + */ + + /* Get EventID */ + jsonvalue = compat_json_object_object_get(jsonitem, "EventID"); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) { + const char* idevent = json_object_get_string(jsonvalue); + + /* Get Action */ + jsonvalue = compat_json_object_object_get(jsonitem, "Action"); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_string)) { + const char* action = json_object_get_string(jsonvalue); + if (action) { + jsonvalue = compat_json_object_object_get(jsonitem, "Params"); + if (jsonvalue && (json_object_get_type(jsonvalue) == json_type_object)) { + /* Parsing params according to the action */ + if (!strcmp(action, "CloseWTPSession")) { + result = ac_backend_parsing_closewtpsession_event(idevent, jsonvalue); + } else if (!strcmp(action, "ResetWTP")) { + result = ac_backend_parsing_resetwtp_event(idevent, jsonvalue); + } else if (!strcmp(action, "AddWLAN")) { + result = ac_backend_parsing_addwlan_event(idevent, jsonvalue); + } else if (!strcmp(action, "UpdateWLAN")) { + result = ac_backend_parsing_updatewlan_event(idevent, jsonvalue); + } else if (!strcmp(action, "DeleteWLAN")) { + result = ac_backend_parsing_deletewlan_event(idevent, jsonvalue); + } + + /* Notify result action */ + ac_backend_soap_update_event(idevent, (!result ? SOAP_EVENT_STATUS_RUNNING : SOAP_EVENT_STATUS_GENERIC_ERROR)); + } + } + } + } + + return result; +} + +/* */ +static int ac_backend_soap_waitevent(void) { + int result = -1; + struct ac_soap_request* request = NULL; + struct ac_http_soap_server* server; + struct json_object* jsonroot = NULL; + + ASSERT(g_ac_backend.soaprequest == NULL); + ASSERT(g_ac_backend.backendsessionid != NULL); + + /* Get HTTP Soap Server */ + server = ac_backend_get_server(); + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Build Soap Request */ + if (!g_ac_backend.endthread) { + request = ac_soapclient_create_request("waitBackendEvent", SOAP_NAMESPACE_URI); + if (request) { + ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); + g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); + + /* Change result timeout */ + g_ac_backend.soaprequest->responsetimeout = SOAP_PROTOCOL_RESPONSE_WAIT_EVENT_TIMEOUT; + } + } + + capwap_lock_exit(&g_ac_backend.lock); + + /* */ + if (!g_ac_backend.soaprequest) { + if (request) { + ac_soapclient_free_request(request); + } + + return -1; + } + + /* Send Request & Recv Response */ + if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { + struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); + if (response) { + /* Wait event result */ + jsonroot = ac_soapclient_parse_json_response(response); + ac_soapclient_free_response(response); + } + } + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Free resource */ + ac_soapclient_close_request(g_ac_backend.soaprequest, 1); + g_ac_backend.soaprequest = NULL; + + capwap_lock_exit(&g_ac_backend.lock); + + /* Parsing JSON command after close event request */ + if (jsonroot) { + if (json_object_get_type(jsonroot) == json_type_array) { + int i; + int length; + + /* Parsing every message into JSON result */ + length = json_object_array_length(jsonroot); + if (!length) { + result = 0; + } else { + for (i = 0; i < length; i++) { + struct json_object* jsonitem = json_object_array_get_idx(jsonroot, i); + if (jsonitem && (json_object_get_type(jsonitem) == json_type_object)) { + result = ac_backend_parsing_event(jsonitem); + if (result) { + break; + } + } + } + } + } + + /* Free JSON */ + json_object_put(jsonroot); + } + + return result; +} + +/* */ +static void ac_backend_soap_leave(void) { + struct ac_soap_request* request; + struct ac_http_soap_server* server; + + ASSERT(g_ac_backend.soaprequest == NULL); + + /* */ + if (!g_ac_backend.backendstatus || !g_ac_backend.backendsessionid) { + return; + } + + /* Get HTTP Soap Server */ + server = ac_backend_get_server(); + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Build Soap Request */ + request = ac_soapclient_create_request("leaveBackend", SOAP_NAMESPACE_URI); + if (request) { + ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); + g_ac_backend.soaprequest = ac_soapclient_prepare_request(request, server); + } + + capwap_lock_exit(&g_ac_backend.lock); + + /* */ + if (!g_ac_backend.soaprequest) { + if (request) { + ac_soapclient_free_request(request); + } + + return; + } + + /* Send Request & Recv Response */ + if (ac_soapclient_send_request(g_ac_backend.soaprequest, "")) { + struct ac_soap_response* response = ac_soapclient_recv_response(g_ac_backend.soaprequest); + if (response) { + ac_soapclient_free_response(response); + } + } + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + /* Free resource */ + ac_soapclient_close_request(g_ac_backend.soaprequest, 1); + g_ac_backend.soaprequest = NULL; + + capwap_lock_exit(&g_ac_backend.lock); +} + +/* */ +static void ac_backend_run(void) { + int connected = 0; + int forcereset = 1; + + capwap_lock_enter(&g_ac_backend.backendlock); + + while (!g_ac_backend.endthread) { + if (connected) { + if (ac_backend_soap_waitevent()) { + if (g_ac_backend.endthread) { + break; + } + + /* Connection error, change Backend Server */ + connected = 0; + capwap_logging_debug("Lost connection with Backend Server"); + capwap_lock_enter(&g_ac_backend.backendlock); + + /* Lost session id */ + capwap_free(g_ac_backend.backendsessionid); + g_ac_backend.backendsessionid = NULL; + + /* Change backend */ + g_ac_backend.activebackend = (g_ac_backend.activebackend + 1) % g_ac.availablebackends->count; + } + } else { + /* Join with a Backend Server */ + if (!ac_backend_soap_join(forcereset)) { + capwap_logging_debug("Joined with Backend Server"); + + /* Join Complete */ + connected = 1; + forcereset = 0; + g_ac_backend.backendstatus = 1; + g_ac_backend.errorjoinbackend = 0; + capwap_lock_exit(&g_ac_backend.backendlock); + } else { + /* Change Backend Server */ + g_ac_backend.activebackend = (g_ac_backend.activebackend + 1) % g_ac.availablebackends->count; + g_ac_backend.errorjoinbackend++; + + /* Wait timeout before continue */ + if (g_ac_backend.errorjoinbackend >= g_ac.availablebackends->count) { + capwap_logging_debug("Unable to join with Backend Server"); + + /* */ + forcereset = 1; + g_ac_backend.backendstatus = 0; + g_ac_backend.errorjoinbackend = 0; + + capwap_lock_exit(&g_ac_backend.backendlock); + + /* Close all sessions */ + ac_msgqueue_close_allsessions(); + + /* Wait before retry join to backend server */ + capwap_event_wait_timeout(&g_ac_backend.wait, AC_BACKEND_WAIT_TIMEOUT); + + capwap_lock_enter(&g_ac_backend.backendlock); + } + } + } + } + + /* Leave Backend */ + ac_backend_soap_leave(); + g_ac_backend.backendstatus = 0; + + /* */ + if (g_ac_backend.backendsessionid) { + capwap_free(g_ac_backend.backendsessionid); + g_ac_backend.backendsessionid = NULL; + } + + /* */ + if (!connected) { + capwap_lock_exit(&g_ac_backend.backendlock); + } +} + +/* */ +static void* ac_backend_thread(void* param) { + capwap_logging_debug("Backend start"); + ac_backend_run(); + capwap_logging_debug("Backend stop"); + + /* Thread exit */ + pthread_exit(NULL); + return NULL; +} + +/* */ +int ac_backend_isconnect(void) { + return (g_ac_backend.backendstatus ? 1 : 0); +} + +/* */ +struct ac_http_soap_request* ac_backend_createrequest_with_session(char* method, char* uri) { + struct ac_http_soap_server* server; + struct ac_soap_request* request; + struct ac_http_soap_request* soaprequest = NULL; + + /* Get active connection only if Backend Management Thread is not trying to connect with a Backend Server */ + capwap_lock_enter(&g_ac_backend.backendlock); + + if (ac_backend_isconnect()) { + server = ac_backend_get_server(); + + /* Build Soap Request */ + request = ac_soapclient_create_request(method, SOAP_NAMESPACE_URI); + if (request) { + soaprequest = ac_soapclient_prepare_request(request, server); + if (soaprequest) { + ac_soapclient_add_param(request, "xs:string", "idsession", g_ac_backend.backendsessionid); + } else { + ac_soapclient_free_request(request); + } + } + } + + capwap_lock_exit(&g_ac_backend.backendlock); + + return soaprequest; +} + +/* */ +int ac_backend_start(void) { + int result; + + memset(&g_ac_backend, 0, sizeof(struct ac_backend_t)); + + /* */ + if (!g_ac.backendacid) { + capwap_logging_error("AC Backend ID isn't set"); + return 0; + } else if (!g_ac.backendversion) { + capwap_logging_error("Backend Protocol Version isn't set"); + return 0; + } else if (!g_ac.availablebackends->count) { + capwap_logging_error("List of available backends is empty"); + return 0; + } + + /* Init */ + capwap_lock_init(&g_ac_backend.lock); + capwap_lock_init(&g_ac_backend.backendlock); + capwap_event_init(&g_ac_backend.wait); + + /* Create thread */ + result = pthread_create(&g_ac_backend.threadid, NULL, ac_backend_thread, NULL); + if (result) { + capwap_logging_debug("Unable create backend thread"); + return 0; + } + + return 1; +} + +/* */ +void ac_backend_stop(void) { + void* dummy; + + g_ac_backend.endthread = 1; + + /* Critical section */ + capwap_lock_enter(&g_ac_backend.lock); + + if (g_ac_backend.soaprequest) { + ac_soapclient_shutdown_request(g_ac_backend.soaprequest); + } + + /* */ + capwap_lock_exit(&g_ac_backend.lock); + capwap_event_signal(&g_ac_backend.wait); + + /* Wait close thread */ + pthread_join(g_ac_backend.threadid, &dummy); +} + +/* */ +void ac_backend_free(void) { + capwap_event_destroy(&g_ac_backend.wait); + capwap_lock_destroy(&g_ac_backend.lock); + capwap_lock_destroy(&g_ac_backend.backendlock); +} diff --git a/src/ac/ac_backend.h b/src/ac/ac_backend.h index 9840a5f..cc5056c 100644 --- a/src/ac/ac_backend.h +++ b/src/ac/ac_backend.h @@ -1,22 +1,22 @@ -#ifndef __AC_BACKEND_HEADER__ -#define __AC_BACKEND_HEADER__ - -/* */ -#define SOAP_NAMESPACE_URI "http://smartcapwap/namespace" - -/* SOAP event status*/ -#define SOAP_EVENT_STATUS_GENERIC_ERROR -1 -#define SOAP_EVENT_STATUS_CANCEL -2 -#define SOAP_EVENT_STATUS_RUNNING 0 -#define SOAP_EVENT_STATUS_COMPLETE 1 - -/* */ -int ac_backend_start(void); -void ac_backend_stop(void); -void ac_backend_free(void); - -/* */ -int ac_backend_isconnect(void); -struct ac_http_soap_request* ac_backend_createrequest_with_session(char* method, char* uri); - -#endif /* __AC_BACKEND_HEADER__ */ +#ifndef __AC_BACKEND_HEADER__ +#define __AC_BACKEND_HEADER__ + +/* */ +#define SOAP_NAMESPACE_URI "http://smartcapwap/namespace" + +/* SOAP event status*/ +#define SOAP_EVENT_STATUS_GENERIC_ERROR -1 +#define SOAP_EVENT_STATUS_CANCEL -2 +#define SOAP_EVENT_STATUS_RUNNING 0 +#define SOAP_EVENT_STATUS_COMPLETE 1 + +/* */ +int ac_backend_start(void); +void ac_backend_stop(void); +void ac_backend_free(void); + +/* */ +int ac_backend_isconnect(void); +struct ac_http_soap_request* ac_backend_createrequest_with_session(char* method, char* uri); + +#endif /* __AC_BACKEND_HEADER__ */ diff --git a/src/ac/ac_ieee80211_data.c b/src/ac/ac_ieee80211_data.c index 9273fb2..aac36e3 100644 --- a/src/ac/ac_ieee80211_data.c +++ b/src/ac/ac_ieee80211_data.c @@ -1,459 +1,459 @@ -#include "ac.h" -#include "ac_session.h" -#include "ac_wlans.h" - -/* */ -static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - - /* Accept probe request only if not sent by WTP */ - if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH)) { - return; - } - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { - return; - } - - /* TODO */ -} - -/* */ -static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - struct ac_station* station; - struct ac_wlan* wlan; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->authetication.ie[0], ielength)) { - return; - } - - /* */ - if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { - station = ac_stations_create_station(session, radioid, mgmt->bssid, mgmt->sa); - if (!station || !station->wlan) { - return; - } - - /* */ - capwap_logging_info("Receive IEEE802.11 Authentication Request from %s station", station->addrtext); - - /* A station is removed if the association does not complete within a given period of time */ - station->timeoutaction = AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; - station->idtimeout = capwap_timeout_set(session->timeout, station->idtimeout, AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE, ac_stations_timeout, station, session); - - /* */ - wlan = station->wlan; - if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { - /* TODO */ - } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - uint16_t algorithm; - uint16_t transactionseqnumber; - uint16_t responsestatuscode; - uint8_t buffer[IEEE80211_MTU]; - struct ieee80211_authentication_params ieee80211_params; - int responselength; - - /* Parsing Information Elements */ - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->authetication.ie[0], ielength)) { - capwap_logging_info("Invalid IEEE802.11 Authentication Request from %s station", station->addrtext); - return; - } - - /* */ - algorithm = __le16_to_cpu(mgmt->authetication.algorithm); - transactionseqnumber = __le16_to_cpu(mgmt->authetication.transactionseqnumber); - - /* */ - responsestatuscode = IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM; - if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_OPEN)) { - if (transactionseqnumber == 1) { - responsestatuscode = IEEE80211_STATUS_SUCCESS; - station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; - } else { - responsestatuscode = IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION; - } - } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP)) { - /* TODO */ - } - - /* Create authentication packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); - memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); - memcpy(ieee80211_params.station, mgmt->sa, MACADDRESS_EUI48_LENGTH); - ieee80211_params.algorithm = algorithm; - ieee80211_params.transactionseqnumber = transactionseqnumber + 1; - ieee80211_params.statuscode = responsestatuscode; - - responselength = ieee80211_create_authentication_response(buffer, sizeof(buffer), &ieee80211_params); - if (responselength > 0) { - /* Send authentication response */ - if (!ac_kmod_send_data(&session->sessionid, wlan->device->radioid, session->binding, buffer, responselength)) { - capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)responsestatuscode); - station->flags |= AC_STATION_FLAGS_AUTHENTICATED; - } else { - capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", station->addrtext); - ac_stations_delete_station(session, station); - } - } else { - capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", station->addrtext); - ac_stations_delete_station(session, station); - } - } - } else if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { - station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da); - if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { - uint16_t algorithm; - uint16_t transactionseqnumber; - uint16_t statuscode; - - /* */ - statuscode = __le16_to_cpu(mgmt->authetication.statuscode); - - /* */ - capwap_logging_info("Receive IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)statuscode); - - if (statuscode == IEEE80211_STATUS_SUCCESS) { - algorithm = __le16_to_cpu(mgmt->authetication.algorithm); - transactionseqnumber = __le16_to_cpu(mgmt->authetication.transactionseqnumber); - - /* Check if authenticate */ - if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { - station->flags |= AC_STATION_FLAGS_AUTHENTICATED; - } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { - /* TODO */ - } - } - } - } -} - -/* */ -static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - struct ac_station* station; - struct ac_wlan* wlan; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { - return; - } - - /* Get station */ - if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { - station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->sa); - if (!station || !station->wlan) { - return; - } - - /* */ - capwap_logging_info("Receive IEEE802.11 Association Request from %s station", station->addrtext); - - /* */ - wlan = station->wlan; - if (!(station->flags & AC_STATION_FLAGS_AUTHENTICATED)) { - /* Invalid station, delete station */ - capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext); - ac_stations_delete_station(session, station); - return; - } - - /* Get Station Info */ - station->capability = __le16_to_cpu(mgmt->associationrequest.capability); - station->listeninterval = __le16_to_cpu(mgmt->associationrequest.listeninterval); - - /* Get supported rates */ - if (ieitems.supported_rates && ((ieitems.supported_rates->len + (ieitems.extended_supported_rates ? ieitems.extended_supported_rates->len : 0)) <= sizeof(station->supportedrates))) { - station->supportedratescount = ieitems.supported_rates->len; - memcpy(station->supportedrates, ieitems.supported_rates->rates, ieitems.supported_rates->len); - if (ieitems.extended_supported_rates) { - station->supportedratescount += ieitems.extended_supported_rates->len; - memcpy(&station->supportedrates[ieitems.supported_rates->len], ieitems.extended_supported_rates->rates, ieitems.extended_supported_rates->len); - } - - /* */ - if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { - /* TODO */ - } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - int responselength; - struct ieee80211_ie_items ieitems; - struct ieee80211_associationresponse_params ieee80211_params; - uint16_t resultstatuscode; - uint8_t buffer[IEEE80211_MTU]; - - /* Parsing Information Elements */ - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { - capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext); - ac_stations_delete_station(session, station); - return; - } - - /* Verify SSID */ - if (ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, NULL) != IEEE80211_VALID_SSID) { - resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; - } else { - /* Check supported rates */ - if (!ieitems.supported_rates || ((ieitems.supported_rates->len + (ieitems.extended_supported_rates ? ieitems.extended_supported_rates->len : 0)) > sizeof(station->supportedrates))) { - resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; - } else { - station->capability = __le16_to_cpu(mgmt->associationrequest.capability); - station->listeninterval = __le16_to_cpu(mgmt->associationrequest.listeninterval); - if (ieee80211_aid_create(wlan->aidbitfield, &station->aid)) { - resultstatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - } else { - /* Get supported rates */ - station->supportedratescount = ieitems.supported_rates->len; - memcpy(station->supportedrates, ieitems.supported_rates->rates, ieitems.supported_rates->len); - if (ieitems.extended_supported_rates) { - station->supportedratescount += ieitems.extended_supported_rates->len; - memcpy(&station->supportedrates[ieitems.supported_rates->len], ieitems.extended_supported_rates->rates, ieitems.extended_supported_rates->len); - } - - /* */ - resultstatuscode = IEEE80211_STATUS_SUCCESS; - } - } - } - - /* Create association response packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); - memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); - memcpy(ieee80211_params.station, mgmt->sa, ETH_ALEN); - ieee80211_params.capability = wlan->capability; - ieee80211_params.statuscode = resultstatuscode; - ieee80211_params.aid = IEEE80211_AID_FIELD | station->aid; - memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); - ieee80211_params.supportedratescount = wlan->device->supportedratescount; - - responselength = ieee80211_create_associationresponse_response(buffer, sizeof(buffer), &ieee80211_params); - if (responselength > 0) { - /* Send association response */ - if (!ac_kmod_send_data(&session->sessionid, wlan->device->radioid, session->binding, buffer, responselength)) { - capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); - - /* Active Station */ - station->flags |= AC_STATION_FLAGS_ASSOCIATE; - ac_stations_authorize_station(session, station); - } else { - capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); - ac_stations_delete_station(session, station); - } - } else { - capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext); - ac_stations_delete_station(session, station); - } - } - } - } -} - -/* */ -static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - struct ac_station* station; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationresponse.ie[0], ielength)) { - return; - } - - /* Get station */ - if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { - station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da); - if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { - capwap_logging_info("Receive IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)mgmt->associationresponse.statuscode); - - if (mgmt->associationresponse.statuscode == IEEE80211_STATUS_SUCCESS) { - /* Get Station Info */ - station->capability = __le16_to_cpu(mgmt->associationresponse.capability); - station->aid = __le16_to_cpu(mgmt->associationresponse.aid); - station->flags |= AC_STATION_FLAGS_ASSOCIATE; - - /* Get supported rates */ - if (ieitems.supported_rates && ((ieitems.supported_rates->len + (ieitems.extended_supported_rates ? ieitems.extended_supported_rates->len : 0)) <= sizeof(station->supportedrates))) { - station->supportedratescount = ieitems.supported_rates->len; - memcpy(station->supportedrates, ieitems.supported_rates->rates, ieitems.supported_rates->len); - if (ieitems.extended_supported_rates) { - station->supportedratescount += ieitems.extended_supported_rates->len; - memcpy(&station->supportedrates[ieitems.supported_rates->len], ieitems.extended_supported_rates->rates, ieitems.extended_supported_rates->len); - } - - /* Active Station */ - ac_stations_authorize_station(session, station); - } - } - } - } -} - -/* */ -static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->reassociationrequest.ie[0], ielength)) { - return; - } - - /* TODO */ -} - -/* */ -static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationresponse)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->reassociationresponse.ie[0], ielength)) { - return; - } - - /* TODO */ -} - -/* */ -static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - struct ieee80211_ie_items ieitems; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->disassociation.ie[0], ielength)) { - return; - } - - /* TODO */ -} - -/* */ -static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { - int ielength; - const uint8_t* stationaddress; - struct ac_station* station; - struct ieee80211_ie_items ieitems; - - /* Parsing Information Elements */ - ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication)); - if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->deauthetication.ie[0], ielength)) { - return; - } - - /* Get station address */ - stationaddress = (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) ? mgmt->sa : mgmt->da); - - /* Delete station */ - station = ac_stations_get_station(session, radioid, NULL, stationaddress); - if (station) { - /* Delete station without forward another IEEE802.11 deauthentication message */ - station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE); - ac_stations_delete_station(session, station); - } -} - -/* */ -static void ac_ieee80211_mgmt_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) { - switch (framecontrol_subtype) { - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest))) { - ac_ieee80211_mgmt_probe_request_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication))) { - ac_ieee80211_mgmt_authentication_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest))) { - ac_ieee80211_mgmt_association_request_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse))) { - ac_ieee80211_mgmt_association_response_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest))) { - ac_ieee80211_mgmt_reassociation_request_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationresponse))) { - ac_ieee80211_mgmt_reassociation_response_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation))) { - ac_ieee80211_mgmt_disassociation_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { - if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication))) { - ac_ieee80211_mgmt_deauthentication_packet(session, radioid, mgmt, mgmtlength); - } - - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION: { - break; - } - } -} - -/* */ -void ac_ieee80211_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header* header, int length) { - uint16_t framecontrol; - uint16_t framecontrol_type; - uint16_t framecontrol_subtype; - - ASSERT(session != NULL); - ASSERT(IS_VALID_RADIOID(radioid)); - ASSERT(header != NULL); - ASSERT(length >= sizeof(struct ieee80211_header)); - - /* Get type frame */ - framecontrol = __le16_to_cpu(header->framecontrol); - framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); - framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); - - /* Parsing frame */ - if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - ac_ieee80211_mgmt_packet(session, radioid, (const struct ieee80211_header_mgmt*)header, length, framecontrol_subtype); - } -} +#include "ac.h" +#include "ac_session.h" +#include "ac_wlans.h" + +/* */ +static void ac_ieee80211_mgmt_probe_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + + /* Accept probe request only if not sent by WTP */ + if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH)) { + return; + } + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->proberequest.ie[0], ielength)) { + return; + } + + /* TODO */ +} + +/* */ +static void ac_ieee80211_mgmt_authentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + struct ac_station* station; + struct ac_wlan* wlan; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->authetication.ie[0], ielength)) { + return; + } + + /* */ + if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { + station = ac_stations_create_station(session, radioid, mgmt->bssid, mgmt->sa); + if (!station || !station->wlan) { + return; + } + + /* */ + capwap_logging_info("Receive IEEE802.11 Authentication Request from %s station", station->addrtext); + + /* A station is removed if the association does not complete within a given period of time */ + station->timeoutaction = AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; + station->idtimeout = capwap_timeout_set(session->timeout, station->idtimeout, AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE, ac_stations_timeout, station, session); + + /* */ + wlan = station->wlan; + if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { + /* TODO */ + } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + uint16_t algorithm; + uint16_t transactionseqnumber; + uint16_t responsestatuscode; + uint8_t buffer[IEEE80211_MTU]; + struct ieee80211_authentication_params ieee80211_params; + int responselength; + + /* Parsing Information Elements */ + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->authetication.ie[0], ielength)) { + capwap_logging_info("Invalid IEEE802.11 Authentication Request from %s station", station->addrtext); + return; + } + + /* */ + algorithm = __le16_to_cpu(mgmt->authetication.algorithm); + transactionseqnumber = __le16_to_cpu(mgmt->authetication.transactionseqnumber); + + /* */ + responsestatuscode = IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM; + if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_OPEN)) { + if (transactionseqnumber == 1) { + responsestatuscode = IEEE80211_STATUS_SUCCESS; + station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; + } else { + responsestatuscode = IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION; + } + } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP)) { + /* TODO */ + } + + /* Create authentication packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); + memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); + memcpy(ieee80211_params.station, mgmt->sa, MACADDRESS_EUI48_LENGTH); + ieee80211_params.algorithm = algorithm; + ieee80211_params.transactionseqnumber = transactionseqnumber + 1; + ieee80211_params.statuscode = responsestatuscode; + + responselength = ieee80211_create_authentication_response(buffer, sizeof(buffer), &ieee80211_params); + if (responselength > 0) { + /* Send authentication response */ + if (!ac_kmod_send_data(&session->sessionid, wlan->device->radioid, session->binding, buffer, responselength)) { + capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)responsestatuscode); + station->flags |= AC_STATION_FLAGS_AUTHENTICATED; + } else { + capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", station->addrtext); + ac_stations_delete_station(session, station); + } + } else { + capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", station->addrtext); + ac_stations_delete_station(session, station); + } + } + } else if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { + station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da); + if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { + uint16_t algorithm; + uint16_t transactionseqnumber; + uint16_t statuscode; + + /* */ + statuscode = __le16_to_cpu(mgmt->authetication.statuscode); + + /* */ + capwap_logging_info("Receive IEEE802.11 Authentication Response to %s station with %d status code", station->addrtext, (int)statuscode); + + if (statuscode == IEEE80211_STATUS_SUCCESS) { + algorithm = __le16_to_cpu(mgmt->authetication.algorithm); + transactionseqnumber = __le16_to_cpu(mgmt->authetication.transactionseqnumber); + + /* Check if authenticate */ + if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { + station->flags |= AC_STATION_FLAGS_AUTHENTICATED; + } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { + /* TODO */ + } + } + } + } +} + +/* */ +static void ac_ieee80211_mgmt_association_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + struct ac_station* station; + struct ac_wlan* wlan; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { + return; + } + + /* Get station */ + if (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && !memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { + station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->sa); + if (!station || !station->wlan) { + return; + } + + /* */ + capwap_logging_info("Receive IEEE802.11 Association Request from %s station", station->addrtext); + + /* */ + wlan = station->wlan; + if (!(station->flags & AC_STATION_FLAGS_AUTHENTICATED)) { + /* Invalid station, delete station */ + capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext); + ac_stations_delete_station(session, station); + return; + } + + /* Get Station Info */ + station->capability = __le16_to_cpu(mgmt->associationrequest.capability); + station->listeninterval = __le16_to_cpu(mgmt->associationrequest.listeninterval); + + /* Get supported rates */ + if (ieitems.supported_rates && ((ieitems.supported_rates->len + (ieitems.extended_supported_rates ? ieitems.extended_supported_rates->len : 0)) <= sizeof(station->supportedrates))) { + station->supportedratescount = ieitems.supported_rates->len; + memcpy(station->supportedrates, ieitems.supported_rates->rates, ieitems.supported_rates->len); + if (ieitems.extended_supported_rates) { + station->supportedratescount += ieitems.extended_supported_rates->len; + memcpy(&station->supportedrates[ieitems.supported_rates->len], ieitems.extended_supported_rates->rates, ieitems.extended_supported_rates->len); + } + + /* */ + if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { + /* TODO */ + } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + int responselength; + struct ieee80211_ie_items ieitems; + struct ieee80211_associationresponse_params ieee80211_params; + uint16_t resultstatuscode; + uint8_t buffer[IEEE80211_MTU]; + + /* Parsing Information Elements */ + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { + capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext); + ac_stations_delete_station(session, station); + return; + } + + /* Verify SSID */ + if (ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, NULL) != IEEE80211_VALID_SSID) { + resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; + } else { + /* Check supported rates */ + if (!ieitems.supported_rates || ((ieitems.supported_rates->len + (ieitems.extended_supported_rates ? ieitems.extended_supported_rates->len : 0)) > sizeof(station->supportedrates))) { + resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; + } else { + station->capability = __le16_to_cpu(mgmt->associationrequest.capability); + station->listeninterval = __le16_to_cpu(mgmt->associationrequest.listeninterval); + if (ieee80211_aid_create(wlan->aidbitfield, &station->aid)) { + resultstatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + } else { + /* Get supported rates */ + station->supportedratescount = ieitems.supported_rates->len; + memcpy(station->supportedrates, ieitems.supported_rates->rates, ieitems.supported_rates->len); + if (ieitems.extended_supported_rates) { + station->supportedratescount += ieitems.extended_supported_rates->len; + memcpy(&station->supportedrates[ieitems.supported_rates->len], ieitems.extended_supported_rates->rates, ieitems.extended_supported_rates->len); + } + + /* */ + resultstatuscode = IEEE80211_STATUS_SUCCESS; + } + } + } + + /* Create association response packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); + memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); + memcpy(ieee80211_params.station, mgmt->sa, ETH_ALEN); + ieee80211_params.capability = wlan->capability; + ieee80211_params.statuscode = resultstatuscode; + ieee80211_params.aid = IEEE80211_AID_FIELD | station->aid; + memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); + ieee80211_params.supportedratescount = wlan->device->supportedratescount; + + responselength = ieee80211_create_associationresponse_response(buffer, sizeof(buffer), &ieee80211_params); + if (responselength > 0) { + /* Send association response */ + if (!ac_kmod_send_data(&session->sessionid, wlan->device->radioid, session->binding, buffer, responselength)) { + capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); + + /* Active Station */ + station->flags |= AC_STATION_FLAGS_ASSOCIATE; + ac_stations_authorize_station(session, station); + } else { + capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); + ac_stations_delete_station(session, station); + } + } else { + capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext); + ac_stations_delete_station(session, station); + } + } + } + } +} + +/* */ +static void ac_ieee80211_mgmt_association_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + struct ac_station* station; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->associationresponse.ie[0], ielength)) { + return; + } + + /* Get station */ + if (!memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) && memcmp(mgmt->bssid, mgmt->da, MACADDRESS_EUI48_LENGTH)) { + station = ac_stations_get_station(session, radioid, mgmt->bssid, mgmt->da); + if (station && station->wlan && (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { + capwap_logging_info("Receive IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)mgmt->associationresponse.statuscode); + + if (mgmt->associationresponse.statuscode == IEEE80211_STATUS_SUCCESS) { + /* Get Station Info */ + station->capability = __le16_to_cpu(mgmt->associationresponse.capability); + station->aid = __le16_to_cpu(mgmt->associationresponse.aid); + station->flags |= AC_STATION_FLAGS_ASSOCIATE; + + /* Get supported rates */ + if (ieitems.supported_rates && ((ieitems.supported_rates->len + (ieitems.extended_supported_rates ? ieitems.extended_supported_rates->len : 0)) <= sizeof(station->supportedrates))) { + station->supportedratescount = ieitems.supported_rates->len; + memcpy(station->supportedrates, ieitems.supported_rates->rates, ieitems.supported_rates->len); + if (ieitems.extended_supported_rates) { + station->supportedratescount += ieitems.extended_supported_rates->len; + memcpy(&station->supportedrates[ieitems.supported_rates->len], ieitems.extended_supported_rates->rates, ieitems.extended_supported_rates->len); + } + + /* Active Station */ + ac_stations_authorize_station(session, station); + } + } + } + } +} + +/* */ +static void ac_ieee80211_mgmt_reassociation_request_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->reassociationrequest.ie[0], ielength)) { + return; + } + + /* TODO */ +} + +/* */ +static void ac_ieee80211_mgmt_reassociation_response_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationresponse)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->reassociationresponse.ie[0], ielength)) { + return; + } + + /* TODO */ +} + +/* */ +static void ac_ieee80211_mgmt_disassociation_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->disassociation.ie[0], ielength)) { + return; + } + + /* TODO */ +} + +/* */ +static void ac_ieee80211_mgmt_deauthentication_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + const uint8_t* stationaddress; + struct ac_station* station; + struct ieee80211_ie_items ieitems; + + /* Parsing Information Elements */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication)); + if (ieee80211_retrieve_information_elements_position(&ieitems, &mgmt->deauthetication.ie[0], ielength)) { + return; + } + + /* Get station address */ + stationaddress = (memcmp(mgmt->bssid, mgmt->sa, MACADDRESS_EUI48_LENGTH) ? mgmt->sa : mgmt->da); + + /* Delete station */ + station = ac_stations_get_station(session, radioid, NULL, stationaddress); + if (station) { + /* Delete station without forward another IEEE802.11 deauthentication message */ + station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE); + ac_stations_delete_station(session, station); + } +} + +/* */ +static void ac_ieee80211_mgmt_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype) { + switch (framecontrol_subtype) { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->proberequest))) { + ac_ieee80211_mgmt_probe_request_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication))) { + ac_ieee80211_mgmt_authentication_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest))) { + ac_ieee80211_mgmt_association_request_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse))) { + ac_ieee80211_mgmt_association_response_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationrequest))) { + ac_ieee80211_mgmt_reassociation_request_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->reassociationresponse))) { + ac_ieee80211_mgmt_reassociation_response_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->disassociation))) { + ac_ieee80211_mgmt_disassociation_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { + if (mgmtlength >= (sizeof(struct ieee80211_header) + sizeof(mgmt->deauthetication))) { + ac_ieee80211_mgmt_deauthentication_packet(session, radioid, mgmt, mgmtlength); + } + + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION: { + break; + } + } +} + +/* */ +void ac_ieee80211_packet(struct ac_session_t* session, uint8_t radioid, const struct ieee80211_header* header, int length) { + uint16_t framecontrol; + uint16_t framecontrol_type; + uint16_t framecontrol_subtype; + + ASSERT(session != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(header != NULL); + ASSERT(length >= sizeof(struct ieee80211_header)); + + /* Get type frame */ + framecontrol = __le16_to_cpu(header->framecontrol); + framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); + framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); + + /* Parsing frame */ + if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { + ac_ieee80211_mgmt_packet(session, radioid, (const struct ieee80211_header_mgmt*)header, length, framecontrol_subtype); + } +} diff --git a/src/ac/ac_json.h b/src/ac/ac_json.h index e4a33d2..c037afe 100644 --- a/src/ac/ac_json.h +++ b/src/ac/ac_json.h @@ -1,92 +1,92 @@ -#ifndef __AC_JSON_HEADER__ -#define __AC_JSON_HEADER__ - -#include "capwap_array.h" -#include - -#define IEEE80211_BINDING_JSON_ROOT "WTPRadio" - -struct ac_json_ieee80211_item { - int valid; - struct capwap_80211_addwlan_element* addwlan; - struct capwap_80211_antenna_element* antenna; - struct capwap_80211_assignbssid_element* assignbssid; - struct capwap_80211_deletewlan_element* deletewlan; - struct capwap_80211_directsequencecontrol_element* directsequencecontrol; - struct capwap_array* iearray; - struct capwap_80211_macoperation_element* macoperation; - struct capwap_80211_miccountermeasures_element* miccountermeasures; - struct capwap_80211_multidomaincapability_element* multidomaincapability; - struct capwap_80211_ofdmcontrol_element* ofdmcontrol; - struct capwap_80211_rateset_element* rateset; - struct capwap_80211_rsnaerrorreport_element* rsnaerrorreport; - struct capwap_80211_statistics_element* statistics; - struct capwap_80211_supportedrates_element* supportedrates; - struct capwap_80211_txpower_element* txpower; - struct capwap_80211_txpowerlevel_element* txpowerlevel; - struct capwap_80211_updatewlan_element* updatewlan; - struct capwap_80211_wtpqos_element* wtpqos; - struct capwap_80211_wtpradioconf_element* wtpradioconf; - struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm; - struct capwap_80211_wtpradioinformation_element* wtpradioinformation; -}; - -struct ac_json_ieee80211_wtpradio { - struct ac_json_ieee80211_item items[RADIOID_MAX_COUNT]; -}; - -/* JSON IEEE 802.11 message elements */ -#include "ac_80211_json_addwlan.h" -#include "ac_80211_json_antenna.h" -#include "ac_80211_json_assignbssid.h" -#include "ac_80211_json_deletewlan.h" -#include "ac_80211_json_directsequencecontrol.h" -#include "ac_80211_json_ie.h" -#include "ac_80211_json_macoperation.h" -#include "ac_80211_json_miccountermeasures.h" -#include "ac_80211_json_multidomaincapability.h" -#include "ac_80211_json_ofdmcontrol.h" -#include "ac_80211_json_rateset.h" -#include "ac_80211_json_rsnaerrorreport.h" -#include "ac_80211_json_statistics.h" -#include "ac_80211_json_supportedrates.h" -#include "ac_80211_json_txpower.h" -#include "ac_80211_json_txpowerlevel.h" -#include "ac_80211_json_updatewlan.h" -#include "ac_80211_json_wtpqos.h" -#include "ac_80211_json_wtpradioconf.h" -#include "ac_80211_json_wtpradiofailalarm.h" -#include "ac_80211_json_wtpradioinformation.h" - -/* */ -struct ac_json_ieee80211_ops { - /* Message Element Type */ - uint16_t type; - - /* Message Element JSON Type */ - char* json_type; - - /* Build message element */ - void* (*create_message_element)(struct json_object* jsonparent, uint16_t radioid); - int (*add_message_element)(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite); - - /* Build JSON */ - void (*create_json)(struct json_object* jsonparent, void* data); -}; - -/* */ -void ac_json_ieee80211_init(struct ac_json_ieee80211_wtpradio* wtpradio); -void ac_json_ieee80211_free(struct ac_json_ieee80211_wtpradio* wtpradio); - -/* */ -int ac_json_ieee80211_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, uint16_t type, void* data, int overwrite); -int ac_json_ieee80211_parsingmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_message_element_itemlist* messageelement); -int ac_json_ieee80211_parsingjson(struct ac_json_ieee80211_wtpradio* wtpradio, struct json_object* jsonroot); - -/* */ -struct json_object* ac_json_ieee80211_getjson(struct ac_json_ieee80211_wtpradio* wtpradio); -void ac_json_ieee80211_buildpacket(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_packet_txmng* txmngpacket); - - - -#endif /* __AC_JSON_HEADER__ */ +#ifndef __AC_JSON_HEADER__ +#define __AC_JSON_HEADER__ + +#include "capwap_array.h" +#include + +#define IEEE80211_BINDING_JSON_ROOT "WTPRadio" + +struct ac_json_ieee80211_item { + int valid; + struct capwap_80211_addwlan_element* addwlan; + struct capwap_80211_antenna_element* antenna; + struct capwap_80211_assignbssid_element* assignbssid; + struct capwap_80211_deletewlan_element* deletewlan; + struct capwap_80211_directsequencecontrol_element* directsequencecontrol; + struct capwap_array* iearray; + struct capwap_80211_macoperation_element* macoperation; + struct capwap_80211_miccountermeasures_element* miccountermeasures; + struct capwap_80211_multidomaincapability_element* multidomaincapability; + struct capwap_80211_ofdmcontrol_element* ofdmcontrol; + struct capwap_80211_rateset_element* rateset; + struct capwap_80211_rsnaerrorreport_element* rsnaerrorreport; + struct capwap_80211_statistics_element* statistics; + struct capwap_80211_supportedrates_element* supportedrates; + struct capwap_80211_txpower_element* txpower; + struct capwap_80211_txpowerlevel_element* txpowerlevel; + struct capwap_80211_updatewlan_element* updatewlan; + struct capwap_80211_wtpqos_element* wtpqos; + struct capwap_80211_wtpradioconf_element* wtpradioconf; + struct capwap_80211_wtpradiofailalarm_element* wtpradiofailalarm; + struct capwap_80211_wtpradioinformation_element* wtpradioinformation; +}; + +struct ac_json_ieee80211_wtpradio { + struct ac_json_ieee80211_item items[RADIOID_MAX_COUNT]; +}; + +/* JSON IEEE 802.11 message elements */ +#include "ac_80211_json_addwlan.h" +#include "ac_80211_json_antenna.h" +#include "ac_80211_json_assignbssid.h" +#include "ac_80211_json_deletewlan.h" +#include "ac_80211_json_directsequencecontrol.h" +#include "ac_80211_json_ie.h" +#include "ac_80211_json_macoperation.h" +#include "ac_80211_json_miccountermeasures.h" +#include "ac_80211_json_multidomaincapability.h" +#include "ac_80211_json_ofdmcontrol.h" +#include "ac_80211_json_rateset.h" +#include "ac_80211_json_rsnaerrorreport.h" +#include "ac_80211_json_statistics.h" +#include "ac_80211_json_supportedrates.h" +#include "ac_80211_json_txpower.h" +#include "ac_80211_json_txpowerlevel.h" +#include "ac_80211_json_updatewlan.h" +#include "ac_80211_json_wtpqos.h" +#include "ac_80211_json_wtpradioconf.h" +#include "ac_80211_json_wtpradiofailalarm.h" +#include "ac_80211_json_wtpradioinformation.h" + +/* */ +struct ac_json_ieee80211_ops { + /* Message Element Type */ + uint16_t type; + + /* Message Element JSON Type */ + char* json_type; + + /* Build message element */ + void* (*create_message_element)(struct json_object* jsonparent, uint16_t radioid); + int (*add_message_element)(struct ac_json_ieee80211_wtpradio* wtpradio, void* data, int overwrite); + + /* Build JSON */ + void (*create_json)(struct json_object* jsonparent, void* data); +}; + +/* */ +void ac_json_ieee80211_init(struct ac_json_ieee80211_wtpradio* wtpradio); +void ac_json_ieee80211_free(struct ac_json_ieee80211_wtpradio* wtpradio); + +/* */ +int ac_json_ieee80211_addmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, uint16_t type, void* data, int overwrite); +int ac_json_ieee80211_parsingmessageelement(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_message_element_itemlist* messageelement); +int ac_json_ieee80211_parsingjson(struct ac_json_ieee80211_wtpradio* wtpradio, struct json_object* jsonroot); + +/* */ +struct json_object* ac_json_ieee80211_getjson(struct ac_json_ieee80211_wtpradio* wtpradio); +void ac_json_ieee80211_buildpacket(struct ac_json_ieee80211_wtpradio* wtpradio, struct capwap_packet_txmng* txmngpacket); + + + +#endif /* __AC_JSON_HEADER__ */ diff --git a/src/ac/ac_kmod.c b/src/ac/ac_kmod.c index e587414..680c495 100644 --- a/src/ac/ac_kmod.c +++ b/src/ac/ac_kmod.c @@ -1,703 +1,703 @@ -#include "ac.h" -#include -#include -#include -#include "ac_session.h" -#include "nlsmartcapwap.h" - -/* Compatibility functions */ -#ifdef HAVE_LIBNL_10 -static uint32_t g_portbitmap[32] = { 0 }; - -static struct nl_sock* nl_socket_alloc_cb(void* cb) { - int i; - struct nl_sock* handle; - uint32_t pid = getpid() & 0x3FFFFF; - - handle = nl_handle_alloc_cb(cb); - for (i = 0; i < 1024; i++) { - if (g_portbitmap[i / 32] & (1 << (i % 32))) { - continue; - } - - g_portbitmap[i / 32] |= 1 << (i % 32); - pid += i << 22; - break; - } - - nl_socket_set_local_port(handle, pid); - return handle; -} - -static void nl_socket_free(struct nl_sock* handle) { - uint32_t port = nl_socket_get_local_port(handle); - - port >>= 22; - g_portbitmap[port / 32] &= ~(1 << (port % 32)); - - nl_handle_destroy(handle); -} -#endif - -/* */ -typedef int (*ac_kmod_valid_cb)(struct nl_msg* msg, void* data); - -/* */ -static struct nl_sock* nl_create_handle(struct nl_cb* cb) { - struct nl_sock* handle; - - handle = nl_socket_alloc_cb(cb); - if (!handle) { - return NULL; - } - - if (genl_connect(handle)) { - nl_socket_free(handle); - return NULL; - } - - return handle; -} - -/* */ -static int ac_kmod_no_seq_check(struct nl_msg* msg, void* arg) { - return NL_OK; -} - -/* */ -static int ac_kmod_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) { - *((int*)arg) = err->error; - return NL_STOP; -} - -/* */ -static int ac_kmod_finish_handler(struct nl_msg* msg, void* arg) { - *((int*)arg) = 0; - return NL_SKIP; -} - -/* */ -static int ac_kmod_ack_handler(struct nl_msg* msg, void* arg) { - *((int*)arg) = 0; - return NL_STOP; -} - -/* */ -static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) { - switch (gnlh->cmd) { - case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: { - if (tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]) { - struct capwap_sessionid_element* sessionid = (struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]); - struct ac_session_t* session = ac_search_session_from_sessionid(sessionid); - - if (session) { - ac_kmod_send_keepalive(sessionid); - ac_session_send_action(session, AC_SESSION_ACTION_RECV_KEEPALIVE, 0, NULL, 0); - ac_session_release_reference(session); - } - } - - break; - } - - case NLSMARTCAPWAP_CMD_RECV_DATA: { - if (tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID] && tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { - struct ac_session_t* session = ac_search_session_from_sessionid((struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID])); - - if (session) { - ac_session_send_action(session, AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET, 0, nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME])); - ac_session_release_reference(session); - } - } - - break; - } - } - - return NL_SKIP; -} - -/* */ -static int ac_kmod_valid_handler(struct nl_msg* msg, void* data) { - struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - return ac_kmod_event_handler(gnlh, tb_msg, data); -} - -/* */ -static int ac_kmod_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, ac_kmod_valid_cb valid_cb, void* data) { - int result; - struct nl_cb* cb; - - /* Clone netlink callback */ - cb = nl_cb_clone(nl_cb); - if (!cb) { - return -1; - } - - /* */ - capwap_lock_enter(&g_ac.kmodhandle.msglock); - - /* Complete send message */ - result = nl_send_auto_complete(nl, msg); - if (result >= 0) { - /* Customize message callback */ - nl_cb_err(cb, NL_CB_CUSTOM, ac_kmod_error_handler, &result); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, ac_kmod_finish_handler, &result); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ac_kmod_ack_handler, &result); - - if (valid_cb) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data); - } - - result = 1; - while (result > 0) { - nl_recvmsgs(nl, cb); - } - } - - /* */ - capwap_lock_exit(&g_ac.kmodhandle.msglock); - nl_cb_put(cb); - - return result; -} - -/* */ -static int ac_kmod_send_and_recv_msg(struct nl_msg* msg, ac_kmod_valid_cb valid_cb, void* data) { - return ac_kmod_send_and_recv(g_ac.kmodhandle.nlmsg, g_ac.kmodhandle.nlmsg_cb, msg, valid_cb, data); -} - -/* */ -static int ac_kmod_link(void) { - int result; - struct nl_msg* msg; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LINK, 0); - - /* */ - result = ac_kmod_send_and_recv(g_ac.kmodhandle.nl, g_ac.kmodhandle.nl_cb, msg, NULL, NULL); - if (result) { - if (result == -EALREADY) { - result = 0; - } else { - capwap_logging_warning("Unable to connect kernel module, error code: %d", result); - } - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static void ac_kmod_event_receive(int fd, void** params, int paramscount) { - int res; - - ASSERT(fd >= 0); - ASSERT(params != NULL); - ASSERT(paramscount == 2); - - /* */ - res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); - if (res) { - capwap_logging_warning("Receive kernel module message failed: %d", res); - } -} - -/* */ -int ac_kmod_send_keepalive(struct capwap_sessionid_element* sessionid) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - - /* */ - capwap_logging_debug("Prepare to send keep-alive"); - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable to send keep-alive: %d", result); - } - capwap_logging_debug("Sent keep-alive"); - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_send_data(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t binding, const uint8_t* data, int length) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - ASSERT(data != NULL); - ASSERT(length > 0); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, binding); - nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, data); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable to send data: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_isconnected(void) { - return (g_ac.kmodhandle.nlsmartcapwap_id ? 1 : 0); -} - -/* */ -int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count) { - int kmodcount = (ac_kmod_isconnected() ? 1 : 0); - - /* */ - if (!kmodcount) { - return 0; - } else if (!fds && !events && !count) { - return kmodcount; - } else if ((count > 0) && (!fds || !events)) { - return -1; - } else if (count < kmodcount) { - return -1; - } - - /* */ - fds[0].fd = g_ac.kmodhandle.nl_fd; - fds[0].events = POLLIN | POLLERR | POLLHUP; - - /* */ - events[0].event_handler = ac_kmod_event_receive; - events[0].params[0] = (void*)g_ac.kmodhandle.nl; - events[0].params[1] = (void*)g_ac.kmodhandle.nl_cb; - events[0].paramscount = 2; - - return kmodcount; -} - -/* */ -int ac_kmod_createdatachannel(int family, unsigned short port) { - int result; - struct nl_msg* msg; - struct sockaddr_storage sockaddr; - - ASSERT((family == AF_INET) || (family == AF_INET6)); - ASSERT(port != 0); - - /* */ - memset(&sockaddr, 0, sizeof(struct sockaddr_storage)); - sockaddr.ss_family = family; - if (sockaddr.ss_family == AF_INET) { - ((struct sockaddr_in*)&sockaddr)->sin_port = htons(port); - } else if (sockaddr.ss_family == AF_INET6) { - ((struct sockaddr_in6*)&sockaddr)->sin6_port = htons(port); - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable to bind kernel socket: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_NEW_SESSION, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_BINDING, binding); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable to create data session: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_delete_datasession(struct capwap_sessionid_element* sessionid) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DELETE_SESSION, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result && (result != ENOENT)) { - capwap_logging_error("Unable to delete data session: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_addwlan(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - ASSERT(IS_VALID_RADIOID(radioid)); - ASSERT(IS_VALID_WLANID(wlanid)); - ASSERT(bssid != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_ADD_WLAN, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlanid); - nla_put(msg, NLSMARTCAPWAP_ATTR_MACADDRESS, MACADDRESS_EUI48_LENGTH, bssid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_MACMODE, macmode); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_TUNNELMODE, tunnelmode); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable to add wlan: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_removewlan(struct capwap_sessionid_element* sessionid) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_REMOVE_WLAN, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result && (result != ENOENT)) { - capwap_logging_error("Unable to remove wlan: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static int cb_kmod_create_iface(struct nl_msg* msg, void* data) { - struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - uint32_t* ifindex = (uint32_t*)data; - - nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]) { - *ifindex = nla_get_u32(tb_msg[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]); - } - - return NL_SKIP; -} - -/* */ -int ac_kmod_create_iface(const char* ifname, uint16_t mtu) { - int result; - struct nl_msg* msg; - uint32_t ifindex = 0; - - ASSERT(ifname != NULL); - ASSERT(mtu > 0); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_ADD_IFACE, 0); - nla_put_string(msg, NLSMARTCAPWAP_ATTR_IFPHY_NAME, ifname); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, cb_kmod_create_iface, &ifindex); - if (!result) { - result = (ifindex ? (int)ifindex : -1); - } else { - capwap_logging_error("Unable to create data session: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_delete_iface(int ifindex) { - int result; - struct nl_msg* msg; - - ASSERT(ifindex > 0); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DELETE_IFACE, 0); - nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFPHY_INDEX, (uint32_t)ifindex); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result && (result != ENOENT)) { - capwap_logging_error("Unable to delete interface: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_authorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress, int ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - ASSERT(macaddress != NULL); - ASSERT(ifindex >= 0); - ASSERT(IS_VALID_RADIOID(radioid)); - ASSERT(vlan < VLAN_MAX); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_AUTH_STATION, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - nla_put(msg, NLSMARTCAPWAP_ATTR_MACADDRESS, MACADDRESS_EUI48_LENGTH, macaddress); - nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFPHY_INDEX, (unsigned long)ifindex); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlanid); - - if (vlan > 0) { - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_VLAN, ifindex); - } - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable to authorize station: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_deauthorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress) { - int result; - struct nl_msg* msg; - - ASSERT(sessionid != NULL); - ASSERT(macaddress != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DEAUTH_STATION, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - nla_put(msg, NLSMARTCAPWAP_ATTR_MACADDRESS, MACADDRESS_EUI48_LENGTH, macaddress); - - /* */ - result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable to deauthorize station: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int ac_kmod_init(void) { - int result; - - /* */ - capwap_lock_init(&g_ac.kmodhandle.msglock); - - /* Configure netlink callback */ - g_ac.kmodhandle.nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!g_ac.kmodhandle.nl_cb) { - ac_kmod_free(); - return -1; - } - - /* Create netlink socket */ - g_ac.kmodhandle.nl = nl_create_handle(g_ac.kmodhandle.nl_cb); - if (!g_ac.kmodhandle.nl) { - ac_kmod_free(); - return -1; - } - - g_ac.kmodhandle.nl_fd = nl_socket_get_fd(g_ac.kmodhandle.nl); - - /* Get nlsmartcapwap netlink family */ - g_ac.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_ac.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME); - if (g_ac.kmodhandle.nlsmartcapwap_id < 0) { - capwap_logging_warning("Unable to found kernel module"); - ac_kmod_free(); - return -1; - } - - /* Configure callback function */ - nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, ac_kmod_no_seq_check, NULL); - nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ac_kmod_valid_handler, NULL); - - /* Link to kernel module */ - result = ac_kmod_link(); - if (result) { - ac_kmod_free(); - return result; - } - - /* Configure netlink message socket */ - g_ac.kmodhandle.nlmsg_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!g_ac.kmodhandle.nlmsg_cb) { - ac_kmod_free(); - return -1; - } - - /* */ - g_ac.kmodhandle.nlmsg = nl_create_handle(g_ac.kmodhandle.nlmsg_cb); - if (!g_ac.kmodhandle.nlmsg) { - ac_kmod_free(); - return -1; - } - - return 0; -} - -/* */ -void ac_kmod_free(void) { - if (g_ac.kmodhandle.nl) { - nl_socket_free(g_ac.kmodhandle.nl); - } - - if (g_ac.kmodhandle.nl_cb) { - nl_cb_put(g_ac.kmodhandle.nl_cb); - } - - if (g_ac.kmodhandle.nlmsg) { - nl_socket_free(g_ac.kmodhandle.nlmsg); - } - - if (g_ac.kmodhandle.nlmsg_cb) { - nl_cb_put(g_ac.kmodhandle.nlmsg_cb); - } - - /* */ - capwap_lock_destroy(&g_ac.kmodhandle.msglock); - - /* */ - memset(&g_ac.kmodhandle, 0, sizeof(struct ac_kmod_handle)); -} +#include "ac.h" +#include +#include +#include +#include "ac_session.h" +#include "nlsmartcapwap.h" + +/* Compatibility functions */ +#ifdef HAVE_LIBNL_10 +static uint32_t g_portbitmap[32] = { 0 }; + +static struct nl_sock* nl_socket_alloc_cb(void* cb) { + int i; + struct nl_sock* handle; + uint32_t pid = getpid() & 0x3FFFFF; + + handle = nl_handle_alloc_cb(cb); + for (i = 0; i < 1024; i++) { + if (g_portbitmap[i / 32] & (1 << (i % 32))) { + continue; + } + + g_portbitmap[i / 32] |= 1 << (i % 32); + pid += i << 22; + break; + } + + nl_socket_set_local_port(handle, pid); + return handle; +} + +static void nl_socket_free(struct nl_sock* handle) { + uint32_t port = nl_socket_get_local_port(handle); + + port >>= 22; + g_portbitmap[port / 32] &= ~(1 << (port % 32)); + + nl_handle_destroy(handle); +} +#endif + +/* */ +typedef int (*ac_kmod_valid_cb)(struct nl_msg* msg, void* data); + +/* */ +static struct nl_sock* nl_create_handle(struct nl_cb* cb) { + struct nl_sock* handle; + + handle = nl_socket_alloc_cb(cb); + if (!handle) { + return NULL; + } + + if (genl_connect(handle)) { + nl_socket_free(handle); + return NULL; + } + + return handle; +} + +/* */ +static int ac_kmod_no_seq_check(struct nl_msg* msg, void* arg) { + return NL_OK; +} + +/* */ +static int ac_kmod_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) { + *((int*)arg) = err->error; + return NL_STOP; +} + +/* */ +static int ac_kmod_finish_handler(struct nl_msg* msg, void* arg) { + *((int*)arg) = 0; + return NL_SKIP; +} + +/* */ +static int ac_kmod_ack_handler(struct nl_msg* msg, void* arg) { + *((int*)arg) = 0; + return NL_STOP; +} + +/* */ +static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) { + switch (gnlh->cmd) { + case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: { + if (tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]) { + struct capwap_sessionid_element* sessionid = (struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID]); + struct ac_session_t* session = ac_search_session_from_sessionid(sessionid); + + if (session) { + ac_kmod_send_keepalive(sessionid); + ac_session_send_action(session, AC_SESSION_ACTION_RECV_KEEPALIVE, 0, NULL, 0); + ac_session_release_reference(session); + } + } + + break; + } + + case NLSMARTCAPWAP_CMD_RECV_DATA: { + if (tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID] && tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { + struct ac_session_t* session = ac_search_session_from_sessionid((struct capwap_sessionid_element*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_SESSION_ID])); + + if (session) { + ac_session_send_action(session, AC_SESSION_ACTION_RECV_IEEE80211_MGMT_PACKET, 0, nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME])); + ac_session_release_reference(session); + } + } + + break; + } + } + + return NL_SKIP; +} + +/* */ +static int ac_kmod_valid_handler(struct nl_msg* msg, void* data) { + struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + return ac_kmod_event_handler(gnlh, tb_msg, data); +} + +/* */ +static int ac_kmod_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, ac_kmod_valid_cb valid_cb, void* data) { + int result; + struct nl_cb* cb; + + /* Clone netlink callback */ + cb = nl_cb_clone(nl_cb); + if (!cb) { + return -1; + } + + /* */ + capwap_lock_enter(&g_ac.kmodhandle.msglock); + + /* Complete send message */ + result = nl_send_auto_complete(nl, msg); + if (result >= 0) { + /* Customize message callback */ + nl_cb_err(cb, NL_CB_CUSTOM, ac_kmod_error_handler, &result); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, ac_kmod_finish_handler, &result); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ac_kmod_ack_handler, &result); + + if (valid_cb) { + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data); + } + + result = 1; + while (result > 0) { + nl_recvmsgs(nl, cb); + } + } + + /* */ + capwap_lock_exit(&g_ac.kmodhandle.msglock); + nl_cb_put(cb); + + return result; +} + +/* */ +static int ac_kmod_send_and_recv_msg(struct nl_msg* msg, ac_kmod_valid_cb valid_cb, void* data) { + return ac_kmod_send_and_recv(g_ac.kmodhandle.nlmsg, g_ac.kmodhandle.nlmsg_cb, msg, valid_cb, data); +} + +/* */ +static int ac_kmod_link(void) { + int result; + struct nl_msg* msg; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LINK, 0); + + /* */ + result = ac_kmod_send_and_recv(g_ac.kmodhandle.nl, g_ac.kmodhandle.nl_cb, msg, NULL, NULL); + if (result) { + if (result == -EALREADY) { + result = 0; + } else { + capwap_logging_warning("Unable to connect kernel module, error code: %d", result); + } + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static void ac_kmod_event_receive(int fd, void** params, int paramscount) { + int res; + + ASSERT(fd >= 0); + ASSERT(params != NULL); + ASSERT(paramscount == 2); + + /* */ + res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); + if (res) { + capwap_logging_warning("Receive kernel module message failed: %d", res); + } +} + +/* */ +int ac_kmod_send_keepalive(struct capwap_sessionid_element* sessionid) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + + /* */ + capwap_logging_debug("Prepare to send keep-alive"); + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable to send keep-alive: %d", result); + } + capwap_logging_debug("Sent keep-alive"); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_send_data(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t binding, const uint8_t* data, int length) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + ASSERT(data != NULL); + ASSERT(length > 0); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, binding); + nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, data); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable to send data: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_isconnected(void) { + return (g_ac.kmodhandle.nlsmartcapwap_id ? 1 : 0); +} + +/* */ +int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count) { + int kmodcount = (ac_kmod_isconnected() ? 1 : 0); + + /* */ + if (!kmodcount) { + return 0; + } else if (!fds && !events && !count) { + return kmodcount; + } else if ((count > 0) && (!fds || !events)) { + return -1; + } else if (count < kmodcount) { + return -1; + } + + /* */ + fds[0].fd = g_ac.kmodhandle.nl_fd; + fds[0].events = POLLIN | POLLERR | POLLHUP; + + /* */ + events[0].event_handler = ac_kmod_event_receive; + events[0].params[0] = (void*)g_ac.kmodhandle.nl; + events[0].params[1] = (void*)g_ac.kmodhandle.nl_cb; + events[0].paramscount = 2; + + return kmodcount; +} + +/* */ +int ac_kmod_createdatachannel(int family, unsigned short port) { + int result; + struct nl_msg* msg; + struct sockaddr_storage sockaddr; + + ASSERT((family == AF_INET) || (family == AF_INET6)); + ASSERT(port != 0); + + /* */ + memset(&sockaddr, 0, sizeof(struct sockaddr_storage)); + sockaddr.ss_family = family; + if (sockaddr.ss_family == AF_INET) { + ((struct sockaddr_in*)&sockaddr)->sin_port = htons(port); + } else if (sockaddr.ss_family == AF_INET6) { + ((struct sockaddr_in6*)&sockaddr)->sin6_port = htons(port); + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable to bind kernel socket: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_NEW_SESSION, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_BINDING, binding); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable to create data session: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_delete_datasession(struct capwap_sessionid_element* sessionid) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DELETE_SESSION, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result && (result != ENOENT)) { + capwap_logging_error("Unable to delete data session: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_addwlan(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(IS_VALID_WLANID(wlanid)); + ASSERT(bssid != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_ADD_WLAN, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlanid); + nla_put(msg, NLSMARTCAPWAP_ATTR_MACADDRESS, MACADDRESS_EUI48_LENGTH, bssid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_MACMODE, macmode); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_TUNNELMODE, tunnelmode); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable to add wlan: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_removewlan(struct capwap_sessionid_element* sessionid) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_REMOVE_WLAN, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result && (result != ENOENT)) { + capwap_logging_error("Unable to remove wlan: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int cb_kmod_create_iface(struct nl_msg* msg, void* data) { + struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + uint32_t* ifindex = (uint32_t*)data; + + nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]) { + *ifindex = nla_get_u32(tb_msg[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]); + } + + return NL_SKIP; +} + +/* */ +int ac_kmod_create_iface(const char* ifname, uint16_t mtu) { + int result; + struct nl_msg* msg; + uint32_t ifindex = 0; + + ASSERT(ifname != NULL); + ASSERT(mtu > 0); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_ADD_IFACE, 0); + nla_put_string(msg, NLSMARTCAPWAP_ATTR_IFPHY_NAME, ifname); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, cb_kmod_create_iface, &ifindex); + if (!result) { + result = (ifindex ? (int)ifindex : -1); + } else { + capwap_logging_error("Unable to create data session: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_delete_iface(int ifindex) { + int result; + struct nl_msg* msg; + + ASSERT(ifindex > 0); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DELETE_IFACE, 0); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFPHY_INDEX, (uint32_t)ifindex); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result && (result != ENOENT)) { + capwap_logging_error("Unable to delete interface: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_authorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress, int ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + ASSERT(macaddress != NULL); + ASSERT(ifindex >= 0); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(vlan < VLAN_MAX); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_AUTH_STATION, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + nla_put(msg, NLSMARTCAPWAP_ATTR_MACADDRESS, MACADDRESS_EUI48_LENGTH, macaddress); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFPHY_INDEX, (unsigned long)ifindex); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlanid); + + if (vlan > 0) { + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_VLAN, ifindex); + } + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable to authorize station: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_deauthorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress) { + int result; + struct nl_msg* msg; + + ASSERT(sessionid != NULL); + ASSERT(macaddress != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_DEAUTH_STATION, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + nla_put(msg, NLSMARTCAPWAP_ATTR_MACADDRESS, MACADDRESS_EUI48_LENGTH, macaddress); + + /* */ + result = ac_kmod_send_and_recv_msg(msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable to deauthorize station: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int ac_kmod_init(void) { + int result; + + /* */ + capwap_lock_init(&g_ac.kmodhandle.msglock); + + /* Configure netlink callback */ + g_ac.kmodhandle.nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!g_ac.kmodhandle.nl_cb) { + ac_kmod_free(); + return -1; + } + + /* Create netlink socket */ + g_ac.kmodhandle.nl = nl_create_handle(g_ac.kmodhandle.nl_cb); + if (!g_ac.kmodhandle.nl) { + ac_kmod_free(); + return -1; + } + + g_ac.kmodhandle.nl_fd = nl_socket_get_fd(g_ac.kmodhandle.nl); + + /* Get nlsmartcapwap netlink family */ + g_ac.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_ac.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME); + if (g_ac.kmodhandle.nlsmartcapwap_id < 0) { + capwap_logging_warning("Unable to found kernel module"); + ac_kmod_free(); + return -1; + } + + /* Configure callback function */ + nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, ac_kmod_no_seq_check, NULL); + nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ac_kmod_valid_handler, NULL); + + /* Link to kernel module */ + result = ac_kmod_link(); + if (result) { + ac_kmod_free(); + return result; + } + + /* Configure netlink message socket */ + g_ac.kmodhandle.nlmsg_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!g_ac.kmodhandle.nlmsg_cb) { + ac_kmod_free(); + return -1; + } + + /* */ + g_ac.kmodhandle.nlmsg = nl_create_handle(g_ac.kmodhandle.nlmsg_cb); + if (!g_ac.kmodhandle.nlmsg) { + ac_kmod_free(); + return -1; + } + + return 0; +} + +/* */ +void ac_kmod_free(void) { + if (g_ac.kmodhandle.nl) { + nl_socket_free(g_ac.kmodhandle.nl); + } + + if (g_ac.kmodhandle.nl_cb) { + nl_cb_put(g_ac.kmodhandle.nl_cb); + } + + if (g_ac.kmodhandle.nlmsg) { + nl_socket_free(g_ac.kmodhandle.nlmsg); + } + + if (g_ac.kmodhandle.nlmsg_cb) { + nl_cb_put(g_ac.kmodhandle.nlmsg_cb); + } + + /* */ + capwap_lock_destroy(&g_ac.kmodhandle.msglock); + + /* */ + memset(&g_ac.kmodhandle, 0, sizeof(struct ac_kmod_handle)); +} diff --git a/src/ac/ac_kmod.h b/src/ac/ac_kmod.h index c933ee8..ac36041 100644 --- a/src/ac/ac_kmod.h +++ b/src/ac/ac_kmod.h @@ -1,71 +1,71 @@ -#ifndef __AC_KMOD_HEADER__ -#define __AC_KMOD_HEADER__ - -/* */ -#ifdef HAVE_LIBNL_10 -#define nl_sock nl_handle -#endif - -/* */ -#define AC_KMOD_MODE_LOCAL 0x00000001 -#define AC_KMOD_MODE_TUNNEL_USERMODE 0x00000002 -#define AC_KMOD_MODE_TUNNEL_KERNELMODE 0x00000003 - -/* */ -#define AC_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000 -#define AC_KMOD_FLAGS_TUNNEL_8023 0x00000001 - -/* */ -struct ac_kmod_handle { - /* Callback */ - struct nl_sock* nl; - int nl_fd; - struct nl_cb* nl_cb; - int nlsmartcapwap_id; - - /* Send message */ - capwap_lock_t msglock; - struct nl_sock* nlmsg; - struct nl_cb* nlmsg_cb; -}; - -/* */ -#define AC_KMOD_EVENT_MAX_ITEMS 2 -struct ac_kmod_event { - void (*event_handler)(int fd, void** params, int paramscount); - int paramscount; - void* params[AC_KMOD_EVENT_MAX_ITEMS]; -}; - -/* */ -int ac_kmod_init(void); -void ac_kmod_free(void); - -/* */ -int ac_kmod_isconnected(void); -int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count); - -/* */ -int ac_kmod_createdatachannel(int family, unsigned short port); - -/* */ -int ac_kmod_send_keepalive(struct capwap_sessionid_element* sessionid); -int ac_kmod_send_data(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t binding, const uint8_t* data, int length); - -/* */ -int ac_kmod_create_iface(const char* ifname, uint16_t mtu); -int ac_kmod_delete_iface(int ifindex); - -/* */ -int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu); -int ac_kmod_delete_datasession(struct capwap_sessionid_element* sessionid); - -/* */ -int ac_kmod_addwlan(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode); -int ac_kmod_removewlan(struct capwap_sessionid_element* sessionid); - -/* */ -int ac_kmod_authorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress, int ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan); -int ac_kmod_deauthorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress); - -#endif /* __AC_KMOD_HEADER__ */ +#ifndef __AC_KMOD_HEADER__ +#define __AC_KMOD_HEADER__ + +/* */ +#ifdef HAVE_LIBNL_10 +#define nl_sock nl_handle +#endif + +/* */ +#define AC_KMOD_MODE_LOCAL 0x00000001 +#define AC_KMOD_MODE_TUNNEL_USERMODE 0x00000002 +#define AC_KMOD_MODE_TUNNEL_KERNELMODE 0x00000003 + +/* */ +#define AC_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000 +#define AC_KMOD_FLAGS_TUNNEL_8023 0x00000001 + +/* */ +struct ac_kmod_handle { + /* Callback */ + struct nl_sock* nl; + int nl_fd; + struct nl_cb* nl_cb; + int nlsmartcapwap_id; + + /* Send message */ + capwap_lock_t msglock; + struct nl_sock* nlmsg; + struct nl_cb* nlmsg_cb; +}; + +/* */ +#define AC_KMOD_EVENT_MAX_ITEMS 2 +struct ac_kmod_event { + void (*event_handler)(int fd, void** params, int paramscount); + int paramscount; + void* params[AC_KMOD_EVENT_MAX_ITEMS]; +}; + +/* */ +int ac_kmod_init(void); +void ac_kmod_free(void); + +/* */ +int ac_kmod_isconnected(void); +int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count); + +/* */ +int ac_kmod_createdatachannel(int family, unsigned short port); + +/* */ +int ac_kmod_send_keepalive(struct capwap_sessionid_element* sessionid); +int ac_kmod_send_data(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t binding, const uint8_t* data, int length); + +/* */ +int ac_kmod_create_iface(const char* ifname, uint16_t mtu); +int ac_kmod_delete_iface(int ifindex); + +/* */ +int ac_kmod_new_datasession(struct capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu); +int ac_kmod_delete_datasession(struct capwap_sessionid_element* sessionid); + +/* */ +int ac_kmod_addwlan(struct capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode); +int ac_kmod_removewlan(struct capwap_sessionid_element* sessionid); + +/* */ +int ac_kmod_authorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress, int ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan); +int ac_kmod_deauthorize_station(struct capwap_sessionid_element* sessionid, const uint8_t* macaddress); + +#endif /* __AC_KMOD_HEADER__ */ diff --git a/src/ac/ac_soap.c b/src/ac/ac_soap.c index f0fb8d8..6c7ca70 100644 --- a/src/ac/ac_soap.c +++ b/src/ac/ac_soap.c @@ -1,868 +1,868 @@ -#include "ac.h" -#include "ac_soap.h" -#include "capwap_socket.h" - -/* */ -#define SOAP_PROTOCOL_CONNECT_TIMEOUT 10000 - -/* */ -#define HTTP_RESPONSE_STATUS_CODE 0 -#define HTTP_RESPONSE_HEADER 1 -#define HTTP_RESPONSE_BODY 2 -#define HTTP_RESPONSE_ERROR 3 - -/* */ -static const char l_encodeblock[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char l_decodeblock[] = - "\x3f\x00\x00\x00\x40\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x00" - "\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" - "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a" - "\x00\x00\x00\x00\x00\x00\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24" - "\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34"; - -/* */ -xmlNodePtr ac_xml_get_children(xmlNodePtr parent) { - xmlNodePtr children; - - ASSERT(parent != NULL); - - /* */ - children = parent->xmlChildrenNode; - while ((children != NULL) && (children->type != XML_ELEMENT_NODE)) { - children = children->next; - } - - return children; -} - -/* */ -xmlNodePtr ac_xml_get_next(xmlNodePtr element) { - xmlNodePtr node; - - ASSERT(element != NULL); - - node = element->next; - while ((node != NULL) && (node->type != XML_ELEMENT_NODE)) { - node = node->next; - } - - return node; -} - -xmlNodePtr ac_xml_search_child(xmlNodePtr parent, char* prefix, char* name) { - xmlNodePtr children; - - ASSERT(parent != NULL); - ASSERT(name != NULL); - - children = ac_xml_get_children(parent); - while (children != NULL) { - if (!xmlStrcmp(children->name, BAD_CAST name) && (!prefix || !xmlStrcmp(children->ns->prefix, BAD_CAST prefix))) { - break; - } - - /* */ - children = ac_xml_get_next(children); - } - - return children; -} - -/* */ -static int ac_soapclient_parsing_url(struct ac_http_soap_server* server, const char* url) { - int length; - int protocol; - int host; - int port; - int hostlength; - int pathlength; - - ASSERT(server != NULL); - ASSERT(url != NULL); - - /* */ - length = strlen(url); - if (length < 8) { - /* Invalid URL */ - return 0; - } - - /* Search protocol */ - protocol = 0; - while (url[protocol] && url[protocol] != ':') { - protocol++; - } - - if (!protocol || (protocol + 3 >= length)) { - /* Invalid URL */ - return 0; - } else if ((url[protocol] != ':') || (url[protocol + 1] != '/') || (url[protocol + 2] != '/')) { - /* Invalid URL */ - return 0; - } - - /* Parsing protocol */ - if (!strncasecmp(url, "http", protocol)) { - server->protocol = SOAP_HTTP_PROTOCOL; - } else if (!strncasecmp(url, "https", protocol)) { - server->protocol = SOAP_HTTPS_PROTOCOL; - } else { - /* Unknown protocol */ - return 0; - } - - protocol += 3; - - /* Search hostname */ - host = protocol; - while (url[host] && (url[host] != ':') && (url[host] != '/')) { - host++; - } - - if (host == protocol) { - /* Invalid hostname */ - return 0; - } - - /* Search port */ - port = host; - if (url[port] == ':') { - while (url[port] && (url[port] != '/')) { - port++; - } - } - - /* Retrieve hostname */ - hostlength = port - protocol; - server->host = capwap_alloc(hostlength + 1); - strncpy(server->host, &url[protocol], hostlength); - server->host[hostlength] = 0; - - /* Parsing hostname */ - if (!capwap_address_from_string(server->host, &server->address)) { - /* Invalid hostname */ - return 0; - } - - if (port == host) { - /* Get default port */ - if (server->protocol == SOAP_HTTP_PROTOCOL) { - CAPWAP_SET_NETWORK_PORT(&server->address, SOAP_HTTP_PORT); - } else if (server->protocol == SOAP_HTTPS_PROTOCOL) { - CAPWAP_SET_NETWORK_PORT(&server->address, SOAP_HTTPS_PORT); - } - } - - /* Retrieve path */ - pathlength = length - port; - if (!pathlength) { - pathlength = 1; - } - - server->path = capwap_alloc(pathlength + 1); - if (length == port) { - strcpy(server->path, "/"); - } else { - strncpy(server->path, &url[port], pathlength); - server->path[pathlength] = 0; - } - - return 1; -} - -/* */ -static int ac_soapclient_connect(struct ac_http_soap_request* httprequest) { - int result = 0; - - if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { - result = capwap_socket_connect(httprequest->sock, &httprequest->server->address, SOAP_PROTOCOL_CONNECT_TIMEOUT); - } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { - result = capwap_socket_connect(httprequest->sock, &httprequest->server->address, SOAP_PROTOCOL_CONNECT_TIMEOUT); - if (result) { - /* Establish SSL/TLS connection */ - httprequest->sslsock = capwap_socket_ssl_connect(httprequest->sock, httprequest->server->sslcontext, SOAP_PROTOCOL_CONNECT_TIMEOUT); - if (!httprequest->sslsock) { - result = 0; - } - } - } - - return result; -} - -/* */ -static int ac_soapclient_send_http(struct ac_http_soap_request* httprequest, char* soapaction, char* body, int length) { - time_t ts; - struct tm stm; - char datetime[32]; - int headerlength; - int result; - char* buffer; - - /* Retrieve datetime */ - ts = time(NULL); - localtime_r(&ts, &stm); - strftime(datetime, 32, "%a, %d %b %Y %T %z", &stm); - - /* Calculate header length */ - headerlength = 150 + length + strlen(httprequest->server->path) + strlen(httprequest->server->host) + strlen(datetime) + strlen((soapaction ? soapaction : "")); - buffer = capwap_alloc(headerlength); - - /* HTTP headers */ - result = snprintf(buffer, headerlength, - "POST %s HTTP/1.1\r\n" - "Host: %s\r\n" - "Date: %s\r\n" - "Content-Length: %d\r\n" - "Content-Type: text/xml\r\n" - "Connection: Close\r\n" - "SoapAction: %s\r\n" - "Expect: 100-continue\r\n" - "\r\n" - "%s", - httprequest->server->path, - httprequest->server->host, - datetime, - length, - (soapaction ? soapaction : ""), - body - ); - - /* Send headers */ - if (result < 0) { - result = 0; - } else { - int sendlength = -1; - - /* Send packet */ - if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { - sendlength = capwap_socket_send(httprequest->sock, buffer, result, httprequest->requesttimeout); - } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { - sendlength = capwap_socket_crypto_send(httprequest->sslsock, buffer, result, httprequest->requesttimeout); - } - - /* Check result */ - result = ((sendlength == result) ? 1 : 0); - } - - /* */ - capwap_free(buffer); - return result; -} - -/* */ -static int ac_soapclient_http_readline(struct ac_http_soap_request* httprequest, char* buffer, int length) { - int result = -1; - int bufferpos = 0; - - for (;;) { - /* Receive packet into temporaly buffer */ - if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { - if (capwap_socket_recv(httprequest->sock, &buffer[bufferpos], 1, httprequest->responsetimeout) != 1) { - break; /* Connection error */ - } - } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { - if (capwap_socket_crypto_recv(httprequest->sslsock, &buffer[bufferpos], 1, httprequest->responsetimeout) != 1) { - break; /* Connection error */ - } - } - - /* Update buffer size */ - bufferpos += 1; - if (bufferpos >= length) { - break; /* Buffer overflow */ - } - - /* Search line */ - if ((bufferpos > 1) && (buffer[bufferpos - 2] == '\r') && (buffer[bufferpos - 1] == '\n')) { - result = bufferpos - 2; - buffer[result] = 0; - break; - } - } - - return result; -} - -/* */ -static int ac_soapclient_xml_io_read(void* ctx, char* buffer, int len) { - int result = -1; - char respbuffer[8192]; - int respbufferlength = 0; - struct ac_http_soap_request* httprequest = (struct ac_http_soap_request*)ctx; - - while ((httprequest->httpstate == HTTP_RESPONSE_STATUS_CODE) || (httprequest->httpstate == HTTP_RESPONSE_HEADER)) { - /* Receive packet into temporaly buffer */ - respbufferlength = ac_soapclient_http_readline(httprequest, respbuffer, sizeof(respbuffer)); - if (respbufferlength == -1) { - httprequest->httpstate = HTTP_RESPONSE_ERROR; - } else if (httprequest->httpstate == HTTP_RESPONSE_STATUS_CODE) { - int temp; - int descpos; - - /* Parse response code */ - temp = sscanf(respbuffer, "HTTP/1.1 %d %n", &httprequest->responsecode, &descpos); - if (temp != 1) { - httprequest->httpstate = HTTP_RESPONSE_ERROR; - break; - } - - /* Parsing headers */ - httprequest->httpstate = HTTP_RESPONSE_HEADER; - } else if (httprequest->httpstate == HTTP_RESPONSE_HEADER) { - char* value; - - if (!respbufferlength) { - if (httprequest->responsecode == HTTP_RESULT_CONTINUE) { - if (!httprequest->contentlength) { - httprequest->httpstate = HTTP_RESPONSE_STATUS_CODE; - } else { - httprequest->httpstate = HTTP_RESPONSE_ERROR; - } - } else if (httprequest->contentxml && (httprequest->contentlength > 0)) { - httprequest->httpstate = HTTP_RESPONSE_BODY; /* Retrieve body */ - } else { - httprequest->httpstate = HTTP_RESPONSE_ERROR; - } - } else { - /* Separate key from value */ - value = strchr(respbuffer, ':'); - if (!value) { - httprequest->httpstate = HTTP_RESPONSE_ERROR; - } else { - *value = 0; - value++; - while (*value == ' ') { - value++; - } - - /* */ - if (!strcmp(respbuffer, "Content-Length")) { - httprequest->contentlength = atoi(value); - if (!httprequest->contentlength) { - httprequest->httpstate = HTTP_RESPONSE_ERROR; - } - } else if (!strcmp(respbuffer, "Content-Type")) { - char* param; - - /* Remove param from value */ - param = strchr(value, ';'); - if (param) { - *param = 0; - } - - if (!strcmp(value, "text/xml")) { - httprequest->contentxml = 1; - } else { - httprequest->httpstate = HTTP_RESPONSE_ERROR; - } - } - } - } - } - } - - if (httprequest->httpstate == HTTP_RESPONSE_BODY) { - if (!httprequest->contentlength) { - return 0; - } - - /* Receive body directly into XML buffer */ - if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { - result = capwap_socket_recv(httprequest->sock, buffer, len, httprequest->responsetimeout); - } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { - result = capwap_socket_crypto_recv(httprequest->sslsock, buffer, len, httprequest->responsetimeout); - } - - if (result > 0) { - httprequest->contentlength -= result; - } - } - - return result; -} - -/* */ -static int ac_soapclient_xml_io_close(void *ctx) { - struct ac_http_soap_request* httprequest = (struct ac_http_soap_request*)ctx; - - if ((httprequest->httpstate != HTTP_RESPONSE_BODY) || httprequest->contentlength) { - return -1; - } - - return 0; -} - -/* */ -static void ac_soapclient_parse_error(void* ctxt, const char* msg, ...) { -} - -/* */ -void ac_soapclient_init(void) { - xmlInitParser(); - xmlSetGenericErrorFunc(NULL, ac_soapclient_parse_error); - xmlThrDefSetGenericErrorFunc(NULL, ac_soapclient_parse_error); -} - -/* */ -void ac_soapclient_free(void) { - xmlCleanupParser(); -} - -/* */ -struct ac_http_soap_server* ac_soapclient_create_server(const char* url) { - struct ac_http_soap_server* server; - - ASSERT(url != NULL); - - /* */ - server = (struct ac_http_soap_server*)capwap_alloc(sizeof(struct ac_http_soap_server)); - memset(server, 0, sizeof(struct ac_http_soap_server)); - - /* */ - if (!ac_soapclient_parsing_url(server, url)) { - ac_soapclient_free_server(server); - return NULL; - } - - return server; -} - -/* */ -void ac_soapclient_free_server(struct ac_http_soap_server* server) { - ASSERT(server != NULL); - - if (server->host) { - capwap_free(server->host); - } - - if (server->path) { - capwap_free(server->path); - } - - if (server->sslcontext) { - capwap_socket_crypto_freecontext(server->sslcontext); - } - - capwap_free(server); -} - -/* */ -struct ac_soap_request* ac_soapclient_create_request(char* method, char* urinamespace) { - char* tagMethod; - struct ac_soap_request* request; - - ASSERT(method != NULL); - ASSERT(urinamespace != NULL); - - /* */ - request = (struct ac_soap_request*)capwap_alloc(sizeof(struct ac_soap_request)); - memset(request, 0, sizeof(struct ac_soap_request)); - - /* Build XML SOAP Request */ - request->xmlDocument = xmlNewDoc(BAD_CAST "1.0"); - request->xmlRoot = xmlNewNode(NULL, BAD_CAST "SOAP-ENV:Envelope"); - xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:xsd", BAD_CAST "http://www.w3.org/2001/XMLSchema"); - xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:xsi", BAD_CAST "http://www.w3.org/2001/XMLSchema-instance"); - xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:SOAP-ENC", BAD_CAST "http://schemas.xmlsoap.org/soap/encoding/"); - xmlNewProp(request->xmlRoot, BAD_CAST "SOAP-ENV:encodingStyle", BAD_CAST "http://schemas.xmlsoap.org/soap/encoding/"); - xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:SOAP-ENV", BAD_CAST "http://schemas.xmlsoap.org/soap/envelope/"); - xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:tns", BAD_CAST urinamespace); - xmlDocSetRootElement(request->xmlDocument, request->xmlRoot); - - xmlNewChild(request->xmlRoot, NULL, BAD_CAST "SOAP-ENV:Header", NULL); - request->xmlBody = xmlNewChild(request->xmlRoot, NULL, BAD_CAST "SOAP-ENV:Body", NULL); - - /* */ - request->method = capwap_duplicate_string(method); - - /* Create request */ - tagMethod = capwap_alloc(strlen(method) + 5); - sprintf(tagMethod, "tns:%s", method); - request->xmlRequest = xmlNewChild(request->xmlBody, NULL, BAD_CAST tagMethod, NULL); - capwap_free(tagMethod); - - return request; -} - -/* */ -void ac_soapclient_free_request(struct ac_soap_request* request) { - ASSERT(request != NULL); - - if (request->xmlDocument) { - xmlFreeDoc(request->xmlDocument); - } - - if (request->method) { - capwap_free(request->method); - } - - capwap_free(request); -} - -/* */ -int ac_soapclient_add_param(struct ac_soap_request* request, const char* type, const char* name, const char* value) { - xmlNodePtr xmlParam; - - ASSERT(request != NULL); - ASSERT(name != NULL); - ASSERT(value != NULL); - - /* */ - xmlParam = xmlNewTextChild(request->xmlRequest, NULL, BAD_CAST name, BAD_CAST value); - if (!xmlParam) { - return 0; - } - - if (type) { - if (!xmlNewProp(xmlParam, BAD_CAST "xsi:type", BAD_CAST type)) { - return 0; - } - } - - return 1; -} - -/* */ -char* ac_soapclient_get_request(struct ac_soap_request* request) { - char* result; - size_t length; - xmlBufferPtr buffer; - - ASSERT(request != NULL); - ASSERT(request->xmlDocument != NULL); - - /* */ - buffer = xmlBufferCreate(); - length = xmlNodeDump(buffer, request->xmlDocument, request->xmlRoot, 1, 0); - - /* Clone XML document string */ - result = capwap_alloc(length + 1); - memcpy(result, (char*)xmlBufferContent(buffer), length); - result[length] = 0; - - /* */ - xmlBufferFree(buffer); - return result; -} - -/* */ -struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_request* request, struct ac_http_soap_server* server) { - struct ac_http_soap_request* httprequest; - - ASSERT(request != NULL); - ASSERT(request->xmlDocument != NULL); - ASSERT(request->xmlRoot != NULL); - ASSERT(server != NULL); - - /* */ - httprequest = (struct ac_http_soap_request*)capwap_alloc(sizeof(struct ac_http_soap_request)); - memset(httprequest, 0, sizeof(struct ac_http_soap_request)); - - /* */ - httprequest->request = request; - httprequest->server = server; - httprequest->requesttimeout = SOAP_PROTOCOL_REQUEST_TIMEOUT; - httprequest->responsetimeout = SOAP_PROTOCOL_RESPONSE_TIMEOUT; - - /* Create socket */ - httprequest->sock = socket(httprequest->server->address.ss.ss_family, SOCK_STREAM, 0); - if (httprequest->sock < 0) { - ac_soapclient_close_request(httprequest, 0); - return NULL; - } - - return httprequest; -} - -/* */ -int ac_soapclient_send_request(struct ac_http_soap_request* httprequest, char* soapaction) { - char* buffer; - size_t length; - xmlBufferPtr xmlBuffer; - - ASSERT(httprequest != NULL); - - /* Retrieve XML SOAP Request */ - xmlBuffer = xmlBufferCreate(); - length = xmlNodeDump(xmlBuffer, httprequest->request->xmlDocument, httprequest->request->xmlRoot, 1, 0); - if (!length) { - return 0; - } - - buffer = (char*)xmlBufferContent(xmlBuffer); - - /* Connect to remote host */ - if (!ac_soapclient_connect(httprequest)) { - xmlBufferFree(xmlBuffer); - return 0; - } - - /* Send HTTP Header */ - if (!ac_soapclient_send_http(httprequest, soapaction, buffer, (int)length)) { - xmlBufferFree(xmlBuffer); - return 0; - } - - /* Sent SOAP Request */ - xmlBufferFree(xmlBuffer); - return 1; -} - -/* */ -void ac_soapclient_shutdown_request(struct ac_http_soap_request* httprequest) { - ASSERT(httprequest != NULL); - - if (httprequest->sslsock) { - capwap_socket_ssl_shutdown(httprequest->sslsock, SOAP_PROTOCOL_CLOSE_TIMEOUT); - } - - if (httprequest->sock >= 0) { - capwap_socket_shutdown(httprequest->sock); - } -} - -/* */ -void ac_soapclient_close_request(struct ac_http_soap_request* httprequest, int closerequest) { - ASSERT(httprequest != NULL); - - /* */ - if (closerequest && httprequest->request) { - ac_soapclient_free_request(httprequest->request); - } - - /* */ - if (httprequest->sslsock) { - capwap_socket_ssl_shutdown(httprequest->sslsock, SOAP_PROTOCOL_CLOSE_TIMEOUT); - capwap_socket_ssl_close(httprequest->sslsock); - capwap_free(httprequest->sslsock); - } - - /* Close socket */ - if (httprequest->sock >= 0) { - capwap_socket_close(httprequest->sock); - } - - capwap_free(httprequest); -} - -/* */ -struct ac_soap_response* ac_soapclient_recv_response(struct ac_http_soap_request* httprequest) { - struct ac_soap_response* response; - - ASSERT(httprequest != NULL); - ASSERT(httprequest->sock >= 0); - - /* */ - response = (struct ac_soap_response*)capwap_alloc(sizeof(struct ac_soap_response)); - memset(response, 0, sizeof(struct ac_soap_response)); - - /* Receive HTTP response into XML callback */ - httprequest->httpstate = HTTP_RESPONSE_STATUS_CODE; - response->xmlDocument = xmlReadIO(ac_soapclient_xml_io_read, ac_soapclient_xml_io_close, (void*)httprequest, "", NULL, 0); - if (!response->xmlDocument) { - ac_soapclient_free_response(response); - return NULL; - } - - /* Parsing response */ - response->responsecode = httprequest->responsecode; - response->xmlRoot = xmlDocGetRootElement(response->xmlDocument); - if (!response->xmlRoot) { - ac_soapclient_free_response(response); - return NULL; - } - - /* Retrieve Body */ - response->xmlBody = ac_xml_search_child(response->xmlRoot, "SOAP-ENV", "Body"); - if (!response->xmlBody) { - ac_soapclient_free_response(response); - return NULL; - } - - /* Retrieve response */ - if (response->responsecode == HTTP_RESULT_OK) { - char* tagMethod = capwap_alloc(strlen(httprequest->request->method) + 9); - sprintf(tagMethod, "%sResponse", httprequest->request->method); - response->xmlResponse = ac_xml_search_child(response->xmlBody, NULL, tagMethod); - capwap_free(tagMethod); - - if (!response->xmlResponse) { - ac_soapclient_free_response(response); - return NULL; - } - - /* Retrieve optional return response */ - response->xmlResponseReturn = ac_xml_search_child(response->xmlResponse, NULL, "return"); - } else { - /* Retrieve Fault */ - response->xmlFault = ac_xml_search_child(response->xmlBody, "SOAP-ENV", "Fault"); - if (!response->xmlFault) { - ac_soapclient_free_response(response); - return NULL; - } - - /* Retrieve FaultCode */ - response->xmlFaultCode = ac_xml_search_child(response->xmlFault, NULL, "faultcode"); - if (!response->xmlFaultCode) { - ac_soapclient_free_response(response); - return NULL; - } - - /* Retrieve FaultString */ - response->xmlFaultString = ac_xml_search_child(response->xmlFault, NULL, "faultstring"); - if (!response->xmlFaultString) { - ac_soapclient_free_response(response); - return NULL; - } - } - - return response; -} - -/* */ -struct json_object* ac_soapclient_parse_json_response(struct ac_soap_response* response) { - int length; - char* json; - xmlChar* xmlResult; - struct json_object* jsonroot; - - ASSERT(response != NULL); - - /* */ - if ((response->responsecode != HTTP_RESULT_OK) || !response->xmlResponseReturn) { - return NULL; - } - - /* Decode base64 result */ - xmlResult = xmlNodeGetContent(response->xmlResponseReturn); - if (!xmlResult) { - return NULL; - } - - length = xmlStrlen(xmlResult); - if (!length) { - xmlFree(xmlResult); - return NULL; - } - - json = (char*)capwap_alloc(AC_BASE64_DECODE_LENGTH(length)); - ac_base64_string_decode((const char*)xmlResult, json); - - xmlFree(xmlResult); - - /* Parsing JSON result */ - jsonroot = json_tokener_parse(json); - capwap_free(json); - - return jsonroot; -} - -/* */ -void ac_soapclient_free_response(struct ac_soap_response* response) { - ASSERT(response != NULL); - - if (response->xmlDocument) { - xmlFreeDoc(response->xmlDocument); - } - - capwap_free(response); -} - -/* */ -int ac_base64_binary_encode(const char* plain, int length, char* encoded) { - int result = 0; - - ASSERT(plain != NULL); - ASSERT(encoded != NULL); - - while (length > 0) { - int len = ((length > 1) ? ((length > 2) ? 3 : 2) : 1); - - /* Encode block */ - encoded[0] = l_encodeblock[plain[0] >> 2]; - encoded[1] = l_encodeblock[((plain[0] & 0x03) << 4) | ((plain[1] & 0xf0) >> 4)]; - encoded[2] = (len > 1 ? l_encodeblock[((plain[1] & 0x0f) << 2) | ((plain[2] & 0xc0) >> 6)] : '='); - encoded[3] = (len > 2 ? l_encodeblock[plain[2] & 0x3f] : '='); - - /* Next block */ - plain += len; - length -= len; - encoded += 4; - result += 4; - } - - return result; -} - -/* */ -void ac_base64_string_encode(const char* plain, char* encoded) { - int result; - - ASSERT(plain != NULL); - ASSERT(encoded != NULL); - - /* Encode base64 */ - result = ac_base64_binary_encode(plain, strlen(plain), encoded); - - /* Terminate string */ - encoded[result] = 0; -} - -/* */ -int ac_base64_binary_decode(const char* encoded, int length, char* plain) { - int i; - char bufdec[3]; - int result = 0; - - ASSERT(encoded != NULL); - ASSERT(plain != NULL); - - while (length > 0) { - int len = 0; - char bufenc[4] = { 0, 0, 0, 0 }; - - for (i = 0; i < 4 && (length > 0); i++) { - char element = 0; - while ((length > 0) && !element) { - element = *encoded++; - element = (((element < 43) || (element > 122)) ? 0 : l_decodeblock[element - 43]); - length--; - } - - if (element) { - len++; - bufenc[i] = element - 1; - } - } - - if (len) { - bufdec[0] = (bufenc[0] << 2 | bufenc[1] >> 4); - bufdec[1] = (bufenc[1] << 4 | bufenc[2] >> 2); - bufdec[2] = (((bufenc[2] << 6) & 0xc0) | bufenc[3]); - - for (i = 0; i < len - 1; i++) { - *plain++ = bufdec[i]; - result++; - } - } - } - - /* Terminate string */ - return result; -} - -/* */ -void ac_base64_string_decode(const char* encoded, char* plain) { - int result; - - ASSERT(encoded != NULL); - ASSERT(plain != NULL); - - /* Decode base64 */ - result = ac_base64_binary_decode(encoded, strlen(encoded), plain); - - /* Terminate string */ - plain[result] = 0; -} +#include "ac.h" +#include "ac_soap.h" +#include "capwap_socket.h" + +/* */ +#define SOAP_PROTOCOL_CONNECT_TIMEOUT 10000 + +/* */ +#define HTTP_RESPONSE_STATUS_CODE 0 +#define HTTP_RESPONSE_HEADER 1 +#define HTTP_RESPONSE_BODY 2 +#define HTTP_RESPONSE_ERROR 3 + +/* */ +static const char l_encodeblock[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char l_decodeblock[] = + "\x3f\x00\x00\x00\x40\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x00" + "\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a" + "\x00\x00\x00\x00\x00\x00\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24" + "\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34"; + +/* */ +xmlNodePtr ac_xml_get_children(xmlNodePtr parent) { + xmlNodePtr children; + + ASSERT(parent != NULL); + + /* */ + children = parent->xmlChildrenNode; + while ((children != NULL) && (children->type != XML_ELEMENT_NODE)) { + children = children->next; + } + + return children; +} + +/* */ +xmlNodePtr ac_xml_get_next(xmlNodePtr element) { + xmlNodePtr node; + + ASSERT(element != NULL); + + node = element->next; + while ((node != NULL) && (node->type != XML_ELEMENT_NODE)) { + node = node->next; + } + + return node; +} + +xmlNodePtr ac_xml_search_child(xmlNodePtr parent, char* prefix, char* name) { + xmlNodePtr children; + + ASSERT(parent != NULL); + ASSERT(name != NULL); + + children = ac_xml_get_children(parent); + while (children != NULL) { + if (!xmlStrcmp(children->name, BAD_CAST name) && (!prefix || !xmlStrcmp(children->ns->prefix, BAD_CAST prefix))) { + break; + } + + /* */ + children = ac_xml_get_next(children); + } + + return children; +} + +/* */ +static int ac_soapclient_parsing_url(struct ac_http_soap_server* server, const char* url) { + int length; + int protocol; + int host; + int port; + int hostlength; + int pathlength; + + ASSERT(server != NULL); + ASSERT(url != NULL); + + /* */ + length = strlen(url); + if (length < 8) { + /* Invalid URL */ + return 0; + } + + /* Search protocol */ + protocol = 0; + while (url[protocol] && url[protocol] != ':') { + protocol++; + } + + if (!protocol || (protocol + 3 >= length)) { + /* Invalid URL */ + return 0; + } else if ((url[protocol] != ':') || (url[protocol + 1] != '/') || (url[protocol + 2] != '/')) { + /* Invalid URL */ + return 0; + } + + /* Parsing protocol */ + if (!strncasecmp(url, "http", protocol)) { + server->protocol = SOAP_HTTP_PROTOCOL; + } else if (!strncasecmp(url, "https", protocol)) { + server->protocol = SOAP_HTTPS_PROTOCOL; + } else { + /* Unknown protocol */ + return 0; + } + + protocol += 3; + + /* Search hostname */ + host = protocol; + while (url[host] && (url[host] != ':') && (url[host] != '/')) { + host++; + } + + if (host == protocol) { + /* Invalid hostname */ + return 0; + } + + /* Search port */ + port = host; + if (url[port] == ':') { + while (url[port] && (url[port] != '/')) { + port++; + } + } + + /* Retrieve hostname */ + hostlength = port - protocol; + server->host = capwap_alloc(hostlength + 1); + strncpy(server->host, &url[protocol], hostlength); + server->host[hostlength] = 0; + + /* Parsing hostname */ + if (!capwap_address_from_string(server->host, &server->address)) { + /* Invalid hostname */ + return 0; + } + + if (port == host) { + /* Get default port */ + if (server->protocol == SOAP_HTTP_PROTOCOL) { + CAPWAP_SET_NETWORK_PORT(&server->address, SOAP_HTTP_PORT); + } else if (server->protocol == SOAP_HTTPS_PROTOCOL) { + CAPWAP_SET_NETWORK_PORT(&server->address, SOAP_HTTPS_PORT); + } + } + + /* Retrieve path */ + pathlength = length - port; + if (!pathlength) { + pathlength = 1; + } + + server->path = capwap_alloc(pathlength + 1); + if (length == port) { + strcpy(server->path, "/"); + } else { + strncpy(server->path, &url[port], pathlength); + server->path[pathlength] = 0; + } + + return 1; +} + +/* */ +static int ac_soapclient_connect(struct ac_http_soap_request* httprequest) { + int result = 0; + + if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { + result = capwap_socket_connect(httprequest->sock, &httprequest->server->address, SOAP_PROTOCOL_CONNECT_TIMEOUT); + } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { + result = capwap_socket_connect(httprequest->sock, &httprequest->server->address, SOAP_PROTOCOL_CONNECT_TIMEOUT); + if (result) { + /* Establish SSL/TLS connection */ + httprequest->sslsock = capwap_socket_ssl_connect(httprequest->sock, httprequest->server->sslcontext, SOAP_PROTOCOL_CONNECT_TIMEOUT); + if (!httprequest->sslsock) { + result = 0; + } + } + } + + return result; +} + +/* */ +static int ac_soapclient_send_http(struct ac_http_soap_request* httprequest, char* soapaction, char* body, int length) { + time_t ts; + struct tm stm; + char datetime[32]; + int headerlength; + int result; + char* buffer; + + /* Retrieve datetime */ + ts = time(NULL); + localtime_r(&ts, &stm); + strftime(datetime, 32, "%a, %d %b %Y %T %z", &stm); + + /* Calculate header length */ + headerlength = 150 + length + strlen(httprequest->server->path) + strlen(httprequest->server->host) + strlen(datetime) + strlen((soapaction ? soapaction : "")); + buffer = capwap_alloc(headerlength); + + /* HTTP headers */ + result = snprintf(buffer, headerlength, + "POST %s HTTP/1.1\r\n" + "Host: %s\r\n" + "Date: %s\r\n" + "Content-Length: %d\r\n" + "Content-Type: text/xml\r\n" + "Connection: Close\r\n" + "SoapAction: %s\r\n" + "Expect: 100-continue\r\n" + "\r\n" + "%s", + httprequest->server->path, + httprequest->server->host, + datetime, + length, + (soapaction ? soapaction : ""), + body + ); + + /* Send headers */ + if (result < 0) { + result = 0; + } else { + int sendlength = -1; + + /* Send packet */ + if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { + sendlength = capwap_socket_send(httprequest->sock, buffer, result, httprequest->requesttimeout); + } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { + sendlength = capwap_socket_crypto_send(httprequest->sslsock, buffer, result, httprequest->requesttimeout); + } + + /* Check result */ + result = ((sendlength == result) ? 1 : 0); + } + + /* */ + capwap_free(buffer); + return result; +} + +/* */ +static int ac_soapclient_http_readline(struct ac_http_soap_request* httprequest, char* buffer, int length) { + int result = -1; + int bufferpos = 0; + + for (;;) { + /* Receive packet into temporaly buffer */ + if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { + if (capwap_socket_recv(httprequest->sock, &buffer[bufferpos], 1, httprequest->responsetimeout) != 1) { + break; /* Connection error */ + } + } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { + if (capwap_socket_crypto_recv(httprequest->sslsock, &buffer[bufferpos], 1, httprequest->responsetimeout) != 1) { + break; /* Connection error */ + } + } + + /* Update buffer size */ + bufferpos += 1; + if (bufferpos >= length) { + break; /* Buffer overflow */ + } + + /* Search line */ + if ((bufferpos > 1) && (buffer[bufferpos - 2] == '\r') && (buffer[bufferpos - 1] == '\n')) { + result = bufferpos - 2; + buffer[result] = 0; + break; + } + } + + return result; +} + +/* */ +static int ac_soapclient_xml_io_read(void* ctx, char* buffer, int len) { + int result = -1; + char respbuffer[8192]; + int respbufferlength = 0; + struct ac_http_soap_request* httprequest = (struct ac_http_soap_request*)ctx; + + while ((httprequest->httpstate == HTTP_RESPONSE_STATUS_CODE) || (httprequest->httpstate == HTTP_RESPONSE_HEADER)) { + /* Receive packet into temporaly buffer */ + respbufferlength = ac_soapclient_http_readline(httprequest, respbuffer, sizeof(respbuffer)); + if (respbufferlength == -1) { + httprequest->httpstate = HTTP_RESPONSE_ERROR; + } else if (httprequest->httpstate == HTTP_RESPONSE_STATUS_CODE) { + int temp; + int descpos; + + /* Parse response code */ + temp = sscanf(respbuffer, "HTTP/1.1 %d %n", &httprequest->responsecode, &descpos); + if (temp != 1) { + httprequest->httpstate = HTTP_RESPONSE_ERROR; + break; + } + + /* Parsing headers */ + httprequest->httpstate = HTTP_RESPONSE_HEADER; + } else if (httprequest->httpstate == HTTP_RESPONSE_HEADER) { + char* value; + + if (!respbufferlength) { + if (httprequest->responsecode == HTTP_RESULT_CONTINUE) { + if (!httprequest->contentlength) { + httprequest->httpstate = HTTP_RESPONSE_STATUS_CODE; + } else { + httprequest->httpstate = HTTP_RESPONSE_ERROR; + } + } else if (httprequest->contentxml && (httprequest->contentlength > 0)) { + httprequest->httpstate = HTTP_RESPONSE_BODY; /* Retrieve body */ + } else { + httprequest->httpstate = HTTP_RESPONSE_ERROR; + } + } else { + /* Separate key from value */ + value = strchr(respbuffer, ':'); + if (!value) { + httprequest->httpstate = HTTP_RESPONSE_ERROR; + } else { + *value = 0; + value++; + while (*value == ' ') { + value++; + } + + /* */ + if (!strcmp(respbuffer, "Content-Length")) { + httprequest->contentlength = atoi(value); + if (!httprequest->contentlength) { + httprequest->httpstate = HTTP_RESPONSE_ERROR; + } + } else if (!strcmp(respbuffer, "Content-Type")) { + char* param; + + /* Remove param from value */ + param = strchr(value, ';'); + if (param) { + *param = 0; + } + + if (!strcmp(value, "text/xml")) { + httprequest->contentxml = 1; + } else { + httprequest->httpstate = HTTP_RESPONSE_ERROR; + } + } + } + } + } + } + + if (httprequest->httpstate == HTTP_RESPONSE_BODY) { + if (!httprequest->contentlength) { + return 0; + } + + /* Receive body directly into XML buffer */ + if (httprequest->server->protocol == SOAP_HTTP_PROTOCOL) { + result = capwap_socket_recv(httprequest->sock, buffer, len, httprequest->responsetimeout); + } else if (httprequest->server->protocol == SOAP_HTTPS_PROTOCOL) { + result = capwap_socket_crypto_recv(httprequest->sslsock, buffer, len, httprequest->responsetimeout); + } + + if (result > 0) { + httprequest->contentlength -= result; + } + } + + return result; +} + +/* */ +static int ac_soapclient_xml_io_close(void *ctx) { + struct ac_http_soap_request* httprequest = (struct ac_http_soap_request*)ctx; + + if ((httprequest->httpstate != HTTP_RESPONSE_BODY) || httprequest->contentlength) { + return -1; + } + + return 0; +} + +/* */ +static void ac_soapclient_parse_error(void* ctxt, const char* msg, ...) { +} + +/* */ +void ac_soapclient_init(void) { + xmlInitParser(); + xmlSetGenericErrorFunc(NULL, ac_soapclient_parse_error); + xmlThrDefSetGenericErrorFunc(NULL, ac_soapclient_parse_error); +} + +/* */ +void ac_soapclient_free(void) { + xmlCleanupParser(); +} + +/* */ +struct ac_http_soap_server* ac_soapclient_create_server(const char* url) { + struct ac_http_soap_server* server; + + ASSERT(url != NULL); + + /* */ + server = (struct ac_http_soap_server*)capwap_alloc(sizeof(struct ac_http_soap_server)); + memset(server, 0, sizeof(struct ac_http_soap_server)); + + /* */ + if (!ac_soapclient_parsing_url(server, url)) { + ac_soapclient_free_server(server); + return NULL; + } + + return server; +} + +/* */ +void ac_soapclient_free_server(struct ac_http_soap_server* server) { + ASSERT(server != NULL); + + if (server->host) { + capwap_free(server->host); + } + + if (server->path) { + capwap_free(server->path); + } + + if (server->sslcontext) { + capwap_socket_crypto_freecontext(server->sslcontext); + } + + capwap_free(server); +} + +/* */ +struct ac_soap_request* ac_soapclient_create_request(char* method, char* urinamespace) { + char* tagMethod; + struct ac_soap_request* request; + + ASSERT(method != NULL); + ASSERT(urinamespace != NULL); + + /* */ + request = (struct ac_soap_request*)capwap_alloc(sizeof(struct ac_soap_request)); + memset(request, 0, sizeof(struct ac_soap_request)); + + /* Build XML SOAP Request */ + request->xmlDocument = xmlNewDoc(BAD_CAST "1.0"); + request->xmlRoot = xmlNewNode(NULL, BAD_CAST "SOAP-ENV:Envelope"); + xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:xsd", BAD_CAST "http://www.w3.org/2001/XMLSchema"); + xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:xsi", BAD_CAST "http://www.w3.org/2001/XMLSchema-instance"); + xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:SOAP-ENC", BAD_CAST "http://schemas.xmlsoap.org/soap/encoding/"); + xmlNewProp(request->xmlRoot, BAD_CAST "SOAP-ENV:encodingStyle", BAD_CAST "http://schemas.xmlsoap.org/soap/encoding/"); + xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:SOAP-ENV", BAD_CAST "http://schemas.xmlsoap.org/soap/envelope/"); + xmlNewProp(request->xmlRoot, BAD_CAST "xmlns:tns", BAD_CAST urinamespace); + xmlDocSetRootElement(request->xmlDocument, request->xmlRoot); + + xmlNewChild(request->xmlRoot, NULL, BAD_CAST "SOAP-ENV:Header", NULL); + request->xmlBody = xmlNewChild(request->xmlRoot, NULL, BAD_CAST "SOAP-ENV:Body", NULL); + + /* */ + request->method = capwap_duplicate_string(method); + + /* Create request */ + tagMethod = capwap_alloc(strlen(method) + 5); + sprintf(tagMethod, "tns:%s", method); + request->xmlRequest = xmlNewChild(request->xmlBody, NULL, BAD_CAST tagMethod, NULL); + capwap_free(tagMethod); + + return request; +} + +/* */ +void ac_soapclient_free_request(struct ac_soap_request* request) { + ASSERT(request != NULL); + + if (request->xmlDocument) { + xmlFreeDoc(request->xmlDocument); + } + + if (request->method) { + capwap_free(request->method); + } + + capwap_free(request); +} + +/* */ +int ac_soapclient_add_param(struct ac_soap_request* request, const char* type, const char* name, const char* value) { + xmlNodePtr xmlParam; + + ASSERT(request != NULL); + ASSERT(name != NULL); + ASSERT(value != NULL); + + /* */ + xmlParam = xmlNewTextChild(request->xmlRequest, NULL, BAD_CAST name, BAD_CAST value); + if (!xmlParam) { + return 0; + } + + if (type) { + if (!xmlNewProp(xmlParam, BAD_CAST "xsi:type", BAD_CAST type)) { + return 0; + } + } + + return 1; +} + +/* */ +char* ac_soapclient_get_request(struct ac_soap_request* request) { + char* result; + size_t length; + xmlBufferPtr buffer; + + ASSERT(request != NULL); + ASSERT(request->xmlDocument != NULL); + + /* */ + buffer = xmlBufferCreate(); + length = xmlNodeDump(buffer, request->xmlDocument, request->xmlRoot, 1, 0); + + /* Clone XML document string */ + result = capwap_alloc(length + 1); + memcpy(result, (char*)xmlBufferContent(buffer), length); + result[length] = 0; + + /* */ + xmlBufferFree(buffer); + return result; +} + +/* */ +struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_request* request, struct ac_http_soap_server* server) { + struct ac_http_soap_request* httprequest; + + ASSERT(request != NULL); + ASSERT(request->xmlDocument != NULL); + ASSERT(request->xmlRoot != NULL); + ASSERT(server != NULL); + + /* */ + httprequest = (struct ac_http_soap_request*)capwap_alloc(sizeof(struct ac_http_soap_request)); + memset(httprequest, 0, sizeof(struct ac_http_soap_request)); + + /* */ + httprequest->request = request; + httprequest->server = server; + httprequest->requesttimeout = SOAP_PROTOCOL_REQUEST_TIMEOUT; + httprequest->responsetimeout = SOAP_PROTOCOL_RESPONSE_TIMEOUT; + + /* Create socket */ + httprequest->sock = socket(httprequest->server->address.ss.ss_family, SOCK_STREAM, 0); + if (httprequest->sock < 0) { + ac_soapclient_close_request(httprequest, 0); + return NULL; + } + + return httprequest; +} + +/* */ +int ac_soapclient_send_request(struct ac_http_soap_request* httprequest, char* soapaction) { + char* buffer; + size_t length; + xmlBufferPtr xmlBuffer; + + ASSERT(httprequest != NULL); + + /* Retrieve XML SOAP Request */ + xmlBuffer = xmlBufferCreate(); + length = xmlNodeDump(xmlBuffer, httprequest->request->xmlDocument, httprequest->request->xmlRoot, 1, 0); + if (!length) { + return 0; + } + + buffer = (char*)xmlBufferContent(xmlBuffer); + + /* Connect to remote host */ + if (!ac_soapclient_connect(httprequest)) { + xmlBufferFree(xmlBuffer); + return 0; + } + + /* Send HTTP Header */ + if (!ac_soapclient_send_http(httprequest, soapaction, buffer, (int)length)) { + xmlBufferFree(xmlBuffer); + return 0; + } + + /* Sent SOAP Request */ + xmlBufferFree(xmlBuffer); + return 1; +} + +/* */ +void ac_soapclient_shutdown_request(struct ac_http_soap_request* httprequest) { + ASSERT(httprequest != NULL); + + if (httprequest->sslsock) { + capwap_socket_ssl_shutdown(httprequest->sslsock, SOAP_PROTOCOL_CLOSE_TIMEOUT); + } + + if (httprequest->sock >= 0) { + capwap_socket_shutdown(httprequest->sock); + } +} + +/* */ +void ac_soapclient_close_request(struct ac_http_soap_request* httprequest, int closerequest) { + ASSERT(httprequest != NULL); + + /* */ + if (closerequest && httprequest->request) { + ac_soapclient_free_request(httprequest->request); + } + + /* */ + if (httprequest->sslsock) { + capwap_socket_ssl_shutdown(httprequest->sslsock, SOAP_PROTOCOL_CLOSE_TIMEOUT); + capwap_socket_ssl_close(httprequest->sslsock); + capwap_free(httprequest->sslsock); + } + + /* Close socket */ + if (httprequest->sock >= 0) { + capwap_socket_close(httprequest->sock); + } + + capwap_free(httprequest); +} + +/* */ +struct ac_soap_response* ac_soapclient_recv_response(struct ac_http_soap_request* httprequest) { + struct ac_soap_response* response; + + ASSERT(httprequest != NULL); + ASSERT(httprequest->sock >= 0); + + /* */ + response = (struct ac_soap_response*)capwap_alloc(sizeof(struct ac_soap_response)); + memset(response, 0, sizeof(struct ac_soap_response)); + + /* Receive HTTP response into XML callback */ + httprequest->httpstate = HTTP_RESPONSE_STATUS_CODE; + response->xmlDocument = xmlReadIO(ac_soapclient_xml_io_read, ac_soapclient_xml_io_close, (void*)httprequest, "", NULL, 0); + if (!response->xmlDocument) { + ac_soapclient_free_response(response); + return NULL; + } + + /* Parsing response */ + response->responsecode = httprequest->responsecode; + response->xmlRoot = xmlDocGetRootElement(response->xmlDocument); + if (!response->xmlRoot) { + ac_soapclient_free_response(response); + return NULL; + } + + /* Retrieve Body */ + response->xmlBody = ac_xml_search_child(response->xmlRoot, "SOAP-ENV", "Body"); + if (!response->xmlBody) { + ac_soapclient_free_response(response); + return NULL; + } + + /* Retrieve response */ + if (response->responsecode == HTTP_RESULT_OK) { + char* tagMethod = capwap_alloc(strlen(httprequest->request->method) + 9); + sprintf(tagMethod, "%sResponse", httprequest->request->method); + response->xmlResponse = ac_xml_search_child(response->xmlBody, NULL, tagMethod); + capwap_free(tagMethod); + + if (!response->xmlResponse) { + ac_soapclient_free_response(response); + return NULL; + } + + /* Retrieve optional return response */ + response->xmlResponseReturn = ac_xml_search_child(response->xmlResponse, NULL, "return"); + } else { + /* Retrieve Fault */ + response->xmlFault = ac_xml_search_child(response->xmlBody, "SOAP-ENV", "Fault"); + if (!response->xmlFault) { + ac_soapclient_free_response(response); + return NULL; + } + + /* Retrieve FaultCode */ + response->xmlFaultCode = ac_xml_search_child(response->xmlFault, NULL, "faultcode"); + if (!response->xmlFaultCode) { + ac_soapclient_free_response(response); + return NULL; + } + + /* Retrieve FaultString */ + response->xmlFaultString = ac_xml_search_child(response->xmlFault, NULL, "faultstring"); + if (!response->xmlFaultString) { + ac_soapclient_free_response(response); + return NULL; + } + } + + return response; +} + +/* */ +struct json_object* ac_soapclient_parse_json_response(struct ac_soap_response* response) { + int length; + char* json; + xmlChar* xmlResult; + struct json_object* jsonroot; + + ASSERT(response != NULL); + + /* */ + if ((response->responsecode != HTTP_RESULT_OK) || !response->xmlResponseReturn) { + return NULL; + } + + /* Decode base64 result */ + xmlResult = xmlNodeGetContent(response->xmlResponseReturn); + if (!xmlResult) { + return NULL; + } + + length = xmlStrlen(xmlResult); + if (!length) { + xmlFree(xmlResult); + return NULL; + } + + json = (char*)capwap_alloc(AC_BASE64_DECODE_LENGTH(length)); + ac_base64_string_decode((const char*)xmlResult, json); + + xmlFree(xmlResult); + + /* Parsing JSON result */ + jsonroot = json_tokener_parse(json); + capwap_free(json); + + return jsonroot; +} + +/* */ +void ac_soapclient_free_response(struct ac_soap_response* response) { + ASSERT(response != NULL); + + if (response->xmlDocument) { + xmlFreeDoc(response->xmlDocument); + } + + capwap_free(response); +} + +/* */ +int ac_base64_binary_encode(const char* plain, int length, char* encoded) { + int result = 0; + + ASSERT(plain != NULL); + ASSERT(encoded != NULL); + + while (length > 0) { + int len = ((length > 1) ? ((length > 2) ? 3 : 2) : 1); + + /* Encode block */ + encoded[0] = l_encodeblock[plain[0] >> 2]; + encoded[1] = l_encodeblock[((plain[0] & 0x03) << 4) | ((plain[1] & 0xf0) >> 4)]; + encoded[2] = (len > 1 ? l_encodeblock[((plain[1] & 0x0f) << 2) | ((plain[2] & 0xc0) >> 6)] : '='); + encoded[3] = (len > 2 ? l_encodeblock[plain[2] & 0x3f] : '='); + + /* Next block */ + plain += len; + length -= len; + encoded += 4; + result += 4; + } + + return result; +} + +/* */ +void ac_base64_string_encode(const char* plain, char* encoded) { + int result; + + ASSERT(plain != NULL); + ASSERT(encoded != NULL); + + /* Encode base64 */ + result = ac_base64_binary_encode(plain, strlen(plain), encoded); + + /* Terminate string */ + encoded[result] = 0; +} + +/* */ +int ac_base64_binary_decode(const char* encoded, int length, char* plain) { + int i; + char bufdec[3]; + int result = 0; + + ASSERT(encoded != NULL); + ASSERT(plain != NULL); + + while (length > 0) { + int len = 0; + char bufenc[4] = { 0, 0, 0, 0 }; + + for (i = 0; i < 4 && (length > 0); i++) { + char element = 0; + while ((length > 0) && !element) { + element = *encoded++; + element = (((element < 43) || (element > 122)) ? 0 : l_decodeblock[element - 43]); + length--; + } + + if (element) { + len++; + bufenc[i] = element - 1; + } + } + + if (len) { + bufdec[0] = (bufenc[0] << 2 | bufenc[1] >> 4); + bufdec[1] = (bufenc[1] << 4 | bufenc[2] >> 2); + bufdec[2] = (((bufenc[2] << 6) & 0xc0) | bufenc[3]); + + for (i = 0; i < len - 1; i++) { + *plain++ = bufdec[i]; + result++; + } + } + } + + /* Terminate string */ + return result; +} + +/* */ +void ac_base64_string_decode(const char* encoded, char* plain) { + int result; + + ASSERT(encoded != NULL); + ASSERT(plain != NULL); + + /* Decode base64 */ + result = ac_base64_binary_decode(encoded, strlen(encoded), plain); + + /* Terminate string */ + plain[result] = 0; +} diff --git a/src/ac/ac_soap.h b/src/ac/ac_soap.h index c563177..c7c47a7 100644 --- a/src/ac/ac_soap.h +++ b/src/ac/ac_soap.h @@ -1,114 +1,114 @@ -#ifndef __AC_SOAP_HEADER__ -#define __AC_SOAP_HEADER__ - -#include -#include - -/* */ -#define SOAP_HTTP_PROTOCOL 1 -#define SOAP_HTTPS_PROTOCOL 2 - -#define SOAP_HTTP_PORT 80 -#define SOAP_HTTPS_PORT 443 - -#define HTTP_RESULT_CONTINUE 100 -#define HTTP_RESULT_OK 200 - -#define SOAP_PROTOCOL_REQUEST_TIMEOUT 10000 -#define SOAP_PROTOCOL_RESPONSE_TIMEOUT 10000 -#define SOAP_PROTOCOL_CLOSE_TIMEOUT 10000 - -/* */ -struct ac_http_soap_server { - int protocol; - union sockaddr_capwap address; - - char* host; - char* path; - - /* SSL/TLS context */ - void* sslcontext; -}; - -/* */ -struct ac_soap_request { - xmlDocPtr xmlDocument; - xmlNodePtr xmlRoot; - xmlNodePtr xmlBody; - xmlNodePtr xmlRequest; - - char* method; -}; - -/* */ -struct ac_http_soap_request { - struct ac_http_soap_server* server; - struct ac_soap_request* request; - - int sock; - int requesttimeout; - int responsetimeout; - - /* SSL info */ - struct capwap_socket_ssl* sslsock; - - /* Information for SOAP Response */ - int httpstate; - int responsecode; - int contentlength; - int contentxml; -}; - -/* */ -struct ac_soap_response { - int responsecode; - xmlDocPtr xmlDocument; - xmlNodePtr xmlRoot; - xmlNodePtr xmlBody; - - /* Valid response */ - xmlNodePtr xmlResponse; - xmlNodePtr xmlResponseReturn; - - /* Fault response */ - xmlNodePtr xmlFault; - xmlNodePtr xmlFaultCode; - xmlNodePtr xmlFaultString; -}; - -/* */ -void ac_soapclient_init(void); -void ac_soapclient_free(void); - -/* */ -struct ac_http_soap_server* ac_soapclient_create_server(const char* url); -void ac_soapclient_free_server(struct ac_http_soap_server* server); - -/* Request */ -struct ac_soap_request* ac_soapclient_create_request(char* method, char* urinamespace); -int ac_soapclient_add_param(struct ac_soap_request* request, const char* type, const char* name, const char* value); -char* ac_soapclient_get_request(struct ac_soap_request* request); -void ac_soapclient_free_request(struct ac_soap_request* request); - -/* Transport Request */ -struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_request* request, struct ac_http_soap_server* server); -int ac_soapclient_send_request(struct ac_http_soap_request* httprequest, char* soapaction); -struct ac_soap_response* ac_soapclient_recv_response(struct ac_http_soap_request* httprequest); - -struct json_object* ac_soapclient_parse_json_response(struct ac_soap_response* response); - -void ac_soapclient_shutdown_request(struct ac_http_soap_request* httprequest); -void ac_soapclient_close_request(struct ac_http_soap_request* httprequest, int closerequest); - -/* Response */ -void ac_soapclient_free_response(struct ac_soap_response* response); - -/* Base64 */ -#define AC_BASE64_ENCODE_LENGTH(x) ((((x) + 2) / 3) * 4 + 1) -#define AC_BASE64_DECODE_LENGTH(x) (((x) / 4) * 3 + 1) -void ac_base64_string_encode(const char* plain, char* encoded); -int ac_base64_binary_encode(const char* plain, int length, char* encoded); -void ac_base64_string_decode(const char* encoded, char* plain); -int ac_base64_binary_decode(const char* encoded, int length, char* plain); - -#endif /* __AC_SOAP_HEADER__ */ +#ifndef __AC_SOAP_HEADER__ +#define __AC_SOAP_HEADER__ + +#include +#include + +/* */ +#define SOAP_HTTP_PROTOCOL 1 +#define SOAP_HTTPS_PROTOCOL 2 + +#define SOAP_HTTP_PORT 80 +#define SOAP_HTTPS_PORT 443 + +#define HTTP_RESULT_CONTINUE 100 +#define HTTP_RESULT_OK 200 + +#define SOAP_PROTOCOL_REQUEST_TIMEOUT 10000 +#define SOAP_PROTOCOL_RESPONSE_TIMEOUT 10000 +#define SOAP_PROTOCOL_CLOSE_TIMEOUT 10000 + +/* */ +struct ac_http_soap_server { + int protocol; + union sockaddr_capwap address; + + char* host; + char* path; + + /* SSL/TLS context */ + void* sslcontext; +}; + +/* */ +struct ac_soap_request { + xmlDocPtr xmlDocument; + xmlNodePtr xmlRoot; + xmlNodePtr xmlBody; + xmlNodePtr xmlRequest; + + char* method; +}; + +/* */ +struct ac_http_soap_request { + struct ac_http_soap_server* server; + struct ac_soap_request* request; + + int sock; + int requesttimeout; + int responsetimeout; + + /* SSL info */ + struct capwap_socket_ssl* sslsock; + + /* Information for SOAP Response */ + int httpstate; + int responsecode; + int contentlength; + int contentxml; +}; + +/* */ +struct ac_soap_response { + int responsecode; + xmlDocPtr xmlDocument; + xmlNodePtr xmlRoot; + xmlNodePtr xmlBody; + + /* Valid response */ + xmlNodePtr xmlResponse; + xmlNodePtr xmlResponseReturn; + + /* Fault response */ + xmlNodePtr xmlFault; + xmlNodePtr xmlFaultCode; + xmlNodePtr xmlFaultString; +}; + +/* */ +void ac_soapclient_init(void); +void ac_soapclient_free(void); + +/* */ +struct ac_http_soap_server* ac_soapclient_create_server(const char* url); +void ac_soapclient_free_server(struct ac_http_soap_server* server); + +/* Request */ +struct ac_soap_request* ac_soapclient_create_request(char* method, char* urinamespace); +int ac_soapclient_add_param(struct ac_soap_request* request, const char* type, const char* name, const char* value); +char* ac_soapclient_get_request(struct ac_soap_request* request); +void ac_soapclient_free_request(struct ac_soap_request* request); + +/* Transport Request */ +struct ac_http_soap_request* ac_soapclient_prepare_request(struct ac_soap_request* request, struct ac_http_soap_server* server); +int ac_soapclient_send_request(struct ac_http_soap_request* httprequest, char* soapaction); +struct ac_soap_response* ac_soapclient_recv_response(struct ac_http_soap_request* httprequest); + +struct json_object* ac_soapclient_parse_json_response(struct ac_soap_response* response); + +void ac_soapclient_shutdown_request(struct ac_http_soap_request* httprequest); +void ac_soapclient_close_request(struct ac_http_soap_request* httprequest, int closerequest); + +/* Response */ +void ac_soapclient_free_response(struct ac_soap_response* response); + +/* Base64 */ +#define AC_BASE64_ENCODE_LENGTH(x) ((((x) + 2) / 3) * 4 + 1) +#define AC_BASE64_DECODE_LENGTH(x) (((x) / 4) * 3 + 1) +void ac_base64_string_encode(const char* plain, char* encoded); +int ac_base64_binary_encode(const char* plain, int length, char* encoded); +void ac_base64_string_decode(const char* encoded, char* plain); +int ac_base64_binary_decode(const char* encoded, int length, char* plain); + +#endif /* __AC_SOAP_HEADER__ */ diff --git a/src/ac/ac_wlans.c b/src/ac/ac_wlans.c index 5c02396..daa930c 100644 --- a/src/ac/ac_wlans.c +++ b/src/ac/ac_wlans.c @@ -1,488 +1,488 @@ -#include "ac.h" -#include "ac_session.h" -#include "ac_wlans.h" -#include "ac_backend.h" - -/* */ -static void ac_stations_reset_station(struct ac_session_t* session, struct ac_station* station, struct ac_wlan* wlan) { - ASSERT(session != NULL); - ASSERT(station != NULL); - - if (station->wlan) { - if (station->aid) { - if (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - ieee80211_aid_free(station->wlan->aidbitfield, station->aid); - } - - station->aid = 0; - } - - /* Remove reference from current WLAN */ - capwap_itemlist_remove(station->wlan->stations, station->wlanitem); - } - - /* Remove timers */ - if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) { - capwap_timeout_deletetimer(session->timeout, station->idtimeout); - station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; - } - - /* */ - station->flags = 0; - - /* Set WLAN */ - station->wlan = wlan; - if (station->wlan) { - capwap_itemlist_insert_after(wlan->stations, NULL, station->wlanitem); - } -} - -/* */ -static void ac_stations_destroy_station(struct ac_session_t* session, struct ac_station* station) { - struct ac_station* authoritativestation; - - ASSERT(session != NULL); - ASSERT(station != NULL); - - /* */ - capwap_logging_info("Destroy station: %s", station->addrtext); - - /* Remove reference from Authoritative Stations List */ - capwap_rwlock_wrlock(&g_ac.authstationslock); - - /* Can delete global reference only if match session handler */ - authoritativestation = (struct ac_station*)capwap_hash_search(g_ac.authstations, station->address); - if (authoritativestation && (authoritativestation->session == session)) { - capwap_hash_delete(g_ac.authstations, station->address); - } - - capwap_rwlock_unlock(&g_ac.authstationslock); - - /* Remove reference from WLAN */ - ac_stations_reset_station(session, station, NULL); - - /* */ - capwap_hash_delete(session->wlans->stations, station->address); - - /* Free station reference with itemlist */ - capwap_itemlist_free(station->wlanitem); -} - -/* */ -static unsigned long ac_wlans_item_gethash(const void* key, unsigned long hashsize) { - uint8_t* macaddress = (uint8_t*)key; - - return ((unsigned long)(macaddress[3] ^ macaddress[4] ^ macaddress[5]) % AC_WLANS_STATIONS_HASH_SIZE); -} - -/* */ -static const void* ac_wlans_item_getkey(const void* data) { - return (const void*)((struct ac_station*)data)->address; -} - -/* */ -static int ac_wlans_item_cmp(const void* key1, const void* key2) { - return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); -} - -/* */ -void ac_wlans_init(struct ac_session_t* session) { - int i; - - ASSERT(session != NULL); - ASSERT(session->wlans == NULL); - - /* */ - session->wlans = (struct ac_wlans*)capwap_alloc(sizeof(struct ac_wlans)); - memset(session->wlans, 0, sizeof(struct ac_wlans)); - - /* */ - session->wlans->stations = capwap_hash_create(AC_WLANS_STATIONS_HASH_SIZE); - session->wlans->stations->item_gethash = ac_wlans_item_gethash; - session->wlans->stations->item_getkey = ac_wlans_item_getkey; - session->wlans->stations->item_cmp = ac_wlans_item_cmp; - - for (i = 0; i < RADIOID_MAX_COUNT; i++) { - session->wlans->devices[i].radioid = i + 1; - } -} - -/* */ -void ac_wlans_destroy(struct ac_session_t* session) { - int i; - struct capwap_list* items; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - - /* */ - for (i = 0; i < RADIOID_MAX_COUNT; i++) { - if (session->wlans->devices[i].wlans) { - items = session->wlans->devices[i].wlans; - - /* Delete WLANS */ - while (items->first) { - ac_wlans_delete_bssid(session, i + 1, ((struct ac_wlan*)items->first->item)->address); - } - - /* */ - capwap_list_free(items); - } - } - - /* */ - ASSERT(session->wlans->stations->count == 0); - - /* */ - capwap_hash_free(session->wlans->stations); - capwap_free(session->wlans); -} - -/* */ -int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan) { - char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(wlan != NULL); - ASSERT(wlan->device != NULL); - ASSERT(IS_VALID_RADIOID(wlan->device->radioid)); - ASSERT(IS_VALID_WLANID(wlan->wlanid)); - - /* */ - if (ac_wlans_get_bssid(session, wlan->device->radioid, wlan->address)) { - return -1; - } - - /* */ - wlan->session = session; - - /* Create WLAN list */ - if (!session->wlans->devices[wlan->device->radioid - 1].wlans) { - session->wlans->devices[wlan->device->radioid - 1].wlans = capwap_list_create(); - } - - /* Append WLAN to list */ - capwap_itemlist_insert_after(session->wlans->devices[wlan->device->radioid - 1].wlans, NULL, wlan->wlanitem); - - /* */ - capwap_logging_info("Added new wlan with radioid: %d, wlanid: %d, bssid: %s", (int)wlan->device->radioid, (int)wlan->wlanid, capwap_printf_macaddress(buffer, wlan->address, MACADDRESS_EUI48_LENGTH)); - return 0; -} - -/* */ -struct ac_wlan* ac_wlans_create_bssid(struct ac_device* device, uint8_t wlanid, const uint8_t* bssid, struct capwap_80211_addwlan_element* addwlan) { - struct ac_wlan* wlan; - struct capwap_list_item* wlanitem; - - ASSERT(device != NULL); - ASSERT(IS_VALID_WLANID(wlanid)); - ASSERT(bssid != NULL); - - /* */ - wlanitem = capwap_itemlist_create(sizeof(struct ac_wlan)); - wlan = (struct ac_wlan*)wlanitem->item; - memset(wlan, 0, sizeof(struct ac_wlan)); - - /* Init WLAN */ - wlan->wlanitem = wlanitem; - memcpy(wlan->address, bssid, MACADDRESS_EUI48_LENGTH); - wlan->device = device; - wlan->wlanid = wlanid; - wlan->stations = capwap_list_create(); - - /* Set capability */ - wlan->capability = addwlan->capability; - - wlan->keyindex = addwlan->keyindex; - wlan->keystatus = addwlan->keystatus; - wlan->keylength = addwlan->keylength; - if (addwlan->key && (addwlan->keylength > 0)) { - wlan->key = (uint8_t*)capwap_clone(addwlan->key, wlan->keylength); - } - - memcpy(wlan->grouptsc, addwlan->grouptsc, CAPWAP_ADD_WLAN_GROUPTSC_LENGTH); - - wlan->qos = addwlan->qos; - wlan->authmode = addwlan->authmode; - wlan->macmode = addwlan->macmode; - wlan->tunnelmode = addwlan->tunnelmode; - - wlan->suppressssid = addwlan->suppressssid; - strcpy(wlan->ssid, (const char*)addwlan->ssid); - - return wlan; -} - -/* */ -struct ac_wlan* ac_wlans_get_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid) { - struct capwap_list_item* search; - struct ac_wlan* wlan = NULL; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(IS_VALID_RADIOID(radioid)); - ASSERT(bssid != NULL); - - /* */ - if (session->wlans->devices[radioid - 1].wlans) { - for (search = session->wlans->devices[radioid - 1].wlans->first; search; search = search->next) { - struct ac_wlan* item = (struct ac_wlan*)search->item; - - if (!memcmp(bssid, item->address, MACADDRESS_EUI48_LENGTH)) { - wlan = item; - break; - } - } - } - - return wlan; -} - -/* */ -struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid) { - struct capwap_list_item* search; - struct ac_wlan* wlan = NULL; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(IS_VALID_RADIOID(radioid)); - ASSERT(IS_VALID_WLANID(wlanid)); - - /* */ - if (session->wlans->devices[radioid - 1].wlans) { - for (search = session->wlans->devices[radioid - 1].wlans->first; search; search = search->next) { - struct ac_wlan* item = (struct ac_wlan*)search->item; - - if (wlanid == item->wlanid) { - wlan = item; - break; - } - } - } - - return wlan; -} - -/* */ -void ac_wlans_free_bssid(struct ac_wlan* wlan) { - ASSERT(wlan != NULL); - - /* Free capability */ - if (wlan->key) { - capwap_free(wlan->key); - } - - /* */ - capwap_list_free(wlan->stations); - capwap_itemlist_free(wlan->wlanitem); -} - -/* */ -void ac_wlans_delete_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid) { - struct capwap_list_item* search; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(IS_VALID_RADIOID(radioid)); - ASSERT(bssid != NULL); - - /* */ - if (session->wlans->devices[radioid - 1].wlans) { - for (search = session->wlans->devices[radioid - 1].wlans->first; search; search = search->next) { - struct ac_wlan* wlan = (struct ac_wlan*)search->item; - - if (!memcmp(bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { - /* Remove stations */ - while (wlan->stations->first) { - ac_stations_destroy_station(session, (struct ac_station*)wlan->stations->first->item); - } - - /* */ - capwap_itemlist_remove(session->wlans->devices[radioid - 1].wlans, search); - ac_wlans_free_bssid(wlan); - break; - } - } - } -} - -/* */ -struct ac_station* ac_stations_get_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address) { - struct ac_station* station; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(address != NULL); - - /* Get station */ - station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); - if (station && (station->flags & AC_STATION_FLAGS_ENABLED) && ((radioid == RADIOID_ANY) || (radioid == station->wlan->device->radioid)) && (!bssid || !memcmp(bssid, station->wlan->address, MACADDRESS_EUI48_LENGTH))) { - return station; - } - - return NULL; -} - -/* */ -struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address) { - char buffer1[CAPWAP_MACADDRESS_EUI48_BUFFER]; - char buffer2[CAPWAP_MACADDRESS_EUI48_BUFFER]; - struct ac_wlan* wlan; - struct ac_station* authoritativestation; - struct ac_station* station = NULL; - struct ac_session_t* authoritativesession = NULL; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(IS_VALID_RADIOID(radioid)); - ASSERT(bssid != NULL); - ASSERT(address != NULL); - - /* */ - capwap_printf_macaddress(buffer1, bssid, MACADDRESS_EUI48_LENGTH); - capwap_printf_macaddress(buffer2, address, MACADDRESS_EUI48_LENGTH); - capwap_logging_info("Create station to radioid: %d, bssid: %s, station address: %s", (int)radioid, buffer1, buffer2); - - /* */ - wlan = ac_wlans_get_bssid(session, radioid, bssid); - if (wlan) { - station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); - if (!station) { - struct capwap_list_item* stationitem = capwap_itemlist_create(sizeof(struct ac_station)); - - station = (struct ac_station*)stationitem->item; - memset(station, 0, sizeof(struct ac_station)); - - /* */ - station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; - memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); - capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH); - station->wlanitem = stationitem; - station->session = session; - - /* */ - capwap_hash_add(session->wlans->stations, (void*)station); - } - - /* Set station to WLAN */ - ac_stations_reset_station(session, station, wlan); - station->flags |= AC_STATION_FLAGS_ENABLED; - - /* Check Authoritative Stations List */ - capwap_rwlock_rdlock(&g_ac.authstationslock); - - authoritativestation = (struct ac_station*)capwap_hash_search(g_ac.authstations, address); - if (authoritativestation && authoritativestation->session) { - authoritativesession = authoritativestation->session; - } - - capwap_rwlock_unlock(&g_ac.authstationslock); - - /* Check Authoritative Session */ - if (authoritativesession != session) { - /* Update Authoritative Stations List */ - capwap_rwlock_wrlock(&g_ac.authstationslock); - capwap_hash_add(g_ac.authstations, (void*)station); - capwap_rwlock_unlock(&g_ac.authstationslock); - - /* Release Station from old Authoritative Session */ - if (authoritativesession) { - ac_session_send_action(authoritativesession, AC_SESSION_ACTION_STATION_ROAMING, 0, (void*)address, MACADDRESS_EUI48_LENGTH); - } - } - } else { - capwap_logging_warning("Unable to find radioid: %d, bssid: %s", (int)radioid, buffer1); - } - - return station; -} - -/* */ -void ac_stations_delete_station(struct ac_session_t* session, struct ac_station* station) { - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(station != NULL); - - /* Deauthorize station */ - ac_stations_deauthorize_station(session, station); - - /* Destroy station reference */ - ac_stations_destroy_station(session, station); -} - -/* */ -void ac_stations_authorize_station(struct ac_session_t* session, struct ac_station* station) { - struct ac_notify_station_configuration_ieee8011_add_station notify; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(station != NULL); - - /* Active Station only if Authenticated, Associated and not Authorizated */ - if ((station->flags & AC_STATION_FLAGS_AUTHENTICATED) && (station->flags & AC_STATION_FLAGS_ASSOCIATE) && !(station->flags & AC_STATION_FLAGS_AUTHORIZED)) { - memset(¬ify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_add_station)); - notify.radioid = station->wlan->device->radioid; - memcpy(notify.address, station->address, MACADDRESS_EUI48_LENGTH); - notify.wlanid = station->wlan->wlanid; - notify.associationid = station->aid; - notify.capabilities = station->capability; - notify.supportedratescount = station->supportedratescount; - memcpy(notify.supportedrates, station->supportedrates, station->supportedratescount); - - ac_session_send_action(session, AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_ADD_STATION, 0, ¬ify, sizeof(struct ac_notify_station_configuration_ieee8011_add_station)); - } -} - -/* */ -void ac_stations_deauthorize_station(struct ac_session_t* session, struct ac_station* station) { - int responselength; - uint8_t buffer[IEEE80211_MTU]; - struct ieee80211_deauthentication_params ieee80211_params; - struct ac_notify_station_configuration_ieee8011_delete_station notify; - - ASSERT(session != NULL); - ASSERT(session->wlans != NULL); - ASSERT(station != NULL); - - if (station->flags & AC_STATION_FLAGS_AUTHORIZED) { - /* Deauthorize station */ - memset(¬ify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_delete_station)); - notify.radioid = station->wlan->device->radioid; - memcpy(notify.address, station->address, MACADDRESS_EUI48_LENGTH); - - /* */ - station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE | AC_STATION_FLAGS_AUTHORIZED); - ac_session_send_action(session, AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_DELETE_STATION, 0, ¬ify, sizeof(struct ac_notify_station_configuration_ieee8011_delete_station)); - } else if (station->flags & AC_STATION_FLAGS_AUTHENTICATED) { - /* Create deauthentication packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_deauthentication_params)); - memcpy(ieee80211_params.bssid, station->wlan->address, MACADDRESS_EUI48_LENGTH); - memcpy(ieee80211_params.station, station->address, MACADDRESS_EUI48_LENGTH); - ieee80211_params.reasoncode = IEEE80211_REASON_PREV_AUTH_NOT_VALID; - - /* */ - responselength = ieee80211_create_deauthentication(buffer, IEEE80211_MTU, &ieee80211_params); - if (responselength > 0) { - station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE); - ac_kmod_send_data(&session->sessionid, station->wlan->device->radioid, session->binding, buffer, responselength); - } - } -} - -/* */ -void ac_stations_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { - struct ac_station* station = (struct ac_station*)context; - - ASSERT(station != NULL); - - if (station->idtimeout == index) { - switch (station->timeoutaction) { - case AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: { - capwap_logging_warning("The %s station has not completed the association in time", station->addrtext); - ac_stations_delete_station((struct ac_session_t*)param, station); - break; - } - } - } -} +#include "ac.h" +#include "ac_session.h" +#include "ac_wlans.h" +#include "ac_backend.h" + +/* */ +static void ac_stations_reset_station(struct ac_session_t* session, struct ac_station* station, struct ac_wlan* wlan) { + ASSERT(session != NULL); + ASSERT(station != NULL); + + if (station->wlan) { + if (station->aid) { + if (station->wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + ieee80211_aid_free(station->wlan->aidbitfield, station->aid); + } + + station->aid = 0; + } + + /* Remove reference from current WLAN */ + capwap_itemlist_remove(station->wlan->stations, station->wlanitem); + } + + /* Remove timers */ + if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) { + capwap_timeout_deletetimer(session->timeout, station->idtimeout); + station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; + } + + /* */ + station->flags = 0; + + /* Set WLAN */ + station->wlan = wlan; + if (station->wlan) { + capwap_itemlist_insert_after(wlan->stations, NULL, station->wlanitem); + } +} + +/* */ +static void ac_stations_destroy_station(struct ac_session_t* session, struct ac_station* station) { + struct ac_station* authoritativestation; + + ASSERT(session != NULL); + ASSERT(station != NULL); + + /* */ + capwap_logging_info("Destroy station: %s", station->addrtext); + + /* Remove reference from Authoritative Stations List */ + capwap_rwlock_wrlock(&g_ac.authstationslock); + + /* Can delete global reference only if match session handler */ + authoritativestation = (struct ac_station*)capwap_hash_search(g_ac.authstations, station->address); + if (authoritativestation && (authoritativestation->session == session)) { + capwap_hash_delete(g_ac.authstations, station->address); + } + + capwap_rwlock_unlock(&g_ac.authstationslock); + + /* Remove reference from WLAN */ + ac_stations_reset_station(session, station, NULL); + + /* */ + capwap_hash_delete(session->wlans->stations, station->address); + + /* Free station reference with itemlist */ + capwap_itemlist_free(station->wlanitem); +} + +/* */ +static unsigned long ac_wlans_item_gethash(const void* key, unsigned long hashsize) { + uint8_t* macaddress = (uint8_t*)key; + + return ((unsigned long)(macaddress[3] ^ macaddress[4] ^ macaddress[5]) % AC_WLANS_STATIONS_HASH_SIZE); +} + +/* */ +static const void* ac_wlans_item_getkey(const void* data) { + return (const void*)((struct ac_station*)data)->address; +} + +/* */ +static int ac_wlans_item_cmp(const void* key1, const void* key2) { + return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); +} + +/* */ +void ac_wlans_init(struct ac_session_t* session) { + int i; + + ASSERT(session != NULL); + ASSERT(session->wlans == NULL); + + /* */ + session->wlans = (struct ac_wlans*)capwap_alloc(sizeof(struct ac_wlans)); + memset(session->wlans, 0, sizeof(struct ac_wlans)); + + /* */ + session->wlans->stations = capwap_hash_create(AC_WLANS_STATIONS_HASH_SIZE); + session->wlans->stations->item_gethash = ac_wlans_item_gethash; + session->wlans->stations->item_getkey = ac_wlans_item_getkey; + session->wlans->stations->item_cmp = ac_wlans_item_cmp; + + for (i = 0; i < RADIOID_MAX_COUNT; i++) { + session->wlans->devices[i].radioid = i + 1; + } +} + +/* */ +void ac_wlans_destroy(struct ac_session_t* session) { + int i; + struct capwap_list* items; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + + /* */ + for (i = 0; i < RADIOID_MAX_COUNT; i++) { + if (session->wlans->devices[i].wlans) { + items = session->wlans->devices[i].wlans; + + /* Delete WLANS */ + while (items->first) { + ac_wlans_delete_bssid(session, i + 1, ((struct ac_wlan*)items->first->item)->address); + } + + /* */ + capwap_list_free(items); + } + } + + /* */ + ASSERT(session->wlans->stations->count == 0); + + /* */ + capwap_hash_free(session->wlans->stations); + capwap_free(session->wlans); +} + +/* */ +int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan) { + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(wlan != NULL); + ASSERT(wlan->device != NULL); + ASSERT(IS_VALID_RADIOID(wlan->device->radioid)); + ASSERT(IS_VALID_WLANID(wlan->wlanid)); + + /* */ + if (ac_wlans_get_bssid(session, wlan->device->radioid, wlan->address)) { + return -1; + } + + /* */ + wlan->session = session; + + /* Create WLAN list */ + if (!session->wlans->devices[wlan->device->radioid - 1].wlans) { + session->wlans->devices[wlan->device->radioid - 1].wlans = capwap_list_create(); + } + + /* Append WLAN to list */ + capwap_itemlist_insert_after(session->wlans->devices[wlan->device->radioid - 1].wlans, NULL, wlan->wlanitem); + + /* */ + capwap_logging_info("Added new wlan with radioid: %d, wlanid: %d, bssid: %s", (int)wlan->device->radioid, (int)wlan->wlanid, capwap_printf_macaddress(buffer, wlan->address, MACADDRESS_EUI48_LENGTH)); + return 0; +} + +/* */ +struct ac_wlan* ac_wlans_create_bssid(struct ac_device* device, uint8_t wlanid, const uint8_t* bssid, struct capwap_80211_addwlan_element* addwlan) { + struct ac_wlan* wlan; + struct capwap_list_item* wlanitem; + + ASSERT(device != NULL); + ASSERT(IS_VALID_WLANID(wlanid)); + ASSERT(bssid != NULL); + + /* */ + wlanitem = capwap_itemlist_create(sizeof(struct ac_wlan)); + wlan = (struct ac_wlan*)wlanitem->item; + memset(wlan, 0, sizeof(struct ac_wlan)); + + /* Init WLAN */ + wlan->wlanitem = wlanitem; + memcpy(wlan->address, bssid, MACADDRESS_EUI48_LENGTH); + wlan->device = device; + wlan->wlanid = wlanid; + wlan->stations = capwap_list_create(); + + /* Set capability */ + wlan->capability = addwlan->capability; + + wlan->keyindex = addwlan->keyindex; + wlan->keystatus = addwlan->keystatus; + wlan->keylength = addwlan->keylength; + if (addwlan->key && (addwlan->keylength > 0)) { + wlan->key = (uint8_t*)capwap_clone(addwlan->key, wlan->keylength); + } + + memcpy(wlan->grouptsc, addwlan->grouptsc, CAPWAP_ADD_WLAN_GROUPTSC_LENGTH); + + wlan->qos = addwlan->qos; + wlan->authmode = addwlan->authmode; + wlan->macmode = addwlan->macmode; + wlan->tunnelmode = addwlan->tunnelmode; + + wlan->suppressssid = addwlan->suppressssid; + strcpy(wlan->ssid, (const char*)addwlan->ssid); + + return wlan; +} + +/* */ +struct ac_wlan* ac_wlans_get_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid) { + struct capwap_list_item* search; + struct ac_wlan* wlan = NULL; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(bssid != NULL); + + /* */ + if (session->wlans->devices[radioid - 1].wlans) { + for (search = session->wlans->devices[radioid - 1].wlans->first; search; search = search->next) { + struct ac_wlan* item = (struct ac_wlan*)search->item; + + if (!memcmp(bssid, item->address, MACADDRESS_EUI48_LENGTH)) { + wlan = item; + break; + } + } + } + + return wlan; +} + +/* */ +struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid) { + struct capwap_list_item* search; + struct ac_wlan* wlan = NULL; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(IS_VALID_WLANID(wlanid)); + + /* */ + if (session->wlans->devices[radioid - 1].wlans) { + for (search = session->wlans->devices[radioid - 1].wlans->first; search; search = search->next) { + struct ac_wlan* item = (struct ac_wlan*)search->item; + + if (wlanid == item->wlanid) { + wlan = item; + break; + } + } + } + + return wlan; +} + +/* */ +void ac_wlans_free_bssid(struct ac_wlan* wlan) { + ASSERT(wlan != NULL); + + /* Free capability */ + if (wlan->key) { + capwap_free(wlan->key); + } + + /* */ + capwap_list_free(wlan->stations); + capwap_itemlist_free(wlan->wlanitem); +} + +/* */ +void ac_wlans_delete_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid) { + struct capwap_list_item* search; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(bssid != NULL); + + /* */ + if (session->wlans->devices[radioid - 1].wlans) { + for (search = session->wlans->devices[radioid - 1].wlans->first; search; search = search->next) { + struct ac_wlan* wlan = (struct ac_wlan*)search->item; + + if (!memcmp(bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { + /* Remove stations */ + while (wlan->stations->first) { + ac_stations_destroy_station(session, (struct ac_station*)wlan->stations->first->item); + } + + /* */ + capwap_itemlist_remove(session->wlans->devices[radioid - 1].wlans, search); + ac_wlans_free_bssid(wlan); + break; + } + } + } +} + +/* */ +struct ac_station* ac_stations_get_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address) { + struct ac_station* station; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(address != NULL); + + /* Get station */ + station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); + if (station && (station->flags & AC_STATION_FLAGS_ENABLED) && ((radioid == RADIOID_ANY) || (radioid == station->wlan->device->radioid)) && (!bssid || !memcmp(bssid, station->wlan->address, MACADDRESS_EUI48_LENGTH))) { + return station; + } + + return NULL; +} + +/* */ +struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address) { + char buffer1[CAPWAP_MACADDRESS_EUI48_BUFFER]; + char buffer2[CAPWAP_MACADDRESS_EUI48_BUFFER]; + struct ac_wlan* wlan; + struct ac_station* authoritativestation; + struct ac_station* station = NULL; + struct ac_session_t* authoritativesession = NULL; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(bssid != NULL); + ASSERT(address != NULL); + + /* */ + capwap_printf_macaddress(buffer1, bssid, MACADDRESS_EUI48_LENGTH); + capwap_printf_macaddress(buffer2, address, MACADDRESS_EUI48_LENGTH); + capwap_logging_info("Create station to radioid: %d, bssid: %s, station address: %s", (int)radioid, buffer1, buffer2); + + /* */ + wlan = ac_wlans_get_bssid(session, radioid, bssid); + if (wlan) { + station = (struct ac_station*)capwap_hash_search(session->wlans->stations, address); + if (!station) { + struct capwap_list_item* stationitem = capwap_itemlist_create(sizeof(struct ac_station)); + + station = (struct ac_station*)stationitem->item; + memset(station, 0, sizeof(struct ac_station)); + + /* */ + station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; + memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); + capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH); + station->wlanitem = stationitem; + station->session = session; + + /* */ + capwap_hash_add(session->wlans->stations, (void*)station); + } + + /* Set station to WLAN */ + ac_stations_reset_station(session, station, wlan); + station->flags |= AC_STATION_FLAGS_ENABLED; + + /* Check Authoritative Stations List */ + capwap_rwlock_rdlock(&g_ac.authstationslock); + + authoritativestation = (struct ac_station*)capwap_hash_search(g_ac.authstations, address); + if (authoritativestation && authoritativestation->session) { + authoritativesession = authoritativestation->session; + } + + capwap_rwlock_unlock(&g_ac.authstationslock); + + /* Check Authoritative Session */ + if (authoritativesession != session) { + /* Update Authoritative Stations List */ + capwap_rwlock_wrlock(&g_ac.authstationslock); + capwap_hash_add(g_ac.authstations, (void*)station); + capwap_rwlock_unlock(&g_ac.authstationslock); + + /* Release Station from old Authoritative Session */ + if (authoritativesession) { + ac_session_send_action(authoritativesession, AC_SESSION_ACTION_STATION_ROAMING, 0, (void*)address, MACADDRESS_EUI48_LENGTH); + } + } + } else { + capwap_logging_warning("Unable to find radioid: %d, bssid: %s", (int)radioid, buffer1); + } + + return station; +} + +/* */ +void ac_stations_delete_station(struct ac_session_t* session, struct ac_station* station) { + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(station != NULL); + + /* Deauthorize station */ + ac_stations_deauthorize_station(session, station); + + /* Destroy station reference */ + ac_stations_destroy_station(session, station); +} + +/* */ +void ac_stations_authorize_station(struct ac_session_t* session, struct ac_station* station) { + struct ac_notify_station_configuration_ieee8011_add_station notify; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(station != NULL); + + /* Active Station only if Authenticated, Associated and not Authorizated */ + if ((station->flags & AC_STATION_FLAGS_AUTHENTICATED) && (station->flags & AC_STATION_FLAGS_ASSOCIATE) && !(station->flags & AC_STATION_FLAGS_AUTHORIZED)) { + memset(¬ify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_add_station)); + notify.radioid = station->wlan->device->radioid; + memcpy(notify.address, station->address, MACADDRESS_EUI48_LENGTH); + notify.wlanid = station->wlan->wlanid; + notify.associationid = station->aid; + notify.capabilities = station->capability; + notify.supportedratescount = station->supportedratescount; + memcpy(notify.supportedrates, station->supportedrates, station->supportedratescount); + + ac_session_send_action(session, AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_ADD_STATION, 0, ¬ify, sizeof(struct ac_notify_station_configuration_ieee8011_add_station)); + } +} + +/* */ +void ac_stations_deauthorize_station(struct ac_session_t* session, struct ac_station* station) { + int responselength; + uint8_t buffer[IEEE80211_MTU]; + struct ieee80211_deauthentication_params ieee80211_params; + struct ac_notify_station_configuration_ieee8011_delete_station notify; + + ASSERT(session != NULL); + ASSERT(session->wlans != NULL); + ASSERT(station != NULL); + + if (station->flags & AC_STATION_FLAGS_AUTHORIZED) { + /* Deauthorize station */ + memset(¬ify, 0, sizeof(struct ac_notify_station_configuration_ieee8011_delete_station)); + notify.radioid = station->wlan->device->radioid; + memcpy(notify.address, station->address, MACADDRESS_EUI48_LENGTH); + + /* */ + station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE | AC_STATION_FLAGS_AUTHORIZED); + ac_session_send_action(session, AC_SESSION_ACTION_STATION_CONFIGURATION_IEEE80211_DELETE_STATION, 0, ¬ify, sizeof(struct ac_notify_station_configuration_ieee8011_delete_station)); + } else if (station->flags & AC_STATION_FLAGS_AUTHENTICATED) { + /* Create deauthentication packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_deauthentication_params)); + memcpy(ieee80211_params.bssid, station->wlan->address, MACADDRESS_EUI48_LENGTH); + memcpy(ieee80211_params.station, station->address, MACADDRESS_EUI48_LENGTH); + ieee80211_params.reasoncode = IEEE80211_REASON_PREV_AUTH_NOT_VALID; + + /* */ + responselength = ieee80211_create_deauthentication(buffer, IEEE80211_MTU, &ieee80211_params); + if (responselength > 0) { + station->flags &= ~(AC_STATION_FLAGS_AUTHENTICATED | AC_STATION_FLAGS_ASSOCIATE); + ac_kmod_send_data(&session->sessionid, station->wlan->device->radioid, session->binding, buffer, responselength); + } + } +} + +/* */ +void ac_stations_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { + struct ac_station* station = (struct ac_station*)context; + + ASSERT(station != NULL); + + if (station->idtimeout == index) { + switch (station->timeoutaction) { + case AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: { + capwap_logging_warning("The %s station has not completed the association in time", station->addrtext); + ac_stations_delete_station((struct ac_session_t*)param, station); + break; + } + } + } +} diff --git a/src/ac/ac_wlans.h b/src/ac/ac_wlans.h index 504d09f..84a4ee7 100644 --- a/src/ac/ac_wlans.h +++ b/src/ac/ac_wlans.h @@ -1,128 +1,128 @@ -#ifndef __AC_WLANS_HEADER__ -#define __AC_WLANS_HEADER__ - -#include "ieee80211.h" - -/* */ -#define RADIOID_ANY 0 - -/* */ -#define AC_WLANS_STATIONS_HASH_SIZE 256 -#define AC_WLANS_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH - -/* AC WLAN */ -struct ac_wlan { - struct capwap_list_item* wlanitem; - struct ac_device* device; - - uint8_t address[MACADDRESS_EUI48_LENGTH]; - uint8_t wlanid; - - /* CAPWAP Session */ - struct ac_session_t* session; - - uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE]; - - /* Stations reference */ - struct capwap_list* stations; - - /* Capability */ - uint16_t capability; - uint8_t keyindex; - uint8_t keystatus; - uint16_t keylength; - uint8_t* key; - uint8_t grouptsc[CAPWAP_ADD_WLAN_GROUPTSC_LENGTH]; - uint8_t qos; - uint8_t authmode; - uint8_t macmode; - uint8_t tunnelmode; - uint8_t suppressssid; - char ssid[IEEE80211_SSID_MAX_LENGTH + 1]; -}; - -/* */ -struct ac_device { - uint8_t radioid; - struct capwap_list* wlans; - - /* Rates */ - unsigned long supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; -}; - -/* */ -struct ac_wlans { - struct ac_device devices[RADIOID_MAX_COUNT]; - - /* Stations */ - struct capwap_hash* stations; -}; - -/* */ -#define AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE 30000 - -/* */ -#define AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE 0x00000001 - -/* */ -#define AC_STATION_FLAGS_ENABLED 0x00000001 -#define AC_STATION_FLAGS_AUTHENTICATED 0x00000002 -#define AC_STATION_FLAGS_ASSOCIATE 0x00000004 -#define AC_STATION_FLAGS_AUTHORIZED 0x00000008 - -/* AC Station */ -struct ac_station { - uint8_t address[MACADDRESS_EUI48_LENGTH]; - char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER]; - - /* */ - unsigned long flags; - - /* Reference of WLAN */ - struct ac_wlan* wlan; - struct capwap_list_item* wlanitem; - - /* Reference of Session */ - struct ac_session_t* session; - - /* Timers */ - int timeoutaction; - unsigned long idtimeout; - - /* */ - uint16_t capability; - uint16_t listeninterval; - uint16_t aid; - - /* */ - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - - /* Authentication */ - uint16_t authalgorithm; -}; - -/* Management WLANS */ -void ac_wlans_init(struct ac_session_t* session); -void ac_wlans_destroy(struct ac_session_t* session); - -/* */ -struct ac_wlan* ac_wlans_create_bssid(struct ac_device* device, uint8_t wlanid, const uint8_t* bssid, struct capwap_80211_addwlan_element* addwlan); -int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan); -struct ac_wlan* ac_wlans_get_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid); -struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid); -void ac_wlans_delete_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid); -void ac_wlans_free_bssid(struct ac_wlan* wlan); - -/* Management Stations */ -struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address); -struct ac_station* ac_stations_get_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address); -void ac_stations_delete_station(struct ac_session_t* session, struct ac_station* station); -void ac_stations_authorize_station(struct ac_session_t* session, struct ac_station* station); -void ac_stations_deauthorize_station(struct ac_session_t* session, struct ac_station* station); - -/* */ -void ac_stations_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); - -#endif /* __AC_WLANS_HEADER__ */ +#ifndef __AC_WLANS_HEADER__ +#define __AC_WLANS_HEADER__ + +#include "ieee80211.h" + +/* */ +#define RADIOID_ANY 0 + +/* */ +#define AC_WLANS_STATIONS_HASH_SIZE 256 +#define AC_WLANS_STATIONS_KEY_SIZE MACADDRESS_EUI48_LENGTH + +/* AC WLAN */ +struct ac_wlan { + struct capwap_list_item* wlanitem; + struct ac_device* device; + + uint8_t address[MACADDRESS_EUI48_LENGTH]; + uint8_t wlanid; + + /* CAPWAP Session */ + struct ac_session_t* session; + + uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE]; + + /* Stations reference */ + struct capwap_list* stations; + + /* Capability */ + uint16_t capability; + uint8_t keyindex; + uint8_t keystatus; + uint16_t keylength; + uint8_t* key; + uint8_t grouptsc[CAPWAP_ADD_WLAN_GROUPTSC_LENGTH]; + uint8_t qos; + uint8_t authmode; + uint8_t macmode; + uint8_t tunnelmode; + uint8_t suppressssid; + char ssid[IEEE80211_SSID_MAX_LENGTH + 1]; +}; + +/* */ +struct ac_device { + uint8_t radioid; + struct capwap_list* wlans; + + /* Rates */ + unsigned long supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; +}; + +/* */ +struct ac_wlans { + struct ac_device devices[RADIOID_MAX_COUNT]; + + /* Stations */ + struct capwap_hash* stations; +}; + +/* */ +#define AC_STATION_TIMEOUT_ASSOCIATION_COMPLETE 30000 + +/* */ +#define AC_STATION_TIMEOUT_ACTION_DEAUTHENTICATE 0x00000001 + +/* */ +#define AC_STATION_FLAGS_ENABLED 0x00000001 +#define AC_STATION_FLAGS_AUTHENTICATED 0x00000002 +#define AC_STATION_FLAGS_ASSOCIATE 0x00000004 +#define AC_STATION_FLAGS_AUTHORIZED 0x00000008 + +/* AC Station */ +struct ac_station { + uint8_t address[MACADDRESS_EUI48_LENGTH]; + char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER]; + + /* */ + unsigned long flags; + + /* Reference of WLAN */ + struct ac_wlan* wlan; + struct capwap_list_item* wlanitem; + + /* Reference of Session */ + struct ac_session_t* session; + + /* Timers */ + int timeoutaction; + unsigned long idtimeout; + + /* */ + uint16_t capability; + uint16_t listeninterval; + uint16_t aid; + + /* */ + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + /* Authentication */ + uint16_t authalgorithm; +}; + +/* Management WLANS */ +void ac_wlans_init(struct ac_session_t* session); +void ac_wlans_destroy(struct ac_session_t* session); + +/* */ +struct ac_wlan* ac_wlans_create_bssid(struct ac_device* device, uint8_t wlanid, const uint8_t* bssid, struct capwap_80211_addwlan_element* addwlan); +int ac_wlans_assign_bssid(struct ac_session_t* session, struct ac_wlan* wlan); +struct ac_wlan* ac_wlans_get_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid); +struct ac_wlan* ac_wlans_get_bssid_with_wlanid(struct ac_session_t* session, uint8_t radioid, uint8_t wlanid); +void ac_wlans_delete_bssid(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid); +void ac_wlans_free_bssid(struct ac_wlan* wlan); + +/* Management Stations */ +struct ac_station* ac_stations_create_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address); +struct ac_station* ac_stations_get_station(struct ac_session_t* session, uint8_t radioid, const uint8_t* bssid, const uint8_t* address); +void ac_stations_delete_station(struct ac_session_t* session, struct ac_station* station); +void ac_stations_authorize_station(struct ac_session_t* session, struct ac_station* station); +void ac_stations_deauthorize_station(struct ac_session_t* session, struct ac_station* station); + +/* */ +void ac_stations_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); + +#endif /* __AC_WLANS_HEADER__ */ diff --git a/src/ac/kmod/Makefile b/src/ac/kmod/Makefile index 3ffd966..90fd7f3 100644 --- a/src/ac/kmod/Makefile +++ b/src/ac/kmod/Makefile @@ -1,18 +1,18 @@ -KVERSION = $(shell uname -r) - -obj-m += smartcapwap.o - -smartcapwap-y := \ - main.o \ - netlinkapp.o \ - capwap.o \ - capwap_private.o \ - station.o \ - socket.o \ - iface.o - -all: - make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules - -clean: - make -C /lib/modules/$(KVERSION)/build M="$(PWD)" clean +KVERSION = $(shell uname -r) + +obj-m += smartcapwap.o + +smartcapwap-y := \ + main.o \ + netlinkapp.o \ + capwap.o \ + capwap_private.o \ + station.o \ + socket.o \ + iface.o + +all: + make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules + +clean: + make -C /lib/modules/$(KVERSION)/build M="$(PWD)" clean diff --git a/src/ac/kmod/capwap.c b/src/ac/kmod/capwap.c index 5a5dd9f..6e4dc33 100644 --- a/src/ac/kmod/capwap.c +++ b/src/ac/kmod/capwap.c @@ -1,789 +1,789 @@ -#include "config.h" -#include -#include -#include -#include -#include "socket.h" -#include "capwap.h" -#include "nlsmartcapwap.h" -#include "netlinkapp.h" - -/* */ -union capwap_addr sc_localaddr; - -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char sc_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; - -/* */ -static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) { - TRACEKMOD("### sc_capwap_fragment_free\n"); - - /* */ - list_del(&fragment->lru_list); - fragment->flags = 0; - - /* Free socket buffer */ - while (fragment->fragments) { - struct sk_buff* next = fragment->fragments->next; - - kfree_skb(fragment->fragments); - fragment->fragments = next; - } -} - -/* */ -static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) { - ktime_t delta; - struct sc_capwap_fragment* fragment; - struct list_head* list = &session->fragments.lru_list; - - TRACEKMOD("### sc_capwap_defrag_evictor\n"); - - /* Light check without lock */ - if (!list_empty(list)) { - spin_lock(&session->fragments.lock); - - /* Remove last old fragment */ - if (!list_empty(list)) { - fragment = list_first_entry(list, struct sc_capwap_fragment, lru_list); - delta = ktime_sub(now, fragment->tstamp); - if ((delta.tv64 < -NSEC_PER_SEC) || (delta.tv64 > NSEC_PER_SEC)) { - TRACEKMOD("*** Expired fragment %hu (%llu %llu)\n", fragment->fragmentid, now.tv64, fragment->tstamp.tv64); - sc_capwap_fragment_free(fragment); - } - } - - spin_unlock(&session->fragments.lock); - } -} - -/* */ -static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) { - int len; - int offset; - struct sk_buff* skb; - struct sk_buff* skbfrag; - struct sc_capwap_header* header; - - TRACEKMOD("### sc_capwap_reasm\n"); - - /* */ - skbfrag = fragment->fragments; - len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; - - /* Create new packet */ - skb = alloc_skb(len + fragment->totallength, GFP_KERNEL); - if (!skb) { - return NULL; - } - - /* The first capwap header is header of reassembled packet without fragment field */ - header = (struct sc_capwap_header*)skb_put(skb, len); - memcpy(header, skbfrag->data, len); - - SET_FLAG_F_HEADER(header, 0); - SET_FLAG_L_HEADER(header, 0); - header->frag_id = (__be16)0; - header->frag_off = (__be16)0; - - /* Copy body */ - while (skbfrag) { - offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; - len = skbfrag->len - offset; - - TRACEKMOD("*** Append fragment size %d\n", len); - - /* */ - memcpy(skb_put(skb, len), skbfrag->data + offset, len); - skbfrag = skbfrag->next; - } - - TRACEKMOD("*** Assemblate capwap data packet with total size %d\n", skb->len); - - return skb; -} - -/* */ -static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) { - uint16_t headersize; - uint16_t frag_id; - struct sk_buff* prev; - struct sk_buff* next; - struct sc_capwap_fragment* fragment; - struct sc_skb_capwap_cb* cb; - struct sk_buff* skb_defrag = NULL; - struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; - - TRACEKMOD("### sc_capwap_defrag\n"); - - /* */ - headersize = GET_HLEN_HEADER(header) * 4; - if (skb->len < headersize) { - goto error; - } - - /* */ - frag_id = be16_to_cpu(header->frag_id); - - /* */ - cb = CAPWAP_SKB_CB(skb); - cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT; - cb->frag_offset = be16_to_cpu(header->frag_off); - cb->frag_length = skb->len - headersize; - - /* */ - spin_lock(&session->fragments.lock); - TRACEKMOD("*** Fragment info: id %hu offset %hu length %hu\n", frag_id, cb->frag_offset, cb->frag_length); - - /* Get fragment */ - fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE]; - if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) { - TRACEKMOD("*** Unable defrag, queue fragment busy\n"); - goto error2; /* Queue fragment busy*/ - } - - /* Init fragment */ - if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) { - fragment->flags = CAPWAP_FRAGMENT_ENABLE; - fragment->fragmentid = frag_id; - fragment->fragments = NULL; - fragment->lastfragment = NULL; - fragment->recvlength = 0; - fragment->totallength = 0; - list_add_tail(&fragment->lru_list, &session->fragments.lru_list); - } - - /* Search fragment position */ - prev = fragment->lastfragment; - if (!prev) { - next = NULL; - } else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) { - if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) <= cb->frag_offset) { - next = NULL; - } else { - sc_capwap_fragment_free(fragment); - TRACEKMOD("*** Unable defrag, overlap error\n"); - goto error2; /* Overlap error */ - } - } else { - prev = NULL; - for (next = fragment->fragments; next != NULL; next = next->next) { - struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next); - - if (next_cb->frag_offset == cb->frag_offset) { - TRACEKMOD("*** Unable defrag, duplicate packet\n"); - goto error2; /* Duplicate packet */ - } else if (next_cb->frag_offset > cb->frag_offset) { - if ((cb->frag_offset + cb->frag_length) <= next_cb->frag_offset) { - break; - } else { - sc_capwap_fragment_free(fragment); - TRACEKMOD("*** Unable defrag, overlap error\n"); - goto error2; /* Overlap error */ - } - } - - prev = next; - } - } - - /* Insert fragment */ - skb->prev = NULL; - skb->next = next; - if (!next) { - fragment->lastfragment = skb; - } - - if (prev) { - prev->next = skb; - } else { - fragment->fragments = skb; - } - - /* Update size */ - fragment->recvlength += cb->frag_length; - if (IS_FLAG_L_HEADER(header)) { - fragment->totallength = cb->frag_offset + cb->frag_length; - fragment->flags |= CAPWAP_FRAGMENT_LAST; - } - - /* Check if receive all fragment */ - if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) { - skb_defrag = sc_capwap_reasm(fragment); - - /* Free fragment complete */ - sc_capwap_fragment_free(fragment); - } else { - /* Update timeout */ - fragment->tstamp = skb->tstamp; - TRACEKMOD("*** Fragment id %hu expire at %llu\n", frag_id, fragment->tstamp.tv64); - - /* Set LRU timeout */ - if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) { - list_move_tail(&fragment->lru_list, &session->fragments.lru_list); - } - } - - spin_unlock(&session->fragments.lock); - - return skb_defrag; - -error2: - spin_unlock(&session->fragments.lock); - -error: - kfree_skb(skb); - return NULL; -} - -/* */ -static unsigned int sc_capwap_80211_hdrlen(__le16 fc) { - unsigned int hdrlen = 24; - - TRACEKMOD("### sc_capwap_80211_hdrlen\n"); - - if (ieee80211_is_data(fc)) { - if (ieee80211_has_a4(fc)) { - hdrlen = 30; - } - - if (ieee80211_is_data_qos(fc)) { - hdrlen += IEEE80211_QOS_CTL_LEN; - if (ieee80211_has_order(fc)) { - hdrlen += IEEE80211_HT_CTL_LEN; - } - } - } else if (ieee80211_is_ctl(fc)) { - if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) { - hdrlen = 10; - } else { - hdrlen = 16; - } - } - - return hdrlen; -} - -/* */ -int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid) { - uint16_t hdrlen; - int head_need; - struct ieee80211_hdr hdr; - int skip_header_bytes; - uint8_t* encaps_data; - int encaps_len; - struct ethhdr* eh = (struct ethhdr*)skb->data; - uint16_t ethertype = ntohs(eh->h_proto); - - TRACEKMOD("### sc_capwap_8023_to_80211\n"); - - /* IEEE 802.11 header */ - hdrlen = 24; - hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_FROMDS); - memcpy(hdr.addr1, eh->h_dest, ETH_ALEN); - memcpy(hdr.addr2, bssid, ETH_ALEN); - memcpy(hdr.addr3, eh->h_source, ETH_ALEN); - hdr.duration_id = 0; - hdr.seq_ctrl = 0; - - /* */ - skip_header_bytes = ETH_HLEN; - if ((ethertype == ETH_P_AARP) || (ethertype == ETH_P_IPX)) { - encaps_data = sc_bridge_tunnel_header; - encaps_len = sizeof(sc_bridge_tunnel_header); - skip_header_bytes -= 2; - } else if (ethertype >= ETH_P_802_3_MIN) { - encaps_data = sc_rfc1042_header; - encaps_len = sizeof(sc_rfc1042_header); - skip_header_bytes -= 2; - } else { - encaps_data = NULL; - encaps_len = 0; - } - - /* Remove IEEE 802.3 header */ - skb_pull(skb, skip_header_bytes); - - /* Check headroom */ - head_need = hdrlen + encaps_len - skb_headroom(skb); - if ((head_need > 0) || skb_cloned(skb)) { - head_need = max(head_need, 0); - if (head_need) { - skb_orphan(skb); - } - - TRACEKMOD("*** Expand headroom skb of: %d\n", head_need); - if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { - return -ENOMEM; - } - - skb->truesize += head_need; - } - - /* Add LLC header */ - if (encaps_data) { - memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); - } - - /* Add IEEE 802.11 header */ - memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); - skb_reset_mac_header(skb); - - return 0; -} - -/* */ -int sc_capwap_80211_to_8023(struct sk_buff* skb) { - struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; - uint16_t hdrlen; - uint16_t ethertype; - uint8_t* payload; - uint8_t dst[ETH_ALEN]; - uint8_t src[ETH_ALEN] __aligned(2); - - TRACEKMOD("### sc_capwap_80211_to_8023\n"); - - /* */ - hdrlen = sc_capwap_80211_hdrlen(hdr->frame_control); - memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); - memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); - - /* */ - if (!pskb_may_pull(skb, hdrlen + 8)) { - return -1; - } - - /* */ - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((ether_addr_equal(payload, sc_rfc1042_header) && (ethertype != ETH_P_AARP) && (ethertype != ETH_P_IPX)) || ether_addr_equal(payload, sc_bridge_tunnel_header))) { - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - struct ethhdr *ehdr; - __be16 len; - - skb_pull(skb, hdrlen); - len = htons(skb->len); - ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); - memcpy(ehdr->h_dest, dst, ETH_ALEN); - memcpy(ehdr->h_source, src, ETH_ALEN); - ehdr->h_proto = len; - } - - return 0; -} - -/* */ -int sc_capwap_bind(union capwap_addr* sockaddr) { - int ret; - - TRACEKMOD("### sc_capwap_bind\n"); - - /* */ - ret = sc_socket_bind(sockaddr); - if (ret) { - return ret; - } - - memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr)); - return 0; -} - -/* */ -void sc_capwap_initsession(struct sc_capwap_session* session) { - TRACEKMOD("### sc_capwap_initsession\n"); - - spin_lock_init(&session->fragmentid_lock); - - /* Defragment packets */ - memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue)); - INIT_LIST_HEAD(&session->fragments.lru_list); - spin_lock_init(&session->fragments.lock); -} - -/* */ -void sc_capwap_freesession(struct sc_capwap_session* session) { - struct sc_capwap_fragment* temp; - struct sc_capwap_fragment* fragment; - - TRACEKMOD("### sc_capwap_freesession\n"); - - /* Free socket buffers */ - list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) { - sc_capwap_fragment_free(fragment); - } -} - -/* */ -uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) { - uint16_t fragmentid; - - TRACEKMOD("### sc_capwap_newfragmentid\n"); - - spin_lock(&session->fragmentid_lock); - fragmentid = session->fragmentid++; - spin_unlock(&session->fragmentid_lock); - - return fragmentid; -} - -/* */ -int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) { - int length; - struct sc_capwap_header* header; - struct sc_capwap_data_message* dataheader; - struct sc_capwap_message_element* msgelement; - - TRACEKMOD("### sc_capwap_createkeepalive\n"); - - /* */ - if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) { - return -ENOMEM; - } - - /* Preamble CAPWAP header */ - header = (struct sc_capwap_header*)buffer; - length = sizeof(struct sc_capwap_header); - buffer += sizeof(struct sc_capwap_header); - - memset(header, 0, sizeof(struct sc_capwap_header)); - SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); - SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); - SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4); - SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211); - SET_FLAG_K_HEADER(header, 1); - - /* CAPWAP Data header */ - dataheader = (struct sc_capwap_data_message*)buffer; - length += sizeof(struct sc_capwap_data_message); - buffer += sizeof(struct sc_capwap_data_message); - - dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)); - - /* CAPWAP Keep-Alive Message Element */ - msgelement = (struct sc_capwap_message_element*)buffer; - length += sizeof(struct sc_capwap_message_element); - buffer += sizeof(struct sc_capwap_message_element); - - msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID); - msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element)); - - /* Session ID */ - memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element)); - length += sizeof(struct sc_capwap_sessionid_element); - - return length; -} - -/* */ -int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) { - int length; - uint16_t headersize; - struct sc_capwap_data_message* dataheader; - struct sc_capwap_message_element* message; - struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; - - TRACEKMOD("### sc_capwap_parsingpacket\n"); - - /* Linearize socket buffer */ - if (skb_linearize(skb)) { - TRACEKMOD("*** Unable to linearize packet\n"); - return -EINVAL; - } - - /* Check header */ - if (skb->len < sizeof(struct sc_capwap_header)) { - TRACEKMOD("*** Invalid capwap header length\n"); - return -EINVAL; - } else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) { - TRACEKMOD("*** Invalid capwap header version\n"); - return -EINVAL; - } else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) { - TRACEKMOD("*** Packet is encrypted\n"); - return -EINVAL; /* Accept only plain packet */ - } - - /* */ - if (IS_FLAG_K_HEADER(header)) { - /* Keep alive can not fragment */ - if (IS_FLAG_F_HEADER(header)) { - TRACEKMOD("*** Keep alive can not fragment\n"); - return -EINVAL; - } - - /* */ - length = skb->len; - headersize = GET_HLEN_HEADER(header) * 4; - if (length < (headersize + sizeof(struct sc_capwap_data_message))) { - TRACEKMOD("*** Invalid capwap data header length\n"); - return -EINVAL; - } - - /* Data message */ - length -= headersize; - dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize); - headersize = ntohs(dataheader->length); - if (length < headersize) { - TRACEKMOD("*** Capwap data header length mismatch\n"); - return -EINVAL; - } - - /* Message elements */ - headersize -= sizeof(struct sc_capwap_data_message); - message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message)); - while (headersize > 0) { - uint16_t msglength = ntohs(message->length); - if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) { - TRACEKMOD("*** Invalid capwap message element length\n"); - return -EINVAL; - } - - /* */ - if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) { - struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element)); - - if (!session) { - session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid); - if (!session) { - TRACEKMOD("*** Receive unknown keep alive without valid session\n"); - return -EINVAL; - } - } else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { - TRACEKMOD("*** Session id mismatch\n"); - return -EINVAL; - } - - /* Session found */ - sc_netlink_notify_recv_keepalive(sockaddr, sessionid); - - /* Parsing complete */ - kfree_skb(skb); - return 0; - } - - /* Next message element */ - msglength += sizeof(struct sc_capwap_message_element); - message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength); - headersize -= msglength; - } - } else if (session) { - if (!skb->tstamp.tv64) { - skb->tstamp = ktime_get(); - } - - /* Cleaning old fragments */ - sc_capwap_defrag_evictor(session, skb->tstamp); - - /* */ - if (IS_FLAG_F_HEADER(header)) { - skb = sc_capwap_defrag(session, skb); - if (!skb) { - return 0; - } - - /* Get new header info */ - header = (struct sc_capwap_header*)skb->data; - } - - /* Parsing data/management packet */ - if (!IS_FLAG_T_HEADER(header)) { - sc_capwap_parsingdatapacket(session, skb); - } else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) { - struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4); - - if (ieee80211_is_data_present(hdr->frame_control)) { - sc_capwap_parsingdatapacket(session, skb); - } else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) { - sc_capwap_parsingmgmtpacket(session, skb); - } - } - - return 0; - } - - return -EINVAL; -} - -/* */ -int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) { - int err; - int size; - int length; - int reserve; - int headroom; - int requestfragment; - __be16 fragmentid = 0; - int fragmentoffset = 0; - struct sc_capwap_header* header; - struct sk_buff* clone = NULL; - int packetlength = skb->len; - - TRACEKMOD("### sc_capwap_forwarddata\n"); - - /* Check headroom */ - headroom = skb_headroom(skb); - reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; - if (skb_is_nonlinear(skb) || (headroom < reserve)) { - TRACEKMOD("*** Copy socket buffer and expand headroom of: %d\n", (reserve - headroom)); - clone = skb_copy_expand(skb, max(headroom, reserve), skb_tailroom(skb), GFP_KERNEL); - if (!clone) { - TRACEKMOD("*** Unable to copy socket buffer\n"); - return -ENOMEM; - } - - skb = clone; - } - - /* Check MTU */ - requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0); - if (requestfragment) { - fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session)); - } - - /* */ - header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength); - while (packetlength > 0) { - memset(header, 0, sizeof(struct sc_capwap_header)); - SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); - SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); - SET_WBID_HEADER(header, binding); - SET_RID_HEADER(header, radioid); - SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1)); - - if (!fragmentoffset) { - uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header); - - if (radioaddr) { - SET_FLAG_M_HEADER(header, 1); - memcpy(headeroption, radioaddr, radioaddrlength); - headeroption += radioaddrlength; - } - - if (winfo) { - SET_FLAG_W_HEADER(header, 1); - memcpy(headeroption, winfo, winfolength); - headeroption += winfolength; - } - - size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; - SET_HLEN_HEADER(header, size / 4); - } else { - size = sizeof(struct sc_capwap_header); - SET_HLEN_HEADER(header, size / 4); - } - - /* Calculate body size */ - length = session->mtu - size; - if (packetlength <= length) { - length = packetlength; - } else if (requestfragment) { - length -= length % 8; /* Capwap fragment size is module 8 */ - } else { - break; - } - - /* Fragment options */ - if (requestfragment) { - SET_FLAG_F_HEADER(header, 1); - if (packetlength == length) { - SET_FLAG_L_HEADER(header, 1); - } - - header->frag_id = fragmentid; - header->frag_off = cpu_to_be16(fragmentoffset); - } - - /* Send packet */ - err = sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr); - TRACEKMOD("*** Send packet result: %d\n", err); - if (err < 0) { - break; - } - - /* */ - header = (struct sc_capwap_header*)(((uint8_t*)header + size + length) - sizeof(struct sc_capwap_header)); - fragmentoffset += length; - packetlength -= length; - } - - if (clone) { - kfree_skb(clone); - } - - return (!packetlength ? 0 : -EIO); -} - -/* */ -void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) { - int i; - char* pos = string; - - for (i = 0; i < 16; i++) { - snprintf(pos, 3, "%02x", sessionid->id[i]); - pos += 2; - } - - *pos = 0; -} - -/* */ -struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) { - struct sc_capwap_radio_addr* radioaddr; - struct sc_capwap_macaddress_eui48* addr; - - TRACEKMOD("### sc_capwap_setwirelessinformation\n"); - - memset(buffer, 0, size); - - radioaddr = (struct sc_capwap_radio_addr*)buffer; - radioaddr->length = MACADDRESS_EUI48_LENGTH; - - addr = (struct sc_capwap_macaddress_eui48*)radioaddr->addr; - memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH); - - return radioaddr; -} - -/* */ -struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) { - struct sc_capwap_wireless_information* winfo; - struct sc_capwap_ieee80211_frame_info* frameinfo; - - TRACEKMOD("### sc_capwap_setwinfo_frameinfo\n"); - - memset(buffer, 0, size); - - winfo = (struct sc_capwap_wireless_information*)buffer; - winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info); - - frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information)); - frameinfo->rssi = rssi; - frameinfo->snr = snr; - frameinfo->rate = cpu_to_be16(rate); - - return winfo; -} - -/* */ -struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap) { - struct sc_capwap_wireless_information* winfo; - struct sc_capwap_destination_wlans* destwlans; - - TRACEKMOD("### sc_capwap_setwinfo_destwlans\n"); - - memset(buffer, 0, size); - - winfo = (struct sc_capwap_wireless_information*)buffer; - winfo->length = sizeof(struct sc_capwap_destination_wlans); - - destwlans = (struct sc_capwap_destination_wlans*)(buffer + sizeof(struct sc_capwap_wireless_information)); - destwlans->wlanidbitmap = cpu_to_be16(wlanidbitmap); - - return winfo; -} +#include "config.h" +#include +#include +#include +#include +#include "socket.h" +#include "capwap.h" +#include "nlsmartcapwap.h" +#include "netlinkapp.h" + +/* */ +union capwap_addr sc_localaddr; + +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char sc_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; + +/* */ +static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) { + TRACEKMOD("### sc_capwap_fragment_free\n"); + + /* */ + list_del(&fragment->lru_list); + fragment->flags = 0; + + /* Free socket buffer */ + while (fragment->fragments) { + struct sk_buff* next = fragment->fragments->next; + + kfree_skb(fragment->fragments); + fragment->fragments = next; + } +} + +/* */ +static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) { + ktime_t delta; + struct sc_capwap_fragment* fragment; + struct list_head* list = &session->fragments.lru_list; + + TRACEKMOD("### sc_capwap_defrag_evictor\n"); + + /* Light check without lock */ + if (!list_empty(list)) { + spin_lock(&session->fragments.lock); + + /* Remove last old fragment */ + if (!list_empty(list)) { + fragment = list_first_entry(list, struct sc_capwap_fragment, lru_list); + delta = ktime_sub(now, fragment->tstamp); + if ((delta.tv64 < -NSEC_PER_SEC) || (delta.tv64 > NSEC_PER_SEC)) { + TRACEKMOD("*** Expired fragment %hu (%llu %llu)\n", fragment->fragmentid, now.tv64, fragment->tstamp.tv64); + sc_capwap_fragment_free(fragment); + } + } + + spin_unlock(&session->fragments.lock); + } +} + +/* */ +static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) { + int len; + int offset; + struct sk_buff* skb; + struct sk_buff* skbfrag; + struct sc_capwap_header* header; + + TRACEKMOD("### sc_capwap_reasm\n"); + + /* */ + skbfrag = fragment->fragments; + len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; + + /* Create new packet */ + skb = alloc_skb(len + fragment->totallength, GFP_KERNEL); + if (!skb) { + return NULL; + } + + /* The first capwap header is header of reassembled packet without fragment field */ + header = (struct sc_capwap_header*)skb_put(skb, len); + memcpy(header, skbfrag->data, len); + + SET_FLAG_F_HEADER(header, 0); + SET_FLAG_L_HEADER(header, 0); + header->frag_id = (__be16)0; + header->frag_off = (__be16)0; + + /* Copy body */ + while (skbfrag) { + offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; + len = skbfrag->len - offset; + + TRACEKMOD("*** Append fragment size %d\n", len); + + /* */ + memcpy(skb_put(skb, len), skbfrag->data + offset, len); + skbfrag = skbfrag->next; + } + + TRACEKMOD("*** Assemblate capwap data packet with total size %d\n", skb->len); + + return skb; +} + +/* */ +static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) { + uint16_t headersize; + uint16_t frag_id; + struct sk_buff* prev; + struct sk_buff* next; + struct sc_capwap_fragment* fragment; + struct sc_skb_capwap_cb* cb; + struct sk_buff* skb_defrag = NULL; + struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; + + TRACEKMOD("### sc_capwap_defrag\n"); + + /* */ + headersize = GET_HLEN_HEADER(header) * 4; + if (skb->len < headersize) { + goto error; + } + + /* */ + frag_id = be16_to_cpu(header->frag_id); + + /* */ + cb = CAPWAP_SKB_CB(skb); + cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT; + cb->frag_offset = be16_to_cpu(header->frag_off); + cb->frag_length = skb->len - headersize; + + /* */ + spin_lock(&session->fragments.lock); + TRACEKMOD("*** Fragment info: id %hu offset %hu length %hu\n", frag_id, cb->frag_offset, cb->frag_length); + + /* Get fragment */ + fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE]; + if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) { + TRACEKMOD("*** Unable defrag, queue fragment busy\n"); + goto error2; /* Queue fragment busy*/ + } + + /* Init fragment */ + if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) { + fragment->flags = CAPWAP_FRAGMENT_ENABLE; + fragment->fragmentid = frag_id; + fragment->fragments = NULL; + fragment->lastfragment = NULL; + fragment->recvlength = 0; + fragment->totallength = 0; + list_add_tail(&fragment->lru_list, &session->fragments.lru_list); + } + + /* Search fragment position */ + prev = fragment->lastfragment; + if (!prev) { + next = NULL; + } else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) { + if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) <= cb->frag_offset) { + next = NULL; + } else { + sc_capwap_fragment_free(fragment); + TRACEKMOD("*** Unable defrag, overlap error\n"); + goto error2; /* Overlap error */ + } + } else { + prev = NULL; + for (next = fragment->fragments; next != NULL; next = next->next) { + struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next); + + if (next_cb->frag_offset == cb->frag_offset) { + TRACEKMOD("*** Unable defrag, duplicate packet\n"); + goto error2; /* Duplicate packet */ + } else if (next_cb->frag_offset > cb->frag_offset) { + if ((cb->frag_offset + cb->frag_length) <= next_cb->frag_offset) { + break; + } else { + sc_capwap_fragment_free(fragment); + TRACEKMOD("*** Unable defrag, overlap error\n"); + goto error2; /* Overlap error */ + } + } + + prev = next; + } + } + + /* Insert fragment */ + skb->prev = NULL; + skb->next = next; + if (!next) { + fragment->lastfragment = skb; + } + + if (prev) { + prev->next = skb; + } else { + fragment->fragments = skb; + } + + /* Update size */ + fragment->recvlength += cb->frag_length; + if (IS_FLAG_L_HEADER(header)) { + fragment->totallength = cb->frag_offset + cb->frag_length; + fragment->flags |= CAPWAP_FRAGMENT_LAST; + } + + /* Check if receive all fragment */ + if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) { + skb_defrag = sc_capwap_reasm(fragment); + + /* Free fragment complete */ + sc_capwap_fragment_free(fragment); + } else { + /* Update timeout */ + fragment->tstamp = skb->tstamp; + TRACEKMOD("*** Fragment id %hu expire at %llu\n", frag_id, fragment->tstamp.tv64); + + /* Set LRU timeout */ + if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) { + list_move_tail(&fragment->lru_list, &session->fragments.lru_list); + } + } + + spin_unlock(&session->fragments.lock); + + return skb_defrag; + +error2: + spin_unlock(&session->fragments.lock); + +error: + kfree_skb(skb); + return NULL; +} + +/* */ +static unsigned int sc_capwap_80211_hdrlen(__le16 fc) { + unsigned int hdrlen = 24; + + TRACEKMOD("### sc_capwap_80211_hdrlen\n"); + + if (ieee80211_is_data(fc)) { + if (ieee80211_has_a4(fc)) { + hdrlen = 30; + } + + if (ieee80211_is_data_qos(fc)) { + hdrlen += IEEE80211_QOS_CTL_LEN; + if (ieee80211_has_order(fc)) { + hdrlen += IEEE80211_HT_CTL_LEN; + } + } + } else if (ieee80211_is_ctl(fc)) { + if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) { + hdrlen = 10; + } else { + hdrlen = 16; + } + } + + return hdrlen; +} + +/* */ +int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid) { + uint16_t hdrlen; + int head_need; + struct ieee80211_hdr hdr; + int skip_header_bytes; + uint8_t* encaps_data; + int encaps_len; + struct ethhdr* eh = (struct ethhdr*)skb->data; + uint16_t ethertype = ntohs(eh->h_proto); + + TRACEKMOD("### sc_capwap_8023_to_80211\n"); + + /* IEEE 802.11 header */ + hdrlen = 24; + hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_FROMDS); + memcpy(hdr.addr1, eh->h_dest, ETH_ALEN); + memcpy(hdr.addr2, bssid, ETH_ALEN); + memcpy(hdr.addr3, eh->h_source, ETH_ALEN); + hdr.duration_id = 0; + hdr.seq_ctrl = 0; + + /* */ + skip_header_bytes = ETH_HLEN; + if ((ethertype == ETH_P_AARP) || (ethertype == ETH_P_IPX)) { + encaps_data = sc_bridge_tunnel_header; + encaps_len = sizeof(sc_bridge_tunnel_header); + skip_header_bytes -= 2; + } else if (ethertype >= ETH_P_802_3_MIN) { + encaps_data = sc_rfc1042_header; + encaps_len = sizeof(sc_rfc1042_header); + skip_header_bytes -= 2; + } else { + encaps_data = NULL; + encaps_len = 0; + } + + /* Remove IEEE 802.3 header */ + skb_pull(skb, skip_header_bytes); + + /* Check headroom */ + head_need = hdrlen + encaps_len - skb_headroom(skb); + if ((head_need > 0) || skb_cloned(skb)) { + head_need = max(head_need, 0); + if (head_need) { + skb_orphan(skb); + } + + TRACEKMOD("*** Expand headroom skb of: %d\n", head_need); + if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { + return -ENOMEM; + } + + skb->truesize += head_need; + } + + /* Add LLC header */ + if (encaps_data) { + memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); + } + + /* Add IEEE 802.11 header */ + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + skb_reset_mac_header(skb); + + return 0; +} + +/* */ +int sc_capwap_80211_to_8023(struct sk_buff* skb) { + struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; + uint16_t hdrlen; + uint16_t ethertype; + uint8_t* payload; + uint8_t dst[ETH_ALEN]; + uint8_t src[ETH_ALEN] __aligned(2); + + TRACEKMOD("### sc_capwap_80211_to_8023\n"); + + /* */ + hdrlen = sc_capwap_80211_hdrlen(hdr->frame_control); + memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); + + /* */ + if (!pskb_may_pull(skb, hdrlen + 8)) { + return -1; + } + + /* */ + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((ether_addr_equal(payload, sc_rfc1042_header) && (ethertype != ETH_P_AARP) && (ethertype != ETH_P_IPX)) || ether_addr_equal(payload, sc_bridge_tunnel_header))) { + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + struct ethhdr *ehdr; + __be16 len; + + skb_pull(skb, hdrlen); + len = htons(skb->len); + ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dst, ETH_ALEN); + memcpy(ehdr->h_source, src, ETH_ALEN); + ehdr->h_proto = len; + } + + return 0; +} + +/* */ +int sc_capwap_bind(union capwap_addr* sockaddr) { + int ret; + + TRACEKMOD("### sc_capwap_bind\n"); + + /* */ + ret = sc_socket_bind(sockaddr); + if (ret) { + return ret; + } + + memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr)); + return 0; +} + +/* */ +void sc_capwap_initsession(struct sc_capwap_session* session) { + TRACEKMOD("### sc_capwap_initsession\n"); + + spin_lock_init(&session->fragmentid_lock); + + /* Defragment packets */ + memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue)); + INIT_LIST_HEAD(&session->fragments.lru_list); + spin_lock_init(&session->fragments.lock); +} + +/* */ +void sc_capwap_freesession(struct sc_capwap_session* session) { + struct sc_capwap_fragment* temp; + struct sc_capwap_fragment* fragment; + + TRACEKMOD("### sc_capwap_freesession\n"); + + /* Free socket buffers */ + list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) { + sc_capwap_fragment_free(fragment); + } +} + +/* */ +uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) { + uint16_t fragmentid; + + TRACEKMOD("### sc_capwap_newfragmentid\n"); + + spin_lock(&session->fragmentid_lock); + fragmentid = session->fragmentid++; + spin_unlock(&session->fragmentid_lock); + + return fragmentid; +} + +/* */ +int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) { + int length; + struct sc_capwap_header* header; + struct sc_capwap_data_message* dataheader; + struct sc_capwap_message_element* msgelement; + + TRACEKMOD("### sc_capwap_createkeepalive\n"); + + /* */ + if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) { + return -ENOMEM; + } + + /* Preamble CAPWAP header */ + header = (struct sc_capwap_header*)buffer; + length = sizeof(struct sc_capwap_header); + buffer += sizeof(struct sc_capwap_header); + + memset(header, 0, sizeof(struct sc_capwap_header)); + SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); + SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); + SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4); + SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211); + SET_FLAG_K_HEADER(header, 1); + + /* CAPWAP Data header */ + dataheader = (struct sc_capwap_data_message*)buffer; + length += sizeof(struct sc_capwap_data_message); + buffer += sizeof(struct sc_capwap_data_message); + + dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)); + + /* CAPWAP Keep-Alive Message Element */ + msgelement = (struct sc_capwap_message_element*)buffer; + length += sizeof(struct sc_capwap_message_element); + buffer += sizeof(struct sc_capwap_message_element); + + msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID); + msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element)); + + /* Session ID */ + memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element)); + length += sizeof(struct sc_capwap_sessionid_element); + + return length; +} + +/* */ +int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) { + int length; + uint16_t headersize; + struct sc_capwap_data_message* dataheader; + struct sc_capwap_message_element* message; + struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; + + TRACEKMOD("### sc_capwap_parsingpacket\n"); + + /* Linearize socket buffer */ + if (skb_linearize(skb)) { + TRACEKMOD("*** Unable to linearize packet\n"); + return -EINVAL; + } + + /* Check header */ + if (skb->len < sizeof(struct sc_capwap_header)) { + TRACEKMOD("*** Invalid capwap header length\n"); + return -EINVAL; + } else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) { + TRACEKMOD("*** Invalid capwap header version\n"); + return -EINVAL; + } else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) { + TRACEKMOD("*** Packet is encrypted\n"); + return -EINVAL; /* Accept only plain packet */ + } + + /* */ + if (IS_FLAG_K_HEADER(header)) { + /* Keep alive can not fragment */ + if (IS_FLAG_F_HEADER(header)) { + TRACEKMOD("*** Keep alive can not fragment\n"); + return -EINVAL; + } + + /* */ + length = skb->len; + headersize = GET_HLEN_HEADER(header) * 4; + if (length < (headersize + sizeof(struct sc_capwap_data_message))) { + TRACEKMOD("*** Invalid capwap data header length\n"); + return -EINVAL; + } + + /* Data message */ + length -= headersize; + dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize); + headersize = ntohs(dataheader->length); + if (length < headersize) { + TRACEKMOD("*** Capwap data header length mismatch\n"); + return -EINVAL; + } + + /* Message elements */ + headersize -= sizeof(struct sc_capwap_data_message); + message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message)); + while (headersize > 0) { + uint16_t msglength = ntohs(message->length); + if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) { + TRACEKMOD("*** Invalid capwap message element length\n"); + return -EINVAL; + } + + /* */ + if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) { + struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element)); + + if (!session) { + session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid); + if (!session) { + TRACEKMOD("*** Receive unknown keep alive without valid session\n"); + return -EINVAL; + } + } else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { + TRACEKMOD("*** Session id mismatch\n"); + return -EINVAL; + } + + /* Session found */ + sc_netlink_notify_recv_keepalive(sockaddr, sessionid); + + /* Parsing complete */ + kfree_skb(skb); + return 0; + } + + /* Next message element */ + msglength += sizeof(struct sc_capwap_message_element); + message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength); + headersize -= msglength; + } + } else if (session) { + if (!skb->tstamp.tv64) { + skb->tstamp = ktime_get(); + } + + /* Cleaning old fragments */ + sc_capwap_defrag_evictor(session, skb->tstamp); + + /* */ + if (IS_FLAG_F_HEADER(header)) { + skb = sc_capwap_defrag(session, skb); + if (!skb) { + return 0; + } + + /* Get new header info */ + header = (struct sc_capwap_header*)skb->data; + } + + /* Parsing data/management packet */ + if (!IS_FLAG_T_HEADER(header)) { + sc_capwap_parsingdatapacket(session, skb); + } else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) { + struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4); + + if (ieee80211_is_data_present(hdr->frame_control)) { + sc_capwap_parsingdatapacket(session, skb); + } else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) { + sc_capwap_parsingmgmtpacket(session, skb); + } + } + + return 0; + } + + return -EINVAL; +} + +/* */ +int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) { + int err; + int size; + int length; + int reserve; + int headroom; + int requestfragment; + __be16 fragmentid = 0; + int fragmentoffset = 0; + struct sc_capwap_header* header; + struct sk_buff* clone = NULL; + int packetlength = skb->len; + + TRACEKMOD("### sc_capwap_forwarddata\n"); + + /* Check headroom */ + headroom = skb_headroom(skb); + reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; + if (skb_is_nonlinear(skb) || (headroom < reserve)) { + TRACEKMOD("*** Copy socket buffer and expand headroom of: %d\n", (reserve - headroom)); + clone = skb_copy_expand(skb, max(headroom, reserve), skb_tailroom(skb), GFP_KERNEL); + if (!clone) { + TRACEKMOD("*** Unable to copy socket buffer\n"); + return -ENOMEM; + } + + skb = clone; + } + + /* Check MTU */ + requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0); + if (requestfragment) { + fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session)); + } + + /* */ + header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength); + while (packetlength > 0) { + memset(header, 0, sizeof(struct sc_capwap_header)); + SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); + SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); + SET_WBID_HEADER(header, binding); + SET_RID_HEADER(header, radioid); + SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1)); + + if (!fragmentoffset) { + uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header); + + if (radioaddr) { + SET_FLAG_M_HEADER(header, 1); + memcpy(headeroption, radioaddr, radioaddrlength); + headeroption += radioaddrlength; + } + + if (winfo) { + SET_FLAG_W_HEADER(header, 1); + memcpy(headeroption, winfo, winfolength); + headeroption += winfolength; + } + + size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; + SET_HLEN_HEADER(header, size / 4); + } else { + size = sizeof(struct sc_capwap_header); + SET_HLEN_HEADER(header, size / 4); + } + + /* Calculate body size */ + length = session->mtu - size; + if (packetlength <= length) { + length = packetlength; + } else if (requestfragment) { + length -= length % 8; /* Capwap fragment size is module 8 */ + } else { + break; + } + + /* Fragment options */ + if (requestfragment) { + SET_FLAG_F_HEADER(header, 1); + if (packetlength == length) { + SET_FLAG_L_HEADER(header, 1); + } + + header->frag_id = fragmentid; + header->frag_off = cpu_to_be16(fragmentoffset); + } + + /* Send packet */ + err = sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr); + TRACEKMOD("*** Send packet result: %d\n", err); + if (err < 0) { + break; + } + + /* */ + header = (struct sc_capwap_header*)(((uint8_t*)header + size + length) - sizeof(struct sc_capwap_header)); + fragmentoffset += length; + packetlength -= length; + } + + if (clone) { + kfree_skb(clone); + } + + return (!packetlength ? 0 : -EIO); +} + +/* */ +void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) { + int i; + char* pos = string; + + for (i = 0; i < 16; i++) { + snprintf(pos, 3, "%02x", sessionid->id[i]); + pos += 2; + } + + *pos = 0; +} + +/* */ +struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) { + struct sc_capwap_radio_addr* radioaddr; + struct sc_capwap_macaddress_eui48* addr; + + TRACEKMOD("### sc_capwap_setwirelessinformation\n"); + + memset(buffer, 0, size); + + radioaddr = (struct sc_capwap_radio_addr*)buffer; + radioaddr->length = MACADDRESS_EUI48_LENGTH; + + addr = (struct sc_capwap_macaddress_eui48*)radioaddr->addr; + memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH); + + return radioaddr; +} + +/* */ +struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) { + struct sc_capwap_wireless_information* winfo; + struct sc_capwap_ieee80211_frame_info* frameinfo; + + TRACEKMOD("### sc_capwap_setwinfo_frameinfo\n"); + + memset(buffer, 0, size); + + winfo = (struct sc_capwap_wireless_information*)buffer; + winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info); + + frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information)); + frameinfo->rssi = rssi; + frameinfo->snr = snr; + frameinfo->rate = cpu_to_be16(rate); + + return winfo; +} + +/* */ +struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap) { + struct sc_capwap_wireless_information* winfo; + struct sc_capwap_destination_wlans* destwlans; + + TRACEKMOD("### sc_capwap_setwinfo_destwlans\n"); + + memset(buffer, 0, size); + + winfo = (struct sc_capwap_wireless_information*)buffer; + winfo->length = sizeof(struct sc_capwap_destination_wlans); + + destwlans = (struct sc_capwap_destination_wlans*)(buffer + sizeof(struct sc_capwap_wireless_information)); + destwlans->wlanidbitmap = cpu_to_be16(wlanidbitmap); + + return winfo; +} diff --git a/src/ac/kmod/capwap.h b/src/ac/kmod/capwap.h index 8b39e7b..d7087c0 100644 --- a/src/ac/kmod/capwap.h +++ b/src/ac/kmod/capwap.h @@ -1,124 +1,124 @@ -#ifndef __KMOD_CAPWAP_HEADER__ -#define __KMOD_CAPWAP_HEADER__ - -#include "capwap_rfc.h" -#include "socket.h" - -/* */ -#define MAX_MTU 9000 -#define DEFAULT_MTU 1450 -#define MIN_MTU 500 -#define IEEE80211_MTU 7981 - -/* */ -#define CAPWAP_FRAGMENT_QUEUE 16 - -/* */ -#define CAPWAP_FRAGMENT_ENABLE 0x0001 -#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002 -#define CAPWAP_FRAGMENT_LAST 0x0004 - -/* */ -#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001 -#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002 -#define SKB_CAPWAP_FLAG_FROM_AC_TAP 0x0004 -#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0008 - -#define SKB_CAPWAP_FLAG_SESSIONID 0x0100 -#define SKB_CAPWAP_FLAG_RADIOID 0x0200 -#define SKB_CAPWAP_FLAG_BINDING 0x0400 -#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0800 -#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000 - -struct sc_skb_capwap_cb { - uint16_t flags; - - /* Session ID */ - struct sc_capwap_sessionid_element sessionid; - - /* Capwap information */ - uint8_t radioid; - uint8_t binding; - - /* Wireless Information */ - uint8_t winfo_rssi; - uint8_t winfo_snr; - uint16_t winfo_rate; - - /* Fragment */ - uint16_t frag_offset; - uint16_t frag_length; -}; - -#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb)) - -/* */ -struct sc_capwap_fragment { - struct list_head lru_list; - - uint8_t flags; - ktime_t tstamp; - - uint16_t fragmentid; - - struct sk_buff* fragments; - struct sk_buff* lastfragment; - int recvlength; - int totallength; -}; - -/* */ -struct sc_capwap_fragment_queue { - spinlock_t lock; - - struct list_head lru_list; - struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE]; -}; - -/* */ -struct sc_capwap_session { - uint16_t mtu; - union capwap_addr peeraddr; - struct sc_capwap_sessionid_element sessionid; - - uint16_t fragmentid; - spinlock_t fragmentid_lock; - - struct sc_capwap_fragment_queue fragments; -}; - -/* */ -extern union capwap_addr sc_localaddr; - -/* Dipendent implementation function */ -void sc_capwap_recvpacket(struct sk_buff* skb); -struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid); - -void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb); -void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb); - -/* Indipendent implementation function */ -int sc_capwap_bind(union capwap_addr* sockaddr); - -void sc_capwap_initsession(struct sc_capwap_session* session); -void sc_capwap_freesession(struct sc_capwap_session* session); -uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session); - -int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid); -int sc_capwap_80211_to_8023(struct sk_buff* skb); - -void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string); - -int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size); -int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb); - -struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid); -struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate); -struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap); - -int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength); - -/* Private funciotn */ -#include "capwap_private.h" - -#endif /* __KMOD_CAPWAP_HEADER__ */ +#ifndef __KMOD_CAPWAP_HEADER__ +#define __KMOD_CAPWAP_HEADER__ + +#include "capwap_rfc.h" +#include "socket.h" + +/* */ +#define MAX_MTU 9000 +#define DEFAULT_MTU 1450 +#define MIN_MTU 500 +#define IEEE80211_MTU 7981 + +/* */ +#define CAPWAP_FRAGMENT_QUEUE 16 + +/* */ +#define CAPWAP_FRAGMENT_ENABLE 0x0001 +#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002 +#define CAPWAP_FRAGMENT_LAST 0x0004 + +/* */ +#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001 +#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002 +#define SKB_CAPWAP_FLAG_FROM_AC_TAP 0x0004 +#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0008 + +#define SKB_CAPWAP_FLAG_SESSIONID 0x0100 +#define SKB_CAPWAP_FLAG_RADIOID 0x0200 +#define SKB_CAPWAP_FLAG_BINDING 0x0400 +#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0800 +#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000 + +struct sc_skb_capwap_cb { + uint16_t flags; + + /* Session ID */ + struct sc_capwap_sessionid_element sessionid; + + /* Capwap information */ + uint8_t radioid; + uint8_t binding; + + /* Wireless Information */ + uint8_t winfo_rssi; + uint8_t winfo_snr; + uint16_t winfo_rate; + + /* Fragment */ + uint16_t frag_offset; + uint16_t frag_length; +}; + +#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb)) + +/* */ +struct sc_capwap_fragment { + struct list_head lru_list; + + uint8_t flags; + ktime_t tstamp; + + uint16_t fragmentid; + + struct sk_buff* fragments; + struct sk_buff* lastfragment; + int recvlength; + int totallength; +}; + +/* */ +struct sc_capwap_fragment_queue { + spinlock_t lock; + + struct list_head lru_list; + struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE]; +}; + +/* */ +struct sc_capwap_session { + uint16_t mtu; + union capwap_addr peeraddr; + struct sc_capwap_sessionid_element sessionid; + + uint16_t fragmentid; + spinlock_t fragmentid_lock; + + struct sc_capwap_fragment_queue fragments; +}; + +/* */ +extern union capwap_addr sc_localaddr; + +/* Dipendent implementation function */ +void sc_capwap_recvpacket(struct sk_buff* skb); +struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid); + +void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb); +void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb); + +/* Indipendent implementation function */ +int sc_capwap_bind(union capwap_addr* sockaddr); + +void sc_capwap_initsession(struct sc_capwap_session* session); +void sc_capwap_freesession(struct sc_capwap_session* session); +uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session); + +int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid); +int sc_capwap_80211_to_8023(struct sk_buff* skb); + +void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string); + +int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size); +int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb); + +struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid); +struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate); +struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap); + +int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength); + +/* Private funciotn */ +#include "capwap_private.h" + +#endif /* __KMOD_CAPWAP_HEADER__ */ diff --git a/src/ac/kmod/capwap_private.c b/src/ac/kmod/capwap_private.c index f448691..2746739 100644 --- a/src/ac/kmod/capwap_private.c +++ b/src/ac/kmod/capwap_private.c @@ -1,1042 +1,1042 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "socket.h" -#include "capwap.h" -#include "nlsmartcapwap.h" -#include "netlinkapp.h" -#include "iface.h" -#include "station.h" - -/* */ -#define SESSION_HASH_SIZE_SHIFT 16 -#define SESSION_HASH_SIZE (1 << SESSION_HASH_SIZE_SHIFT) -#define MAX_WORKER_THREAD 32 - -/* */ -static DEFINE_MUTEX(sc_session_update_mutex); - -/* Sessions */ -static struct list_head sc_session_setup_list; -static struct list_head sc_session_running_list; - -static struct sc_capwap_session_priv* __rcu sc_session_hash_ipaddr[SESSION_HASH_SIZE]; -static struct sc_capwap_session_priv* __rcu sc_session_hash_sessionid[SESSION_HASH_SIZE]; - -/* Threads */ -static DEFINE_SPINLOCK(sc_session_threads_lock); -static uint32_t sc_session_threads_pos; -static uint32_t sc_session_threads_count; -static struct sc_capwap_workthread sc_session_threads[MAX_WORKER_THREAD]; - -/* */ -static uint32_t sc_capwap_hash_ipaddr(const union capwap_addr* peeraddr) { - TRACEKMOD("### sc_capwap_hash_ipaddr\n"); - - return hash_32(((peeraddr->ss.ss_family == AF_INET) ? peeraddr->sin.sin_addr.s_addr : ipv6_addr_hash(&peeraddr->sin6.sin6_addr)), SESSION_HASH_SIZE_SHIFT); -} - -/* */ -static uint32_t sc_capwap_hash_sessionid(const struct sc_capwap_sessionid_element* sessionid) { - TRACEKMOD("### sc_capwap_hash_sessionid\n"); - - return ((sessionid->id32[0] ^ sessionid->id32[1] ^ sessionid->id32[2] ^ sessionid->id32[3]) % SESSION_HASH_SIZE); -} - -/* */ -static void sc_capwap_closesession(struct sc_capwap_session_priv* sessionpriv) { - uint32_t hash; - struct sc_capwap_session_priv* search; - struct sc_capwap_station* temp; - struct sc_capwap_station* station; - - TRACEKMOD("### sc_capwap_closesession\n"); - - /* Close stations */ - list_for_each_entry_safe(station, temp, &sessionpriv->list_stations, list_session) { - sc_stations_releaseconnection(station); - sc_stations_free(station); - } - - /* */ - if (!list_empty(&sessionpriv->list_stations)) { - TRACEKMOD("*** Bug: the list stations of session is not empty\n"); - } - - if (!list_empty(&sessionpriv->list_connections)) { - TRACEKMOD("*** Bug: the list connections of session is not empty\n"); - } - - /* Remove session from list reference */ - if (sessionpriv->session.peeraddr.ss.ss_family != AF_UNSPEC) { - /* IP Address */ - hash = sc_capwap_hash_ipaddr(&sessionpriv->session.peeraddr); - search = rcu_dereference_protected(sc_session_hash_ipaddr[hash], sc_capwap_update_lock_is_locked()); - - if (search) { - if (search == sessionpriv) { - rcu_assign_pointer(sc_session_hash_ipaddr[hash], sessionpriv->next_ipaddr); - } else { - while (rcu_access_pointer(search->next_ipaddr) && (rcu_access_pointer(search->next_ipaddr) != sessionpriv)) { - search = rcu_dereference_protected(search->next_ipaddr, sc_capwap_update_lock_is_locked()); - } - - if (rcu_access_pointer(search->next_ipaddr)) { - rcu_assign_pointer(search->next_ipaddr, sessionpriv->next_ipaddr); - } - } - } - - /* Session ID */ - hash = sc_capwap_hash_sessionid(&sessionpriv->session.sessionid); - search = rcu_dereference_protected(sc_session_hash_sessionid[hash], sc_capwap_update_lock_is_locked()); - - if (search) { - if (search == sessionpriv) { - rcu_assign_pointer(sc_session_hash_sessionid[hash], sessionpriv->next_sessionid); - } else { - while (rcu_access_pointer(search->next_sessionid) && (rcu_access_pointer(search->next_sessionid) != sessionpriv)) { - search = rcu_dereference_protected(search->next_sessionid, sc_capwap_update_lock_is_locked()); - } - - if (rcu_access_pointer(search->next_sessionid)) { - rcu_assign_pointer(search->next_sessionid, sessionpriv->next_sessionid); - } - } - } - } - - /* */ - list_del_rcu(&sessionpriv->list); - synchronize_net(); - - /* Free memory */ - sc_capwap_freesession(&sessionpriv->session); - kfree(sessionpriv); -} - -/* */ -static void sc_capwap_closesessions(void) { - struct sc_capwap_session_priv* sessionpriv; - struct sc_capwap_session_priv* temp; - - TRACEKMOD("### sc_capwap_closesessions\n"); - - /* */ - sc_capwap_update_lock(); - - /* */ - list_for_each_entry_safe(sessionpriv, temp, &sc_session_setup_list, list) { - sc_capwap_closesession(sessionpriv); - } - - /* */ - list_for_each_entry_safe(sessionpriv, temp, &sc_session_running_list, list) { - sc_capwap_closesession(sessionpriv); - } - - /* */ - sc_capwap_update_unlock(); -} - -/* */ -static struct sc_capwap_session_priv* sc_capwap_getsession_ipaddr(const union capwap_addr* sockaddr) { - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_getsession_ipaddr\n"); - - /* */ - sessionpriv = rcu_dereference_check(sc_session_hash_ipaddr[sc_capwap_hash_ipaddr(sockaddr)], sc_capwap_update_lock_is_locked()); - while (sessionpriv) { - if (!sc_addr_compare(sockaddr, &sessionpriv->session.peeraddr)) { - break; - } - - /* */ - sessionpriv = rcu_dereference_check(sessionpriv->next_ipaddr, sc_capwap_update_lock_is_locked()); - } - - return sessionpriv; -} - -/* */ -static struct sc_capwap_session_priv* sc_capwap_getsession_sessionid(const struct sc_capwap_sessionid_element* sessionid) { - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_getsession_sessionid\n"); - - /* */ - sessionpriv = rcu_dereference_check(sc_session_hash_sessionid[sc_capwap_hash_sessionid(sessionid)], sc_capwap_update_lock_is_locked()); - while (sessionpriv) { - if (!memcmp(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { - break; - } - - /* */ - sessionpriv = rcu_dereference_check(sessionpriv->next_sessionid, sc_capwap_update_lock_is_locked()); - } - - return sessionpriv; -} - -/* */ -static int sc_capwap_deletesetupsession(const struct sc_capwap_sessionid_element* sessionid) { - int ret = -ENOENT; - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_deletesetupsession\n"); - - /* */ - sc_capwap_update_lock(); - - list_for_each_entry(sessionpriv, &sc_session_setup_list, list) { - if (!memcmp(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { -#ifdef DEBUGKMOD - do { - char sessionname[33]; - sc_capwap_sessionid_printf(&sessionpriv->session.sessionid, sessionname); - TRACEKMOD("*** Delete setup session: %s\n", sessionname); - } while(0); -#endif - sc_capwap_closesession(sessionpriv); - ret = 0; - break; - } - } - - /* */ - sc_capwap_update_unlock(); - return ret; -} - -/* */ -static int sc_capwap_deleterunningsession(const struct sc_capwap_sessionid_element* sessionid) { - int ret = -ENOENT; - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_deleterunningsession\n"); - - /* */ - sc_capwap_update_lock(); - - /* Search session with address hash */ - sessionpriv = sc_capwap_getsession_sessionid(sessionid); - if (sessionpriv) { -#ifdef DEBUGKMOD - do { - char sessionname[33]; - sc_capwap_sessionid_printf(&sessionpriv->session.sessionid, sessionname); - TRACEKMOD("*** Delete running session: %s\n", sessionname); - } while(0); -#endif - sc_capwap_closesession(sessionpriv); - ret = 0; - } - - /* */ - sc_capwap_update_unlock(); - return ret; -} - -/* */ -static int sc_capwap_restrictbroadcastpacket(struct sk_buff* skb, int is80211) { - TRACEKMOD("### sc_capwap_restrictbroadcastpacket\n"); - - /* TODO: limit some broadcast packet (DHCP) */ - - return 0; -} - -/* */ -static int sc_capwap_sendpacket_wtp(struct sc_capwap_session_priv* sessionpriv, uint8_t radioid, uint8_t wlanid, struct sk_buff* skb, int is80211) { - uint32_t flags = 0; - struct sc_capwap_radio_addr* radioaddr = NULL; - uint8_t radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED]; - struct sc_capwap_wlan* wlan = &sessionpriv->wlans[radioid - 1][wlanid - 1]; - - TRACEKMOD("### sc_capwap_sendpacket_wtp\n"); - - /* */ - if (!wlan->used) { - return -EINVAL; - } - - /* Datalink header convertion */ - if (is80211 && (wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_8023)) { - sc_capwap_80211_to_8023(skb); - flags |= NLSMARTCAPWAP_FLAGS_TUNNEL_8023; - radioaddr = sc_capwap_setradiomacaddress(radioaddrbuffer, CAPWAP_RADIO_EUI48_LENGTH_PADDED, wlan->bssid); - } else if (!is80211 && (wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211)) { - sc_capwap_8023_to_80211(skb, wlan->bssid); - } - - /* Forward packet */ - return sc_capwap_forwarddata(&sessionpriv->session, radioid, sessionpriv->binding, skb, flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), NULL, 0); -} - -/* */ -static void sc_capwap_sendbroadcastpacket_wtp(struct sc_netdev_priv* netpriv, uint16_t vlan, struct sk_buff* skb, struct sc_capwap_session_priv* ignore) { - struct sk_buff* clone; - struct sc_capwap_connection* connection; - struct sc_capwap_wireless_information* winfo; - uint8_t buffer[CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED]; - int headroom = sizeof(struct sc_capwap_header) + CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED; - - TRACEKMOD("### sc_capwap_sendbroadcastpacket_wtp\n"); - - /* */ - if (headroom < skb_headroom(skb)) { - headroom = skb_headroom(skb); - } - - /* Send packet for every connection */ - list_for_each_entry_rcu(connection, &netpriv->list_connections, list_dev) { - if ((connection->vlan == vlan) && (connection->sessionpriv != ignore)) { - clone = skb_copy_expand(skb, headroom, skb_tailroom(skb), GFP_KERNEL); - if (!clone) { - break; - } - - /* Forward packet */ - winfo = sc_capwap_setwinfo_destwlans(buffer, CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED, connection->wlanidmask); - sc_capwap_forwarddata(&connection->sessionpriv->session, connection->radioid, connection->sessionpriv->binding, clone, NLSMARTCAPWAP_FLAGS_TUNNEL_8023, NULL, 0, winfo, CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED); - kfree_skb(clone); - } - } -} - -/* */ -static void sc_capwap_sendpacket_iface(struct sc_capwap_station* station, struct sk_buff* skb) { - struct sc_netdev_priv* devpriv = rcu_dereference(station->devpriv); - - TRACEKMOD("### sc_capwap_sendpacket_iface\n"); - - /* */ - if (devpriv->dev->flags & IFF_UP) { - if (station->vlan) { - skb = vlan_insert_tag(skb, htons(ETH_P_8021Q), station->vlan & VLAN_VID_MASK); - if (!skb) { - /* Unable add VLAN id */ - spin_lock(&devpriv->lock); - devpriv->dev->stats.rx_dropped++; - spin_unlock(&devpriv->lock); - return; - } - } - - /* Prepare to send packet */ - skb_reset_mac_header(skb); - skb->protocol = eth_type_trans(skb, devpriv->dev); - - /* Send packet */ - netif_rx_ni(skb); - TRACEKMOD("*** Send packet with size %d to interface %s\n", skb->len, devpriv->dev->name); - - /* Update stats */ - spin_lock(&devpriv->lock); - devpriv->dev->stats.rx_packets++; - devpriv->dev->stats.rx_bytes += skb->len; - spin_unlock(&devpriv->lock); - } else { - /* Drop packet */ - kfree_skb(skb); - - spin_lock(&devpriv->lock); - devpriv->dev->stats.rx_dropped++; - spin_unlock(&devpriv->lock); - } -} - -/* */ -static int sc_capwap_thread_recvpacket(struct sk_buff* skb) { - int ret = 1; - struct sc_capwap_session_priv* sessionpriv; - struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb); - - TRACEKMOD("### sc_capwap_thread_recvpacket\n"); - - /* */ - if (cb->flags & SKB_CAPWAP_FLAG_FROM_USER_SPACE) { - TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_USER_SPACE\n"); - - /* Send packet*/ - rcu_read_lock(); - - sessionpriv = sc_capwap_getsession_sessionid(&cb->sessionid); - if (sessionpriv) { - if (sc_capwap_forwarddata(&sessionpriv->session, cb->radioid, cb->binding, skb, 0, NULL, 0, NULL, 0)) { - TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n"); - } - } else { - TRACEKMOD("*** Unable to find session\n"); - } - - rcu_read_unlock(); - } else if (cb->flags & SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL) { - union capwap_addr peeraddr; - - TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL\n"); - - /* Get peer address */ - if (!sc_socket_getpeeraddr(skb, &peeraddr)) { - if (skb_pull(skb, sizeof(struct udphdr))) { - rcu_read_lock(); - - sessionpriv = sc_capwap_getsession_ipaddr(&peeraddr); - ret = sc_capwap_parsingpacket((sessionpriv ? &sessionpriv->session : NULL), &peeraddr, skb); - - rcu_read_unlock(); - } else { - TRACEKMOD("*** Invalid packet\n"); - ret = -EOVERFLOW; - } - } else { - TRACEKMOD("*** Unable get address from packet\n"); - ret = -EINVAL; - } - } else if (cb->flags & SKB_CAPWAP_FLAG_FROM_AC_TAP) { - uint16_t vlan = 0; - struct ethhdr* eh = eth_hdr(skb); - struct sc_capwap_station* station; - - TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_AC_TAP\n"); - - /* Retrieve VLAN */ - if (vlan_tx_tag_present(skb)) { - vlan = vlan_tx_tag_get_id(skb); - } else if (eh->h_proto == htons(ETH_P_8021Q)) { - vlan = ntohs(vlan_eth_hdr(skb)->h_vlan_TCI) & VLAN_VID_MASK; - - /* Remove 802.1q from packet */ - memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); - skb_pull(skb, VLAN_HLEN); - skb_reset_mac_header(skb); - } - - rcu_read_lock(); - - if (is_multicast_ether_addr(eh->h_dest)) { - TRACEKMOD("*** Receive broadcast/multicast packet\n"); - - if (!sc_capwap_restrictbroadcastpacket(skb, 0)) { - sc_capwap_sendbroadcastpacket_wtp((struct sc_netdev_priv*)netdev_priv(skb->dev), vlan, skb, NULL); - } - } else { - station = sc_stations_search(eh->h_dest); - if (station && (station->vlan == vlan)) { - sc_capwap_sendpacket_wtp(rcu_dereference(station->sessionpriv), station->radioid, station->wlanid, skb, 0); - } else { - TRACEKMOD("*** Unable to found station from macaddress\n"); - ret = -EINVAL; - } - } - - rcu_read_unlock(); - } - - return ret; -} - -/* */ -static int sc_capwap_thread(void* data) { - struct sk_buff* skb; - struct sc_capwap_workthread* thread = (struct sc_capwap_workthread*)data; - - TRACEKMOD("### sc_capwap_thread\n"); - TRACEKMOD("*** Thread start: %d\n", smp_processor_id()); - - for (;;) { - wait_event_interruptible(thread->waitevent, (skb_queue_len(&thread->queue) > 0) || kthread_should_stop()); - if (kthread_should_stop()) { - break; - } - - /* Get packet */ - skb = skb_dequeue(&thread->queue); - if (!skb) { - TRACEKMOD("*** Nothing from thread %d\n", smp_processor_id()); - continue; - } - - /* */ - TRACEKMOD("*** Thread receive packet %d\n", smp_processor_id()); - if (sc_capwap_thread_recvpacket(skb)) { - TRACEKMOD("*** Free packet\n"); - kfree_skb(skb); - } - } - - /* Purge queue */ - skb_queue_purge(&thread->queue); - - TRACEKMOD("*** Thread end: %d\n", smp_processor_id()); - return 0; -} - -/* */ -void sc_capwap_update_lock(void) { - mutex_lock(&sc_session_update_mutex); -} - -/* */ -void sc_capwap_update_unlock(void) { - mutex_unlock(&sc_session_update_mutex); -} - -/* */ -#ifdef CONFIG_PROVE_LOCKING -int sc_capwap_update_lock_is_locked(void) { - return lockdep_is_held(&sc_session_update_mutex); -} -#endif - -/* */ -int sc_capwap_sendkeepalive(const struct sc_capwap_sessionid_element* sessionid) { - int ret; - int length; - struct sc_capwap_session_priv* sessionpriv; - uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE]; - - TRACEKMOD("### sc_capwap_sendkeepalive\n"); - - /* */ - rcu_read_lock(); - - /* Get session */ - sessionpriv = sc_capwap_getsession_sessionid(sessionid); - if (!sessionpriv) { - TRACEKMOD("*** Unknown keep-alive session\n"); - ret = -ENOENT; - goto done; - } - -#ifdef DEBUGKMOD - do { - char sessionname[33]; - sc_capwap_sessionid_printf(&sessionpriv->session.sessionid, sessionname); - TRACEKMOD("*** Send keep-alive session: %s\n", sessionname); - } while(0); -#endif - - /* Build keepalive */ - length = sc_capwap_createkeepalive(&sessionpriv->session.sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE); - - /* Send packet */ - ret = sc_socket_send(SOCKET_UDP, buffer, length, &sessionpriv->session.peeraddr); - TRACEKMOD("*** Send keep-alive result: %d\n", ret); - if (ret > 0) { - ret = 0; - } - -done: - rcu_read_unlock(); - return ret; -} - -/* */ -int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu) { - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_newsession\n"); - -#ifdef DEBUGKMOD - do { - char sessionname[33]; - sc_capwap_sessionid_printf(sessionid, sessionname); - TRACEKMOD("*** Create session: %s\n", sessionname); - } while(0); -#endif - - /* */ - sessionpriv = (struct sc_capwap_session_priv*)kzalloc(sizeof(struct sc_capwap_session_priv), GFP_KERNEL); - if (!sessionpriv) { - TRACEKMOD("*** Unable to create session\n"); - return -ENOMEM; - } - - /* Initialize session */ - sc_capwap_initsession(&sessionpriv->session); - memcpy(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element)); - sessionpriv->binding = binding; - sessionpriv->session.mtu = mtu; - INIT_LIST_HEAD(&sessionpriv->list_stations); - INIT_LIST_HEAD(&sessionpriv->list_connections); - - /* Add to setup session list */ - sc_capwap_update_lock(); - list_add_rcu(&sessionpriv->list, &sc_session_setup_list); - sc_capwap_update_unlock(); - - TRACEKMOD("*** Create session\n"); - return 0; -} - -/* */ -int sc_capwap_init(void) { - unsigned long i; - unsigned long cpu; - int err = -ENOMEM; - - TRACEKMOD("### sc_capwap_init\n"); - - /* Init session */ - memset(&sc_localaddr, 0, sizeof(union capwap_addr)); - INIT_LIST_HEAD(&sc_session_setup_list); - INIT_LIST_HEAD(&sc_session_running_list); - - /* */ - memset(sc_session_hash_ipaddr, 0, sizeof(struct sc_capwap_session_priv*) * SESSION_HASH_SIZE); - memset(sc_session_hash_sessionid, 0, sizeof(struct sc_capwap_session_priv*) * SESSION_HASH_SIZE); - - /* Create threads */ - sc_session_threads_pos = 0; - sc_session_threads_count = 0; - for_each_online_cpu(cpu) { - memset(&sc_session_threads[sc_session_threads_count], 0, sizeof(struct sc_capwap_workthread)); - - /* Create thread and bind to cpu */ - sc_session_threads[sc_session_threads_count].thread = kthread_create(sc_capwap_thread, &sc_session_threads[sc_session_threads_count], "smartcapwap/%u", sc_session_threads_count); - if (!IS_ERR(sc_session_threads[sc_session_threads_count].thread)) { - kthread_bind(sc_session_threads[sc_session_threads_count].thread, cpu); - - /* */ - sc_session_threads_count++; - if (sc_session_threads_count == MAX_WORKER_THREAD) { - break; - } - } else { - err = PTR_ERR(sc_session_threads[sc_session_threads_count].thread); - sc_session_threads[sc_session_threads_count].thread = NULL; - goto error; - } - } - - /* Init sockect */ - err = sc_socket_init(); - if (err) { - goto error; - } - - /* Start threads */ - for (i = 0; i < sc_session_threads_count; i++) { - skb_queue_head_init(&sc_session_threads[i].queue); - init_waitqueue_head(&sc_session_threads[i].waitevent); - wake_up_process(sc_session_threads[i].thread); - } - - return 0; - -error: - for (i = 0; i < sc_session_threads_count; i++) { - if (sc_session_threads[i].thread) { - kthread_stop(sc_session_threads[i].thread); - } - } - - return err; -} - -/* */ -void sc_capwap_close(void) { - uint32_t i; - - TRACEKMOD("### sc_capwap_close\n"); - - /* Close */ - sc_socket_close(); - sc_capwap_closesessions(); - sc_iface_closeall(); - - /* Terminate threads */ - for (i = 0; i < sc_session_threads_count; i++) { - kthread_stop(sc_session_threads[i].thread); - } -} - -/* */ -int sc_capwap_deletesession(const struct sc_capwap_sessionid_element* sessionid) { - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_deletesession\n"); - -#ifdef DEBUGKMOD - do { - char sessionname[33]; - sc_capwap_sessionid_printf(sessionid, sessionname); - TRACEKMOD("*** Delete session: %s\n", sessionname); - } while(0); -#endif - - /* Searching item with read lock */ - rcu_read_lock(); - - /* Search into running session list */ - if (sc_capwap_getsession_sessionid(sessionid)) { - rcu_read_unlock(); - - /* Remove session */ - return sc_capwap_deleterunningsession(sessionid); - } - - /* Search into setup session list */ - list_for_each_entry_rcu(sessionpriv, &sc_session_setup_list, list) { - if (!memcmp(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { - rcu_read_unlock(); - - /* Remove session with sessionid */ - return sc_capwap_deletesetupsession(sessionid); - } - } - - rcu_read_unlock(); - - TRACEKMOD("*** Session not found\n"); - return -ENOENT; -} - -/* */ -int sc_capwap_addwlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode) { - int err = -ENOENT; - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_addwlan\n"); - - /* */ - sc_capwap_update_lock(); - - /* Search session and interface */ - sessionpriv = sc_capwap_getsession_sessionid(sessionid); - if (sessionpriv) { - struct sc_capwap_wlan* wlan = &sessionpriv->wlans[radioid - 1][wlanid - 1]; - - memcpy(wlan->bssid, bssid, MACADDRESS_EUI48_LENGTH); - wlan->macmode = macmode; - wlan->tunnelmode = tunnelmode; - wlan->used = 1; - err = 0; - } - - sc_capwap_update_unlock(); - - return err; -} - -/* */ -int sc_capwap_removewlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid) { - int err = -ENOENT; - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_removewlan\n"); - - /* */ - sc_capwap_update_lock(); - - /* Search session and interface */ - sessionpriv = sc_capwap_getsession_sessionid(sessionid); - if (sessionpriv) { - sessionpriv->wlans[radioid - 1][wlanid - 1].used = 0; - } - - sc_capwap_update_unlock(); - - return err; -} - -/* */ -void sc_capwap_recvpacket(struct sk_buff* skb) { - uint32_t pos; - - TRACEKMOD("### sc_capwap_recvpacket\n"); - - spin_lock(&sc_session_threads_lock); - sc_session_threads_pos = ((sc_session_threads_pos + 1) % sc_session_threads_count); - pos = sc_session_threads_pos; - spin_unlock(&sc_session_threads_lock); - - TRACEKMOD("*** Add packet (flags 0x%04x size %d) to thread: %u\n", (int)CAPWAP_SKB_CB(skb)->flags, (int)skb->len, pos); - - /* Queue packet */ - skb_queue_tail(&sc_session_threads[pos].queue, skb); - wake_up_interruptible(&sc_session_threads[pos].waitevent); -} - -/* */ -struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid) { - uint32_t hash; - struct sc_capwap_session_priv* search; - struct sc_capwap_session_priv* sessionpriv = NULL; - - TRACEKMOD("### sc_capwap_recvunknownkeepalive\n"); - -#ifdef DEBUGKMOD - do { - char sessionname[33]; - sc_capwap_sessionid_printf(sessionid, sessionname); - TRACEKMOD("*** Receive unknown keep-alive: %s\n", sessionname); - } while(0); -#endif - - /* Change read lock to update lock */ - rcu_read_unlock(); - sc_capwap_update_lock(); - - /* Search and remove from setup session */ - list_for_each_entry(search, &sc_session_setup_list, list) { - if (!memcmp(&search->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { - sessionpriv = search; - break; - } - } - - /* */ - if (!sessionpriv) { - TRACEKMOD("*** Setup session not found\n"); - goto done; - } - - /* */ - list_del_rcu(&sessionpriv->list); - synchronize_net(); - - /* */ - memcpy(&sessionpriv->session.peeraddr, sockaddr, sizeof(union capwap_addr)); - list_add_rcu(&sessionpriv->list, &sc_session_running_list); - - /* */ - hash = sc_capwap_hash_ipaddr(sockaddr); - sessionpriv->next_ipaddr = rcu_dereference_protected(sc_session_hash_ipaddr[hash], sc_capwap_update_lock_is_locked()); - rcu_assign_pointer(sc_session_hash_ipaddr[hash], sessionpriv); - - /* */ - hash = sc_capwap_hash_sessionid(sessionid); - sessionpriv->next_sessionid = rcu_dereference_protected(sc_session_hash_sessionid[hash], sc_capwap_update_lock_is_locked()); - rcu_assign_pointer(sc_session_hash_sessionid[hash], sessionpriv); - -done: - rcu_read_lock(); - sc_capwap_update_unlock(); - - /* */ - return (sessionpriv ? &sessionpriv->session : NULL); -} - -/* */ -void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) { - uint8_t* pos; - uint8_t* srcaddress; - uint8_t* dstaddress; - struct sc_capwap_station* srcstation; - struct sc_capwap_station* dststation; - struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; - int is80211 = (IS_FLAG_T_HEADER(header) ? 1 : 0); - struct sc_capwap_radio_addr* radioaddr = NULL; - int radioaddrsize = 0; - struct sc_capwap_wireless_information* winfo = NULL; - int winfosize = 0; - - TRACEKMOD("### sc_capwap_parsingdatapacket\n"); - - /* Retrieve optional attribute */ - pos = skb->data + sizeof(struct sc_capwap_header); - if (IS_FLAG_M_HEADER(header)) { - radioaddr = (struct sc_capwap_radio_addr*)pos; - radioaddrsize = (sizeof(struct sc_capwap_radio_addr) + radioaddr->length + 3) & ~3; - pos += radioaddrsize; - } - - if (IS_FLAG_W_HEADER(header)) { - winfo = (struct sc_capwap_wireless_information*)pos; - winfosize = (sizeof(struct sc_capwap_wireless_information) + winfo->length + 3) & ~3; - pos += winfosize; - } - - /* Body packet */ - skb_pull(skb, GET_HLEN_HEADER(header) * 4); - srcaddress = (is80211 ? ieee80211_get_SA((struct ieee80211_hdr*)skb->data) : (uint8_t*)((struct ethhdr*)skb->data)->h_source); - dstaddress = (is80211 ? ieee80211_get_DA((struct ieee80211_hdr*)skb->data) : (uint8_t*)((struct ethhdr*)skb->data)->h_dest); - - /* Search source station */ - srcstation = sc_stations_search(srcaddress); - if (srcstation) { - struct sc_capwap_session_priv* srcsessionpriv = rcu_dereference(srcstation->sessionpriv); - struct sc_capwap_wlan* wlan = &srcsessionpriv->wlans[srcstation->radioid - 1][srcstation->wlanid - 1]; - - if (wlan->used) { - /* Check tunnel mode */ - if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { - if (is_multicast_ether_addr(dstaddress)) { - if (is80211) { - sc_capwap_80211_to_8023(skb); - } - - /* Forward to any session with same connection */ - if (!srcsessionpriv->isolation && !sc_capwap_restrictbroadcastpacket(skb, is80211)) { - sc_capwap_sendbroadcastpacket_wtp(rcu_dereference(srcstation->devpriv), srcstation->vlan, skb, srcsessionpriv); - } - - /* Forward to physical interface */ - sc_capwap_sendpacket_iface(srcstation, skb); - } else { - /* Search destination station */ - dststation = sc_stations_search(dstaddress); - if (dststation) { - /* Forward packet */ - if (!srcsessionpriv->isolation && (srcsessionpriv != rcu_access_pointer(dststation->sessionpriv))) { - sc_capwap_sendpacket_wtp(rcu_dereference(dststation->sessionpriv), dststation->radioid, dststation->wlanid, skb, is80211); - } - - kfree_skb(skb); - } else { - if (is80211) { - sc_capwap_80211_to_8023(skb); - } - - /* Forward to physical interface */ - sc_capwap_sendpacket_iface(srcstation, skb); - } - } - } else { - TRACEKMOD("*** Receive packet from local tunnel mode wlan session\n"); - kfree_skb(skb); - } - } else { - TRACEKMOD("*** Receive packet from disable wlan\n"); - kfree_skb(skb); - } - } else { - TRACEKMOD("*** Receive packet from unknown station\n"); - kfree_skb(skb); - } -} - -/* */ -void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) { - TRACEKMOD("### sc_capwap_parsingmgmtpacket\n"); - - /* Send packet with capwap header into userspace */ - sc_netlink_notify_recv_data(&session->sessionid, skb->data, skb->len); - kfree_skb(skb); -} - -/* */ -int sc_capwap_authstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address, uint32_t ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan) { - int err = 0; - struct sc_capwap_station* station; - struct sc_netdev_priv* devpriv; - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_authstation\n"); - - if (!IS_VALID_RADIOID(radioid)) { - return -EINVAL; - } - - /* */ - sc_capwap_update_lock(); - - /* Search session and interface */ - sessionpriv = sc_capwap_getsession_sessionid(sessionid); - if (sessionpriv) { - devpriv = sc_iface_search(ifindex); - if (devpriv) { - /* Create or Update Station */ - station = sc_stations_search(address); - if (station) { - /* Release old connection */ - sc_stations_releaseconnection(station); - - /* */ - station->vlan = vlan; - station->radioid = radioid; - station->wlanid = wlanid; - - /* Update interface */ - if (rcu_access_pointer(station->devpriv) != devpriv) { - rcu_assign_pointer(station->devpriv, devpriv); - list_replace(&station->list_dev, &devpriv->list_stations); - } - - /* Update session */ - if (rcu_access_pointer(station->sessionpriv) != sessionpriv) { - rcu_assign_pointer(station->sessionpriv, sessionpriv); - list_replace(&station->list_session, &sessionpriv->list_stations); - } - } else { - station = (struct sc_capwap_station*)kzalloc(sizeof(struct sc_capwap_station), GFP_KERNEL); - if (station) { - memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); - station->vlan = vlan; - station->radioid = radioid; - station->wlanid = wlanid; - - /* Assign interface */ - rcu_assign_pointer(station->devpriv, devpriv); - list_add(&station->list_dev, &devpriv->list_stations); - - /* Assign session */ - rcu_assign_pointer(station->sessionpriv, sessionpriv); - list_add(&station->list_session, &sessionpriv->list_stations); - - /* Add station */ - sc_stations_add(station); - } else { - TRACEKMOD("*** Unable to create station\n"); - err = -ENOMEM; - } - } - - /* Set new connection */ - if (!err && station) { - err = sc_stations_setconnection(station); - if (err) { - TRACEKMOD("*** Unable to set connection\n"); - sc_stations_free(station); - } - } - } else { - TRACEKMOD("*** Unable to find interface\n"); - err = -EINVAL; - } - } else { - TRACEKMOD("*** Unable to find session\n"); - err = -EINVAL; - } - - sc_capwap_update_unlock(); - - return err; -} - -/* */ -int sc_capwap_deauthstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address) { - int err = -ENOENT; - struct sc_capwap_station* station; - struct sc_capwap_session_priv* sessionpriv; - - TRACEKMOD("### sc_capwap_deauthstation\n"); - - sc_capwap_update_lock(); - - sessionpriv = sc_capwap_getsession_sessionid(sessionid); - if (sessionpriv) { - station = sc_stations_search(address); - if (station && (rcu_access_pointer(station->sessionpriv) == sessionpriv)) { - sc_stations_releaseconnection(station); - sc_stations_free(station); - err = 0; - } - } - - sc_capwap_update_unlock(); - - return err; -} +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "socket.h" +#include "capwap.h" +#include "nlsmartcapwap.h" +#include "netlinkapp.h" +#include "iface.h" +#include "station.h" + +/* */ +#define SESSION_HASH_SIZE_SHIFT 16 +#define SESSION_HASH_SIZE (1 << SESSION_HASH_SIZE_SHIFT) +#define MAX_WORKER_THREAD 32 + +/* */ +static DEFINE_MUTEX(sc_session_update_mutex); + +/* Sessions */ +static struct list_head sc_session_setup_list; +static struct list_head sc_session_running_list; + +static struct sc_capwap_session_priv* __rcu sc_session_hash_ipaddr[SESSION_HASH_SIZE]; +static struct sc_capwap_session_priv* __rcu sc_session_hash_sessionid[SESSION_HASH_SIZE]; + +/* Threads */ +static DEFINE_SPINLOCK(sc_session_threads_lock); +static uint32_t sc_session_threads_pos; +static uint32_t sc_session_threads_count; +static struct sc_capwap_workthread sc_session_threads[MAX_WORKER_THREAD]; + +/* */ +static uint32_t sc_capwap_hash_ipaddr(const union capwap_addr* peeraddr) { + TRACEKMOD("### sc_capwap_hash_ipaddr\n"); + + return hash_32(((peeraddr->ss.ss_family == AF_INET) ? peeraddr->sin.sin_addr.s_addr : ipv6_addr_hash(&peeraddr->sin6.sin6_addr)), SESSION_HASH_SIZE_SHIFT); +} + +/* */ +static uint32_t sc_capwap_hash_sessionid(const struct sc_capwap_sessionid_element* sessionid) { + TRACEKMOD("### sc_capwap_hash_sessionid\n"); + + return ((sessionid->id32[0] ^ sessionid->id32[1] ^ sessionid->id32[2] ^ sessionid->id32[3]) % SESSION_HASH_SIZE); +} + +/* */ +static void sc_capwap_closesession(struct sc_capwap_session_priv* sessionpriv) { + uint32_t hash; + struct sc_capwap_session_priv* search; + struct sc_capwap_station* temp; + struct sc_capwap_station* station; + + TRACEKMOD("### sc_capwap_closesession\n"); + + /* Close stations */ + list_for_each_entry_safe(station, temp, &sessionpriv->list_stations, list_session) { + sc_stations_releaseconnection(station); + sc_stations_free(station); + } + + /* */ + if (!list_empty(&sessionpriv->list_stations)) { + TRACEKMOD("*** Bug: the list stations of session is not empty\n"); + } + + if (!list_empty(&sessionpriv->list_connections)) { + TRACEKMOD("*** Bug: the list connections of session is not empty\n"); + } + + /* Remove session from list reference */ + if (sessionpriv->session.peeraddr.ss.ss_family != AF_UNSPEC) { + /* IP Address */ + hash = sc_capwap_hash_ipaddr(&sessionpriv->session.peeraddr); + search = rcu_dereference_protected(sc_session_hash_ipaddr[hash], sc_capwap_update_lock_is_locked()); + + if (search) { + if (search == sessionpriv) { + rcu_assign_pointer(sc_session_hash_ipaddr[hash], sessionpriv->next_ipaddr); + } else { + while (rcu_access_pointer(search->next_ipaddr) && (rcu_access_pointer(search->next_ipaddr) != sessionpriv)) { + search = rcu_dereference_protected(search->next_ipaddr, sc_capwap_update_lock_is_locked()); + } + + if (rcu_access_pointer(search->next_ipaddr)) { + rcu_assign_pointer(search->next_ipaddr, sessionpriv->next_ipaddr); + } + } + } + + /* Session ID */ + hash = sc_capwap_hash_sessionid(&sessionpriv->session.sessionid); + search = rcu_dereference_protected(sc_session_hash_sessionid[hash], sc_capwap_update_lock_is_locked()); + + if (search) { + if (search == sessionpriv) { + rcu_assign_pointer(sc_session_hash_sessionid[hash], sessionpriv->next_sessionid); + } else { + while (rcu_access_pointer(search->next_sessionid) && (rcu_access_pointer(search->next_sessionid) != sessionpriv)) { + search = rcu_dereference_protected(search->next_sessionid, sc_capwap_update_lock_is_locked()); + } + + if (rcu_access_pointer(search->next_sessionid)) { + rcu_assign_pointer(search->next_sessionid, sessionpriv->next_sessionid); + } + } + } + } + + /* */ + list_del_rcu(&sessionpriv->list); + synchronize_net(); + + /* Free memory */ + sc_capwap_freesession(&sessionpriv->session); + kfree(sessionpriv); +} + +/* */ +static void sc_capwap_closesessions(void) { + struct sc_capwap_session_priv* sessionpriv; + struct sc_capwap_session_priv* temp; + + TRACEKMOD("### sc_capwap_closesessions\n"); + + /* */ + sc_capwap_update_lock(); + + /* */ + list_for_each_entry_safe(sessionpriv, temp, &sc_session_setup_list, list) { + sc_capwap_closesession(sessionpriv); + } + + /* */ + list_for_each_entry_safe(sessionpriv, temp, &sc_session_running_list, list) { + sc_capwap_closesession(sessionpriv); + } + + /* */ + sc_capwap_update_unlock(); +} + +/* */ +static struct sc_capwap_session_priv* sc_capwap_getsession_ipaddr(const union capwap_addr* sockaddr) { + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_getsession_ipaddr\n"); + + /* */ + sessionpriv = rcu_dereference_check(sc_session_hash_ipaddr[sc_capwap_hash_ipaddr(sockaddr)], sc_capwap_update_lock_is_locked()); + while (sessionpriv) { + if (!sc_addr_compare(sockaddr, &sessionpriv->session.peeraddr)) { + break; + } + + /* */ + sessionpriv = rcu_dereference_check(sessionpriv->next_ipaddr, sc_capwap_update_lock_is_locked()); + } + + return sessionpriv; +} + +/* */ +static struct sc_capwap_session_priv* sc_capwap_getsession_sessionid(const struct sc_capwap_sessionid_element* sessionid) { + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_getsession_sessionid\n"); + + /* */ + sessionpriv = rcu_dereference_check(sc_session_hash_sessionid[sc_capwap_hash_sessionid(sessionid)], sc_capwap_update_lock_is_locked()); + while (sessionpriv) { + if (!memcmp(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { + break; + } + + /* */ + sessionpriv = rcu_dereference_check(sessionpriv->next_sessionid, sc_capwap_update_lock_is_locked()); + } + + return sessionpriv; +} + +/* */ +static int sc_capwap_deletesetupsession(const struct sc_capwap_sessionid_element* sessionid) { + int ret = -ENOENT; + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_deletesetupsession\n"); + + /* */ + sc_capwap_update_lock(); + + list_for_each_entry(sessionpriv, &sc_session_setup_list, list) { + if (!memcmp(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { +#ifdef DEBUGKMOD + do { + char sessionname[33]; + sc_capwap_sessionid_printf(&sessionpriv->session.sessionid, sessionname); + TRACEKMOD("*** Delete setup session: %s\n", sessionname); + } while(0); +#endif + sc_capwap_closesession(sessionpriv); + ret = 0; + break; + } + } + + /* */ + sc_capwap_update_unlock(); + return ret; +} + +/* */ +static int sc_capwap_deleterunningsession(const struct sc_capwap_sessionid_element* sessionid) { + int ret = -ENOENT; + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_deleterunningsession\n"); + + /* */ + sc_capwap_update_lock(); + + /* Search session with address hash */ + sessionpriv = sc_capwap_getsession_sessionid(sessionid); + if (sessionpriv) { +#ifdef DEBUGKMOD + do { + char sessionname[33]; + sc_capwap_sessionid_printf(&sessionpriv->session.sessionid, sessionname); + TRACEKMOD("*** Delete running session: %s\n", sessionname); + } while(0); +#endif + sc_capwap_closesession(sessionpriv); + ret = 0; + } + + /* */ + sc_capwap_update_unlock(); + return ret; +} + +/* */ +static int sc_capwap_restrictbroadcastpacket(struct sk_buff* skb, int is80211) { + TRACEKMOD("### sc_capwap_restrictbroadcastpacket\n"); + + /* TODO: limit some broadcast packet (DHCP) */ + + return 0; +} + +/* */ +static int sc_capwap_sendpacket_wtp(struct sc_capwap_session_priv* sessionpriv, uint8_t radioid, uint8_t wlanid, struct sk_buff* skb, int is80211) { + uint32_t flags = 0; + struct sc_capwap_radio_addr* radioaddr = NULL; + uint8_t radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED]; + struct sc_capwap_wlan* wlan = &sessionpriv->wlans[radioid - 1][wlanid - 1]; + + TRACEKMOD("### sc_capwap_sendpacket_wtp\n"); + + /* */ + if (!wlan->used) { + return -EINVAL; + } + + /* Datalink header convertion */ + if (is80211 && (wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_8023)) { + sc_capwap_80211_to_8023(skb); + flags |= NLSMARTCAPWAP_FLAGS_TUNNEL_8023; + radioaddr = sc_capwap_setradiomacaddress(radioaddrbuffer, CAPWAP_RADIO_EUI48_LENGTH_PADDED, wlan->bssid); + } else if (!is80211 && (wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211)) { + sc_capwap_8023_to_80211(skb, wlan->bssid); + } + + /* Forward packet */ + return sc_capwap_forwarddata(&sessionpriv->session, radioid, sessionpriv->binding, skb, flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), NULL, 0); +} + +/* */ +static void sc_capwap_sendbroadcastpacket_wtp(struct sc_netdev_priv* netpriv, uint16_t vlan, struct sk_buff* skb, struct sc_capwap_session_priv* ignore) { + struct sk_buff* clone; + struct sc_capwap_connection* connection; + struct sc_capwap_wireless_information* winfo; + uint8_t buffer[CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED]; + int headroom = sizeof(struct sc_capwap_header) + CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED; + + TRACEKMOD("### sc_capwap_sendbroadcastpacket_wtp\n"); + + /* */ + if (headroom < skb_headroom(skb)) { + headroom = skb_headroom(skb); + } + + /* Send packet for every connection */ + list_for_each_entry_rcu(connection, &netpriv->list_connections, list_dev) { + if ((connection->vlan == vlan) && (connection->sessionpriv != ignore)) { + clone = skb_copy_expand(skb, headroom, skb_tailroom(skb), GFP_KERNEL); + if (!clone) { + break; + } + + /* Forward packet */ + winfo = sc_capwap_setwinfo_destwlans(buffer, CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED, connection->wlanidmask); + sc_capwap_forwarddata(&connection->sessionpriv->session, connection->radioid, connection->sessionpriv->binding, clone, NLSMARTCAPWAP_FLAGS_TUNNEL_8023, NULL, 0, winfo, CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED); + kfree_skb(clone); + } + } +} + +/* */ +static void sc_capwap_sendpacket_iface(struct sc_capwap_station* station, struct sk_buff* skb) { + struct sc_netdev_priv* devpriv = rcu_dereference(station->devpriv); + + TRACEKMOD("### sc_capwap_sendpacket_iface\n"); + + /* */ + if (devpriv->dev->flags & IFF_UP) { + if (station->vlan) { + skb = vlan_insert_tag(skb, htons(ETH_P_8021Q), station->vlan & VLAN_VID_MASK); + if (!skb) { + /* Unable add VLAN id */ + spin_lock(&devpriv->lock); + devpriv->dev->stats.rx_dropped++; + spin_unlock(&devpriv->lock); + return; + } + } + + /* Prepare to send packet */ + skb_reset_mac_header(skb); + skb->protocol = eth_type_trans(skb, devpriv->dev); + + /* Send packet */ + netif_rx_ni(skb); + TRACEKMOD("*** Send packet with size %d to interface %s\n", skb->len, devpriv->dev->name); + + /* Update stats */ + spin_lock(&devpriv->lock); + devpriv->dev->stats.rx_packets++; + devpriv->dev->stats.rx_bytes += skb->len; + spin_unlock(&devpriv->lock); + } else { + /* Drop packet */ + kfree_skb(skb); + + spin_lock(&devpriv->lock); + devpriv->dev->stats.rx_dropped++; + spin_unlock(&devpriv->lock); + } +} + +/* */ +static int sc_capwap_thread_recvpacket(struct sk_buff* skb) { + int ret = 1; + struct sc_capwap_session_priv* sessionpriv; + struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb); + + TRACEKMOD("### sc_capwap_thread_recvpacket\n"); + + /* */ + if (cb->flags & SKB_CAPWAP_FLAG_FROM_USER_SPACE) { + TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_USER_SPACE\n"); + + /* Send packet*/ + rcu_read_lock(); + + sessionpriv = sc_capwap_getsession_sessionid(&cb->sessionid); + if (sessionpriv) { + if (sc_capwap_forwarddata(&sessionpriv->session, cb->radioid, cb->binding, skb, 0, NULL, 0, NULL, 0)) { + TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n"); + } + } else { + TRACEKMOD("*** Unable to find session\n"); + } + + rcu_read_unlock(); + } else if (cb->flags & SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL) { + union capwap_addr peeraddr; + + TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL\n"); + + /* Get peer address */ + if (!sc_socket_getpeeraddr(skb, &peeraddr)) { + if (skb_pull(skb, sizeof(struct udphdr))) { + rcu_read_lock(); + + sessionpriv = sc_capwap_getsession_ipaddr(&peeraddr); + ret = sc_capwap_parsingpacket((sessionpriv ? &sessionpriv->session : NULL), &peeraddr, skb); + + rcu_read_unlock(); + } else { + TRACEKMOD("*** Invalid packet\n"); + ret = -EOVERFLOW; + } + } else { + TRACEKMOD("*** Unable get address from packet\n"); + ret = -EINVAL; + } + } else if (cb->flags & SKB_CAPWAP_FLAG_FROM_AC_TAP) { + uint16_t vlan = 0; + struct ethhdr* eh = eth_hdr(skb); + struct sc_capwap_station* station; + + TRACEKMOD("*** Receive SKB_CAPWAP_FLAG_FROM_AC_TAP\n"); + + /* Retrieve VLAN */ + if (vlan_tx_tag_present(skb)) { + vlan = vlan_tx_tag_get_id(skb); + } else if (eh->h_proto == htons(ETH_P_8021Q)) { + vlan = ntohs(vlan_eth_hdr(skb)->h_vlan_TCI) & VLAN_VID_MASK; + + /* Remove 802.1q from packet */ + memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); + skb_pull(skb, VLAN_HLEN); + skb_reset_mac_header(skb); + } + + rcu_read_lock(); + + if (is_multicast_ether_addr(eh->h_dest)) { + TRACEKMOD("*** Receive broadcast/multicast packet\n"); + + if (!sc_capwap_restrictbroadcastpacket(skb, 0)) { + sc_capwap_sendbroadcastpacket_wtp((struct sc_netdev_priv*)netdev_priv(skb->dev), vlan, skb, NULL); + } + } else { + station = sc_stations_search(eh->h_dest); + if (station && (station->vlan == vlan)) { + sc_capwap_sendpacket_wtp(rcu_dereference(station->sessionpriv), station->radioid, station->wlanid, skb, 0); + } else { + TRACEKMOD("*** Unable to found station from macaddress\n"); + ret = -EINVAL; + } + } + + rcu_read_unlock(); + } + + return ret; +} + +/* */ +static int sc_capwap_thread(void* data) { + struct sk_buff* skb; + struct sc_capwap_workthread* thread = (struct sc_capwap_workthread*)data; + + TRACEKMOD("### sc_capwap_thread\n"); + TRACEKMOD("*** Thread start: %d\n", smp_processor_id()); + + for (;;) { + wait_event_interruptible(thread->waitevent, (skb_queue_len(&thread->queue) > 0) || kthread_should_stop()); + if (kthread_should_stop()) { + break; + } + + /* Get packet */ + skb = skb_dequeue(&thread->queue); + if (!skb) { + TRACEKMOD("*** Nothing from thread %d\n", smp_processor_id()); + continue; + } + + /* */ + TRACEKMOD("*** Thread receive packet %d\n", smp_processor_id()); + if (sc_capwap_thread_recvpacket(skb)) { + TRACEKMOD("*** Free packet\n"); + kfree_skb(skb); + } + } + + /* Purge queue */ + skb_queue_purge(&thread->queue); + + TRACEKMOD("*** Thread end: %d\n", smp_processor_id()); + return 0; +} + +/* */ +void sc_capwap_update_lock(void) { + mutex_lock(&sc_session_update_mutex); +} + +/* */ +void sc_capwap_update_unlock(void) { + mutex_unlock(&sc_session_update_mutex); +} + +/* */ +#ifdef CONFIG_PROVE_LOCKING +int sc_capwap_update_lock_is_locked(void) { + return lockdep_is_held(&sc_session_update_mutex); +} +#endif + +/* */ +int sc_capwap_sendkeepalive(const struct sc_capwap_sessionid_element* sessionid) { + int ret; + int length; + struct sc_capwap_session_priv* sessionpriv; + uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE]; + + TRACEKMOD("### sc_capwap_sendkeepalive\n"); + + /* */ + rcu_read_lock(); + + /* Get session */ + sessionpriv = sc_capwap_getsession_sessionid(sessionid); + if (!sessionpriv) { + TRACEKMOD("*** Unknown keep-alive session\n"); + ret = -ENOENT; + goto done; + } + +#ifdef DEBUGKMOD + do { + char sessionname[33]; + sc_capwap_sessionid_printf(&sessionpriv->session.sessionid, sessionname); + TRACEKMOD("*** Send keep-alive session: %s\n", sessionname); + } while(0); +#endif + + /* Build keepalive */ + length = sc_capwap_createkeepalive(&sessionpriv->session.sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE); + + /* Send packet */ + ret = sc_socket_send(SOCKET_UDP, buffer, length, &sessionpriv->session.peeraddr); + TRACEKMOD("*** Send keep-alive result: %d\n", ret); + if (ret > 0) { + ret = 0; + } + +done: + rcu_read_unlock(); + return ret; +} + +/* */ +int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu) { + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_newsession\n"); + +#ifdef DEBUGKMOD + do { + char sessionname[33]; + sc_capwap_sessionid_printf(sessionid, sessionname); + TRACEKMOD("*** Create session: %s\n", sessionname); + } while(0); +#endif + + /* */ + sessionpriv = (struct sc_capwap_session_priv*)kzalloc(sizeof(struct sc_capwap_session_priv), GFP_KERNEL); + if (!sessionpriv) { + TRACEKMOD("*** Unable to create session\n"); + return -ENOMEM; + } + + /* Initialize session */ + sc_capwap_initsession(&sessionpriv->session); + memcpy(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element)); + sessionpriv->binding = binding; + sessionpriv->session.mtu = mtu; + INIT_LIST_HEAD(&sessionpriv->list_stations); + INIT_LIST_HEAD(&sessionpriv->list_connections); + + /* Add to setup session list */ + sc_capwap_update_lock(); + list_add_rcu(&sessionpriv->list, &sc_session_setup_list); + sc_capwap_update_unlock(); + + TRACEKMOD("*** Create session\n"); + return 0; +} + +/* */ +int sc_capwap_init(void) { + unsigned long i; + unsigned long cpu; + int err = -ENOMEM; + + TRACEKMOD("### sc_capwap_init\n"); + + /* Init session */ + memset(&sc_localaddr, 0, sizeof(union capwap_addr)); + INIT_LIST_HEAD(&sc_session_setup_list); + INIT_LIST_HEAD(&sc_session_running_list); + + /* */ + memset(sc_session_hash_ipaddr, 0, sizeof(struct sc_capwap_session_priv*) * SESSION_HASH_SIZE); + memset(sc_session_hash_sessionid, 0, sizeof(struct sc_capwap_session_priv*) * SESSION_HASH_SIZE); + + /* Create threads */ + sc_session_threads_pos = 0; + sc_session_threads_count = 0; + for_each_online_cpu(cpu) { + memset(&sc_session_threads[sc_session_threads_count], 0, sizeof(struct sc_capwap_workthread)); + + /* Create thread and bind to cpu */ + sc_session_threads[sc_session_threads_count].thread = kthread_create(sc_capwap_thread, &sc_session_threads[sc_session_threads_count], "smartcapwap/%u", sc_session_threads_count); + if (!IS_ERR(sc_session_threads[sc_session_threads_count].thread)) { + kthread_bind(sc_session_threads[sc_session_threads_count].thread, cpu); + + /* */ + sc_session_threads_count++; + if (sc_session_threads_count == MAX_WORKER_THREAD) { + break; + } + } else { + err = PTR_ERR(sc_session_threads[sc_session_threads_count].thread); + sc_session_threads[sc_session_threads_count].thread = NULL; + goto error; + } + } + + /* Init sockect */ + err = sc_socket_init(); + if (err) { + goto error; + } + + /* Start threads */ + for (i = 0; i < sc_session_threads_count; i++) { + skb_queue_head_init(&sc_session_threads[i].queue); + init_waitqueue_head(&sc_session_threads[i].waitevent); + wake_up_process(sc_session_threads[i].thread); + } + + return 0; + +error: + for (i = 0; i < sc_session_threads_count; i++) { + if (sc_session_threads[i].thread) { + kthread_stop(sc_session_threads[i].thread); + } + } + + return err; +} + +/* */ +void sc_capwap_close(void) { + uint32_t i; + + TRACEKMOD("### sc_capwap_close\n"); + + /* Close */ + sc_socket_close(); + sc_capwap_closesessions(); + sc_iface_closeall(); + + /* Terminate threads */ + for (i = 0; i < sc_session_threads_count; i++) { + kthread_stop(sc_session_threads[i].thread); + } +} + +/* */ +int sc_capwap_deletesession(const struct sc_capwap_sessionid_element* sessionid) { + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_deletesession\n"); + +#ifdef DEBUGKMOD + do { + char sessionname[33]; + sc_capwap_sessionid_printf(sessionid, sessionname); + TRACEKMOD("*** Delete session: %s\n", sessionname); + } while(0); +#endif + + /* Searching item with read lock */ + rcu_read_lock(); + + /* Search into running session list */ + if (sc_capwap_getsession_sessionid(sessionid)) { + rcu_read_unlock(); + + /* Remove session */ + return sc_capwap_deleterunningsession(sessionid); + } + + /* Search into setup session list */ + list_for_each_entry_rcu(sessionpriv, &sc_session_setup_list, list) { + if (!memcmp(&sessionpriv->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { + rcu_read_unlock(); + + /* Remove session with sessionid */ + return sc_capwap_deletesetupsession(sessionid); + } + } + + rcu_read_unlock(); + + TRACEKMOD("*** Session not found\n"); + return -ENOENT; +} + +/* */ +int sc_capwap_addwlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode) { + int err = -ENOENT; + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_addwlan\n"); + + /* */ + sc_capwap_update_lock(); + + /* Search session and interface */ + sessionpriv = sc_capwap_getsession_sessionid(sessionid); + if (sessionpriv) { + struct sc_capwap_wlan* wlan = &sessionpriv->wlans[radioid - 1][wlanid - 1]; + + memcpy(wlan->bssid, bssid, MACADDRESS_EUI48_LENGTH); + wlan->macmode = macmode; + wlan->tunnelmode = tunnelmode; + wlan->used = 1; + err = 0; + } + + sc_capwap_update_unlock(); + + return err; +} + +/* */ +int sc_capwap_removewlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid) { + int err = -ENOENT; + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_removewlan\n"); + + /* */ + sc_capwap_update_lock(); + + /* Search session and interface */ + sessionpriv = sc_capwap_getsession_sessionid(sessionid); + if (sessionpriv) { + sessionpriv->wlans[radioid - 1][wlanid - 1].used = 0; + } + + sc_capwap_update_unlock(); + + return err; +} + +/* */ +void sc_capwap_recvpacket(struct sk_buff* skb) { + uint32_t pos; + + TRACEKMOD("### sc_capwap_recvpacket\n"); + + spin_lock(&sc_session_threads_lock); + sc_session_threads_pos = ((sc_session_threads_pos + 1) % sc_session_threads_count); + pos = sc_session_threads_pos; + spin_unlock(&sc_session_threads_lock); + + TRACEKMOD("*** Add packet (flags 0x%04x size %d) to thread: %u\n", (int)CAPWAP_SKB_CB(skb)->flags, (int)skb->len, pos); + + /* Queue packet */ + skb_queue_tail(&sc_session_threads[pos].queue, skb); + wake_up_interruptible(&sc_session_threads[pos].waitevent); +} + +/* */ +struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid) { + uint32_t hash; + struct sc_capwap_session_priv* search; + struct sc_capwap_session_priv* sessionpriv = NULL; + + TRACEKMOD("### sc_capwap_recvunknownkeepalive\n"); + +#ifdef DEBUGKMOD + do { + char sessionname[33]; + sc_capwap_sessionid_printf(sessionid, sessionname); + TRACEKMOD("*** Receive unknown keep-alive: %s\n", sessionname); + } while(0); +#endif + + /* Change read lock to update lock */ + rcu_read_unlock(); + sc_capwap_update_lock(); + + /* Search and remove from setup session */ + list_for_each_entry(search, &sc_session_setup_list, list) { + if (!memcmp(&search->session.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { + sessionpriv = search; + break; + } + } + + /* */ + if (!sessionpriv) { + TRACEKMOD("*** Setup session not found\n"); + goto done; + } + + /* */ + list_del_rcu(&sessionpriv->list); + synchronize_net(); + + /* */ + memcpy(&sessionpriv->session.peeraddr, sockaddr, sizeof(union capwap_addr)); + list_add_rcu(&sessionpriv->list, &sc_session_running_list); + + /* */ + hash = sc_capwap_hash_ipaddr(sockaddr); + sessionpriv->next_ipaddr = rcu_dereference_protected(sc_session_hash_ipaddr[hash], sc_capwap_update_lock_is_locked()); + rcu_assign_pointer(sc_session_hash_ipaddr[hash], sessionpriv); + + /* */ + hash = sc_capwap_hash_sessionid(sessionid); + sessionpriv->next_sessionid = rcu_dereference_protected(sc_session_hash_sessionid[hash], sc_capwap_update_lock_is_locked()); + rcu_assign_pointer(sc_session_hash_sessionid[hash], sessionpriv); + +done: + rcu_read_lock(); + sc_capwap_update_unlock(); + + /* */ + return (sessionpriv ? &sessionpriv->session : NULL); +} + +/* */ +void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) { + uint8_t* pos; + uint8_t* srcaddress; + uint8_t* dstaddress; + struct sc_capwap_station* srcstation; + struct sc_capwap_station* dststation; + struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; + int is80211 = (IS_FLAG_T_HEADER(header) ? 1 : 0); + struct sc_capwap_radio_addr* radioaddr = NULL; + int radioaddrsize = 0; + struct sc_capwap_wireless_information* winfo = NULL; + int winfosize = 0; + + TRACEKMOD("### sc_capwap_parsingdatapacket\n"); + + /* Retrieve optional attribute */ + pos = skb->data + sizeof(struct sc_capwap_header); + if (IS_FLAG_M_HEADER(header)) { + radioaddr = (struct sc_capwap_radio_addr*)pos; + radioaddrsize = (sizeof(struct sc_capwap_radio_addr) + radioaddr->length + 3) & ~3; + pos += radioaddrsize; + } + + if (IS_FLAG_W_HEADER(header)) { + winfo = (struct sc_capwap_wireless_information*)pos; + winfosize = (sizeof(struct sc_capwap_wireless_information) + winfo->length + 3) & ~3; + pos += winfosize; + } + + /* Body packet */ + skb_pull(skb, GET_HLEN_HEADER(header) * 4); + srcaddress = (is80211 ? ieee80211_get_SA((struct ieee80211_hdr*)skb->data) : (uint8_t*)((struct ethhdr*)skb->data)->h_source); + dstaddress = (is80211 ? ieee80211_get_DA((struct ieee80211_hdr*)skb->data) : (uint8_t*)((struct ethhdr*)skb->data)->h_dest); + + /* Search source station */ + srcstation = sc_stations_search(srcaddress); + if (srcstation) { + struct sc_capwap_session_priv* srcsessionpriv = rcu_dereference(srcstation->sessionpriv); + struct sc_capwap_wlan* wlan = &srcsessionpriv->wlans[srcstation->radioid - 1][srcstation->wlanid - 1]; + + if (wlan->used) { + /* Check tunnel mode */ + if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { + if (is_multicast_ether_addr(dstaddress)) { + if (is80211) { + sc_capwap_80211_to_8023(skb); + } + + /* Forward to any session with same connection */ + if (!srcsessionpriv->isolation && !sc_capwap_restrictbroadcastpacket(skb, is80211)) { + sc_capwap_sendbroadcastpacket_wtp(rcu_dereference(srcstation->devpriv), srcstation->vlan, skb, srcsessionpriv); + } + + /* Forward to physical interface */ + sc_capwap_sendpacket_iface(srcstation, skb); + } else { + /* Search destination station */ + dststation = sc_stations_search(dstaddress); + if (dststation) { + /* Forward packet */ + if (!srcsessionpriv->isolation && (srcsessionpriv != rcu_access_pointer(dststation->sessionpriv))) { + sc_capwap_sendpacket_wtp(rcu_dereference(dststation->sessionpriv), dststation->radioid, dststation->wlanid, skb, is80211); + } + + kfree_skb(skb); + } else { + if (is80211) { + sc_capwap_80211_to_8023(skb); + } + + /* Forward to physical interface */ + sc_capwap_sendpacket_iface(srcstation, skb); + } + } + } else { + TRACEKMOD("*** Receive packet from local tunnel mode wlan session\n"); + kfree_skb(skb); + } + } else { + TRACEKMOD("*** Receive packet from disable wlan\n"); + kfree_skb(skb); + } + } else { + TRACEKMOD("*** Receive packet from unknown station\n"); + kfree_skb(skb); + } +} + +/* */ +void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) { + TRACEKMOD("### sc_capwap_parsingmgmtpacket\n"); + + /* Send packet with capwap header into userspace */ + sc_netlink_notify_recv_data(&session->sessionid, skb->data, skb->len); + kfree_skb(skb); +} + +/* */ +int sc_capwap_authstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address, uint32_t ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan) { + int err = 0; + struct sc_capwap_station* station; + struct sc_netdev_priv* devpriv; + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_authstation\n"); + + if (!IS_VALID_RADIOID(radioid)) { + return -EINVAL; + } + + /* */ + sc_capwap_update_lock(); + + /* Search session and interface */ + sessionpriv = sc_capwap_getsession_sessionid(sessionid); + if (sessionpriv) { + devpriv = sc_iface_search(ifindex); + if (devpriv) { + /* Create or Update Station */ + station = sc_stations_search(address); + if (station) { + /* Release old connection */ + sc_stations_releaseconnection(station); + + /* */ + station->vlan = vlan; + station->radioid = radioid; + station->wlanid = wlanid; + + /* Update interface */ + if (rcu_access_pointer(station->devpriv) != devpriv) { + rcu_assign_pointer(station->devpriv, devpriv); + list_replace(&station->list_dev, &devpriv->list_stations); + } + + /* Update session */ + if (rcu_access_pointer(station->sessionpriv) != sessionpriv) { + rcu_assign_pointer(station->sessionpriv, sessionpriv); + list_replace(&station->list_session, &sessionpriv->list_stations); + } + } else { + station = (struct sc_capwap_station*)kzalloc(sizeof(struct sc_capwap_station), GFP_KERNEL); + if (station) { + memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); + station->vlan = vlan; + station->radioid = radioid; + station->wlanid = wlanid; + + /* Assign interface */ + rcu_assign_pointer(station->devpriv, devpriv); + list_add(&station->list_dev, &devpriv->list_stations); + + /* Assign session */ + rcu_assign_pointer(station->sessionpriv, sessionpriv); + list_add(&station->list_session, &sessionpriv->list_stations); + + /* Add station */ + sc_stations_add(station); + } else { + TRACEKMOD("*** Unable to create station\n"); + err = -ENOMEM; + } + } + + /* Set new connection */ + if (!err && station) { + err = sc_stations_setconnection(station); + if (err) { + TRACEKMOD("*** Unable to set connection\n"); + sc_stations_free(station); + } + } + } else { + TRACEKMOD("*** Unable to find interface\n"); + err = -EINVAL; + } + } else { + TRACEKMOD("*** Unable to find session\n"); + err = -EINVAL; + } + + sc_capwap_update_unlock(); + + return err; +} + +/* */ +int sc_capwap_deauthstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address) { + int err = -ENOENT; + struct sc_capwap_station* station; + struct sc_capwap_session_priv* sessionpriv; + + TRACEKMOD("### sc_capwap_deauthstation\n"); + + sc_capwap_update_lock(); + + sessionpriv = sc_capwap_getsession_sessionid(sessionid); + if (sessionpriv) { + station = sc_stations_search(address); + if (station && (rcu_access_pointer(station->sessionpriv) == sessionpriv)) { + sc_stations_releaseconnection(station); + sc_stations_free(station); + err = 0; + } + } + + sc_capwap_update_unlock(); + + return err; +} diff --git a/src/ac/kmod/capwap_private.h b/src/ac/kmod/capwap_private.h index 35b0222..44bead8 100644 --- a/src/ac/kmod/capwap_private.h +++ b/src/ac/kmod/capwap_private.h @@ -1,67 +1,67 @@ -#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__ -#define __KMOD_CAPWAP_PRIVATE_HEADER__ - -/* */ -struct sc_capwap_wlan { - int used; - - uint8_t bssid[MACADDRESS_EUI48_LENGTH]; - uint8_t macmode; - uint8_t tunnelmode; -}; - -/* */ -struct sc_capwap_session_priv { - struct sc_capwap_session session; - - struct list_head list; - struct sc_capwap_session_priv* __rcu next_ipaddr; - struct sc_capwap_session_priv* __rcu next_sessionid; - - struct list_head list_stations; - struct list_head list_connections; - - /* */ - int isolation; - uint8_t binding; - struct sc_capwap_wlan wlans[CAPWAP_RADIOID_MAX_COUNT][CAPWAP_WLANID_MAX_COUNT]; -}; - -/* */ -struct sc_capwap_workthread { - struct task_struct* thread; - - struct sk_buff_head queue; - wait_queue_head_t waitevent; -}; - -/* */ -int sc_capwap_init(void); -void sc_capwap_close(void); - -/* */ -void sc_capwap_update_lock(void); -void sc_capwap_update_unlock(void); - -#ifdef CONFIG_PROVE_LOCKING -int sc_capwap_update_lock_is_locked(void); -#else -static inline int sc_capwap_update_lock_is_locked(void) { return 1; } -#endif - -/* */ -int sc_capwap_sendkeepalive(const struct sc_capwap_sessionid_element* sessionid); - -/* */ -int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu); -int sc_capwap_deletesession(const struct sc_capwap_sessionid_element* sessionid); - -/* */ -int sc_capwap_addwlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode); -int sc_capwap_removewlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid); - -/* */ -int sc_capwap_authstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address, uint32_t ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan); -int sc_capwap_deauthstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address); - -#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */ +#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__ +#define __KMOD_CAPWAP_PRIVATE_HEADER__ + +/* */ +struct sc_capwap_wlan { + int used; + + uint8_t bssid[MACADDRESS_EUI48_LENGTH]; + uint8_t macmode; + uint8_t tunnelmode; +}; + +/* */ +struct sc_capwap_session_priv { + struct sc_capwap_session session; + + struct list_head list; + struct sc_capwap_session_priv* __rcu next_ipaddr; + struct sc_capwap_session_priv* __rcu next_sessionid; + + struct list_head list_stations; + struct list_head list_connections; + + /* */ + int isolation; + uint8_t binding; + struct sc_capwap_wlan wlans[CAPWAP_RADIOID_MAX_COUNT][CAPWAP_WLANID_MAX_COUNT]; +}; + +/* */ +struct sc_capwap_workthread { + struct task_struct* thread; + + struct sk_buff_head queue; + wait_queue_head_t waitevent; +}; + +/* */ +int sc_capwap_init(void); +void sc_capwap_close(void); + +/* */ +void sc_capwap_update_lock(void); +void sc_capwap_update_unlock(void); + +#ifdef CONFIG_PROVE_LOCKING +int sc_capwap_update_lock_is_locked(void); +#else +static inline int sc_capwap_update_lock_is_locked(void) { return 1; } +#endif + +/* */ +int sc_capwap_sendkeepalive(const struct sc_capwap_sessionid_element* sessionid); + +/* */ +int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu); +int sc_capwap_deletesession(const struct sc_capwap_sessionid_element* sessionid); + +/* */ +int sc_capwap_addwlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode); +int sc_capwap_removewlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid); + +/* */ +int sc_capwap_authstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address, uint32_t ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan); +int sc_capwap_deauthstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address); + +#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */ diff --git a/src/ac/kmod/capwap_rfc.h b/src/ac/kmod/capwap_rfc.h index 84b81aa..6981ac2 100644 --- a/src/ac/kmod/capwap_rfc.h +++ b/src/ac/kmod/capwap_rfc.h @@ -1,187 +1,187 @@ -#ifndef __KMOD_CAPWAP_RFC_HEADER__ -#define __KMOD_CAPWAP_RFC_HEADER__ - -#include -#include - -/* */ -#define CAPWAP_RADIOID_MAX_COUNT 31 -#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT)) - -#define CAPWAP_WLANID_MAX_COUNT 16 -#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT)) - -/* */ -#define CAPWAP_WIRELESS_BINDING_NONE 0 -#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 - -/* */ -#define CAPWAP_ELEMENT_SESSIONID 35 - -/* */ -#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \ - sizeof(struct sc_capwap_header) + \ - sizeof(struct sc_capwap_data_message) + \ - sizeof(struct sc_capwap_message_element) + \ - sizeof(struct sc_capwap_sessionid_element)) - -/* Preamble */ -struct sc_capwap_preamble { -#if defined(__BIG_ENDIAN_BITFIELD) - uint8_t version: 4, - type: 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - uint8_t type: 4, - version: 4; -#endif -} __packed; - -/* DTLS header */ -struct sc_capwap_dtls_header { - struct sc_capwap_preamble preamble; - uint8_t reserved[3]; -} __packed; - -/* Plain header */ -struct sc_capwap_header { - struct sc_capwap_preamble preamble; -#if defined(__BIG_ENDIAN_BITFIELD) - uint16_t hlen: 5, - rid: 5, - wbid: 5, - flag_t: 1; - uint8_t flag_f: 1, - flag_l: 1, - flag_w: 1, - flag_m: 1, - flag_k: 1, - flag_res: 3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - uint16_t _rid_hi: 3, - hlen: 5, - flag_t: 1, - wbid: 5, - _rid_lo: 2; - uint8_t flag_res: 3, - flag_k: 1, - flag_m: 1, - flag_w: 1, - flag_l: 1, - flag_f: 1; -#endif - __be16 frag_id; - __be16 frag_off; -} __packed; - -/* Mac Address */ -#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8 -#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12 -#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12 -struct sc_capwap_radio_addr { - uint8_t length; - uint8_t addr[0]; -} __packed; - -/* Wireless Information */ -#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8 -#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8 -#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8 -struct sc_capwap_wireless_information { - uint8_t length; -} __packed; - -/* IEEE802.11 Wireless Information */ -struct sc_capwap_ieee80211_frame_info { - uint8_t rssi; - uint8_t snr; - __be16 rate; -} __packed; - -/* Destination WLANs */ -struct sc_capwap_destination_wlans { - __be16 wlanidbitmap; - __be16 reserved; -} __packed; - -/* */ -#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED) - -/* Data channel message */ -struct sc_capwap_data_message { - __be16 length; -} __packed; - -/* Message element */ -struct sc_capwap_message_element { - __be16 type; - __be16 length; -} __packed; - -/* Session id message element */ -struct sc_capwap_sessionid_element { - union { - uint8_t id[16]; - uint32_t id32[4]; - }; -} __packed; - -/* */ -#define MACADDRESS_EUI48_LENGTH 6 -struct sc_capwap_macaddress_eui48 { - uint8_t addr[MACADDRESS_EUI48_LENGTH]; -} __packed; - -/* */ -#define MACADDRESS_EUI64_LENGTH 8 -struct sc_capwap_macaddress_eui64 { - uint8_t addr[MACADDRESS_EUI64_LENGTH]; -} __packed; - -/* Capwap preamble */ -#define CAPWAP_PROTOCOL_VERSION 0 -#define CAPWAP_PREAMBLE_HEADER 0 -#define CAPWAP_PREAMBLE_DTLS_HEADER 1 - -#define CAPWAP_WIRELESS_BINDING_NONE 0 -#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 - -/* */ -#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)) - -/* */ -#define GET_VERSION_HEADER(x) ((x)->preamble.version) -#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y)) -#define GET_TYPE_HEADER(x) ((x)->preamble.type) -#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y)) - -#define GET_HLEN_HEADER(x) ((x)->hlen) -#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y)) -#if defined(__BIG_ENDIAN_BITFIELD) - #define GET_RID_HEADER(x) ((uint8_t)((x)->rid)) - #define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y)) -#elif defined(__LITTLE_ENDIAN_BITFIELD) - #define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo))) - #define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); }) -#endif -#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid)) -#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y)) - -#define IS_FLAG_T_HEADER(x) ((x)->flag_t) -#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0)) -#define IS_FLAG_F_HEADER(x) ((x)->flag_f) -#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0)) -#define IS_FLAG_L_HEADER(x) ((x)->flag_l) -#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0)) -#define IS_FLAG_W_HEADER(x) ((x)->flag_w) -#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0)) -#define IS_FLAG_M_HEADER(x) ((x)->flag_m) -#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0)) -#define IS_FLAG_K_HEADER(x) ((x)->flag_k) -#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0)) - -/* IEEE 802.11 Add WLAN */ -#define CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL 0 -#define CAPWAP_ADD_WLAN_TUNNELMODE_8023 1 -#define CAPWAP_ADD_WLAN_TUNNELMODE_80211 2 - -#endif /* __KMOD_CAPWAP_RFC_HEADER__ */ +#ifndef __KMOD_CAPWAP_RFC_HEADER__ +#define __KMOD_CAPWAP_RFC_HEADER__ + +#include +#include + +/* */ +#define CAPWAP_RADIOID_MAX_COUNT 31 +#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT)) + +#define CAPWAP_WLANID_MAX_COUNT 16 +#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT)) + +/* */ +#define CAPWAP_WIRELESS_BINDING_NONE 0 +#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 + +/* */ +#define CAPWAP_ELEMENT_SESSIONID 35 + +/* */ +#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \ + sizeof(struct sc_capwap_header) + \ + sizeof(struct sc_capwap_data_message) + \ + sizeof(struct sc_capwap_message_element) + \ + sizeof(struct sc_capwap_sessionid_element)) + +/* Preamble */ +struct sc_capwap_preamble { +#if defined(__BIG_ENDIAN_BITFIELD) + uint8_t version: 4, + type: 4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + uint8_t type: 4, + version: 4; +#endif +} __packed; + +/* DTLS header */ +struct sc_capwap_dtls_header { + struct sc_capwap_preamble preamble; + uint8_t reserved[3]; +} __packed; + +/* Plain header */ +struct sc_capwap_header { + struct sc_capwap_preamble preamble; +#if defined(__BIG_ENDIAN_BITFIELD) + uint16_t hlen: 5, + rid: 5, + wbid: 5, + flag_t: 1; + uint8_t flag_f: 1, + flag_l: 1, + flag_w: 1, + flag_m: 1, + flag_k: 1, + flag_res: 3; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + uint16_t _rid_hi: 3, + hlen: 5, + flag_t: 1, + wbid: 5, + _rid_lo: 2; + uint8_t flag_res: 3, + flag_k: 1, + flag_m: 1, + flag_w: 1, + flag_l: 1, + flag_f: 1; +#endif + __be16 frag_id; + __be16 frag_off; +} __packed; + +/* Mac Address */ +#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8 +#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12 +#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12 +struct sc_capwap_radio_addr { + uint8_t length; + uint8_t addr[0]; +} __packed; + +/* Wireless Information */ +#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8 +#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8 +#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8 +struct sc_capwap_wireless_information { + uint8_t length; +} __packed; + +/* IEEE802.11 Wireless Information */ +struct sc_capwap_ieee80211_frame_info { + uint8_t rssi; + uint8_t snr; + __be16 rate; +} __packed; + +/* Destination WLANs */ +struct sc_capwap_destination_wlans { + __be16 wlanidbitmap; + __be16 reserved; +} __packed; + +/* */ +#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED) + +/* Data channel message */ +struct sc_capwap_data_message { + __be16 length; +} __packed; + +/* Message element */ +struct sc_capwap_message_element { + __be16 type; + __be16 length; +} __packed; + +/* Session id message element */ +struct sc_capwap_sessionid_element { + union { + uint8_t id[16]; + uint32_t id32[4]; + }; +} __packed; + +/* */ +#define MACADDRESS_EUI48_LENGTH 6 +struct sc_capwap_macaddress_eui48 { + uint8_t addr[MACADDRESS_EUI48_LENGTH]; +} __packed; + +/* */ +#define MACADDRESS_EUI64_LENGTH 8 +struct sc_capwap_macaddress_eui64 { + uint8_t addr[MACADDRESS_EUI64_LENGTH]; +} __packed; + +/* Capwap preamble */ +#define CAPWAP_PROTOCOL_VERSION 0 +#define CAPWAP_PREAMBLE_HEADER 0 +#define CAPWAP_PREAMBLE_DTLS_HEADER 1 + +#define CAPWAP_WIRELESS_BINDING_NONE 0 +#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 + +/* */ +#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)) + +/* */ +#define GET_VERSION_HEADER(x) ((x)->preamble.version) +#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y)) +#define GET_TYPE_HEADER(x) ((x)->preamble.type) +#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y)) + +#define GET_HLEN_HEADER(x) ((x)->hlen) +#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y)) +#if defined(__BIG_ENDIAN_BITFIELD) + #define GET_RID_HEADER(x) ((uint8_t)((x)->rid)) + #define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y)) +#elif defined(__LITTLE_ENDIAN_BITFIELD) + #define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo))) + #define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); }) +#endif +#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid)) +#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y)) + +#define IS_FLAG_T_HEADER(x) ((x)->flag_t) +#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0)) +#define IS_FLAG_F_HEADER(x) ((x)->flag_f) +#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0)) +#define IS_FLAG_L_HEADER(x) ((x)->flag_l) +#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0)) +#define IS_FLAG_W_HEADER(x) ((x)->flag_w) +#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0)) +#define IS_FLAG_M_HEADER(x) ((x)->flag_m) +#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0)) +#define IS_FLAG_K_HEADER(x) ((x)->flag_k) +#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0)) + +/* IEEE 802.11 Add WLAN */ +#define CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL 0 +#define CAPWAP_ADD_WLAN_TUNNELMODE_8023 1 +#define CAPWAP_ADD_WLAN_TUNNELMODE_80211 2 + +#endif /* __KMOD_CAPWAP_RFC_HEADER__ */ diff --git a/src/ac/kmod/config.h b/src/ac/kmod/config.h index 2d1ff7c..31725fc 100644 --- a/src/ac/kmod/config.h +++ b/src/ac/kmod/config.h @@ -1,13 +1,13 @@ -#ifndef __KMOD_CONFIG_HEADER__ -#define __KMOD_CONFIG_HEADER__ - -#define DEBUGKMOD 1 - -#ifdef DEBUGKMOD -#define TRACEKMOD(s, args...) printk("(%d) " s, smp_processor_id(), ##args) -#else -#define TRACEKMOD(s, args...) -#endif - -#endif /* __KMOD_CONFIG_HEADER__ */ - +#ifndef __KMOD_CONFIG_HEADER__ +#define __KMOD_CONFIG_HEADER__ + +#define DEBUGKMOD 1 + +#ifdef DEBUGKMOD +#define TRACEKMOD(s, args...) printk("(%d) " s, smp_processor_id(), ##args) +#else +#define TRACEKMOD(s, args...) +#endif + +#endif /* __KMOD_CONFIG_HEADER__ */ + diff --git a/src/ac/kmod/iface.c b/src/ac/kmod/iface.c index 573e26a..ca0ca99 100644 --- a/src/ac/kmod/iface.c +++ b/src/ac/kmod/iface.c @@ -1,300 +1,300 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include "iface.h" -#include "station.h" -#include "capwap.h" - -/* */ -#define CAPWAP_IFACE_COUNT 8 -#define CAPWAP_IFACE_HASH(x) ((x) % CAPWAP_IFACE_COUNT) - -static LIST_HEAD(sc_iface_list); -static struct sc_netdev_priv* __rcu sc_iface_hash[CAPWAP_IFACE_COUNT]; - -/* */ -static void sc_iface_netdev_uninit(struct net_device* dev) { - struct sc_netdev_priv* search; - struct sc_capwap_station* temp; - struct sc_capwap_station* station; - int hash = CAPWAP_IFACE_HASH(dev->ifindex); - struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev); - - TRACEKMOD("### sc_iface_netdev_uninit\n"); - - sc_capwap_update_lock(); - - /* Close stations */ - list_for_each_entry_safe(station, temp, &priv->list_stations, list_dev) { - sc_stations_releaseconnection(station); - sc_stations_free(station); - } - - /* */ - if (!list_empty(&priv->list_stations)) { - TRACEKMOD("*** Bug: the list stations of interface is not empty\n"); - } - - if (!list_empty(&priv->list_connections)) { - TRACEKMOD("*** Bug: the list connections of interface is not empty\n"); - } - - /* Remove interface from hash */ - search = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked()); - if (search) { - if (priv == search) { - netif_tx_lock_bh(dev); - netif_carrier_off(dev); - netif_tx_unlock_bh(dev); - - rcu_assign_pointer(sc_iface_hash[hash], priv->next); - - list_del_rcu(&priv->list); - synchronize_net(); - - dev_put(dev); - } else { - while (rcu_access_pointer(search->next) && (rcu_access_pointer(search->next) != priv)) { - search = rcu_dereference_protected(search->next, sc_capwap_update_lock_is_locked()); - } - - if (rcu_access_pointer(search->next)) { - netif_tx_lock_bh(dev); - netif_carrier_off(dev); - netif_tx_unlock_bh(dev); - - rcu_assign_pointer(search->next, priv->next); - - list_del_rcu(&priv->list); - synchronize_net(); - - dev_put(dev); - } - } - } - - sc_capwap_update_unlock(); -} - -/* */ -static int sc_iface_netdev_open(struct net_device* dev) { - TRACEKMOD("### sc_iface_netdev_open\n"); - - netif_start_queue(dev); - return 0; -} - -/* */ -static int sc_iface_netdev_stop(struct net_device* dev) { - TRACEKMOD("### sc_iface_netdev_stop\n"); - - netif_stop_queue(dev); - return 0; -} - -/* */ -static int sc_iface_netdev_tx(struct sk_buff* skb, struct net_device* dev) { - struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev); - - TRACEKMOD("### sc_iface_netdev_tx %d\n", smp_processor_id()); - - if (dev->flags & IFF_UP) { - /* Ignore 802.1ad */ - if (skb->vlan_proto == htons(ETH_P_8021AD) || (eth_hdr(skb)->h_proto == htons(ETH_P_8021AD))) { - goto drop; - } - - /* */ - spin_lock(&priv->lock); - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - spin_unlock(&priv->lock); - - /* */ - CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_AC_TAP; - sc_capwap_recvpacket(skb); - } else { - goto drop; - } - - return 0; - -drop: - /* Drop packet */ - kfree_skb(skb); - - /* */ - spin_lock(&priv->lock); - dev->stats.rx_dropped++; - spin_unlock(&priv->lock); - - return 0; -} - -/* */ -static int sc_iface_netdev_change_mtu(struct net_device* dev, int new_mtu) { - TRACEKMOD("### sc_iface_netdev_change_mtu\n"); - - /* TODO */ - return 0; -} - -/* */ -static void sc_iface_netdev_setup(struct net_device* dev) { - struct sc_netdev_priv* devpriv = (struct sc_netdev_priv*)netdev_priv(dev); - - TRACEKMOD("### sc_iface_netdev_setup\n"); - - /* */ - memset(devpriv, 0, sizeof(struct sc_netdev_priv)); - devpriv->dev = dev; - spin_lock_init(&devpriv->lock); - INIT_LIST_HEAD(&devpriv->list_stations); - INIT_LIST_HEAD(&devpriv->list_connections); -} - -/* */ -static const struct net_device_ops capwap_netdev_ops = { - .ndo_uninit = sc_iface_netdev_uninit, - .ndo_open = sc_iface_netdev_open, - .ndo_stop = sc_iface_netdev_stop, - .ndo_start_xmit = sc_iface_netdev_tx, - .ndo_change_mtu = sc_iface_netdev_change_mtu, -}; - -/* */ -int sc_iface_create(const char* ifname, uint16_t mtu) { - int err; - int hash; - struct net_device* dev; - struct sc_netdev_priv* priv; - - TRACEKMOD("### sc_iface_create\n"); - - /* Create interface */ - dev = alloc_netdev(sizeof(struct sc_netdev_priv), ifname, sc_iface_netdev_setup); - if (!dev) { - return -ENOMEM; - } - - /* */ - priv = (struct sc_netdev_priv*)netdev_priv(dev); - dev->netdev_ops = &capwap_netdev_ops; - ether_setup(dev); - - eth_hw_addr_random(dev); - - dev->mtu = mtu; - - dev->hw_features = NETIF_F_HW_CSUM; - dev->features = dev->hw_features; - - /* */ - err = register_netdev(dev); - if (err) { - free_netdev(dev); - return err; - } - - /* */ - hash = CAPWAP_IFACE_HASH(dev->ifindex); - - /* */ - sc_capwap_update_lock(); - - list_add_rcu(&priv->list, &sc_iface_list); - - priv->next = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked()); - rcu_assign_pointer(sc_iface_hash[hash], priv); - dev_hold(dev); - - sc_capwap_update_unlock(); - - /* Enable carrier */ - netif_tx_lock_bh(dev); - netif_carrier_on(dev); - netif_tx_unlock_bh(dev); - - return dev->ifindex; -} - -/* */ -int sc_iface_delete(uint32_t ifindex) { - struct sc_netdev_priv* priv; - struct net_device* dev = NULL; - - TRACEKMOD("### sc_iface_delete\n"); - - rcu_read_lock(); - - /* Search device */ - priv = sc_iface_search(ifindex); - if (priv) { - dev = priv->dev; - } - - rcu_read_unlock(); - - /* */ - if (!dev) { - return -ENOENT; - } - - /* Unregister device */ - unregister_netdev(dev); - free_netdev(dev); - - return 0; -} - -/* */ -struct sc_netdev_priv* sc_iface_search(uint32_t ifindex) { - struct sc_netdev_priv* priv; - - TRACEKMOD("### sc_iface_search\n"); - - priv = rcu_dereference_check(sc_iface_hash[CAPWAP_IFACE_HASH(ifindex)], lockdep_is_held(&sc_iface_mutex)); - while (priv) { - if (priv->dev->ifindex == ifindex) { - break; - } - - /* */ - priv = rcu_dereference_check(priv->next, lockdep_is_held(&sc_iface_mutex)); - } - - return priv; -} - -/* */ -void sc_iface_closeall(void) { - struct sc_netdev_priv* priv; - - TRACEKMOD("### sc_iface_closeall\n"); - - for (;;) { - struct net_device* dev = NULL; - - rcu_read_lock(); - - /* Get device */ - priv = list_first_or_null_rcu(&sc_iface_list, struct sc_netdev_priv, list); - if (priv) { - dev = priv->dev; - } - - rcu_read_unlock(); - - /* */ - if (!dev) { - break; - } - - /* Unregister device */ - unregister_netdev(dev); - free_netdev(dev); - } -} +#include "config.h" +#include +#include +#include +#include +#include +#include "iface.h" +#include "station.h" +#include "capwap.h" + +/* */ +#define CAPWAP_IFACE_COUNT 8 +#define CAPWAP_IFACE_HASH(x) ((x) % CAPWAP_IFACE_COUNT) + +static LIST_HEAD(sc_iface_list); +static struct sc_netdev_priv* __rcu sc_iface_hash[CAPWAP_IFACE_COUNT]; + +/* */ +static void sc_iface_netdev_uninit(struct net_device* dev) { + struct sc_netdev_priv* search; + struct sc_capwap_station* temp; + struct sc_capwap_station* station; + int hash = CAPWAP_IFACE_HASH(dev->ifindex); + struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev); + + TRACEKMOD("### sc_iface_netdev_uninit\n"); + + sc_capwap_update_lock(); + + /* Close stations */ + list_for_each_entry_safe(station, temp, &priv->list_stations, list_dev) { + sc_stations_releaseconnection(station); + sc_stations_free(station); + } + + /* */ + if (!list_empty(&priv->list_stations)) { + TRACEKMOD("*** Bug: the list stations of interface is not empty\n"); + } + + if (!list_empty(&priv->list_connections)) { + TRACEKMOD("*** Bug: the list connections of interface is not empty\n"); + } + + /* Remove interface from hash */ + search = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked()); + if (search) { + if (priv == search) { + netif_tx_lock_bh(dev); + netif_carrier_off(dev); + netif_tx_unlock_bh(dev); + + rcu_assign_pointer(sc_iface_hash[hash], priv->next); + + list_del_rcu(&priv->list); + synchronize_net(); + + dev_put(dev); + } else { + while (rcu_access_pointer(search->next) && (rcu_access_pointer(search->next) != priv)) { + search = rcu_dereference_protected(search->next, sc_capwap_update_lock_is_locked()); + } + + if (rcu_access_pointer(search->next)) { + netif_tx_lock_bh(dev); + netif_carrier_off(dev); + netif_tx_unlock_bh(dev); + + rcu_assign_pointer(search->next, priv->next); + + list_del_rcu(&priv->list); + synchronize_net(); + + dev_put(dev); + } + } + } + + sc_capwap_update_unlock(); +} + +/* */ +static int sc_iface_netdev_open(struct net_device* dev) { + TRACEKMOD("### sc_iface_netdev_open\n"); + + netif_start_queue(dev); + return 0; +} + +/* */ +static int sc_iface_netdev_stop(struct net_device* dev) { + TRACEKMOD("### sc_iface_netdev_stop\n"); + + netif_stop_queue(dev); + return 0; +} + +/* */ +static int sc_iface_netdev_tx(struct sk_buff* skb, struct net_device* dev) { + struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev); + + TRACEKMOD("### sc_iface_netdev_tx %d\n", smp_processor_id()); + + if (dev->flags & IFF_UP) { + /* Ignore 802.1ad */ + if (skb->vlan_proto == htons(ETH_P_8021AD) || (eth_hdr(skb)->h_proto == htons(ETH_P_8021AD))) { + goto drop; + } + + /* */ + spin_lock(&priv->lock); + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + spin_unlock(&priv->lock); + + /* */ + CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_AC_TAP; + sc_capwap_recvpacket(skb); + } else { + goto drop; + } + + return 0; + +drop: + /* Drop packet */ + kfree_skb(skb); + + /* */ + spin_lock(&priv->lock); + dev->stats.rx_dropped++; + spin_unlock(&priv->lock); + + return 0; +} + +/* */ +static int sc_iface_netdev_change_mtu(struct net_device* dev, int new_mtu) { + TRACEKMOD("### sc_iface_netdev_change_mtu\n"); + + /* TODO */ + return 0; +} + +/* */ +static void sc_iface_netdev_setup(struct net_device* dev) { + struct sc_netdev_priv* devpriv = (struct sc_netdev_priv*)netdev_priv(dev); + + TRACEKMOD("### sc_iface_netdev_setup\n"); + + /* */ + memset(devpriv, 0, sizeof(struct sc_netdev_priv)); + devpriv->dev = dev; + spin_lock_init(&devpriv->lock); + INIT_LIST_HEAD(&devpriv->list_stations); + INIT_LIST_HEAD(&devpriv->list_connections); +} + +/* */ +static const struct net_device_ops capwap_netdev_ops = { + .ndo_uninit = sc_iface_netdev_uninit, + .ndo_open = sc_iface_netdev_open, + .ndo_stop = sc_iface_netdev_stop, + .ndo_start_xmit = sc_iface_netdev_tx, + .ndo_change_mtu = sc_iface_netdev_change_mtu, +}; + +/* */ +int sc_iface_create(const char* ifname, uint16_t mtu) { + int err; + int hash; + struct net_device* dev; + struct sc_netdev_priv* priv; + + TRACEKMOD("### sc_iface_create\n"); + + /* Create interface */ + dev = alloc_netdev(sizeof(struct sc_netdev_priv), ifname, sc_iface_netdev_setup); + if (!dev) { + return -ENOMEM; + } + + /* */ + priv = (struct sc_netdev_priv*)netdev_priv(dev); + dev->netdev_ops = &capwap_netdev_ops; + ether_setup(dev); + + eth_hw_addr_random(dev); + + dev->mtu = mtu; + + dev->hw_features = NETIF_F_HW_CSUM; + dev->features = dev->hw_features; + + /* */ + err = register_netdev(dev); + if (err) { + free_netdev(dev); + return err; + } + + /* */ + hash = CAPWAP_IFACE_HASH(dev->ifindex); + + /* */ + sc_capwap_update_lock(); + + list_add_rcu(&priv->list, &sc_iface_list); + + priv->next = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked()); + rcu_assign_pointer(sc_iface_hash[hash], priv); + dev_hold(dev); + + sc_capwap_update_unlock(); + + /* Enable carrier */ + netif_tx_lock_bh(dev); + netif_carrier_on(dev); + netif_tx_unlock_bh(dev); + + return dev->ifindex; +} + +/* */ +int sc_iface_delete(uint32_t ifindex) { + struct sc_netdev_priv* priv; + struct net_device* dev = NULL; + + TRACEKMOD("### sc_iface_delete\n"); + + rcu_read_lock(); + + /* Search device */ + priv = sc_iface_search(ifindex); + if (priv) { + dev = priv->dev; + } + + rcu_read_unlock(); + + /* */ + if (!dev) { + return -ENOENT; + } + + /* Unregister device */ + unregister_netdev(dev); + free_netdev(dev); + + return 0; +} + +/* */ +struct sc_netdev_priv* sc_iface_search(uint32_t ifindex) { + struct sc_netdev_priv* priv; + + TRACEKMOD("### sc_iface_search\n"); + + priv = rcu_dereference_check(sc_iface_hash[CAPWAP_IFACE_HASH(ifindex)], lockdep_is_held(&sc_iface_mutex)); + while (priv) { + if (priv->dev->ifindex == ifindex) { + break; + } + + /* */ + priv = rcu_dereference_check(priv->next, lockdep_is_held(&sc_iface_mutex)); + } + + return priv; +} + +/* */ +void sc_iface_closeall(void) { + struct sc_netdev_priv* priv; + + TRACEKMOD("### sc_iface_closeall\n"); + + for (;;) { + struct net_device* dev = NULL; + + rcu_read_lock(); + + /* Get device */ + priv = list_first_or_null_rcu(&sc_iface_list, struct sc_netdev_priv, list); + if (priv) { + dev = priv->dev; + } + + rcu_read_unlock(); + + /* */ + if (!dev) { + break; + } + + /* Unregister device */ + unregister_netdev(dev); + free_netdev(dev); + } +} diff --git a/src/ac/kmod/iface.h b/src/ac/kmod/iface.h index f2c43b4..d487778 100644 --- a/src/ac/kmod/iface.h +++ b/src/ac/kmod/iface.h @@ -1,27 +1,27 @@ -#ifndef __KMOD_AC_IFACE_HEADER__ -#define __KMOD_AC_IFACE_HEADER__ - -/* */ -struct sc_netdev_priv { - struct list_head list; - struct net_device* dev; - - spinlock_t lock; - - struct list_head list_stations; - struct list_head list_connections; - - struct sc_netdev_priv* __rcu next; -}; - -/* */ -int sc_iface_create(const char* ifname, uint16_t mtu); -int sc_iface_delete(uint32_t ifindex); - -/* */ -struct sc_netdev_priv* sc_iface_search(uint32_t ifindex); - -/* */ -void sc_iface_closeall(void); - -#endif /* __KMOD_AC_IFACE_HEADER__ */ +#ifndef __KMOD_AC_IFACE_HEADER__ +#define __KMOD_AC_IFACE_HEADER__ + +/* */ +struct sc_netdev_priv { + struct list_head list; + struct net_device* dev; + + spinlock_t lock; + + struct list_head list_stations; + struct list_head list_connections; + + struct sc_netdev_priv* __rcu next; +}; + +/* */ +int sc_iface_create(const char* ifname, uint16_t mtu); +int sc_iface_delete(uint32_t ifindex); + +/* */ +struct sc_netdev_priv* sc_iface_search(uint32_t ifindex); + +/* */ +void sc_iface_closeall(void); + +#endif /* __KMOD_AC_IFACE_HEADER__ */ diff --git a/src/ac/kmod/main.c b/src/ac/kmod/main.c index 5c9661a..375e14e 100644 --- a/src/ac/kmod/main.c +++ b/src/ac/kmod/main.c @@ -1,32 +1,32 @@ -#include "config.h" -#include -#include -#include "netlinkapp.h" - -/* */ -static int __init smartcapwap_ac_init(void) { - int ret; - - TRACEKMOD("### smartcapwap_ac_init\n"); - - /* Initialize netlink */ - ret = sc_netlink_init(); - if (ret) { - return ret; - } - - return ret; -} -module_init(smartcapwap_ac_init); - -/* */ -static void __exit smartcapwap_ac_exit(void) { - TRACEKMOD("### smartcapwap_ac_exit\n"); - - sc_netlink_exit(); -} -module_exit(smartcapwap_ac_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Massimo Vellucci "); -MODULE_DESCRIPTION("SmartCAPWAP AC Data Channel Module"); +#include "config.h" +#include +#include +#include "netlinkapp.h" + +/* */ +static int __init smartcapwap_ac_init(void) { + int ret; + + TRACEKMOD("### smartcapwap_ac_init\n"); + + /* Initialize netlink */ + ret = sc_netlink_init(); + if (ret) { + return ret; + } + + return ret; +} +module_init(smartcapwap_ac_init); + +/* */ +static void __exit smartcapwap_ac_exit(void) { + TRACEKMOD("### smartcapwap_ac_exit\n"); + + sc_netlink_exit(); +} +module_exit(smartcapwap_ac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Massimo Vellucci "); +MODULE_DESCRIPTION("SmartCAPWAP AC Data Channel Module"); diff --git a/src/ac/kmod/netlinkapp.c b/src/ac/kmod/netlinkapp.c index d5e6355..0dd98da 100644 --- a/src/ac/kmod/netlinkapp.c +++ b/src/ac/kmod/netlinkapp.c @@ -1,611 +1,611 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nlsmartcapwap.h" -#include "netlinkapp.h" -#include "capwap.h" -#include "iface.h" - -/* */ -static u32 sc_netlink_usermodeid; - -/* */ -static int sc_netlink_pre_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info); -static void sc_netlink_post_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info); - -/* Netlink Family */ -static struct genl_family sc_netlink_family = { - .id = GENL_ID_GENERATE, - .name = NLSMARTCAPWAP_GENL_NAME, - .hdrsize = 0, - .version = 1, - .maxattr = NLSMARTCAPWAP_ATTR_MAX, - .netnsok = true, - .pre_doit = sc_netlink_pre_doit, - .post_doit = sc_netlink_post_doit, -}; - -/* */ -static int sc_netlink_pre_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_pre_doit: %d\n", (int)ops->cmd); - - return 0; -} - -/* */ -static void sc_netlink_post_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_post_doit: %d\n", (int)ops->cmd); -} - -/* */ -static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) { - union capwap_addr sockaddr; - - TRACEKMOD("### sc_netlink_bind\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Get bind address */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) { - return -EINVAL; - } - - memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage)); - if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) { - return -EINVAL; - } - - /* Bind socket */ - return sc_capwap_bind(&sockaddr); -} - -/* */ -static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_send_keepalive\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Check Session ID */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) { - return -EINVAL; - } - - /* Send keep-alive packet */ - return sc_capwap_sendkeepalive((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID])); -} - -/* */ -static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) { - int length; - struct sk_buff* skbdata; - struct sc_skb_capwap_cb* cb; - - TRACEKMOD("### sc_netlink_send_data\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { - return -EINVAL; - } - - /* Create socket buffer */ - length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]); - skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL); - if (!skbdata) { - return -ENOMEM; - } - - /* Reserve space for Capwap Header */ - skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH); - - /* Copy data into socket buffer */ - memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length); - - /* */ - cb = CAPWAP_SKB_CB(skbdata); - cb->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE | SKB_CAPWAP_FLAG_SESSIONID | SKB_CAPWAP_FLAG_RADIOID | SKB_CAPWAP_FLAG_BINDING; - memcpy(&cb->sessionid, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), sizeof(struct sc_capwap_sessionid_element)); - cb->radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); - cb->binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]); - - /* */ - sc_capwap_recvpacket(skbdata); - return 0; -} - -/* */ -static int sc_netlink_new_session(struct sk_buff* skb, struct genl_info* info) { - uint16_t mtu = DEFAULT_MTU; - - TRACEKMOD("### sc_netlink_new_session\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Check Session ID & Binding */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) { - return -EINVAL; - } - - /* Get MTU */ - if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) { - mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]); - if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) { - return -EINVAL; - } - } - - /* New session */ - return sc_capwap_newsession((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]), mtu); -} - -/* */ -static int sc_netlink_delete_session(struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_delete_session\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Check Session ID */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) { - return -EINVAL; - } - - /* Delete session */ - return sc_capwap_deletesession((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID])); -} - -/* */ -static int sc_netlink_add_wlan(struct sk_buff* skb, struct genl_info* info) { - uint8_t radioid; - uint8_t wlanid; - - TRACEKMOD("### sc_netlink_add_wlan\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Check params */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID] || !info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS] || !info->attrs[NLSMARTCAPWAP_ATTR_MACMODE] || !info->attrs[NLSMARTCAPWAP_ATTR_TUNNELMODE]) { - return -EINVAL; - } - - /* */ - radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); - wlanid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]); - if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { - return -EINVAL; - } - - /* */ - return sc_capwap_addwlan((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), radioid, wlanid, (uint8_t*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_MACMODE]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_TUNNELMODE])); -} - -/* */ -static int sc_netlink_remove_wlan(struct sk_buff* skb, struct genl_info* info) { - uint8_t radioid; - uint8_t wlanid; - - TRACEKMOD("### sc_netlink_remove_wlan\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Check Session ID */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID]) { - return -EINVAL; - } - - /* */ - radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); - wlanid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]); - if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { - return -EINVAL; - } - - return sc_capwap_removewlan((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), radioid, wlanid); -} - -/* */ -static int sc_netlink_auth_station(struct sk_buff* skb, struct genl_info* info) { - uint8_t radioid; - uint8_t wlanid; - uint16_t vlan = 0; - - TRACEKMOD("### sc_netlink_auth_station\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Check params */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS] || !info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID]) { - return -EINVAL; - } - - /* */ - radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); - wlanid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]); - if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { - return -EINVAL; - } - - /* VLAN */ - if (info->attrs[NLSMARTCAPWAP_ATTR_VLAN]) { - vlan = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_VLAN]); - } - - /* */ - return sc_capwap_authstation((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), (uint8_t*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS]), nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]), radioid, wlanid, vlan); -} - -/* */ -static int sc_netlink_deauth_station(struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_deauth_station\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Check params */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS]) { - return -EINVAL; - } - - /* */ - return sc_capwap_deauthstation((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), (uint8_t*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS])); -} - -/* */ -static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) { - int ret; - - TRACEKMOD("### sc_netlink_link\n"); - - /* */ - if (sc_netlink_usermodeid) { - TRACEKMOD("*** Busy kernel link\n"); - return -EBUSY; - } - - /* Initialize library */ - ret = sc_capwap_init(); - if (ret) { - return ret; - } - - /* Deny unload module */ - try_module_get(THIS_MODULE); - sc_netlink_usermodeid = info->snd_portid; - - return 0; -} - -/* */ -static int sc_netlink_add_iface(struct sk_buff* skb, struct genl_info* info) { - int err; - void* hdr; - uint16_t mtu; - int ifindex; - struct sk_buff *msg; - - TRACEKMOD("### sc_netlink_add_iface\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_NAME] || !info->attrs[NLSMARTCAPWAP_ATTR_MTU]) { - return -EINVAL; - } - - /* */ - mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]); - if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) { - return -EINVAL; - } - - /* */ - ifindex = sc_iface_create((char*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_NAME]), mtu); - if (ifindex < 0) { - return ifindex; - } - - /* Send response */ - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto error; - } - - hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_ADD_IFACE); - if (IS_ERR(hdr)) { - err = PTR_ERR(hdr); - goto error2; - } - - if (nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFPHY_INDEX, (uint32_t)ifindex)) { - err = -ENOBUFS; - goto error2; - } - - genlmsg_end(msg, hdr); - return genlmsg_reply(msg, info); - -error2: - nlmsg_free(msg); - -error: - sc_iface_delete((uint32_t)ifindex); - return err; -} - -/* */ -static int sc_netlink_delete_iface(struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_delete_iface\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]) { - return -EINVAL; - } - - return sc_iface_delete(nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX])); -} - -/* */ -static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) { - struct netlink_notify* notify = (struct netlink_notify*)_notify; - - /* */ - if ((state == NETLINK_URELEASE) && (sc_netlink_usermodeid == notify->portid)) { - /* Close capwap engine */ - sc_capwap_close(); - - /* Allow unload module */ - module_put(THIS_MODULE); - sc_netlink_usermodeid = 0; - } - - return NOTIFY_DONE; -} - -/* */ -static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = { - [NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 }, - [NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) }, - [NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_WLANID] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_MACMODE] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_TUNNELMODE] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) }, - [NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN + CAPWAP_HEADER_MAX_LENGTH }, - [NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 }, - [NLSMARTCAPWAP_ATTR_IFPHY_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ }, - [NLSMARTCAPWAP_ATTR_IFPHY_INDEX] = { .type = NLA_U32 }, - [NLSMARTCAPWAP_ATTR_MACADDRESS] = { .type = NLA_BINARY, .len = MACADDRESS_EUI48_LENGTH }, - [NLSMARTCAPWAP_ATTR_BSSID] = { .type = NLA_BINARY, .len = MACADDRESS_EUI48_LENGTH }, - [NLSMARTCAPWAP_ATTR_VLAN] = { .type = NLA_U16 }, -}; - -/* Netlink Ops */ -static struct genl_ops sc_netlink_ops[] = { - { - .cmd = NLSMARTCAPWAP_CMD_LINK, - .doit = sc_netlink_link, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_ADD_IFACE, - .doit = sc_netlink_add_iface, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_DELETE_IFACE, - .doit = sc_netlink_delete_iface, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_BIND, - .doit = sc_netlink_bind, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, - .doit = sc_netlink_send_keepalive, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_SEND_DATA, - .doit = sc_netlink_send_data, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_NEW_SESSION, - .doit = sc_netlink_new_session, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_DELETE_SESSION, - .doit = sc_netlink_delete_session, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_ADD_WLAN, - .doit = sc_netlink_add_wlan, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_REMOVE_WLAN, - .doit = sc_netlink_remove_wlan, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_AUTH_STATION, - .doit = sc_netlink_auth_station, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_DEAUTH_STATION, - .doit = sc_netlink_deauth_station, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, -}; - -/* Netlink notify */ -static struct notifier_block sc_netlink_notifier = { - .notifier_call = sc_netlink_notify, -}; - -/* */ -int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) { - void* msg; - struct sk_buff* sk_msg; - - TRACEKMOD("### sc_netlink_notify_recv_keepalive\n"); - - /* Alloc message */ - sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!sk_msg) { - return -ENOMEM; - } - - /* Set command */ - msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE); - if (!msg) { - goto error; - } - - /* */ - if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid)) { - goto error2; - } - - /* Send message */ - genlmsg_end(sk_msg, msg); - return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); - -error2: - genlmsg_cancel(sk_msg, msg); -error: - nlmsg_free(sk_msg); - return -ENOMEM; -} - -/* */ -int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length) { - void* msg; - struct sk_buff* sk_msg; - - TRACEKMOD("### sc_netlink_notify_recv_data\n"); - - /* Alloc message */ - sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!sk_msg) { - return -ENOMEM; - } - - /* Set command */ - msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA); - if (!msg) { - goto error; - } - - /* */ - if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid) || - nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) { - goto error2; - } - - /* Send message */ - genlmsg_end(sk_msg, msg); - return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); - -error2: - genlmsg_cancel(sk_msg, msg); -error: - nlmsg_free(sk_msg); - return -ENOMEM; -} - -/* */ -int sc_netlink_init(void) { - int ret; - - TRACEKMOD("### sc_netlink_init\n"); - - /* Register netlink family */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) - ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops, sizeof(sc_netlink_ops) / sizeof(sc_netlink_ops[0])); -#else - ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops); -#endif - if (ret) { - return ret; - } - - /* Register netlink notifier */ - ret = netlink_register_notifier(&sc_netlink_notifier); - if (ret) { - genl_unregister_family(&sc_netlink_family); - return ret; - } - - return 0; -} - -/* */ -void sc_netlink_exit(void) { - TRACEKMOD("### sc_netlink_exit\n"); - - netlink_unregister_notifier(&sc_netlink_notifier); - genl_unregister_family(&sc_netlink_family); -} +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nlsmartcapwap.h" +#include "netlinkapp.h" +#include "capwap.h" +#include "iface.h" + +/* */ +static u32 sc_netlink_usermodeid; + +/* */ +static int sc_netlink_pre_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info); +static void sc_netlink_post_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info); + +/* Netlink Family */ +static struct genl_family sc_netlink_family = { + .id = GENL_ID_GENERATE, + .name = NLSMARTCAPWAP_GENL_NAME, + .hdrsize = 0, + .version = 1, + .maxattr = NLSMARTCAPWAP_ATTR_MAX, + .netnsok = true, + .pre_doit = sc_netlink_pre_doit, + .post_doit = sc_netlink_post_doit, +}; + +/* */ +static int sc_netlink_pre_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_pre_doit: %d\n", (int)ops->cmd); + + return 0; +} + +/* */ +static void sc_netlink_post_doit(struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_post_doit: %d\n", (int)ops->cmd); +} + +/* */ +static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) { + union capwap_addr sockaddr; + + TRACEKMOD("### sc_netlink_bind\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Get bind address */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) { + return -EINVAL; + } + + memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage)); + if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) { + return -EINVAL; + } + + /* Bind socket */ + return sc_capwap_bind(&sockaddr); +} + +/* */ +static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_send_keepalive\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Check Session ID */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) { + return -EINVAL; + } + + /* Send keep-alive packet */ + return sc_capwap_sendkeepalive((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID])); +} + +/* */ +static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) { + int length; + struct sk_buff* skbdata; + struct sc_skb_capwap_cb* cb; + + TRACEKMOD("### sc_netlink_send_data\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { + return -EINVAL; + } + + /* Create socket buffer */ + length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]); + skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL); + if (!skbdata) { + return -ENOMEM; + } + + /* Reserve space for Capwap Header */ + skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH); + + /* Copy data into socket buffer */ + memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length); + + /* */ + cb = CAPWAP_SKB_CB(skbdata); + cb->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE | SKB_CAPWAP_FLAG_SESSIONID | SKB_CAPWAP_FLAG_RADIOID | SKB_CAPWAP_FLAG_BINDING; + memcpy(&cb->sessionid, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), sizeof(struct sc_capwap_sessionid_element)); + cb->radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); + cb->binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]); + + /* */ + sc_capwap_recvpacket(skbdata); + return 0; +} + +/* */ +static int sc_netlink_new_session(struct sk_buff* skb, struct genl_info* info) { + uint16_t mtu = DEFAULT_MTU; + + TRACEKMOD("### sc_netlink_new_session\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Check Session ID & Binding */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) { + return -EINVAL; + } + + /* Get MTU */ + if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) { + mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]); + if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) { + return -EINVAL; + } + } + + /* New session */ + return sc_capwap_newsession((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]), mtu); +} + +/* */ +static int sc_netlink_delete_session(struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_delete_session\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Check Session ID */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) { + return -EINVAL; + } + + /* Delete session */ + return sc_capwap_deletesession((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID])); +} + +/* */ +static int sc_netlink_add_wlan(struct sk_buff* skb, struct genl_info* info) { + uint8_t radioid; + uint8_t wlanid; + + TRACEKMOD("### sc_netlink_add_wlan\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Check params */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID] || !info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS] || !info->attrs[NLSMARTCAPWAP_ATTR_MACMODE] || !info->attrs[NLSMARTCAPWAP_ATTR_TUNNELMODE]) { + return -EINVAL; + } + + /* */ + radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); + wlanid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]); + if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { + return -EINVAL; + } + + /* */ + return sc_capwap_addwlan((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), radioid, wlanid, (uint8_t*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_MACMODE]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_TUNNELMODE])); +} + +/* */ +static int sc_netlink_remove_wlan(struct sk_buff* skb, struct genl_info* info) { + uint8_t radioid; + uint8_t wlanid; + + TRACEKMOD("### sc_netlink_remove_wlan\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Check Session ID */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID]) { + return -EINVAL; + } + + /* */ + radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); + wlanid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]); + if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { + return -EINVAL; + } + + return sc_capwap_removewlan((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), radioid, wlanid); +} + +/* */ +static int sc_netlink_auth_station(struct sk_buff* skb, struct genl_info* info) { + uint8_t radioid; + uint8_t wlanid; + uint16_t vlan = 0; + + TRACEKMOD("### sc_netlink_auth_station\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Check params */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS] || !info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX] || !info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID]) { + return -EINVAL; + } + + /* */ + radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); + wlanid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]); + if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { + return -EINVAL; + } + + /* VLAN */ + if (info->attrs[NLSMARTCAPWAP_ATTR_VLAN]) { + vlan = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_VLAN]); + } + + /* */ + return sc_capwap_authstation((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), (uint8_t*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS]), nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]), radioid, wlanid, vlan); +} + +/* */ +static int sc_netlink_deauth_station(struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_deauth_station\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Check params */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] || !info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS]) { + return -EINVAL; + } + + /* */ + return sc_capwap_deauthstation((struct sc_capwap_sessionid_element*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), (uint8_t*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_MACADDRESS])); +} + +/* */ +static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) { + int ret; + + TRACEKMOD("### sc_netlink_link\n"); + + /* */ + if (sc_netlink_usermodeid) { + TRACEKMOD("*** Busy kernel link\n"); + return -EBUSY; + } + + /* Initialize library */ + ret = sc_capwap_init(); + if (ret) { + return ret; + } + + /* Deny unload module */ + try_module_get(THIS_MODULE); + sc_netlink_usermodeid = info->snd_portid; + + return 0; +} + +/* */ +static int sc_netlink_add_iface(struct sk_buff* skb, struct genl_info* info) { + int err; + void* hdr; + uint16_t mtu; + int ifindex; + struct sk_buff *msg; + + TRACEKMOD("### sc_netlink_add_iface\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_NAME] || !info->attrs[NLSMARTCAPWAP_ATTR_MTU]) { + return -EINVAL; + } + + /* */ + mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]); + if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) { + return -EINVAL; + } + + /* */ + ifindex = sc_iface_create((char*)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_NAME]), mtu); + if (ifindex < 0) { + return ifindex; + } + + /* Send response */ + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto error; + } + + hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_ADD_IFACE); + if (IS_ERR(hdr)) { + err = PTR_ERR(hdr); + goto error2; + } + + if (nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFPHY_INDEX, (uint32_t)ifindex)) { + err = -ENOBUFS; + goto error2; + } + + genlmsg_end(msg, hdr); + return genlmsg_reply(msg, info); + +error2: + nlmsg_free(msg); + +error: + sc_iface_delete((uint32_t)ifindex); + return err; +} + +/* */ +static int sc_netlink_delete_iface(struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_delete_iface\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX]) { + return -EINVAL; + } + + return sc_iface_delete(nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFPHY_INDEX])); +} + +/* */ +static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) { + struct netlink_notify* notify = (struct netlink_notify*)_notify; + + /* */ + if ((state == NETLINK_URELEASE) && (sc_netlink_usermodeid == notify->portid)) { + /* Close capwap engine */ + sc_capwap_close(); + + /* Allow unload module */ + module_put(THIS_MODULE); + sc_netlink_usermodeid = 0; + } + + return NOTIFY_DONE; +} + +/* */ +static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = { + [NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 }, + [NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) }, + [NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_WLANID] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_MACMODE] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_TUNNELMODE] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) }, + [NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN + CAPWAP_HEADER_MAX_LENGTH }, + [NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 }, + [NLSMARTCAPWAP_ATTR_IFPHY_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ }, + [NLSMARTCAPWAP_ATTR_IFPHY_INDEX] = { .type = NLA_U32 }, + [NLSMARTCAPWAP_ATTR_MACADDRESS] = { .type = NLA_BINARY, .len = MACADDRESS_EUI48_LENGTH }, + [NLSMARTCAPWAP_ATTR_BSSID] = { .type = NLA_BINARY, .len = MACADDRESS_EUI48_LENGTH }, + [NLSMARTCAPWAP_ATTR_VLAN] = { .type = NLA_U16 }, +}; + +/* Netlink Ops */ +static struct genl_ops sc_netlink_ops[] = { + { + .cmd = NLSMARTCAPWAP_CMD_LINK, + .doit = sc_netlink_link, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_ADD_IFACE, + .doit = sc_netlink_add_iface, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_DELETE_IFACE, + .doit = sc_netlink_delete_iface, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_BIND, + .doit = sc_netlink_bind, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, + .doit = sc_netlink_send_keepalive, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_SEND_DATA, + .doit = sc_netlink_send_data, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_NEW_SESSION, + .doit = sc_netlink_new_session, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_DELETE_SESSION, + .doit = sc_netlink_delete_session, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_ADD_WLAN, + .doit = sc_netlink_add_wlan, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_REMOVE_WLAN, + .doit = sc_netlink_remove_wlan, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_AUTH_STATION, + .doit = sc_netlink_auth_station, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_DEAUTH_STATION, + .doit = sc_netlink_deauth_station, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +/* Netlink notify */ +static struct notifier_block sc_netlink_notifier = { + .notifier_call = sc_netlink_notify, +}; + +/* */ +int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) { + void* msg; + struct sk_buff* sk_msg; + + TRACEKMOD("### sc_netlink_notify_recv_keepalive\n"); + + /* Alloc message */ + sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!sk_msg) { + return -ENOMEM; + } + + /* Set command */ + msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE); + if (!msg) { + goto error; + } + + /* */ + if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid)) { + goto error2; + } + + /* Send message */ + genlmsg_end(sk_msg, msg); + return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); + +error2: + genlmsg_cancel(sk_msg, msg); +error: + nlmsg_free(sk_msg); + return -ENOMEM; +} + +/* */ +int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length) { + void* msg; + struct sk_buff* sk_msg; + + TRACEKMOD("### sc_netlink_notify_recv_data\n"); + + /* Alloc message */ + sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!sk_msg) { + return -ENOMEM; + } + + /* Set command */ + msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA); + if (!msg) { + goto error; + } + + /* */ + if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct sc_capwap_sessionid_element), sessionid) || + nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) { + goto error2; + } + + /* Send message */ + genlmsg_end(sk_msg, msg); + return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); + +error2: + genlmsg_cancel(sk_msg, msg); +error: + nlmsg_free(sk_msg); + return -ENOMEM; +} + +/* */ +int sc_netlink_init(void) { + int ret; + + TRACEKMOD("### sc_netlink_init\n"); + + /* Register netlink family */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) + ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops, sizeof(sc_netlink_ops) / sizeof(sc_netlink_ops[0])); +#else + ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops); +#endif + if (ret) { + return ret; + } + + /* Register netlink notifier */ + ret = netlink_register_notifier(&sc_netlink_notifier); + if (ret) { + genl_unregister_family(&sc_netlink_family); + return ret; + } + + return 0; +} + +/* */ +void sc_netlink_exit(void) { + TRACEKMOD("### sc_netlink_exit\n"); + + netlink_unregister_notifier(&sc_netlink_notifier); + genl_unregister_family(&sc_netlink_family); +} diff --git a/src/ac/kmod/netlinkapp.h b/src/ac/kmod/netlinkapp.h index 8318ff8..780b002 100644 --- a/src/ac/kmod/netlinkapp.h +++ b/src/ac/kmod/netlinkapp.h @@ -1,15 +1,15 @@ -#ifndef __KMOD_AC_NETLINKAPP_HEADER__ -#define __KMOD_AC_NETLINKAPP_HEADER__ - -#include "capwap_rfc.h" -#include "socket.h" - -/* */ -int sc_netlink_init(void); -void sc_netlink_exit(void); - -/* */ -int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid); -int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length); - -#endif /* __KMOD_AC_NETLINKAPP_HEADER__ */ +#ifndef __KMOD_AC_NETLINKAPP_HEADER__ +#define __KMOD_AC_NETLINKAPP_HEADER__ + +#include "capwap_rfc.h" +#include "socket.h" + +/* */ +int sc_netlink_init(void); +void sc_netlink_exit(void); + +/* */ +int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid); +int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length); + +#endif /* __KMOD_AC_NETLINKAPP_HEADER__ */ diff --git a/src/ac/kmod/nlsmartcapwap.h b/src/ac/kmod/nlsmartcapwap.h index 0680a03..ea52956 100644 --- a/src/ac/kmod/nlsmartcapwap.h +++ b/src/ac/kmod/nlsmartcapwap.h @@ -1,73 +1,73 @@ -#ifndef __AC_NLSMARTCAPWAP_HEADER__ -#define __AC_NLSMARTCAPWAP_HEADER__ - -/* */ -#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_ac" - -/* */ -#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001 - -/* */ -enum sc_netlink_attrs { - NLSMARTCAPWAP_ATTR_UNSPEC, - - NLSMARTCAPWAP_ATTR_FLAGS, - - NLSMARTCAPWAP_ATTR_SESSION_ID, - - NLSMARTCAPWAP_ATTR_RADIOID, - NLSMARTCAPWAP_ATTR_WLANID, - NLSMARTCAPWAP_ATTR_BINDING, - NLSMARTCAPWAP_ATTR_MACMODE, - NLSMARTCAPWAP_ATTR_TUNNELMODE, - - NLSMARTCAPWAP_ATTR_ADDRESS, - NLSMARTCAPWAP_ATTR_MTU, - - NLSMARTCAPWAP_ATTR_DATA_FRAME, - - NLSMARTCAPWAP_ATTR_IFPHY_NAME, - NLSMARTCAPWAP_ATTR_IFPHY_INDEX, - - NLSMARTCAPWAP_ATTR_MACADDRESS, - NLSMARTCAPWAP_ATTR_BSSID, - - NLSMARTCAPWAP_ATTR_VLAN, - - /* Last attribute */ - __NLSMARTCAPWAP_ATTR_AFTER_LAST, - NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1 -}; - -/* */ -enum sc_netlink_commands { - NLSMARTCAPWAP_CMD_UNSPEC, - - NLSMARTCAPWAP_CMD_LINK, - - NLSMARTCAPWAP_CMD_ADD_IFACE, - NLSMARTCAPWAP_CMD_DELETE_IFACE, - - NLSMARTCAPWAP_CMD_BIND, - - NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, - NLSMARTCAPWAP_CMD_RECV_KEEPALIVE, - - NLSMARTCAPWAP_CMD_NEW_SESSION, - NLSMARTCAPWAP_CMD_DELETE_SESSION, - - NLSMARTCAPWAP_CMD_ADD_WLAN, - NLSMARTCAPWAP_CMD_REMOVE_WLAN, - - NLSMARTCAPWAP_CMD_SEND_DATA, - NLSMARTCAPWAP_CMD_RECV_DATA, - - NLSMARTCAPWAP_CMD_AUTH_STATION, - NLSMARTCAPWAP_CMD_DEAUTH_STATION, - - /* Last command */ - __NLSMARTCAPWAP_CMD_AFTER_LAST, - NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1 -}; - -#endif /* __AC_NLSMARTCAPWAP_HEADER__ */ +#ifndef __AC_NLSMARTCAPWAP_HEADER__ +#define __AC_NLSMARTCAPWAP_HEADER__ + +/* */ +#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_ac" + +/* */ +#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001 + +/* */ +enum sc_netlink_attrs { + NLSMARTCAPWAP_ATTR_UNSPEC, + + NLSMARTCAPWAP_ATTR_FLAGS, + + NLSMARTCAPWAP_ATTR_SESSION_ID, + + NLSMARTCAPWAP_ATTR_RADIOID, + NLSMARTCAPWAP_ATTR_WLANID, + NLSMARTCAPWAP_ATTR_BINDING, + NLSMARTCAPWAP_ATTR_MACMODE, + NLSMARTCAPWAP_ATTR_TUNNELMODE, + + NLSMARTCAPWAP_ATTR_ADDRESS, + NLSMARTCAPWAP_ATTR_MTU, + + NLSMARTCAPWAP_ATTR_DATA_FRAME, + + NLSMARTCAPWAP_ATTR_IFPHY_NAME, + NLSMARTCAPWAP_ATTR_IFPHY_INDEX, + + NLSMARTCAPWAP_ATTR_MACADDRESS, + NLSMARTCAPWAP_ATTR_BSSID, + + NLSMARTCAPWAP_ATTR_VLAN, + + /* Last attribute */ + __NLSMARTCAPWAP_ATTR_AFTER_LAST, + NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1 +}; + +/* */ +enum sc_netlink_commands { + NLSMARTCAPWAP_CMD_UNSPEC, + + NLSMARTCAPWAP_CMD_LINK, + + NLSMARTCAPWAP_CMD_ADD_IFACE, + NLSMARTCAPWAP_CMD_DELETE_IFACE, + + NLSMARTCAPWAP_CMD_BIND, + + NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, + NLSMARTCAPWAP_CMD_RECV_KEEPALIVE, + + NLSMARTCAPWAP_CMD_NEW_SESSION, + NLSMARTCAPWAP_CMD_DELETE_SESSION, + + NLSMARTCAPWAP_CMD_ADD_WLAN, + NLSMARTCAPWAP_CMD_REMOVE_WLAN, + + NLSMARTCAPWAP_CMD_SEND_DATA, + NLSMARTCAPWAP_CMD_RECV_DATA, + + NLSMARTCAPWAP_CMD_AUTH_STATION, + NLSMARTCAPWAP_CMD_DEAUTH_STATION, + + /* Last command */ + __NLSMARTCAPWAP_CMD_AFTER_LAST, + NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1 +}; + +#endif /* __AC_NLSMARTCAPWAP_HEADER__ */ diff --git a/src/ac/kmod/socket.c b/src/ac/kmod/socket.c index eba63c2..29ba410 100644 --- a/src/ac/kmod/socket.c +++ b/src/ac/kmod/socket.c @@ -1,227 +1,227 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "socket.h" -#include "capwap.h" - -/* Socket */ -#define SOCKET_COUNT 2 -static struct socket* sc_sockets[SOCKET_COUNT]; - -/* */ -int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) { - TRACEKMOD("### sc_socket_recvpacket\n"); - - /* */ - CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL; - - /* */ - sc_capwap_recvpacket(skb); - return 0; -} - -/* */ -static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) { - int ret; - - TRACEKMOD("### sc_socket_create\n"); - - /* Create socket */ - ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]); - if (ret) { - return ret; - } - - /* Bind to interface */ - ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr)); - if (ret) { - goto failure; - } - - /* Set callback */ - udp_sk(sc_sockets[type]->sk)->encap_type = 1; - udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket; - - /* */ - if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) { - union capwap_addr localaddr; - int localaddrsize = sizeof(union capwap_addr); - - /* Retrieve port */ - ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize); - if (ret) { - goto failure; - } - - /* */ - if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) { - sockaddr->sin.sin_port = localaddr.sin.sin_port; - } else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) { - sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port; - } else { - ret = -EFAULT; - goto failure; - } - } - - return 0; - -failure: - sock_release(sc_sockets[type]); - sc_sockets[type] = 0; - return ret; -} - -/* */ -int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) { - unsigned char* nethdr; - - TRACEKMOD("### sc_socket_getpeeraddr\n"); - - /* */ - nethdr = skb_network_header(skb); - if (!nethdr) { - return -EINVAL; - } - - /* */ - switch (ntohs(skb->protocol)) { - case ETH_P_IP: { - /* Validate IPv4 header */ - if ((nethdr[0] & 0xf0) != 0x40) { - return -EINVAL; - } - - /* Retrieve address */ - peeraddr->sin.sin_family = AF_INET; - peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr; - peeraddr->sin.sin_port = udp_hdr(skb)->source; - break; - } - - case ETH_P_IPV6: { - /* Validate IPv6 header */ - if ((nethdr[0] & 0xf0) != 0x60) { - return -EINVAL; - } - - /* Retrieve address */ - peeraddr->sin6.sin6_family = AF_INET6; - memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr)); - peeraddr->sin6.sin6_port = udp_hdr(skb)->source; - break; - } - - default: { - return -EINVAL; - } - } - - return 0; -} - -/* */ -int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) { - struct kvec vec; - struct msghdr msg; - - TRACEKMOD("### sc_socket_send\n"); - - /* */ - vec.iov_base = buffer; - vec.iov_len = length; - - /* */ - memset(&msg, 0, sizeof(struct msghdr)); - msg.msg_name = sockaddr; - msg.msg_namelen = sizeof(union capwap_addr); - msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; - - /* */ - return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length); -} - -/* */ -int sc_socket_init(void) { - TRACEKMOD("### sc_socket_init\n"); - - memset(sc_sockets, 0, sizeof(sc_sockets)); - return 0; -} - -/* */ -int sc_socket_bind(union capwap_addr* sockaddr) { - int ret; - - TRACEKMOD("### sc_socket_bind\n"); - - /* */ - if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) { - return -EBUSY; - } - - /* UDP socket */ - ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP); - if (ret) { - goto failure; - } - - /* UDPLite socket */ - ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE); - if (ret) { - goto failure; - } - - /* */ - udp_encap_enable(); - if (sockaddr->ss.ss_family == AF_INET6) { - udpv6_encap_enable(); - } - - return 0; - -failure: - sc_socket_close(); - return ret; -} - -/* */ -void sc_socket_close(void) { - TRACEKMOD("### sc_socket_close\n"); - - /* Close sockets */ - if (sc_sockets[SOCKET_UDP]) { - kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR); - sock_release(sc_sockets[SOCKET_UDP]); - } - - if (sc_sockets[SOCKET_UDPLITE]) { - kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR); - sock_release(sc_sockets[SOCKET_UDPLITE]); - } - - memset(sc_sockets, 0, sizeof(sc_sockets)); -} - -/* */ -int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) { - TRACEKMOD("### sc_addr_compare\n"); - - if (addr1->ss.ss_family == addr2->ss.ss_family) { - if (addr1->ss.ss_family == AF_INET) { - return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1); - } else if (addr1->ss.ss_family == AF_INET6) { - return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1); - } - } - - return -1; -} +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "socket.h" +#include "capwap.h" + +/* Socket */ +#define SOCKET_COUNT 2 +static struct socket* sc_sockets[SOCKET_COUNT]; + +/* */ +int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) { + TRACEKMOD("### sc_socket_recvpacket\n"); + + /* */ + CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL; + + /* */ + sc_capwap_recvpacket(skb); + return 0; +} + +/* */ +static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) { + int ret; + + TRACEKMOD("### sc_socket_create\n"); + + /* Create socket */ + ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]); + if (ret) { + return ret; + } + + /* Bind to interface */ + ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr)); + if (ret) { + goto failure; + } + + /* Set callback */ + udp_sk(sc_sockets[type]->sk)->encap_type = 1; + udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket; + + /* */ + if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) { + union capwap_addr localaddr; + int localaddrsize = sizeof(union capwap_addr); + + /* Retrieve port */ + ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize); + if (ret) { + goto failure; + } + + /* */ + if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) { + sockaddr->sin.sin_port = localaddr.sin.sin_port; + } else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) { + sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port; + } else { + ret = -EFAULT; + goto failure; + } + } + + return 0; + +failure: + sock_release(sc_sockets[type]); + sc_sockets[type] = 0; + return ret; +} + +/* */ +int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) { + unsigned char* nethdr; + + TRACEKMOD("### sc_socket_getpeeraddr\n"); + + /* */ + nethdr = skb_network_header(skb); + if (!nethdr) { + return -EINVAL; + } + + /* */ + switch (ntohs(skb->protocol)) { + case ETH_P_IP: { + /* Validate IPv4 header */ + if ((nethdr[0] & 0xf0) != 0x40) { + return -EINVAL; + } + + /* Retrieve address */ + peeraddr->sin.sin_family = AF_INET; + peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr; + peeraddr->sin.sin_port = udp_hdr(skb)->source; + break; + } + + case ETH_P_IPV6: { + /* Validate IPv6 header */ + if ((nethdr[0] & 0xf0) != 0x60) { + return -EINVAL; + } + + /* Retrieve address */ + peeraddr->sin6.sin6_family = AF_INET6; + memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr)); + peeraddr->sin6.sin6_port = udp_hdr(skb)->source; + break; + } + + default: { + return -EINVAL; + } + } + + return 0; +} + +/* */ +int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) { + struct kvec vec; + struct msghdr msg; + + TRACEKMOD("### sc_socket_send\n"); + + /* */ + vec.iov_base = buffer; + vec.iov_len = length; + + /* */ + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = sockaddr; + msg.msg_namelen = sizeof(union capwap_addr); + msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; + + /* */ + return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length); +} + +/* */ +int sc_socket_init(void) { + TRACEKMOD("### sc_socket_init\n"); + + memset(sc_sockets, 0, sizeof(sc_sockets)); + return 0; +} + +/* */ +int sc_socket_bind(union capwap_addr* sockaddr) { + int ret; + + TRACEKMOD("### sc_socket_bind\n"); + + /* */ + if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) { + return -EBUSY; + } + + /* UDP socket */ + ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP); + if (ret) { + goto failure; + } + + /* UDPLite socket */ + ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE); + if (ret) { + goto failure; + } + + /* */ + udp_encap_enable(); + if (sockaddr->ss.ss_family == AF_INET6) { + udpv6_encap_enable(); + } + + return 0; + +failure: + sc_socket_close(); + return ret; +} + +/* */ +void sc_socket_close(void) { + TRACEKMOD("### sc_socket_close\n"); + + /* Close sockets */ + if (sc_sockets[SOCKET_UDP]) { + kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR); + sock_release(sc_sockets[SOCKET_UDP]); + } + + if (sc_sockets[SOCKET_UDPLITE]) { + kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR); + sock_release(sc_sockets[SOCKET_UDPLITE]); + } + + memset(sc_sockets, 0, sizeof(sc_sockets)); +} + +/* */ +int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) { + TRACEKMOD("### sc_addr_compare\n"); + + if (addr1->ss.ss_family == addr2->ss.ss_family) { + if (addr1->ss.ss_family == AF_INET) { + return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1); + } else if (addr1->ss.ss_family == AF_INET6) { + return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1); + } + } + + return -1; +} diff --git a/src/ac/kmod/socket.h b/src/ac/kmod/socket.h index a993b77..32a7c67 100644 --- a/src/ac/kmod/socket.h +++ b/src/ac/kmod/socket.h @@ -1,35 +1,35 @@ -#ifndef __KMOD_SOCKET_HEADER__ -#define __KMOD_SOCKET_HEADER__ - -#include -#include -#include -#include - -/* */ -#define SOCKET_UDP 0 -#define SOCKET_UDPLITE 1 - -/* Universal socket address */ -union capwap_addr { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - struct sockaddr_storage ss; -}; - -/* */ -int sc_socket_init(void); -void sc_socket_close(void); - -/* */ -int sc_socket_bind(union capwap_addr* sockaddr); -int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr); - -/* */ -int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr); - -/* */ -int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2); - -#endif /* __KMOD_SOCKET_HEADER__ */ +#ifndef __KMOD_SOCKET_HEADER__ +#define __KMOD_SOCKET_HEADER__ + +#include +#include +#include +#include + +/* */ +#define SOCKET_UDP 0 +#define SOCKET_UDPLITE 1 + +/* Universal socket address */ +union capwap_addr { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct sockaddr_storage ss; +}; + +/* */ +int sc_socket_init(void); +void sc_socket_close(void); + +/* */ +int sc_socket_bind(union capwap_addr* sockaddr); +int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr); + +/* */ +int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr); + +/* */ +int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2); + +#endif /* __KMOD_SOCKET_HEADER__ */ diff --git a/src/ac/kmod/station.c b/src/ac/kmod/station.c index 21c87c1..899e3ae 100644 --- a/src/ac/kmod/station.c +++ b/src/ac/kmod/station.c @@ -1,157 +1,157 @@ -#include "config.h" -#include -#include -#include -#include -#include "station.h" -#include "capwap.h" -#include "iface.h" - -/* */ -#define STATION_HASH_SIZE 65536 - -/* */ -static LIST_HEAD(sc_station_list); -static struct sc_capwap_station* __rcu sc_station_hash_addr[STATION_HASH_SIZE]; - -/* */ -static uint32_t sc_stations_hash_addr(const uint8_t* macaddress) { - TRACEKMOD("### sc_stations_hash_addr\n"); - - return (((((uint32_t)macaddress[4] << 8) | (uint32_t)macaddress[5]) ^ ((uint32_t)macaddress[3] << 4)) % STATION_HASH_SIZE); -} - -/* */ -static struct sc_capwap_connection* sc_stations_searchconnection(struct sc_capwap_station* station) { - struct sc_capwap_connection* connection; - struct sc_capwap_session_priv* sessionpriv = rcu_access_pointer(station->sessionpriv); - struct sc_netdev_priv* devpriv = rcu_access_pointer(station->devpriv); - - TRACEKMOD("### sc_stations_searchconnection\n"); - - list_for_each_entry(connection, &sessionpriv->list_connections, list_session) { - if ((connection->devpriv == devpriv) && (connection->radioid == station->radioid) && (connection->vlan == station->vlan)) { - return connection; - } - } - - return NULL; -} - -/* */ -void sc_stations_add(struct sc_capwap_station* station) { - uint32_t hash; - - TRACEKMOD("### sc_stations_add\n"); - - /* */ - list_add_rcu(&station->list, &sc_station_list); - - hash = sc_stations_hash_addr(station->address); - station->next_addr = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked()); - rcu_assign_pointer(sc_station_hash_addr[hash], station); -} - -/* */ -struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress) { - struct sc_capwap_station* station; - - TRACEKMOD("### sc_stations_search\n"); - - /* */ - station = rcu_dereference_check(sc_station_hash_addr[sc_stations_hash_addr(macaddress)], sc_capwap_update_lock_is_locked()); - while (station) { - if (!memcmp(&station->address, macaddress, MACADDRESS_EUI48_LENGTH)) { - break; - } - - /* */ - station = rcu_dereference_check(station->next_addr, sc_capwap_update_lock_is_locked()); - } - - return station; -} - -/* */ -void sc_stations_free(struct sc_capwap_station* station) { - uint32_t hash; - struct sc_capwap_station* search; - - TRACEKMOD("### sc_stations_free\n"); - - /* */ - hash = sc_stations_hash_addr(station->address); - search = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked()); - - if (search) { - if (search == station) { - rcu_assign_pointer(sc_station_hash_addr[hash], station->next_addr); - } else { - while (rcu_access_pointer(search->next_addr) && (rcu_access_pointer(search->next_addr) != station)) { - search = rcu_dereference_protected(search->next_addr, sc_capwap_update_lock_is_locked()); - } - - if (rcu_access_pointer(search->next_addr)) { - rcu_assign_pointer(search->next_addr, station->next_addr); - } - } - } - - /* */ - list_del_rcu(&station->list_dev); - list_del_rcu(&station->list_session); - synchronize_net(); - - kfree(station); -} - -/* */ -int sc_stations_setconnection(struct sc_capwap_station* station) { - struct sc_capwap_connection* connection; - - TRACEKMOD("### sc_stations_setconnection\n"); - - /* */ - connection = sc_stations_searchconnection(station); - if (!connection) { - connection = (struct sc_capwap_connection*)kzalloc(sizeof(struct sc_capwap_connection), GFP_KERNEL); - if (!connection) { - TRACEKMOD("*** Unable to create connection\n"); - return -ENOMEM; - } - - /* */ - connection->sessionpriv = rcu_access_pointer(station->sessionpriv); - list_add_rcu(&connection->list_session, &connection->sessionpriv->list_connections); - connection->devpriv = rcu_access_pointer(station->devpriv); - list_add_rcu(&connection->list_dev, &connection->devpriv->list_connections); - connection->radioid = station->radioid; - connection->vlan = station->vlan; - } - - /* */ - connection->count++; - connection->wlanidmask |= 1 << (station->wlanid - 1); - return 0; -} - -/* */ -void sc_stations_releaseconnection(struct sc_capwap_station* station) { - struct sc_capwap_connection* connection; - - TRACEKMOD("### sc_stations_releaseconnection\n"); - - connection = sc_stations_searchconnection(station); - if (connection) { - TRACEKMOD("*** Release connection reference %d\n", connection->count); - - connection->count--; - if (!connection->count) { - list_del_rcu(&connection->list_session); - list_del_rcu(&connection->list_dev); - synchronize_net(); - - kfree(connection); - } - } -} +#include "config.h" +#include +#include +#include +#include +#include "station.h" +#include "capwap.h" +#include "iface.h" + +/* */ +#define STATION_HASH_SIZE 65536 + +/* */ +static LIST_HEAD(sc_station_list); +static struct sc_capwap_station* __rcu sc_station_hash_addr[STATION_HASH_SIZE]; + +/* */ +static uint32_t sc_stations_hash_addr(const uint8_t* macaddress) { + TRACEKMOD("### sc_stations_hash_addr\n"); + + return (((((uint32_t)macaddress[4] << 8) | (uint32_t)macaddress[5]) ^ ((uint32_t)macaddress[3] << 4)) % STATION_HASH_SIZE); +} + +/* */ +static struct sc_capwap_connection* sc_stations_searchconnection(struct sc_capwap_station* station) { + struct sc_capwap_connection* connection; + struct sc_capwap_session_priv* sessionpriv = rcu_access_pointer(station->sessionpriv); + struct sc_netdev_priv* devpriv = rcu_access_pointer(station->devpriv); + + TRACEKMOD("### sc_stations_searchconnection\n"); + + list_for_each_entry(connection, &sessionpriv->list_connections, list_session) { + if ((connection->devpriv == devpriv) && (connection->radioid == station->radioid) && (connection->vlan == station->vlan)) { + return connection; + } + } + + return NULL; +} + +/* */ +void sc_stations_add(struct sc_capwap_station* station) { + uint32_t hash; + + TRACEKMOD("### sc_stations_add\n"); + + /* */ + list_add_rcu(&station->list, &sc_station_list); + + hash = sc_stations_hash_addr(station->address); + station->next_addr = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked()); + rcu_assign_pointer(sc_station_hash_addr[hash], station); +} + +/* */ +struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress) { + struct sc_capwap_station* station; + + TRACEKMOD("### sc_stations_search\n"); + + /* */ + station = rcu_dereference_check(sc_station_hash_addr[sc_stations_hash_addr(macaddress)], sc_capwap_update_lock_is_locked()); + while (station) { + if (!memcmp(&station->address, macaddress, MACADDRESS_EUI48_LENGTH)) { + break; + } + + /* */ + station = rcu_dereference_check(station->next_addr, sc_capwap_update_lock_is_locked()); + } + + return station; +} + +/* */ +void sc_stations_free(struct sc_capwap_station* station) { + uint32_t hash; + struct sc_capwap_station* search; + + TRACEKMOD("### sc_stations_free\n"); + + /* */ + hash = sc_stations_hash_addr(station->address); + search = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked()); + + if (search) { + if (search == station) { + rcu_assign_pointer(sc_station_hash_addr[hash], station->next_addr); + } else { + while (rcu_access_pointer(search->next_addr) && (rcu_access_pointer(search->next_addr) != station)) { + search = rcu_dereference_protected(search->next_addr, sc_capwap_update_lock_is_locked()); + } + + if (rcu_access_pointer(search->next_addr)) { + rcu_assign_pointer(search->next_addr, station->next_addr); + } + } + } + + /* */ + list_del_rcu(&station->list_dev); + list_del_rcu(&station->list_session); + synchronize_net(); + + kfree(station); +} + +/* */ +int sc_stations_setconnection(struct sc_capwap_station* station) { + struct sc_capwap_connection* connection; + + TRACEKMOD("### sc_stations_setconnection\n"); + + /* */ + connection = sc_stations_searchconnection(station); + if (!connection) { + connection = (struct sc_capwap_connection*)kzalloc(sizeof(struct sc_capwap_connection), GFP_KERNEL); + if (!connection) { + TRACEKMOD("*** Unable to create connection\n"); + return -ENOMEM; + } + + /* */ + connection->sessionpriv = rcu_access_pointer(station->sessionpriv); + list_add_rcu(&connection->list_session, &connection->sessionpriv->list_connections); + connection->devpriv = rcu_access_pointer(station->devpriv); + list_add_rcu(&connection->list_dev, &connection->devpriv->list_connections); + connection->radioid = station->radioid; + connection->vlan = station->vlan; + } + + /* */ + connection->count++; + connection->wlanidmask |= 1 << (station->wlanid - 1); + return 0; +} + +/* */ +void sc_stations_releaseconnection(struct sc_capwap_station* station) { + struct sc_capwap_connection* connection; + + TRACEKMOD("### sc_stations_releaseconnection\n"); + + connection = sc_stations_searchconnection(station); + if (connection) { + TRACEKMOD("*** Release connection reference %d\n", connection->count); + + connection->count--; + if (!connection->count) { + list_del_rcu(&connection->list_session); + list_del_rcu(&connection->list_dev); + synchronize_net(); + + kfree(connection); + } + } +} diff --git a/src/ac/kmod/station.h b/src/ac/kmod/station.h index e69a292..2e277e2 100644 --- a/src/ac/kmod/station.h +++ b/src/ac/kmod/station.h @@ -1,58 +1,58 @@ -#ifndef __KMOD_AC_STATION_HEADER__ -#define __KMOD_AC_STATION_HEADER__ - -#include "capwap_rfc.h" - -/* */ -struct sc_capwap_connection { - int count; - - /* Session */ - struct sc_capwap_session_priv* sessionpriv; - struct list_head list_session; - - /* Interface */ - struct sc_netdev_priv* devpriv; - struct list_head list_dev; - - /* */ - uint16_t vlan; - uint8_t radioid; - uint8_t wlanidmask; -}; - -/* */ -struct sc_capwap_station { - struct list_head list; - - /* */ - uint8_t address[MACADDRESS_EUI48_LENGTH]; - struct sc_capwap_station* __rcu next_addr; - - /* Session */ - struct sc_capwap_session_priv* __rcu sessionpriv; - struct list_head list_session; - - /* Interface */ - struct sc_netdev_priv* __rcu devpriv; - struct list_head list_dev; - - /* */ - uint8_t bssid[MACADDRESS_EUI48_LENGTH]; - uint16_t vlan; - uint8_t radioid; - uint8_t wlanid; -}; - -/* */ -void sc_stations_add(struct sc_capwap_station* station); -void sc_stations_free(struct sc_capwap_station* station); - -/* */ -struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress); - -/* */ -int sc_stations_setconnection(struct sc_capwap_station* station); -void sc_stations_releaseconnection(struct sc_capwap_station* station); - -#endif /* __KMOD_AC_STATION_HEADER__ */ +#ifndef __KMOD_AC_STATION_HEADER__ +#define __KMOD_AC_STATION_HEADER__ + +#include "capwap_rfc.h" + +/* */ +struct sc_capwap_connection { + int count; + + /* Session */ + struct sc_capwap_session_priv* sessionpriv; + struct list_head list_session; + + /* Interface */ + struct sc_netdev_priv* devpriv; + struct list_head list_dev; + + /* */ + uint16_t vlan; + uint8_t radioid; + uint8_t wlanidmask; +}; + +/* */ +struct sc_capwap_station { + struct list_head list; + + /* */ + uint8_t address[MACADDRESS_EUI48_LENGTH]; + struct sc_capwap_station* __rcu next_addr; + + /* Session */ + struct sc_capwap_session_priv* __rcu sessionpriv; + struct list_head list_session; + + /* Interface */ + struct sc_netdev_priv* __rcu devpriv; + struct list_head list_dev; + + /* */ + uint8_t bssid[MACADDRESS_EUI48_LENGTH]; + uint16_t vlan; + uint8_t radioid; + uint8_t wlanid; +}; + +/* */ +void sc_stations_add(struct sc_capwap_station* station); +void sc_stations_free(struct sc_capwap_station* station); + +/* */ +struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress); + +/* */ +int sc_stations_setconnection(struct sc_capwap_station* station); +void sc_stations_releaseconnection(struct sc_capwap_station* station); + +#endif /* __KMOD_AC_STATION_HEADER__ */ diff --git a/src/common/binding/ieee80211/ieee80211.c b/src/common/binding/ieee80211/ieee80211.c index 033d465..b925341 100644 --- a/src/common/binding/ieee80211/ieee80211.c +++ b/src/common/binding/ieee80211/ieee80211.c @@ -1,729 +1,729 @@ -#include "capwap.h" -#include "ieee80211.h" - -/* */ -static int ieee80211_ie_set_ssid(uint8_t* buffer, const char* ssid, int hidessid) { - struct ieee80211_ie_ssid* iessid = (struct ieee80211_ie_ssid*)buffer; - - ASSERT(buffer != NULL); - ASSERT(ssid != NULL); - - iessid->id = IEEE80211_IE_SSID; - if (hidessid) { - iessid->len = 0; - } else { - iessid->len = strlen(ssid); - if (iessid->len > IEEE80211_IE_SSID_MAX_LENGTH) { - return -1; - } - - strncpy((char*)iessid->ssid, ssid, iessid->len); - } - - return sizeof(struct ieee80211_ie_ssid) + iessid->len; -} - -/* */ -static int ieee80211_ie_set_supportedrates(uint8_t* buffer, uint8_t* supportedrates, int supportedratescount) { - int i; - int count; - struct ieee80211_ie_supported_rates* iesupportedrates = (struct ieee80211_ie_supported_rates*)buffer; - - ASSERT(buffer != NULL); - ASSERT(supportedrates != NULL); - ASSERT(supportedratescount > 0); - - /* IE accept max only 8 rate */ - count = supportedratescount; - if (count > 8) { - count = 8; - } - - /* */ - iesupportedrates->id = IEEE80211_IE_SUPPORTED_RATES; - iesupportedrates->len = count; - - for (i = 0; i < count; i++) { - iesupportedrates->rates[i] = supportedrates[i]; - } - - return sizeof(struct ieee80211_ie_supported_rates) + iesupportedrates->len; -} - -/* */ -static int ieee80211_ie_set_extendedsupportedrates(uint8_t* buffer, uint8_t* supportedrates, int supportedratescount) { - int i, j; - struct ieee80211_ie_extended_supported_rates* ieextendedsupportedrates = (struct ieee80211_ie_extended_supported_rates*)buffer; - - ASSERT(buffer != NULL); - ASSERT(supportedrates != NULL); - - /* IE accept only > 8 rate */ - if (supportedratescount <= IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH) { - return 0; - } - - /* */ - ieextendedsupportedrates->id = IEEE80211_IE_EXTENDED_SUPPORTED_RATES; - ieextendedsupportedrates->len = supportedratescount - IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH; - - for (i = IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH, j = 0; i < supportedratescount; i++, j++) { - ieextendedsupportedrates->rates[j] = supportedrates[i]; - } - - return sizeof(struct ieee80211_ie_extended_supported_rates) + ieextendedsupportedrates->len; -} - -/* */ -static int ieee80211_ie_set_dsss(uint8_t* buffer, uint8_t channel) { - struct ieee80211_ie_dsss* iedsss = (struct ieee80211_ie_dsss*)buffer; - - ASSERT(buffer != NULL); - - iedsss->id = IEEE80211_IE_DSSS; - iedsss->len = IEEE80211_IE_DSSS_LENGTH; - iedsss->channel = channel; - - return sizeof(struct ieee80211_ie_dsss); -} - -/* */ -static int ieee80211_ie_set_erp(uint8_t* buffer, uint32_t mode, uint8_t erpinfo) { - struct ieee80211_ie_erp* ieerp = (struct ieee80211_ie_erp*)buffer; - - ASSERT(buffer != NULL); - - if (!(mode & IEEE80211_RADIO_TYPE_80211G)) { - return 0; - } - - ieerp->id = IEEE80211_IE_ERP; - ieerp->len = IEEE80211_IE_ERP_LENGTH; - ieerp->params = erpinfo; - - return sizeof(struct ieee80211_ie_erp); -} - -/* */ -int ieee80211_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length) { - ASSERT(items != NULL); - ASSERT(data != NULL); - - /* */ - memset(items, 0, sizeof(struct ieee80211_ie_items)); - - /* Parsing */ - while (length >= 2) { - uint8_t ie_id = data[0]; - uint8_t ie_len = data[1]; - - /* Parsing Information Element */ - switch (ie_id) { - case IEEE80211_IE_SSID: { - if (ie_len > IEEE80211_IE_SSID_MAX_LENGTH) { - return -1; - } - - items->ssid = (struct ieee80211_ie_ssid*)data; - break; - } - - case IEEE80211_IE_SUPPORTED_RATES: { - if ((ie_len < IEEE80211_IE_SUPPORTED_RATES_MIN_LENGTH) || (ie_len > IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH)) { - return -1; - } - - items->supported_rates = (struct ieee80211_ie_supported_rates*)data; - break; - } - - case IEEE80211_IE_DSSS: { - if (ie_len != IEEE80211_IE_DSSS_LENGTH) { - return -1; - } - - items->dsss = (struct ieee80211_ie_dsss*)data; - break; - } - - case IEEE80211_IE_COUNTRY: { - if (ie_len < IEEE80211_IE_COUNTRY_MIN_LENGTH) { - return -1; - } - - items->country = (struct ieee80211_ie_country*)data; - break; - } - - case IEEE80211_IE_CHALLENGE_TEXT: { - if (ie_len < IEEE80211_IE_CHALLENGE_TEXT_MIN_LENGTH) { - return -1; - } - - items->challenge_text = (struct ieee80211_ie_challenge_text*)data; - break; - } - - case IEEE80211_IE_ERP: { - if (ie_len != IEEE80211_IE_ERP_LENGTH) { - return -1; - } - - items->erp = (struct ieee80211_ie_erp*)data; - break; - } - - case IEEE80211_IE_EXTENDED_SUPPORTED_RATES: { - if (ie_len < IEEE80211_IE_EXTENDED_SUPPORTED_MIN_LENGTH) { - return -1; - } - - items->extended_supported_rates = (struct ieee80211_ie_extended_supported_rates*)data; - break; - } - - case IEEE80211_IE_EDCA_PARAMETER_SET: { - if (ie_len != IEEE80211_IE_EDCA_PARAMETER_SET_LENGTH) { - return -1; - } - - items->edca_parameter_set = (struct ieee80211_ie_edca_parameter_set*)data; - break; - } - - case IEEE80211_IE_QOS_CAPABILITY: { - if (ie_len != IEEE80211_IE_QOS_CAPABILITY_LENGTH) { - return -1; - } - - items->qos_capability = (struct ieee80211_ie_qos_capability*)data; - break; - } - - case IEEE80211_IE_POWER_CONSTRAINT: { - if (ie_len != IEEE80211_IE_POWER_CONSTRAINT_LENGTH) { - return -1; - } - - items->power_constraint = (struct ieee80211_ie_power_constraint*)data; - break; - } - - case IEEE80211_IE_SSID_LIST: { - items->ssid_list = (struct ieee80211_ie_ssid_list*)data; - break; - } - } - - /* Next Information Element */ - data += sizeof(struct ieee80211_ie) + ie_len; - length -= sizeof(struct ieee80211_ie) + ie_len; - } - - return (!length ? 0 : -1); -} - -/* */ -int ieee80211_aid_create(uint32_t* aidbitfield, uint16_t* aid) { - int i, j; - - ASSERT(aidbitfield != NULL); - ASSERT(aid != NULL); - - /* Search free aid bitfield */ - for (i = 0; i < IEEE80211_AID_BITFIELD_SIZE; i++) { - if (aidbitfield[i] != 0xffffffff) { - uint32_t bitfield = aidbitfield[i]; - - /* Search free bit */ - for (j = 0; j < 32; j++) { - if (!(bitfield & (1 << j))) { - *aid = i * 32 + j + 1; - if (*aid <= IEEE80211_AID_MAX_VALUE) { - aidbitfield[i] |= (1 << j); - return 0; - } - - break; - } - } - - break; - } - } - - *aid = 0; - return -1; -} - -/* */ -void ieee80211_aid_free(uint32_t* aidbitfield, uint16_t aid) { - ASSERT(aidbitfield != NULL); - ASSERT((aid > 0) && (aid <= IEEE80211_AID_MAX_VALUE)); - - aidbitfield[(aid - 1) / 32] &= ~(1 << ((aid - 1) % 32)); -} - -/* */ -unsigned long ieee80211_frequency_to_channel(uint32_t freq) { - if ((freq >= 2412) && (freq <= 2472)) { - return (freq - 2407) / 5; - } else if (freq == 2484) { - return 14; - } else if ((freq >= 4915) && (freq <= 4980)) { - return (freq - 4000) / 5; - } else if ((freq >= 5035) && (freq <= 5825)) { - return (freq - 5000) / 5; - } - - return 0; -} - -/* */ -int ieee80211_is_broadcast_addr(const uint8_t* addr) { - return (((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)) ? 1 : 0); -} - -/* */ -const uint8_t* ieee80211_get_sa_addr(const struct ieee80211_header* header) { - uint16_t framecontrol; - uint16_t framecontrol_type; - - ASSERT(header); - - /* Get type frame */ - framecontrol = __le16_to_cpu(header->framecontrol); - framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); - - if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - return header->address2; - } else if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_DATA) { - switch (framecontrol & (IEEE80211_FRAME_CONTROL_MASK_TODS | IEEE80211_FRAME_CONTROL_MASK_FROMDS)) { - case 0: { - return header->address2; - } - - case IEEE80211_FRAME_CONTROL_MASK_TODS: { - return header->address2; - } - - case IEEE80211_FRAME_CONTROL_MASK_FROMDS: { - return header->address3; - } - } - } - - return NULL; -} - -const uint8_t* ieee80211_get_da_addr(const struct ieee80211_header* header) { - uint16_t framecontrol; - uint16_t framecontrol_type; - - ASSERT(header); - - /* Get type frame */ - framecontrol = __le16_to_cpu(header->framecontrol); - framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); - - if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - return header->address1; - } else if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_DATA) { - switch (framecontrol & (IEEE80211_FRAME_CONTROL_MASK_TODS | IEEE80211_FRAME_CONTROL_MASK_FROMDS)) { - case 0: { - return header->address1; - } - - case IEEE80211_FRAME_CONTROL_MASK_TODS: { - return header->address3; - } - - case IEEE80211_FRAME_CONTROL_MASK_FROMDS: { - return header->address1; - } - } - } - - return NULL; -} - -/* */ -const uint8_t* ieee80211_get_bssid_addr(const struct ieee80211_header* header) { - uint16_t framecontrol; - uint16_t framecontrol_type; - - ASSERT(header); - - /* Get type frame */ - framecontrol = __le16_to_cpu(header->framecontrol); - framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); - - if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - return header->address3; - } else if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_DATA) { - switch (framecontrol & (IEEE80211_FRAME_CONTROL_MASK_TODS | IEEE80211_FRAME_CONTROL_MASK_FROMDS)) { - case 0: { - return header->address3; - } - - case IEEE80211_FRAME_CONTROL_MASK_TODS: { - return header->address1; - } - - case IEEE80211_FRAME_CONTROL_MASK_FROMDS: { - return header->address2; - } - } - } - - return NULL; -} - -/* */ -int ieee80211_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struct ieee80211_ie_ssid_list* isssidlist) { - int ssidlength; - - ASSERT(ssid != NULL); - - if (!iessid) { - return IEEE80211_WRONG_SSID; - } - - /* Check SSID */ - ssidlength = strlen((char*)ssid); - if ((ssidlength == iessid->len) && !memcmp(ssid, iessid->ssid, ssidlength)) { - return IEEE80211_VALID_SSID; - } - - /* Check SSID list */ - if (isssidlist) { - int length = isssidlist->len; - uint8_t* pos = isssidlist->lists; - - while (length >= sizeof(struct ieee80211_ie)) { - struct ieee80211_ie_ssid* ssiditem = (struct ieee80211_ie_ssid*)pos; - - /* Check buffer */ - length -= sizeof(struct ieee80211_ie); - if ((ssiditem->id != IEEE80211_IE_SSID) || !ssiditem->len || (length < ssiditem->len)) { - break; - } else if ((ssidlength == ssiditem->len) && !memcmp(ssid, ssiditem->ssid, ssidlength)) { - return IEEE80211_VALID_SSID; - } - - /* Next */ - length -= ssiditem->len; - pos += sizeof(struct ieee80211_ie) + ssiditem->len; - } - } - - return (!iessid->len ? IEEE80211_WILDCARD_SSID : IEEE80211_WRONG_SSID); -} - -/* */ -uint8_t ieee80211_get_erpinfo(uint32_t mode, int olbc, unsigned long stationnonerpcount, unsigned long stationnoshortpreamblecount, int shortpreamble) { - uint8_t result = 0; - - /* Erp mode is valid only in IEEE 802.11 g*/ - if (mode & IEEE80211_RADIO_TYPE_80211G) { - if (olbc) { - result |= IEEE80211_ERP_INFO_USE_PROTECTION; - } - - if (stationnonerpcount > 0) { - result |= (IEEE80211_ERP_INFO_NON_ERP_PRESENT | IEEE80211_ERP_INFO_USE_PROTECTION); - } - - if (!shortpreamble || (stationnoshortpreamblecount > 0)) { - result |= IEEE80211_ERP_INFO_BARKER_PREAMBLE_MODE; - } - } - - return result; -} - - -/* */ -int ieee80211_create_beacon(uint8_t* buffer, int length, struct ieee80211_beacon_params* params) { - int result; - uint8_t* pos; - struct ieee80211_header_mgmt* header; - - ASSERT(buffer != NULL); - - /* */ - header = (struct ieee80211_header_mgmt*)buffer; - params->headbeacon = buffer; - - /* Management header frame */ - header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_BEACON); - header->durationid = __cpu_to_le16(0); - memset(header->da, 0xff, ETH_ALEN); - memcpy(header->sa, params->bssid, ETH_ALEN); - memcpy(header->bssid, params->bssid, ETH_ALEN); - header->sequencecontrol = __cpu_to_le16(0); - memset(header->beacon.timestamp, 0, sizeof(header->beacon.timestamp)); - header->beacon.beaconinterval = __cpu_to_le16(params->beaconperiod); - header->beacon.capability = __cpu_to_le16(params->capability); - - /* Header frame size */ - params->headbeaconlength = (int)((uint8_t*)&header->beacon.ie[0] - (uint8_t*)header); - pos = buffer + params->headbeaconlength; - - /* Information Element: SSID */ - result = ieee80211_ie_set_ssid(pos, params->ssid, (params->ssid_hidden ? 1 : 0)); - if (result < 0) { - return -1; - } - - pos += result; - params->headbeaconlength += result; - - /* Information Element: Supported Rates */ - result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); - if (result < 0) { - return -1; - } - - pos += result; - params->headbeaconlength += result; - - /* Information Element: DSSS */ - result = ieee80211_ie_set_dsss(pos, params->channel); - if (result < 0) { - return -1; - } - - pos += result; - params->headbeaconlength += result; - - /* Separate Information Elements into two block between IE TIM */ - params->tailbeacon = pos; - params->tailbeaconlength = 0; - - /* Information Element: Country */ - /* TODO */ - - /* Information Element: ERP */ - result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo); - if (result < 0) { - return -1; - } - - pos += result; - params->tailbeaconlength += result; - - /* Information Element: Extended Supported Rates */ - result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); - if (result < 0) { - return -1; - } - - pos += result; - params->tailbeaconlength += result; - - /* Probe Response offload */ - if (params->flags & IEEE80221_CREATE_BEACON_FLAGS_PROBE_RESPONSE_OFFLOAD) { - struct ieee80211_probe_response_params proberesponseparams; - - /* */ - memset(&proberesponseparams, 0, sizeof(struct ieee80211_probe_response_params)); - memcpy(proberesponseparams.bssid, params->bssid, ETH_ALEN); - proberesponseparams.beaconperiod = params->beaconperiod; - proberesponseparams.capability = params->capability; - proberesponseparams.ssid = params->ssid; - memcpy(proberesponseparams.supportedrates, params->supportedrates, params->supportedratescount); - proberesponseparams.supportedratescount = params->supportedratescount; - proberesponseparams.mode = params->mode; - proberesponseparams.erpinfo = params->erpinfo; - proberesponseparams.channel = params->channel; - - /* */ - params->proberesponseoffload = pos; - params->proberesponseoffloadlength = ieee80211_create_probe_response(pos, (int)(pos - buffer), &proberesponseparams); - if (params->proberesponseoffloadlength < 0) { - return -1; - } - - /* */ - pos += params->proberesponseoffloadlength; - } - - return (int)(pos - buffer); -} - -/* */ -int ieee80211_create_probe_response(uint8_t* buffer, int length, struct ieee80211_probe_response_params* params) { - int result; - uint8_t* pos; - int responselength; - struct ieee80211_header_mgmt* header; - - ASSERT(buffer != NULL); - - /* */ - header = (struct ieee80211_header_mgmt*)buffer; - - /* Management header frame */ - header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESPONSE); - header->durationid = __cpu_to_le16(0); - memcpy(header->da, params->station, ETH_ALEN); - memcpy(header->sa, params->bssid, ETH_ALEN); - memcpy(header->bssid, params->bssid, ETH_ALEN); - header->sequencecontrol = __cpu_to_le16(0); - memset(header->proberesponse.timestamp, 0, sizeof(header->proberesponse.timestamp)); - header->proberesponse.beaconinterval = __cpu_to_le16(params->beaconperiod); - header->proberesponse.capability = __cpu_to_le16(params->capability); - - /* Header frame size */ - responselength = (int)((uint8_t*)&header->proberesponse.ie[0] - (uint8_t*)header); - pos = buffer + responselength; - - /* Information Element: SSID */ - result = ieee80211_ie_set_ssid(pos, params->ssid, 0); - if (result < 0) { - return -1; - } - - pos += result; - responselength += result; - - /* Information Element: Supported Rates */ - result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); - if (result < 0) { - return -1; - } - - pos += result; - responselength += result; - - /* Information Element: DSSS */ - result = ieee80211_ie_set_dsss(pos, params->channel); - if (result < 0) { - return -1; - } - - pos += result; - responselength += result; - - /* Information Element: Country */ - /* TODO */ - - /* Information Element: ERP */ - result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo); - if (result < 0) { - return -1; - } - - pos += result; - responselength += result; - - /* Information Element: Extended Supported Rates */ - result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); - if (result < 0) { - return -1; - } - - /*pos += result;*/ /* Comment for disable Dead inscrement Clang Analyzer warning */ - responselength += result; - - return responselength; -} - -/* */ -int ieee80211_create_authentication_response(uint8_t* buffer, int length, struct ieee80211_authentication_params* params) { - int responselength; - struct ieee80211_header_mgmt* header; - - ASSERT(buffer != NULL); - - /* */ - header = (struct ieee80211_header_mgmt*)buffer; - - /* Management header frame */ - header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION); - header->durationid = __cpu_to_le16(0); - memcpy(header->da, params->station, ETH_ALEN); - memcpy(header->sa, params->bssid, ETH_ALEN); - memcpy(header->bssid, params->bssid, ETH_ALEN); - header->sequencecontrol = __cpu_to_le16(0); - header->authetication.algorithm = __cpu_to_le16(params->algorithm); - header->authetication.transactionseqnumber = __cpu_to_le16(params->transactionseqnumber); - header->authetication.statuscode = __cpu_to_le16(params->statuscode); - - /* Header frame size */ - responselength = (int)((uint8_t*)&header->authetication.ie[0] - (uint8_t*)header); - - /* TODO: add custon IE */ - - return responselength; -} - -/* */ -int ieee80211_create_associationresponse_response(uint8_t* buffer, int length, struct ieee80211_associationresponse_params* params) { - uint8_t* pos; - int result; - int responselength; - struct ieee80211_header_mgmt* header; - - ASSERT(buffer != NULL); - - /* */ - header = (struct ieee80211_header_mgmt*)buffer; - - /* Management header frame */ - header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE); - header->durationid = __cpu_to_le16(0); - memcpy(header->da, params->station, ETH_ALEN); - memcpy(header->sa, params->bssid, ETH_ALEN); - memcpy(header->bssid, params->bssid, ETH_ALEN); - header->sequencecontrol = __cpu_to_le16(0); - header->associationresponse.capability = __cpu_to_le16(params->capability); - header->associationresponse.statuscode = __cpu_to_le16(params->statuscode); - header->associationresponse.aid = __cpu_to_le16(params->aid); - - /* Header frame size */ - responselength = (int)((uint8_t*)&header->associationresponse.ie[0] - (uint8_t*)header); - pos = buffer + responselength; - - /* Information Element: Supported Rates */ - result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); - if (result < 0) { - return -1; - } - - pos += result; - responselength += result; - - /* Information Element: Extended Supported Rates */ - result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); - if (result < 0) { - return -1; - } - - /*pos += result;*/ /* Comment for disable Dead inscrement Clang Analyzer warning */ - responselength += result; - - return responselength; -} - -/* */ -int ieee80211_create_deauthentication(uint8_t* buffer, int length, struct ieee80211_deauthentication_params* params) { - struct ieee80211_header_mgmt* header; - - ASSERT(buffer != NULL); - - /* */ - header = (struct ieee80211_header_mgmt*)buffer; - - /* Management header frame */ - header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION); - header->durationid = __cpu_to_le16(0); - memcpy(header->da, params->station, ETH_ALEN); - memcpy(header->sa, params->bssid, ETH_ALEN); - memcpy(header->bssid, params->bssid, ETH_ALEN); - header->sequencecontrol = __cpu_to_le16(0); - header->deauthetication.reasoncode = __cpu_to_le16(params->reasoncode); - - return (int)((uint8_t*)&header->deauthetication.ie[0] - (uint8_t*)header); -} +#include "capwap.h" +#include "ieee80211.h" + +/* */ +static int ieee80211_ie_set_ssid(uint8_t* buffer, const char* ssid, int hidessid) { + struct ieee80211_ie_ssid* iessid = (struct ieee80211_ie_ssid*)buffer; + + ASSERT(buffer != NULL); + ASSERT(ssid != NULL); + + iessid->id = IEEE80211_IE_SSID; + if (hidessid) { + iessid->len = 0; + } else { + iessid->len = strlen(ssid); + if (iessid->len > IEEE80211_IE_SSID_MAX_LENGTH) { + return -1; + } + + strncpy((char*)iessid->ssid, ssid, iessid->len); + } + + return sizeof(struct ieee80211_ie_ssid) + iessid->len; +} + +/* */ +static int ieee80211_ie_set_supportedrates(uint8_t* buffer, uint8_t* supportedrates, int supportedratescount) { + int i; + int count; + struct ieee80211_ie_supported_rates* iesupportedrates = (struct ieee80211_ie_supported_rates*)buffer; + + ASSERT(buffer != NULL); + ASSERT(supportedrates != NULL); + ASSERT(supportedratescount > 0); + + /* IE accept max only 8 rate */ + count = supportedratescount; + if (count > 8) { + count = 8; + } + + /* */ + iesupportedrates->id = IEEE80211_IE_SUPPORTED_RATES; + iesupportedrates->len = count; + + for (i = 0; i < count; i++) { + iesupportedrates->rates[i] = supportedrates[i]; + } + + return sizeof(struct ieee80211_ie_supported_rates) + iesupportedrates->len; +} + +/* */ +static int ieee80211_ie_set_extendedsupportedrates(uint8_t* buffer, uint8_t* supportedrates, int supportedratescount) { + int i, j; + struct ieee80211_ie_extended_supported_rates* ieextendedsupportedrates = (struct ieee80211_ie_extended_supported_rates*)buffer; + + ASSERT(buffer != NULL); + ASSERT(supportedrates != NULL); + + /* IE accept only > 8 rate */ + if (supportedratescount <= IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH) { + return 0; + } + + /* */ + ieextendedsupportedrates->id = IEEE80211_IE_EXTENDED_SUPPORTED_RATES; + ieextendedsupportedrates->len = supportedratescount - IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH; + + for (i = IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH, j = 0; i < supportedratescount; i++, j++) { + ieextendedsupportedrates->rates[j] = supportedrates[i]; + } + + return sizeof(struct ieee80211_ie_extended_supported_rates) + ieextendedsupportedrates->len; +} + +/* */ +static int ieee80211_ie_set_dsss(uint8_t* buffer, uint8_t channel) { + struct ieee80211_ie_dsss* iedsss = (struct ieee80211_ie_dsss*)buffer; + + ASSERT(buffer != NULL); + + iedsss->id = IEEE80211_IE_DSSS; + iedsss->len = IEEE80211_IE_DSSS_LENGTH; + iedsss->channel = channel; + + return sizeof(struct ieee80211_ie_dsss); +} + +/* */ +static int ieee80211_ie_set_erp(uint8_t* buffer, uint32_t mode, uint8_t erpinfo) { + struct ieee80211_ie_erp* ieerp = (struct ieee80211_ie_erp*)buffer; + + ASSERT(buffer != NULL); + + if (!(mode & IEEE80211_RADIO_TYPE_80211G)) { + return 0; + } + + ieerp->id = IEEE80211_IE_ERP; + ieerp->len = IEEE80211_IE_ERP_LENGTH; + ieerp->params = erpinfo; + + return sizeof(struct ieee80211_ie_erp); +} + +/* */ +int ieee80211_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length) { + ASSERT(items != NULL); + ASSERT(data != NULL); + + /* */ + memset(items, 0, sizeof(struct ieee80211_ie_items)); + + /* Parsing */ + while (length >= 2) { + uint8_t ie_id = data[0]; + uint8_t ie_len = data[1]; + + /* Parsing Information Element */ + switch (ie_id) { + case IEEE80211_IE_SSID: { + if (ie_len > IEEE80211_IE_SSID_MAX_LENGTH) { + return -1; + } + + items->ssid = (struct ieee80211_ie_ssid*)data; + break; + } + + case IEEE80211_IE_SUPPORTED_RATES: { + if ((ie_len < IEEE80211_IE_SUPPORTED_RATES_MIN_LENGTH) || (ie_len > IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH)) { + return -1; + } + + items->supported_rates = (struct ieee80211_ie_supported_rates*)data; + break; + } + + case IEEE80211_IE_DSSS: { + if (ie_len != IEEE80211_IE_DSSS_LENGTH) { + return -1; + } + + items->dsss = (struct ieee80211_ie_dsss*)data; + break; + } + + case IEEE80211_IE_COUNTRY: { + if (ie_len < IEEE80211_IE_COUNTRY_MIN_LENGTH) { + return -1; + } + + items->country = (struct ieee80211_ie_country*)data; + break; + } + + case IEEE80211_IE_CHALLENGE_TEXT: { + if (ie_len < IEEE80211_IE_CHALLENGE_TEXT_MIN_LENGTH) { + return -1; + } + + items->challenge_text = (struct ieee80211_ie_challenge_text*)data; + break; + } + + case IEEE80211_IE_ERP: { + if (ie_len != IEEE80211_IE_ERP_LENGTH) { + return -1; + } + + items->erp = (struct ieee80211_ie_erp*)data; + break; + } + + case IEEE80211_IE_EXTENDED_SUPPORTED_RATES: { + if (ie_len < IEEE80211_IE_EXTENDED_SUPPORTED_MIN_LENGTH) { + return -1; + } + + items->extended_supported_rates = (struct ieee80211_ie_extended_supported_rates*)data; + break; + } + + case IEEE80211_IE_EDCA_PARAMETER_SET: { + if (ie_len != IEEE80211_IE_EDCA_PARAMETER_SET_LENGTH) { + return -1; + } + + items->edca_parameter_set = (struct ieee80211_ie_edca_parameter_set*)data; + break; + } + + case IEEE80211_IE_QOS_CAPABILITY: { + if (ie_len != IEEE80211_IE_QOS_CAPABILITY_LENGTH) { + return -1; + } + + items->qos_capability = (struct ieee80211_ie_qos_capability*)data; + break; + } + + case IEEE80211_IE_POWER_CONSTRAINT: { + if (ie_len != IEEE80211_IE_POWER_CONSTRAINT_LENGTH) { + return -1; + } + + items->power_constraint = (struct ieee80211_ie_power_constraint*)data; + break; + } + + case IEEE80211_IE_SSID_LIST: { + items->ssid_list = (struct ieee80211_ie_ssid_list*)data; + break; + } + } + + /* Next Information Element */ + data += sizeof(struct ieee80211_ie) + ie_len; + length -= sizeof(struct ieee80211_ie) + ie_len; + } + + return (!length ? 0 : -1); +} + +/* */ +int ieee80211_aid_create(uint32_t* aidbitfield, uint16_t* aid) { + int i, j; + + ASSERT(aidbitfield != NULL); + ASSERT(aid != NULL); + + /* Search free aid bitfield */ + for (i = 0; i < IEEE80211_AID_BITFIELD_SIZE; i++) { + if (aidbitfield[i] != 0xffffffff) { + uint32_t bitfield = aidbitfield[i]; + + /* Search free bit */ + for (j = 0; j < 32; j++) { + if (!(bitfield & (1 << j))) { + *aid = i * 32 + j + 1; + if (*aid <= IEEE80211_AID_MAX_VALUE) { + aidbitfield[i] |= (1 << j); + return 0; + } + + break; + } + } + + break; + } + } + + *aid = 0; + return -1; +} + +/* */ +void ieee80211_aid_free(uint32_t* aidbitfield, uint16_t aid) { + ASSERT(aidbitfield != NULL); + ASSERT((aid > 0) && (aid <= IEEE80211_AID_MAX_VALUE)); + + aidbitfield[(aid - 1) / 32] &= ~(1 << ((aid - 1) % 32)); +} + +/* */ +unsigned long ieee80211_frequency_to_channel(uint32_t freq) { + if ((freq >= 2412) && (freq <= 2472)) { + return (freq - 2407) / 5; + } else if (freq == 2484) { + return 14; + } else if ((freq >= 4915) && (freq <= 4980)) { + return (freq - 4000) / 5; + } else if ((freq >= 5035) && (freq <= 5825)) { + return (freq - 5000) / 5; + } + + return 0; +} + +/* */ +int ieee80211_is_broadcast_addr(const uint8_t* addr) { + return (((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)) ? 1 : 0); +} + +/* */ +const uint8_t* ieee80211_get_sa_addr(const struct ieee80211_header* header) { + uint16_t framecontrol; + uint16_t framecontrol_type; + + ASSERT(header); + + /* Get type frame */ + framecontrol = __le16_to_cpu(header->framecontrol); + framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); + + if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { + return header->address2; + } else if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_DATA) { + switch (framecontrol & (IEEE80211_FRAME_CONTROL_MASK_TODS | IEEE80211_FRAME_CONTROL_MASK_FROMDS)) { + case 0: { + return header->address2; + } + + case IEEE80211_FRAME_CONTROL_MASK_TODS: { + return header->address2; + } + + case IEEE80211_FRAME_CONTROL_MASK_FROMDS: { + return header->address3; + } + } + } + + return NULL; +} + +const uint8_t* ieee80211_get_da_addr(const struct ieee80211_header* header) { + uint16_t framecontrol; + uint16_t framecontrol_type; + + ASSERT(header); + + /* Get type frame */ + framecontrol = __le16_to_cpu(header->framecontrol); + framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); + + if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { + return header->address1; + } else if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_DATA) { + switch (framecontrol & (IEEE80211_FRAME_CONTROL_MASK_TODS | IEEE80211_FRAME_CONTROL_MASK_FROMDS)) { + case 0: { + return header->address1; + } + + case IEEE80211_FRAME_CONTROL_MASK_TODS: { + return header->address3; + } + + case IEEE80211_FRAME_CONTROL_MASK_FROMDS: { + return header->address1; + } + } + } + + return NULL; +} + +/* */ +const uint8_t* ieee80211_get_bssid_addr(const struct ieee80211_header* header) { + uint16_t framecontrol; + uint16_t framecontrol_type; + + ASSERT(header); + + /* Get type frame */ + framecontrol = __le16_to_cpu(header->framecontrol); + framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); + + if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { + return header->address3; + } else if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_DATA) { + switch (framecontrol & (IEEE80211_FRAME_CONTROL_MASK_TODS | IEEE80211_FRAME_CONTROL_MASK_FROMDS)) { + case 0: { + return header->address3; + } + + case IEEE80211_FRAME_CONTROL_MASK_TODS: { + return header->address1; + } + + case IEEE80211_FRAME_CONTROL_MASK_FROMDS: { + return header->address2; + } + } + } + + return NULL; +} + +/* */ +int ieee80211_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struct ieee80211_ie_ssid_list* isssidlist) { + int ssidlength; + + ASSERT(ssid != NULL); + + if (!iessid) { + return IEEE80211_WRONG_SSID; + } + + /* Check SSID */ + ssidlength = strlen((char*)ssid); + if ((ssidlength == iessid->len) && !memcmp(ssid, iessid->ssid, ssidlength)) { + return IEEE80211_VALID_SSID; + } + + /* Check SSID list */ + if (isssidlist) { + int length = isssidlist->len; + uint8_t* pos = isssidlist->lists; + + while (length >= sizeof(struct ieee80211_ie)) { + struct ieee80211_ie_ssid* ssiditem = (struct ieee80211_ie_ssid*)pos; + + /* Check buffer */ + length -= sizeof(struct ieee80211_ie); + if ((ssiditem->id != IEEE80211_IE_SSID) || !ssiditem->len || (length < ssiditem->len)) { + break; + } else if ((ssidlength == ssiditem->len) && !memcmp(ssid, ssiditem->ssid, ssidlength)) { + return IEEE80211_VALID_SSID; + } + + /* Next */ + length -= ssiditem->len; + pos += sizeof(struct ieee80211_ie) + ssiditem->len; + } + } + + return (!iessid->len ? IEEE80211_WILDCARD_SSID : IEEE80211_WRONG_SSID); +} + +/* */ +uint8_t ieee80211_get_erpinfo(uint32_t mode, int olbc, unsigned long stationnonerpcount, unsigned long stationnoshortpreamblecount, int shortpreamble) { + uint8_t result = 0; + + /* Erp mode is valid only in IEEE 802.11 g*/ + if (mode & IEEE80211_RADIO_TYPE_80211G) { + if (olbc) { + result |= IEEE80211_ERP_INFO_USE_PROTECTION; + } + + if (stationnonerpcount > 0) { + result |= (IEEE80211_ERP_INFO_NON_ERP_PRESENT | IEEE80211_ERP_INFO_USE_PROTECTION); + } + + if (!shortpreamble || (stationnoshortpreamblecount > 0)) { + result |= IEEE80211_ERP_INFO_BARKER_PREAMBLE_MODE; + } + } + + return result; +} + + +/* */ +int ieee80211_create_beacon(uint8_t* buffer, int length, struct ieee80211_beacon_params* params) { + int result; + uint8_t* pos; + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + + /* */ + header = (struct ieee80211_header_mgmt*)buffer; + params->headbeacon = buffer; + + /* Management header frame */ + header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_BEACON); + header->durationid = __cpu_to_le16(0); + memset(header->da, 0xff, ETH_ALEN); + memcpy(header->sa, params->bssid, ETH_ALEN); + memcpy(header->bssid, params->bssid, ETH_ALEN); + header->sequencecontrol = __cpu_to_le16(0); + memset(header->beacon.timestamp, 0, sizeof(header->beacon.timestamp)); + header->beacon.beaconinterval = __cpu_to_le16(params->beaconperiod); + header->beacon.capability = __cpu_to_le16(params->capability); + + /* Header frame size */ + params->headbeaconlength = (int)((uint8_t*)&header->beacon.ie[0] - (uint8_t*)header); + pos = buffer + params->headbeaconlength; + + /* Information Element: SSID */ + result = ieee80211_ie_set_ssid(pos, params->ssid, (params->ssid_hidden ? 1 : 0)); + if (result < 0) { + return -1; + } + + pos += result; + params->headbeaconlength += result; + + /* Information Element: Supported Rates */ + result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + params->headbeaconlength += result; + + /* Information Element: DSSS */ + result = ieee80211_ie_set_dsss(pos, params->channel); + if (result < 0) { + return -1; + } + + pos += result; + params->headbeaconlength += result; + + /* Separate Information Elements into two block between IE TIM */ + params->tailbeacon = pos; + params->tailbeaconlength = 0; + + /* Information Element: Country */ + /* TODO */ + + /* Information Element: ERP */ + result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo); + if (result < 0) { + return -1; + } + + pos += result; + params->tailbeaconlength += result; + + /* Information Element: Extended Supported Rates */ + result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + params->tailbeaconlength += result; + + /* Probe Response offload */ + if (params->flags & IEEE80221_CREATE_BEACON_FLAGS_PROBE_RESPONSE_OFFLOAD) { + struct ieee80211_probe_response_params proberesponseparams; + + /* */ + memset(&proberesponseparams, 0, sizeof(struct ieee80211_probe_response_params)); + memcpy(proberesponseparams.bssid, params->bssid, ETH_ALEN); + proberesponseparams.beaconperiod = params->beaconperiod; + proberesponseparams.capability = params->capability; + proberesponseparams.ssid = params->ssid; + memcpy(proberesponseparams.supportedrates, params->supportedrates, params->supportedratescount); + proberesponseparams.supportedratescount = params->supportedratescount; + proberesponseparams.mode = params->mode; + proberesponseparams.erpinfo = params->erpinfo; + proberesponseparams.channel = params->channel; + + /* */ + params->proberesponseoffload = pos; + params->proberesponseoffloadlength = ieee80211_create_probe_response(pos, (int)(pos - buffer), &proberesponseparams); + if (params->proberesponseoffloadlength < 0) { + return -1; + } + + /* */ + pos += params->proberesponseoffloadlength; + } + + return (int)(pos - buffer); +} + +/* */ +int ieee80211_create_probe_response(uint8_t* buffer, int length, struct ieee80211_probe_response_params* params) { + int result; + uint8_t* pos; + int responselength; + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + + /* */ + header = (struct ieee80211_header_mgmt*)buffer; + + /* Management header frame */ + header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESPONSE); + header->durationid = __cpu_to_le16(0); + memcpy(header->da, params->station, ETH_ALEN); + memcpy(header->sa, params->bssid, ETH_ALEN); + memcpy(header->bssid, params->bssid, ETH_ALEN); + header->sequencecontrol = __cpu_to_le16(0); + memset(header->proberesponse.timestamp, 0, sizeof(header->proberesponse.timestamp)); + header->proberesponse.beaconinterval = __cpu_to_le16(params->beaconperiod); + header->proberesponse.capability = __cpu_to_le16(params->capability); + + /* Header frame size */ + responselength = (int)((uint8_t*)&header->proberesponse.ie[0] - (uint8_t*)header); + pos = buffer + responselength; + + /* Information Element: SSID */ + result = ieee80211_ie_set_ssid(pos, params->ssid, 0); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: Supported Rates */ + result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: DSSS */ + result = ieee80211_ie_set_dsss(pos, params->channel); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: Country */ + /* TODO */ + + /* Information Element: ERP */ + result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: Extended Supported Rates */ + result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + /*pos += result;*/ /* Comment for disable Dead inscrement Clang Analyzer warning */ + responselength += result; + + return responselength; +} + +/* */ +int ieee80211_create_authentication_response(uint8_t* buffer, int length, struct ieee80211_authentication_params* params) { + int responselength; + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + + /* */ + header = (struct ieee80211_header_mgmt*)buffer; + + /* Management header frame */ + header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION); + header->durationid = __cpu_to_le16(0); + memcpy(header->da, params->station, ETH_ALEN); + memcpy(header->sa, params->bssid, ETH_ALEN); + memcpy(header->bssid, params->bssid, ETH_ALEN); + header->sequencecontrol = __cpu_to_le16(0); + header->authetication.algorithm = __cpu_to_le16(params->algorithm); + header->authetication.transactionseqnumber = __cpu_to_le16(params->transactionseqnumber); + header->authetication.statuscode = __cpu_to_le16(params->statuscode); + + /* Header frame size */ + responselength = (int)((uint8_t*)&header->authetication.ie[0] - (uint8_t*)header); + + /* TODO: add custon IE */ + + return responselength; +} + +/* */ +int ieee80211_create_associationresponse_response(uint8_t* buffer, int length, struct ieee80211_associationresponse_params* params) { + uint8_t* pos; + int result; + int responselength; + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + + /* */ + header = (struct ieee80211_header_mgmt*)buffer; + + /* Management header frame */ + header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE); + header->durationid = __cpu_to_le16(0); + memcpy(header->da, params->station, ETH_ALEN); + memcpy(header->sa, params->bssid, ETH_ALEN); + memcpy(header->bssid, params->bssid, ETH_ALEN); + header->sequencecontrol = __cpu_to_le16(0); + header->associationresponse.capability = __cpu_to_le16(params->capability); + header->associationresponse.statuscode = __cpu_to_le16(params->statuscode); + header->associationresponse.aid = __cpu_to_le16(params->aid); + + /* Header frame size */ + responselength = (int)((uint8_t*)&header->associationresponse.ie[0] - (uint8_t*)header); + pos = buffer + responselength; + + /* Information Element: Supported Rates */ + result = ieee80211_ie_set_supportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + pos += result; + responselength += result; + + /* Information Element: Extended Supported Rates */ + result = ieee80211_ie_set_extendedsupportedrates(pos, params->supportedrates, params->supportedratescount); + if (result < 0) { + return -1; + } + + /*pos += result;*/ /* Comment for disable Dead inscrement Clang Analyzer warning */ + responselength += result; + + return responselength; +} + +/* */ +int ieee80211_create_deauthentication(uint8_t* buffer, int length, struct ieee80211_deauthentication_params* params) { + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + + /* */ + header = (struct ieee80211_header_mgmt*)buffer; + + /* Management header frame */ + header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION); + header->durationid = __cpu_to_le16(0); + memcpy(header->da, params->station, ETH_ALEN); + memcpy(header->sa, params->bssid, ETH_ALEN); + memcpy(header->bssid, params->bssid, ETH_ALEN); + header->sequencecontrol = __cpu_to_le16(0); + header->deauthetication.reasoncode = __cpu_to_le16(params->reasoncode); + + return (int)((uint8_t*)&header->deauthetication.ie[0] - (uint8_t*)header); +} diff --git a/src/common/binding/ieee80211/ieee80211.h b/src/common/binding/ieee80211/ieee80211.h index 2d0df25..718b483 100644 --- a/src/common/binding/ieee80211/ieee80211.h +++ b/src/common/binding/ieee80211/ieee80211.h @@ -1,606 +1,606 @@ -#ifndef __CAPWAP_IEEE802_11_HEADER__ -#define __CAPWAP_IEEE802_11_HEADER__ - -#include -#include -#include - -#ifndef STRUCT_PACKED -#define STRUCT_PACKED __attribute__((__packed__)) -#endif - -/* Global values */ -#define IEEE80211_MTU 7981 -#define IEEE80211_SUPPORTEDRATE_MAX_COUNT 16 -#define IEEE80211_MAX_STATIONS 2007 -#define IEEE80211_SSID_MAX_LENGTH 32 - - -/* Radio type with value same of IEEE802.11 Radio Information Message Element */ -#define IEEE80211_RADIO_TYPE_80211B 0x00000001 -#define IEEE80211_RADIO_TYPE_80211A 0x00000002 -#define IEEE80211_RADIO_TYPE_80211G 0x00000004 -#define IEEE80211_RADIO_TYPE_80211N 0x00000008 - -/* */ -#define IS_IEEE80211_FREQ_BG(x) (((x >= 2412) && (x <= 2484)) ? 1 : 0) -#define IS_IEEE80211_FREQ_A(x) ((((x >= 4915) && (x <= 4980)) || ((x >= 5035) && (x <= 5825))) ? 1 : 0) - -/* Rate into multiple of 500Kbps */ -#define IEEE80211_RATE_1M 2 -#define IEEE80211_RATE_2M 4 -#define IEEE80211_RATE_5_5M 11 -#define IEEE80211_RATE_11M 22 -#define IEEE80211_RATE_6M 12 -#define IEEE80211_RATE_9M 18 -#define IEEE80211_RATE_12M 24 -#define IEEE80211_RATE_18M 36 -#define IEEE80211_RATE_24M 48 -#define IEEE80211_RATE_36M 72 -#define IEEE80211_RATE_48M 96 -#define IEEE80211_RATE_54M 108 -#define IEEE80211_RATE_80211N 127 - -#define IS_IEEE80211_RATE_B(x) (((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M) || (x == IEEE80211_RATE_5_5M) || (x == IEEE80211_RATE_11M)) ? 1 : 0) -#define IS_IEEE80211_RATE_G(x) (((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_9M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_18M) || (x == IEEE80211_RATE_24M) || (x == IEEE80211_RATE_36M) || (x == IEEE80211_RATE_48M) || (x == IEEE80211_RATE_54M)) ? 1 : 0) -#define IS_IEEE80211_RATE_A(x) (((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_9M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_18M) || (x == IEEE80211_RATE_24M) || (x == IEEE80211_RATE_36M) || (x == IEEE80211_RATE_48M) || (x == IEEE80211_RATE_54M)) ? 1 : 0) -#define IS_IEEE80211_RATE_N(x) ((x == IEEE80211_RATE_80211N) ? 1 : 0) - -#define IEEE80211_BASICRATE 128 -#define IS_IEEE80211_BASICRATE_B(x) ((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M)) -#define IS_IEEE80211_BASICRATE_G(x) ((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M) || (x == IEEE80211_RATE_5_5M) || (x == IEEE80211_RATE_11M)) -#define IS_IEEE80211_BASICRATE_A(x) ((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_24M)) - -/* Frame control type */ -#define IEEE80211_FRAMECONTROL_TYPE_MGMT 0 -#define IEEE80211_FRAMECONTROL_TYPE_CTRL 1 -#define IEEE80211_FRAMECONTROL_TYPE_DATA 2 - -/* Frame control Management subtype */ -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST 0 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE 1 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST 2 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE 3 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST 4 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESPONSE 5 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_TIMING_ADV 6 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_BEACON 8 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ATIM 9 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION 10 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION 11 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION 12 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION 13 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION_NOACK 14 - -/* Frame control Control subtype */ -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CTRLWRAPPER 7 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_BLOCKACK_REQ 8 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_BLOCKACK 9 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_PSPOLL 10 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_RTS 11 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CTS 12 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_ACK 13 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CFEND 14 -#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CFEND_CFACK 15 - -/* Frame control Data subtype */ -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA 0 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA_CFACK 1 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA_CFPOLL 2 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA_CFACK_CFPOLL 3 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_NULL 4 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_CFACK 5 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_CFPOLL 6 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_CFACK_CFPOLL 7 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA 8 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA_CFACK 9 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA_CFPOLL 10 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA_CFACK_CFPOLL 11 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSNULL 12 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSCFPOLL 14 -#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSCFACK_CFPOLL 15 - -/* */ -#define IEEE80211_FRAME_CONTROL_MASK_PROTOCOL_VERSION 0x0003 -#define IEEE80211_FRAME_CONTROL_MASK_TYPE 0x000c -#define IEEE80211_FRAME_CONTROL_MASK_SUBTYPE 0x00f0 -#define IEEE80211_FRAME_CONTROL_MASK_TODS 0x0100 -#define IEEE80211_FRAME_CONTROL_MASK_FROMDS 0x0200 -#define IEEE80211_FRAME_CONTROL_MASK_MORE_FRAGMENT 0x0400 -#define IEEE80211_FRAME_CONTROL_MASK_RETRY 0x0800 -#define IEEE80211_FRAME_CONTROL_MASK_POWER_MANAGEMENT 0x1000 -#define IEEE80211_FRAME_CONTROL_MASK_MORE_DATA 0x2000 -#define IEEE80211_FRAME_CONTROL_MASK_PROTECTED_FRAME 0x4000 -#define IEEE80211_FRAME_CONTROL_MASK_ORDER 0x8000 - -#define IEEE80211_FRAME_CONTROL(type, stype) __cpu_to_le16((type << 2) | (stype << 4)) -#define IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol) (((framecontrol) & IEEE80211_FRAME_CONTROL_MASK_TYPE) >> 2) -#define IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol) (((framecontrol) & IEEE80211_FRAME_CONTROL_MASK_SUBTYPE) >> 4) - -/* IEEE802.11 Status Code */ -#define IEEE80211_STATUS_SUCCESS 0 -#define IEEE80211_STATUS_UNSPECIFIED_FAILURE 1 -#define IEEE80211_STATUS_TDLS_WAKEUP_ALTERNATE 2 -#define IEEE80211_STATUS_TDLS_WAKEUP_REJECT 3 -#define IEEE80211_STATUS_SECURITY_DISABLED 5 -#define IEEE80211_STATUS_UNACCEPTABLE_LIFETIME 6 -#define IEEE80211_STATUS_NOT_IN_SAME_BSS 7 -#define IEEE80211_STATUS_CAPS_UNSUPPORTED 10 -#define IEEE80211_STATUS_REASSOCIATION_NO_ASSOCIATE 11 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_UNSPEC 12 -#define IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM 13 -#define IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION 14 -#define IEEE80211_STATUS_CHALLENGE_FAIL 15 -#define IEEE80211_STATUS_AUTHENTICATION_TIMEOUT 16 -#define IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_RATES 18 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_NOSHORT 19 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_NOPBCC 20 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_NOAGILITY 21 -#define IEEE80211_STATUS_SPEC_MGMT_REQUIRED 22 -#define IEEE80211_STATUS_PWR_CAPABILITY_NOT_VALID 23 -#define IEEE80211_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_SHORT_SLOT_TIME 25 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_DSSS_OFDM 26 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_HT 27 -#define IEEE80211_STATUS_R0KH_UNREACHABLE 28 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_PCO 29 -#define IEEE80211_STATUS_ASSOCIATION_REJECTED_TEMPORARILY 30 -#define IEEE80211_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 -#define IEEE80211_STATUS_UNSPECIFIED_QOS_FAILURE 32 -#define IEEE80211_STATUS_QOS_INSUFFICIENT_BANDWIDTH 33 -#define IEEE80211_STATUS_EXCESSIVE_FRAME_LOST 34 -#define IEEE80211_STATUS_STA_NOT_SUPPORT_QOS_FACILITY 35 -#define IEEE80211_STATUS_REQUEST_DECLINED 37 -#define IEEE80211_STATUS_INVALID_PARAMETERS 38 -#define IEEE80211_STATUS_REJECTED_WITH_SUGGESTED_CHANGES 39 -#define IEEE80211_STATUS_INVALID_IE 40 -#define IEEE80211_STATUS_GROUP_CIPHER_NOT_VALID 41 -#define IEEE80211_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 -#define IEEE80211_STATUS_AKMP_NOT_VALID 43 -#define IEEE80211_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 -#define IEEE80211_STATUS_INVALID_RSN_IE_CAPAB 45 -#define IEEE80211_STATUS_CIPHER_REJECTED_PER_POLICY 46 -#define IEEE80211_STATUS_TS_NOT_CREATED 47 -#define IEEE80211_STATUS_DIRECT_LINK_NOT_ALLOWED 48 -#define IEEE80211_STATUS_DEST_STA_NOT_PRESENT 49 -#define IEEE80211_STATUS_DEST_STA_NOT_QOS_STA 50 -#define IEEE80211_STATUS_ASSOCIATION_DENIED_LISTEN_INT_TOO_LARGE 51 -#define IEEE80211_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 -#define IEEE80211_STATUS_INVALID_PMKID 53 -#define IEEE80211_STATUS_INVALID_MDIE 54 -#define IEEE80211_STATUS_INVALID_FTIE 55 -#define IEEE80211_STATUS_REQUEST_TCLAS_NOT_SUPPORTED 56 -#define IEEE80211_STATUS_INSUFFICIENT_TCLAS 57 -#define IEEE80211_STATUS_TS_NOT_BEEN_CREATED 58 -#define IEEE80211_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59 -#define IEEE80211_STATUS_NO_OUTSTANDING_GAS_REQ 60 -#define IEEE80211_STATUS_GAS_RESP_NOT_RECEIVED 61 -#define IEEE80211_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62 -#define IEEE80211_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63 -#define IEEE80211_STATUS_REQ_REFUSED_HOME 64 -#define IEEE80211_STATUS_ADV_SRV_UNREACHABLE 65 -#define IEEE80211_STATUS_REQ_REFUSED_SSPN 67 -#define IEEE80211_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68 -#define IEEE80211_STATUS_INVALID_RSNIE 72 -#define IEEE80211_STATUS_UAPSD_COEXISTENCE_NOT_SUPPORTED 73 -#define IEEE80211_STATUS_REQUEST_UAPSD_COEXISTENCE_NOT_SUPPORTED 74 -#define IEEE80211_STATUS_REQUEST_INTERVAL_NOT SUPPORTED 75 -#define IEEE80211_STATUS_ANTI_CLOGGING_TOKEN_REQ 76 -#define IEEE80211_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77 -#define IEEE80211_STATUS_CANNOT_FIND_ALTERNATIVE_TBTT 78 -#define IEEE80211_STATUS_TRANSMISSION_FAILURE 79 -#define IEEE80211_STATUS_REQUYESTED_TCLAS_NOT_SUPPORTED 80 -#define IEEE80211_STATUS_TCLAS_RESOURCES_EXHAUSTED 81 -#define IEEE80211_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82 -#define IEEE80211_STATUS_REFUSED_EXTERNAL_REASON 92 -#define IEEE80211_STATUS_REFUSED_AP_OUT_OF_MEMORY 93 -#define IEEE80211_STATUS_REJECTED_EMERGENCY_SERVICES_NOT_SUPPORTED 94 -#define IEEE80211_STATUS_QUERY_RESPONSE_OUTSTANDING 95 -#define IEEE80211_STATUS_MCCAOP_RESERVATION_CONFLICT 100 -#define IEEE80211_STATUS_MAF_LIMIT_EXCEEDED 101 -#define IEEE80211_STATUS_MCCA_TRACK_LIMIT_EXCEEDED 102 - -/* IEEE802.11 Reason code */ -#define IEEE80211_REASON_UNSPECIFIED 1 -#define IEEE80211_REASON_PREV_AUTH_NOT_VALID 2 -#define IEEE80211_REASON_DEAUTH_LEAVING 3 -#define IEEE80211_REASON_DISASSOC_DUE_TO_INACTIVITY 4 -#define IEEE80211_REASON_DISASSOC_AP_BUSY 5 -#define IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 -#define IEEE80211_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 -#define IEEE80211_REASON_DISASSOC_STA_HAS_LEFT 8 -#define IEEE80211_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 -#define IEEE80211_REASON_PWR_CAPABILITY_NOT_VALID 10 -#define IEEE80211_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 -#define IEEE80211_REASON_INVALID_IE 13 -#define IEEE80211_REASON_MICHAEL_MIC_FAILURE 14 -#define IEEE80211_REASON_4WAY_HANDSHAKE_TIMEOUT 15 -#define IEEE80211_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 -#define IEEE80211_REASON_IE_IN_4WAY_DIFFERS 17 -#define IEEE80211_REASON_GROUP_CIPHER_NOT_VALID 18 -#define IEEE80211_REASON_PAIRWISE_CIPHER_NOT_VALID 19 -#define IEEE80211_REASON_AKMP_NOT_VALID 20 -#define IEEE80211_REASON_UNSUPPORTED_RSN_IE_VERSION 21 -#define IEEE80211_REASON_INVALID_RSN_IE_CAPAB 22 -#define IEEE80211_REASON_IEEE_802_1X_AUTH_FAILED 23 -#define IEEE80211_REASON_CIPHER_SUITE_REJECTED 24 -#define IEEE80211_REASON_TDLS_TEARDOWN_UNREACHABLE 25 -#define IEEE80211_REASON_TDLS_TEARDOWN_UNSPECIFIED 26 -#define IEEE80211_REASON_DISASSOC_LOW_ACK 34 - -/* IEEE802.11 Authentication Algorithm */ -#define IEEE80211_AUTHENTICATION_ALGORITHM_OPEN 0 -#define IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY 1 -#define IEEE80211_AUTHENTICATION_ALGORITHM_FAST_BSS 2 -#define IEEE80211_AUTHENTICATION_ALGORITHM_SAE 3 - -/* */ -#define IEEE80211_AID_FIELD 0xC000 -#define IEEE80211_AID_MAX_VALUE 2007 - -/* */ -#define IEEE80211_ERP_INFO_NON_ERP_PRESENT 0x01 -#define IEEE80211_ERP_INFO_USE_PROTECTION 0x02 -#define IEEE80211_ERP_INFO_BARKER_PREAMBLE_MODE 0x04 - -/* */ -#define IEEE80211_CAPABILITY_ESS 0x0001 -#define IEEE80211_CAPABILITY_IBSS 0x0002 -#define IEEE80211_CAPABILITY_CFPOLLABLE 0x0004 -#define IEEE80211_CAPABILITY_CFPOLLREQUEST 0x0008 -#define IEEE80211_CAPABILITY_PRIVACY 0x0010 -#define IEEE80211_CAPABILITY_SHORTPREAMBLE 0x0020 -#define IEEE80211_CAPABILITY_PBCC 0x0040 -#define IEEE80211_CAPABILITY_CHANNELAGILITY 0x0080 -#define IEEE80211_CAPABILITY_SPECTRUMMAN 0x0100 -#define IEEE80211_CAPABILITY_QOS 0x0200 -#define IEEE80211_CAPABILITY_SHORTSLOTTIME 0x0400 -#define IEEE80211_CAPABILITY_APSD 0x0800 -#define IEEE80211_CAPABILITY_DSSS_OFDM 0x2000 -#define IEEE80211_CAPABILITY_DELAYEDACK 0x4000 -#define IEEE80211_CAPABILITY_IMMEDIATEACK 0x8000 - -/* 802.11 Packet - IEEE802.11 is a little-endian protocol */ -struct ieee80211_header { - __le16 framecontrol; - __le16 durationid; - uint8_t address1[ETH_ALEN]; - uint8_t address2[ETH_ALEN]; - uint8_t address3[ETH_ALEN]; - __le16 sequencecontrol; -} STRUCT_PACKED; - -/* */ -struct ieee80211_header_mgmt { - __le16 framecontrol; - __le16 durationid; - uint8_t da[ETH_ALEN]; - uint8_t sa[ETH_ALEN]; - uint8_t bssid[ETH_ALEN]; - __le16 sequencecontrol; - - union { - struct { - uint8_t timestamp[8]; - __le16 beaconinterval; - __le16 capability; - uint8_t ie[0]; - } STRUCT_PACKED beacon; - - struct { - uint8_t ie[0]; - } STRUCT_PACKED proberequest; - - struct { - uint8_t timestamp[8]; - __le16 beaconinterval; - __le16 capability; - uint8_t ie[0]; - } STRUCT_PACKED proberesponse; - - struct { - __le16 algorithm; - __le16 transactionseqnumber; - __le16 statuscode; - uint8_t ie[0]; - } STRUCT_PACKED authetication; - - struct { - __le16 capability; - __le16 listeninterval; - uint8_t ie[0]; - } STRUCT_PACKED associationrequest; - - struct { - __le16 capability; - __le16 statuscode; - __le16 aid; - uint8_t ie[0]; - } STRUCT_PACKED associationresponse; - - struct { - __le16 capability; - __le16 listeninterval; - uint8_t currentap[6]; - uint8_t ie[0]; - } STRUCT_PACKED reassociationrequest; - - struct { - __le16 capability; - __le16 statuscode; - __le16 aid; - uint8_t ie[0]; - } STRUCT_PACKED reassociationresponse; - - struct { - __le16 reasoncode; - uint8_t ie[0]; - } STRUCT_PACKED deauthetication; - - struct { - __le16 reasoncode; - uint8_t ie[0]; - } STRUCT_PACKED disassociation; - }; -} STRUCT_PACKED; - -/* 802.11 Generic information element */ -struct ieee80211_ie { - uint8_t id; - uint8_t len; -} STRUCT_PACKED; - -/* 802.11 SSID information element */ -#define IEEE80211_IE_SSID 0 -#define IEEE80211_IE_SSID_MAX_LENGTH 32 - -struct ieee80211_ie_ssid { - uint8_t id; - uint8_t len; - uint8_t ssid[0]; -} STRUCT_PACKED; - -/* 802.11 Supported Rates information element */ -#define IEEE80211_IE_SUPPORTED_RATES 1 -#define IEEE80211_IE_SUPPORTED_RATES_MIN_LENGTH 1 -#define IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH 8 - -struct ieee80211_ie_supported_rates { - uint8_t id; - uint8_t len; - uint8_t rates[0]; -} STRUCT_PACKED; - -/* 802.11 DSSS information element */ -#define IEEE80211_IE_DSSS 3 -#define IEEE80211_IE_DSSS_LENGTH 1 - -struct ieee80211_ie_dsss { - uint8_t id; - uint8_t len; - uint8_t channel; -} STRUCT_PACKED; - -/* 802.11 Country information element */ -#define IEEE80211_IE_COUNTRY 7 -#define IEEE80211_IE_COUNTRY_MIN_LENGTH 6 - -struct ieee80211_ie_country_channelgroup { - uint8_t firstchannel; - uint8_t numberchannels; - uint8_t maxtxpower; -} STRUCT_PACKED; - -struct ieee80211_ie_country { - uint8_t id; - uint8_t len; - uint8_t country[3]; - uint8_t channelgroup[0]; -} STRUCT_PACKED; - -/* 802.11 Challenge text information element */ -#define IEEE80211_IE_CHALLENGE_TEXT 16 -#define IEEE80211_IE_CHALLENGE_TEXT_MIN_LENGTH 3 - -struct ieee80211_ie_challenge_text { - uint8_t id; - uint8_t len; - uint8_t challengetext[0]; -} STRUCT_PACKED; - -/* 802.11 ERP information element */ -#define IEEE80211_IE_ERP 42 -#define IEEE80211_IE_ERP_LENGTH 1 - -struct ieee80211_ie_erp { - uint8_t id; - uint8_t len; - uint8_t params; -} STRUCT_PACKED; - -/* 802.11 Extended Supported Rates information element */ -#define IEEE80211_IE_EXTENDED_SUPPORTED_RATES 50 -#define IEEE80211_IE_EXTENDED_SUPPORTED_MIN_LENGTH 1 - -struct ieee80211_ie_extended_supported_rates { - uint8_t id; - uint8_t len; - uint8_t rates[0]; -} STRUCT_PACKED; - -/* 802.11 EDCA Parameter Set information element */ -#define IEEE80211_IE_EDCA_PARAMETER_SET 12 -#define IEEE80211_IE_EDCA_PARAMETER_SET_LENGTH 18 - -#define EDCA_PARAMETER_RECORD_AC_BE_FIELD 0 -#define EDCA_PARAMETER_RECORD_AC_BK_FIELD 1 -#define EDCA_PARAMETER_RECORD_AC_VI_FIELD 2 -#define EDCA_PARAMETER_RECORD_AC_VO_FIELD 3 - -struct ieee80211_ie_edca_parameter_set { - uint8_t id; - uint8_t len; - /* TODO */ -} STRUCT_PACKED; - -/* 802.11 QoS Capability information element */ -#define IEEE80211_IE_QOS_CAPABILITY 46 -#define IEEE80211_IE_QOS_CAPABILITY_LENGTH 1 - -struct ieee80211_ie_qos_capability { - uint8_t id; - uint8_t len; - /* TODO */ -} STRUCT_PACKED; - -/* 802.11 Power Constraint information element */ -#define IEEE80211_IE_POWER_CONSTRAINT 32 -#define IEEE80211_IE_POWER_CONSTRAINT_LENGTH 1 - -struct ieee80211_ie_power_constraint { - uint8_t id; - uint8_t len; - /* TODO */ -} STRUCT_PACKED; - -/* 802.11 SSID List */ -#define IEEE80211_IE_SSID_LIST 84 - -struct ieee80211_ie_ssid_list { - uint8_t id; - uint8_t len; - uint8_t lists[0]; -} STRUCT_PACKED; - -/* 802.11 All information elements */ -struct ieee80211_ie_items { - struct ieee80211_ie_ssid* ssid; - struct ieee80211_ie_supported_rates* supported_rates; - struct ieee80211_ie_dsss* dsss; - struct ieee80211_ie_country* country; - struct ieee80211_ie_challenge_text* challenge_text; - struct ieee80211_ie_erp* erp; - struct ieee80211_ie_extended_supported_rates* extended_supported_rates; - struct ieee80211_ie_edca_parameter_set* edca_parameter_set; - struct ieee80211_ie_qos_capability* qos_capability; - struct ieee80211_ie_power_constraint* power_constraint; - struct ieee80211_ie_ssid_list* ssid_list; -}; - -/* IEEE 802.11 functions */ -uint8_t ieee80211_get_erpinfo(uint32_t mode, int olbc, unsigned long stationnonerpcount, unsigned long stationnoshortpreamblecount, int shortpreamble); - -/* Management Beacon */ -#define IEEE80221_CREATE_BEACON_FLAGS_PROBE_RESPONSE_OFFLOAD 0x00000001 - -struct ieee80211_beacon_params { - unsigned long flags; - - uint8_t* headbeacon; - int headbeaconlength; - uint8_t* tailbeacon; - int tailbeaconlength; - - uint8_t bssid[ETH_ALEN]; - - uint16_t beaconperiod; - uint16_t capability; - - const char* ssid; - int ssid_hidden; - - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - - uint8_t channel; - - uint32_t mode; - uint8_t erpinfo; - - uint8_t* proberesponseoffload; - int proberesponseoffloadlength; -}; - -int ieee80211_create_beacon(uint8_t* buffer, int length, struct ieee80211_beacon_params* params); - -/* Management Probe Response */ -struct ieee80211_probe_response_params { - uint8_t bssid[ETH_ALEN]; - uint8_t station[ETH_ALEN]; - - uint16_t beaconperiod; - uint16_t capability; - - const char* ssid; - - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - - uint8_t channel; - - uint32_t mode; - uint8_t erpinfo; -}; - -int ieee80211_create_probe_response(uint8_t* buffer, int length, struct ieee80211_probe_response_params* params); - -/* Management Authentication */ -struct ieee80211_authentication_params { - uint8_t bssid[ETH_ALEN]; - uint8_t station[ETH_ALEN]; - - uint16_t algorithm; - uint16_t transactionseqnumber; - uint16_t statuscode; -}; - -int ieee80211_create_authentication_response(uint8_t* buffer, int length, struct ieee80211_authentication_params* params); - -/* Management Association Response */ -struct ieee80211_associationresponse_params { - uint8_t bssid[ETH_ALEN]; - uint8_t station[ETH_ALEN]; - - uint16_t capability; - uint16_t statuscode; - uint16_t aid; - - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; -}; - -int ieee80211_create_associationresponse_response(uint8_t* buffer, int length, struct ieee80211_associationresponse_params* params); - -/* Management Deauthentication */ -struct ieee80211_deauthentication_params { - uint8_t bssid[ETH_ALEN]; - uint8_t station[ETH_ALEN]; - - uint16_t reasoncode; -}; - -int ieee80211_create_deauthentication(uint8_t* buffer, int length, struct ieee80211_deauthentication_params* params); - -/* Utils */ -int ieee80211_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length); -unsigned long ieee80211_frequency_to_channel(uint32_t freq); -int ieee80211_is_broadcast_addr(const uint8_t* addr); - -/* */ -const uint8_t* ieee80211_get_sa_addr(const struct ieee80211_header* header); -const uint8_t* ieee80211_get_da_addr(const struct ieee80211_header* header); -const uint8_t* ieee80211_get_bssid_addr(const struct ieee80211_header* header); - -/* */ -#define IEEE80211_VALID_SSID 1 -#define IEEE80211_WILDCARD_SSID 0 -#define IEEE80211_WRONG_SSID -1 -int ieee80211_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struct ieee80211_ie_ssid_list* isssidlist); - -/* IEEE802.11 Aid management */ -#define IEEE80211_AID_BITFIELD_SIZE 63 -int ieee80211_aid_create(uint32_t* aidbitfield, uint16_t* aid); -void ieee80211_aid_free(uint32_t* aidbitfield, uint16_t aid); - -#endif /* __CAPWAP_IEEE802_11_HEADER__ */ +#ifndef __CAPWAP_IEEE802_11_HEADER__ +#define __CAPWAP_IEEE802_11_HEADER__ + +#include +#include +#include + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED __attribute__((__packed__)) +#endif + +/* Global values */ +#define IEEE80211_MTU 7981 +#define IEEE80211_SUPPORTEDRATE_MAX_COUNT 16 +#define IEEE80211_MAX_STATIONS 2007 +#define IEEE80211_SSID_MAX_LENGTH 32 + + +/* Radio type with value same of IEEE802.11 Radio Information Message Element */ +#define IEEE80211_RADIO_TYPE_80211B 0x00000001 +#define IEEE80211_RADIO_TYPE_80211A 0x00000002 +#define IEEE80211_RADIO_TYPE_80211G 0x00000004 +#define IEEE80211_RADIO_TYPE_80211N 0x00000008 + +/* */ +#define IS_IEEE80211_FREQ_BG(x) (((x >= 2412) && (x <= 2484)) ? 1 : 0) +#define IS_IEEE80211_FREQ_A(x) ((((x >= 4915) && (x <= 4980)) || ((x >= 5035) && (x <= 5825))) ? 1 : 0) + +/* Rate into multiple of 500Kbps */ +#define IEEE80211_RATE_1M 2 +#define IEEE80211_RATE_2M 4 +#define IEEE80211_RATE_5_5M 11 +#define IEEE80211_RATE_11M 22 +#define IEEE80211_RATE_6M 12 +#define IEEE80211_RATE_9M 18 +#define IEEE80211_RATE_12M 24 +#define IEEE80211_RATE_18M 36 +#define IEEE80211_RATE_24M 48 +#define IEEE80211_RATE_36M 72 +#define IEEE80211_RATE_48M 96 +#define IEEE80211_RATE_54M 108 +#define IEEE80211_RATE_80211N 127 + +#define IS_IEEE80211_RATE_B(x) (((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M) || (x == IEEE80211_RATE_5_5M) || (x == IEEE80211_RATE_11M)) ? 1 : 0) +#define IS_IEEE80211_RATE_G(x) (((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_9M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_18M) || (x == IEEE80211_RATE_24M) || (x == IEEE80211_RATE_36M) || (x == IEEE80211_RATE_48M) || (x == IEEE80211_RATE_54M)) ? 1 : 0) +#define IS_IEEE80211_RATE_A(x) (((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_9M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_18M) || (x == IEEE80211_RATE_24M) || (x == IEEE80211_RATE_36M) || (x == IEEE80211_RATE_48M) || (x == IEEE80211_RATE_54M)) ? 1 : 0) +#define IS_IEEE80211_RATE_N(x) ((x == IEEE80211_RATE_80211N) ? 1 : 0) + +#define IEEE80211_BASICRATE 128 +#define IS_IEEE80211_BASICRATE_B(x) ((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M)) +#define IS_IEEE80211_BASICRATE_G(x) ((x == IEEE80211_RATE_1M) || (x == IEEE80211_RATE_2M) || (x == IEEE80211_RATE_5_5M) || (x == IEEE80211_RATE_11M)) +#define IS_IEEE80211_BASICRATE_A(x) ((x == IEEE80211_RATE_6M) || (x == IEEE80211_RATE_12M) || (x == IEEE80211_RATE_24M)) + +/* Frame control type */ +#define IEEE80211_FRAMECONTROL_TYPE_MGMT 0 +#define IEEE80211_FRAMECONTROL_TYPE_CTRL 1 +#define IEEE80211_FRAMECONTROL_TYPE_DATA 2 + +/* Frame control Management subtype */ +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST 0 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE 1 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST 2 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE 3 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST 4 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESPONSE 5 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_TIMING_ADV 6 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_BEACON 8 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ATIM 9 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION 10 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION 11 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION 12 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION 13 +#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION_NOACK 14 + +/* Frame control Control subtype */ +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CTRLWRAPPER 7 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_BLOCKACK_REQ 8 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_BLOCKACK 9 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_PSPOLL 10 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_RTS 11 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CTS 12 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_ACK 13 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CFEND 14 +#define IEEE80211_FRAMECONTROL_CTRL_SUBTYPE_CFEND_CFACK 15 + +/* Frame control Data subtype */ +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA 0 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA_CFACK 1 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA_CFPOLL 2 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_DATA_CFACK_CFPOLL 3 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_NULL 4 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_CFACK 5 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_CFPOLL 6 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_CFACK_CFPOLL 7 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA 8 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA_CFACK 9 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA_CFPOLL 10 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSDATA_CFACK_CFPOLL 11 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSNULL 12 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSCFPOLL 14 +#define IEEE80211_FRAMECONTROL_DATA_SUBTYPE_QOSCFACK_CFPOLL 15 + +/* */ +#define IEEE80211_FRAME_CONTROL_MASK_PROTOCOL_VERSION 0x0003 +#define IEEE80211_FRAME_CONTROL_MASK_TYPE 0x000c +#define IEEE80211_FRAME_CONTROL_MASK_SUBTYPE 0x00f0 +#define IEEE80211_FRAME_CONTROL_MASK_TODS 0x0100 +#define IEEE80211_FRAME_CONTROL_MASK_FROMDS 0x0200 +#define IEEE80211_FRAME_CONTROL_MASK_MORE_FRAGMENT 0x0400 +#define IEEE80211_FRAME_CONTROL_MASK_RETRY 0x0800 +#define IEEE80211_FRAME_CONTROL_MASK_POWER_MANAGEMENT 0x1000 +#define IEEE80211_FRAME_CONTROL_MASK_MORE_DATA 0x2000 +#define IEEE80211_FRAME_CONTROL_MASK_PROTECTED_FRAME 0x4000 +#define IEEE80211_FRAME_CONTROL_MASK_ORDER 0x8000 + +#define IEEE80211_FRAME_CONTROL(type, stype) __cpu_to_le16((type << 2) | (stype << 4)) +#define IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol) (((framecontrol) & IEEE80211_FRAME_CONTROL_MASK_TYPE) >> 2) +#define IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol) (((framecontrol) & IEEE80211_FRAME_CONTROL_MASK_SUBTYPE) >> 4) + +/* IEEE802.11 Status Code */ +#define IEEE80211_STATUS_SUCCESS 0 +#define IEEE80211_STATUS_UNSPECIFIED_FAILURE 1 +#define IEEE80211_STATUS_TDLS_WAKEUP_ALTERNATE 2 +#define IEEE80211_STATUS_TDLS_WAKEUP_REJECT 3 +#define IEEE80211_STATUS_SECURITY_DISABLED 5 +#define IEEE80211_STATUS_UNACCEPTABLE_LIFETIME 6 +#define IEEE80211_STATUS_NOT_IN_SAME_BSS 7 +#define IEEE80211_STATUS_CAPS_UNSUPPORTED 10 +#define IEEE80211_STATUS_REASSOCIATION_NO_ASSOCIATE 11 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_UNSPEC 12 +#define IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM 13 +#define IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION 14 +#define IEEE80211_STATUS_CHALLENGE_FAIL 15 +#define IEEE80211_STATUS_AUTHENTICATION_TIMEOUT 16 +#define IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_RATES 18 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_NOSHORT 19 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_NOPBCC 20 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_NOAGILITY 21 +#define IEEE80211_STATUS_SPEC_MGMT_REQUIRED 22 +#define IEEE80211_STATUS_PWR_CAPABILITY_NOT_VALID 23 +#define IEEE80211_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_SHORT_SLOT_TIME 25 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_DSSS_OFDM 26 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_HT 27 +#define IEEE80211_STATUS_R0KH_UNREACHABLE 28 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_NO_PCO 29 +#define IEEE80211_STATUS_ASSOCIATION_REJECTED_TEMPORARILY 30 +#define IEEE80211_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 +#define IEEE80211_STATUS_UNSPECIFIED_QOS_FAILURE 32 +#define IEEE80211_STATUS_QOS_INSUFFICIENT_BANDWIDTH 33 +#define IEEE80211_STATUS_EXCESSIVE_FRAME_LOST 34 +#define IEEE80211_STATUS_STA_NOT_SUPPORT_QOS_FACILITY 35 +#define IEEE80211_STATUS_REQUEST_DECLINED 37 +#define IEEE80211_STATUS_INVALID_PARAMETERS 38 +#define IEEE80211_STATUS_REJECTED_WITH_SUGGESTED_CHANGES 39 +#define IEEE80211_STATUS_INVALID_IE 40 +#define IEEE80211_STATUS_GROUP_CIPHER_NOT_VALID 41 +#define IEEE80211_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 +#define IEEE80211_STATUS_AKMP_NOT_VALID 43 +#define IEEE80211_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 +#define IEEE80211_STATUS_INVALID_RSN_IE_CAPAB 45 +#define IEEE80211_STATUS_CIPHER_REJECTED_PER_POLICY 46 +#define IEEE80211_STATUS_TS_NOT_CREATED 47 +#define IEEE80211_STATUS_DIRECT_LINK_NOT_ALLOWED 48 +#define IEEE80211_STATUS_DEST_STA_NOT_PRESENT 49 +#define IEEE80211_STATUS_DEST_STA_NOT_QOS_STA 50 +#define IEEE80211_STATUS_ASSOCIATION_DENIED_LISTEN_INT_TOO_LARGE 51 +#define IEEE80211_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 +#define IEEE80211_STATUS_INVALID_PMKID 53 +#define IEEE80211_STATUS_INVALID_MDIE 54 +#define IEEE80211_STATUS_INVALID_FTIE 55 +#define IEEE80211_STATUS_REQUEST_TCLAS_NOT_SUPPORTED 56 +#define IEEE80211_STATUS_INSUFFICIENT_TCLAS 57 +#define IEEE80211_STATUS_TS_NOT_BEEN_CREATED 58 +#define IEEE80211_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59 +#define IEEE80211_STATUS_NO_OUTSTANDING_GAS_REQ 60 +#define IEEE80211_STATUS_GAS_RESP_NOT_RECEIVED 61 +#define IEEE80211_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62 +#define IEEE80211_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63 +#define IEEE80211_STATUS_REQ_REFUSED_HOME 64 +#define IEEE80211_STATUS_ADV_SRV_UNREACHABLE 65 +#define IEEE80211_STATUS_REQ_REFUSED_SSPN 67 +#define IEEE80211_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68 +#define IEEE80211_STATUS_INVALID_RSNIE 72 +#define IEEE80211_STATUS_UAPSD_COEXISTENCE_NOT_SUPPORTED 73 +#define IEEE80211_STATUS_REQUEST_UAPSD_COEXISTENCE_NOT_SUPPORTED 74 +#define IEEE80211_STATUS_REQUEST_INTERVAL_NOT SUPPORTED 75 +#define IEEE80211_STATUS_ANTI_CLOGGING_TOKEN_REQ 76 +#define IEEE80211_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77 +#define IEEE80211_STATUS_CANNOT_FIND_ALTERNATIVE_TBTT 78 +#define IEEE80211_STATUS_TRANSMISSION_FAILURE 79 +#define IEEE80211_STATUS_REQUYESTED_TCLAS_NOT_SUPPORTED 80 +#define IEEE80211_STATUS_TCLAS_RESOURCES_EXHAUSTED 81 +#define IEEE80211_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82 +#define IEEE80211_STATUS_REFUSED_EXTERNAL_REASON 92 +#define IEEE80211_STATUS_REFUSED_AP_OUT_OF_MEMORY 93 +#define IEEE80211_STATUS_REJECTED_EMERGENCY_SERVICES_NOT_SUPPORTED 94 +#define IEEE80211_STATUS_QUERY_RESPONSE_OUTSTANDING 95 +#define IEEE80211_STATUS_MCCAOP_RESERVATION_CONFLICT 100 +#define IEEE80211_STATUS_MAF_LIMIT_EXCEEDED 101 +#define IEEE80211_STATUS_MCCA_TRACK_LIMIT_EXCEEDED 102 + +/* IEEE802.11 Reason code */ +#define IEEE80211_REASON_UNSPECIFIED 1 +#define IEEE80211_REASON_PREV_AUTH_NOT_VALID 2 +#define IEEE80211_REASON_DEAUTH_LEAVING 3 +#define IEEE80211_REASON_DISASSOC_DUE_TO_INACTIVITY 4 +#define IEEE80211_REASON_DISASSOC_AP_BUSY 5 +#define IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 +#define IEEE80211_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 +#define IEEE80211_REASON_DISASSOC_STA_HAS_LEFT 8 +#define IEEE80211_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 +#define IEEE80211_REASON_PWR_CAPABILITY_NOT_VALID 10 +#define IEEE80211_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 +#define IEEE80211_REASON_INVALID_IE 13 +#define IEEE80211_REASON_MICHAEL_MIC_FAILURE 14 +#define IEEE80211_REASON_4WAY_HANDSHAKE_TIMEOUT 15 +#define IEEE80211_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 +#define IEEE80211_REASON_IE_IN_4WAY_DIFFERS 17 +#define IEEE80211_REASON_GROUP_CIPHER_NOT_VALID 18 +#define IEEE80211_REASON_PAIRWISE_CIPHER_NOT_VALID 19 +#define IEEE80211_REASON_AKMP_NOT_VALID 20 +#define IEEE80211_REASON_UNSUPPORTED_RSN_IE_VERSION 21 +#define IEEE80211_REASON_INVALID_RSN_IE_CAPAB 22 +#define IEEE80211_REASON_IEEE_802_1X_AUTH_FAILED 23 +#define IEEE80211_REASON_CIPHER_SUITE_REJECTED 24 +#define IEEE80211_REASON_TDLS_TEARDOWN_UNREACHABLE 25 +#define IEEE80211_REASON_TDLS_TEARDOWN_UNSPECIFIED 26 +#define IEEE80211_REASON_DISASSOC_LOW_ACK 34 + +/* IEEE802.11 Authentication Algorithm */ +#define IEEE80211_AUTHENTICATION_ALGORITHM_OPEN 0 +#define IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY 1 +#define IEEE80211_AUTHENTICATION_ALGORITHM_FAST_BSS 2 +#define IEEE80211_AUTHENTICATION_ALGORITHM_SAE 3 + +/* */ +#define IEEE80211_AID_FIELD 0xC000 +#define IEEE80211_AID_MAX_VALUE 2007 + +/* */ +#define IEEE80211_ERP_INFO_NON_ERP_PRESENT 0x01 +#define IEEE80211_ERP_INFO_USE_PROTECTION 0x02 +#define IEEE80211_ERP_INFO_BARKER_PREAMBLE_MODE 0x04 + +/* */ +#define IEEE80211_CAPABILITY_ESS 0x0001 +#define IEEE80211_CAPABILITY_IBSS 0x0002 +#define IEEE80211_CAPABILITY_CFPOLLABLE 0x0004 +#define IEEE80211_CAPABILITY_CFPOLLREQUEST 0x0008 +#define IEEE80211_CAPABILITY_PRIVACY 0x0010 +#define IEEE80211_CAPABILITY_SHORTPREAMBLE 0x0020 +#define IEEE80211_CAPABILITY_PBCC 0x0040 +#define IEEE80211_CAPABILITY_CHANNELAGILITY 0x0080 +#define IEEE80211_CAPABILITY_SPECTRUMMAN 0x0100 +#define IEEE80211_CAPABILITY_QOS 0x0200 +#define IEEE80211_CAPABILITY_SHORTSLOTTIME 0x0400 +#define IEEE80211_CAPABILITY_APSD 0x0800 +#define IEEE80211_CAPABILITY_DSSS_OFDM 0x2000 +#define IEEE80211_CAPABILITY_DELAYEDACK 0x4000 +#define IEEE80211_CAPABILITY_IMMEDIATEACK 0x8000 + +/* 802.11 Packet - IEEE802.11 is a little-endian protocol */ +struct ieee80211_header { + __le16 framecontrol; + __le16 durationid; + uint8_t address1[ETH_ALEN]; + uint8_t address2[ETH_ALEN]; + uint8_t address3[ETH_ALEN]; + __le16 sequencecontrol; +} STRUCT_PACKED; + +/* */ +struct ieee80211_header_mgmt { + __le16 framecontrol; + __le16 durationid; + uint8_t da[ETH_ALEN]; + uint8_t sa[ETH_ALEN]; + uint8_t bssid[ETH_ALEN]; + __le16 sequencecontrol; + + union { + struct { + uint8_t timestamp[8]; + __le16 beaconinterval; + __le16 capability; + uint8_t ie[0]; + } STRUCT_PACKED beacon; + + struct { + uint8_t ie[0]; + } STRUCT_PACKED proberequest; + + struct { + uint8_t timestamp[8]; + __le16 beaconinterval; + __le16 capability; + uint8_t ie[0]; + } STRUCT_PACKED proberesponse; + + struct { + __le16 algorithm; + __le16 transactionseqnumber; + __le16 statuscode; + uint8_t ie[0]; + } STRUCT_PACKED authetication; + + struct { + __le16 capability; + __le16 listeninterval; + uint8_t ie[0]; + } STRUCT_PACKED associationrequest; + + struct { + __le16 capability; + __le16 statuscode; + __le16 aid; + uint8_t ie[0]; + } STRUCT_PACKED associationresponse; + + struct { + __le16 capability; + __le16 listeninterval; + uint8_t currentap[6]; + uint8_t ie[0]; + } STRUCT_PACKED reassociationrequest; + + struct { + __le16 capability; + __le16 statuscode; + __le16 aid; + uint8_t ie[0]; + } STRUCT_PACKED reassociationresponse; + + struct { + __le16 reasoncode; + uint8_t ie[0]; + } STRUCT_PACKED deauthetication; + + struct { + __le16 reasoncode; + uint8_t ie[0]; + } STRUCT_PACKED disassociation; + }; +} STRUCT_PACKED; + +/* 802.11 Generic information element */ +struct ieee80211_ie { + uint8_t id; + uint8_t len; +} STRUCT_PACKED; + +/* 802.11 SSID information element */ +#define IEEE80211_IE_SSID 0 +#define IEEE80211_IE_SSID_MAX_LENGTH 32 + +struct ieee80211_ie_ssid { + uint8_t id; + uint8_t len; + uint8_t ssid[0]; +} STRUCT_PACKED; + +/* 802.11 Supported Rates information element */ +#define IEEE80211_IE_SUPPORTED_RATES 1 +#define IEEE80211_IE_SUPPORTED_RATES_MIN_LENGTH 1 +#define IEEE80211_IE_SUPPORTED_RATES_MAX_LENGTH 8 + +struct ieee80211_ie_supported_rates { + uint8_t id; + uint8_t len; + uint8_t rates[0]; +} STRUCT_PACKED; + +/* 802.11 DSSS information element */ +#define IEEE80211_IE_DSSS 3 +#define IEEE80211_IE_DSSS_LENGTH 1 + +struct ieee80211_ie_dsss { + uint8_t id; + uint8_t len; + uint8_t channel; +} STRUCT_PACKED; + +/* 802.11 Country information element */ +#define IEEE80211_IE_COUNTRY 7 +#define IEEE80211_IE_COUNTRY_MIN_LENGTH 6 + +struct ieee80211_ie_country_channelgroup { + uint8_t firstchannel; + uint8_t numberchannels; + uint8_t maxtxpower; +} STRUCT_PACKED; + +struct ieee80211_ie_country { + uint8_t id; + uint8_t len; + uint8_t country[3]; + uint8_t channelgroup[0]; +} STRUCT_PACKED; + +/* 802.11 Challenge text information element */ +#define IEEE80211_IE_CHALLENGE_TEXT 16 +#define IEEE80211_IE_CHALLENGE_TEXT_MIN_LENGTH 3 + +struct ieee80211_ie_challenge_text { + uint8_t id; + uint8_t len; + uint8_t challengetext[0]; +} STRUCT_PACKED; + +/* 802.11 ERP information element */ +#define IEEE80211_IE_ERP 42 +#define IEEE80211_IE_ERP_LENGTH 1 + +struct ieee80211_ie_erp { + uint8_t id; + uint8_t len; + uint8_t params; +} STRUCT_PACKED; + +/* 802.11 Extended Supported Rates information element */ +#define IEEE80211_IE_EXTENDED_SUPPORTED_RATES 50 +#define IEEE80211_IE_EXTENDED_SUPPORTED_MIN_LENGTH 1 + +struct ieee80211_ie_extended_supported_rates { + uint8_t id; + uint8_t len; + uint8_t rates[0]; +} STRUCT_PACKED; + +/* 802.11 EDCA Parameter Set information element */ +#define IEEE80211_IE_EDCA_PARAMETER_SET 12 +#define IEEE80211_IE_EDCA_PARAMETER_SET_LENGTH 18 + +#define EDCA_PARAMETER_RECORD_AC_BE_FIELD 0 +#define EDCA_PARAMETER_RECORD_AC_BK_FIELD 1 +#define EDCA_PARAMETER_RECORD_AC_VI_FIELD 2 +#define EDCA_PARAMETER_RECORD_AC_VO_FIELD 3 + +struct ieee80211_ie_edca_parameter_set { + uint8_t id; + uint8_t len; + /* TODO */ +} STRUCT_PACKED; + +/* 802.11 QoS Capability information element */ +#define IEEE80211_IE_QOS_CAPABILITY 46 +#define IEEE80211_IE_QOS_CAPABILITY_LENGTH 1 + +struct ieee80211_ie_qos_capability { + uint8_t id; + uint8_t len; + /* TODO */ +} STRUCT_PACKED; + +/* 802.11 Power Constraint information element */ +#define IEEE80211_IE_POWER_CONSTRAINT 32 +#define IEEE80211_IE_POWER_CONSTRAINT_LENGTH 1 + +struct ieee80211_ie_power_constraint { + uint8_t id; + uint8_t len; + /* TODO */ +} STRUCT_PACKED; + +/* 802.11 SSID List */ +#define IEEE80211_IE_SSID_LIST 84 + +struct ieee80211_ie_ssid_list { + uint8_t id; + uint8_t len; + uint8_t lists[0]; +} STRUCT_PACKED; + +/* 802.11 All information elements */ +struct ieee80211_ie_items { + struct ieee80211_ie_ssid* ssid; + struct ieee80211_ie_supported_rates* supported_rates; + struct ieee80211_ie_dsss* dsss; + struct ieee80211_ie_country* country; + struct ieee80211_ie_challenge_text* challenge_text; + struct ieee80211_ie_erp* erp; + struct ieee80211_ie_extended_supported_rates* extended_supported_rates; + struct ieee80211_ie_edca_parameter_set* edca_parameter_set; + struct ieee80211_ie_qos_capability* qos_capability; + struct ieee80211_ie_power_constraint* power_constraint; + struct ieee80211_ie_ssid_list* ssid_list; +}; + +/* IEEE 802.11 functions */ +uint8_t ieee80211_get_erpinfo(uint32_t mode, int olbc, unsigned long stationnonerpcount, unsigned long stationnoshortpreamblecount, int shortpreamble); + +/* Management Beacon */ +#define IEEE80221_CREATE_BEACON_FLAGS_PROBE_RESPONSE_OFFLOAD 0x00000001 + +struct ieee80211_beacon_params { + unsigned long flags; + + uint8_t* headbeacon; + int headbeaconlength; + uint8_t* tailbeacon; + int tailbeaconlength; + + uint8_t bssid[ETH_ALEN]; + + uint16_t beaconperiod; + uint16_t capability; + + const char* ssid; + int ssid_hidden; + + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + uint8_t channel; + + uint32_t mode; + uint8_t erpinfo; + + uint8_t* proberesponseoffload; + int proberesponseoffloadlength; +}; + +int ieee80211_create_beacon(uint8_t* buffer, int length, struct ieee80211_beacon_params* params); + +/* Management Probe Response */ +struct ieee80211_probe_response_params { + uint8_t bssid[ETH_ALEN]; + uint8_t station[ETH_ALEN]; + + uint16_t beaconperiod; + uint16_t capability; + + const char* ssid; + + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + uint8_t channel; + + uint32_t mode; + uint8_t erpinfo; +}; + +int ieee80211_create_probe_response(uint8_t* buffer, int length, struct ieee80211_probe_response_params* params); + +/* Management Authentication */ +struct ieee80211_authentication_params { + uint8_t bssid[ETH_ALEN]; + uint8_t station[ETH_ALEN]; + + uint16_t algorithm; + uint16_t transactionseqnumber; + uint16_t statuscode; +}; + +int ieee80211_create_authentication_response(uint8_t* buffer, int length, struct ieee80211_authentication_params* params); + +/* Management Association Response */ +struct ieee80211_associationresponse_params { + uint8_t bssid[ETH_ALEN]; + uint8_t station[ETH_ALEN]; + + uint16_t capability; + uint16_t statuscode; + uint16_t aid; + + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; +}; + +int ieee80211_create_associationresponse_response(uint8_t* buffer, int length, struct ieee80211_associationresponse_params* params); + +/* Management Deauthentication */ +struct ieee80211_deauthentication_params { + uint8_t bssid[ETH_ALEN]; + uint8_t station[ETH_ALEN]; + + uint16_t reasoncode; +}; + +int ieee80211_create_deauthentication(uint8_t* buffer, int length, struct ieee80211_deauthentication_params* params); + +/* Utils */ +int ieee80211_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length); +unsigned long ieee80211_frequency_to_channel(uint32_t freq); +int ieee80211_is_broadcast_addr(const uint8_t* addr); + +/* */ +const uint8_t* ieee80211_get_sa_addr(const struct ieee80211_header* header); +const uint8_t* ieee80211_get_da_addr(const struct ieee80211_header* header); +const uint8_t* ieee80211_get_bssid_addr(const struct ieee80211_header* header); + +/* */ +#define IEEE80211_VALID_SSID 1 +#define IEEE80211_WILDCARD_SSID 0 +#define IEEE80211_WRONG_SSID -1 +int ieee80211_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struct ieee80211_ie_ssid_list* isssidlist); + +/* IEEE802.11 Aid management */ +#define IEEE80211_AID_BITFIELD_SIZE 63 +int ieee80211_aid_create(uint32_t* aidbitfield, uint16_t* aid); +void ieee80211_aid_free(uint32_t* aidbitfield, uint16_t aid); + +#endif /* __CAPWAP_IEEE802_11_HEADER__ */ diff --git a/src/common/capwap_hash.c b/src/common/capwap_hash.c index aed0548..476cbff 100644 --- a/src/common/capwap_hash.c +++ b/src/common/capwap_hash.c @@ -1,555 +1,555 @@ -#include "capwap.h" -#include "capwap_hash.h" - -/* */ -static void capwap_hash_free_item(struct capwap_hash* hash, struct capwap_hash_item* item) { - ASSERT(hash != NULL); - ASSERT(item != NULL); - - if (item->data && hash->item_free) { - hash->item_free(item->data); - } - - capwap_free(item); -} - -/* */ -static void capwap_hash_free_items(struct capwap_hash* hash, struct capwap_hash_item* item) { - ASSERT(hash != NULL); - ASSERT(item != NULL); - - /* Free child */ - if (item->left) { - capwap_hash_free_items(hash, item->left); - } - - if (item->right) { - capwap_hash_free_items(hash, item->right); - } - - /* */ - capwap_hash_free_item(hash, item); -} - -/* */ -static struct capwap_hash_item* capwap_hash_search_items(struct capwap_hash* hash, struct capwap_hash_item* item, const void* key) { - int result; - struct capwap_hash_item* search; - - ASSERT(hash != NULL); - ASSERT(key != NULL); - - search = item; - while (search) { - result = hash->item_cmp(key, hash->item_getkey(search->data)); - - if (!result) { - return search; - } else if (result < 0) { - search = item->left; - } else if (result > 0) { - search = item->right; - } - } - - return NULL; -} - -/* */ -static int capwap_hash_foreach_items(struct capwap_hash* hash, struct capwap_hash_item* item, capwap_hash_item_foreach item_foreach, void* param) { - int result; - - ASSERT(hash != NULL); - ASSERT(item_foreach != NULL); - ASSERT(item != NULL); - - /* */ - if (item->left) { - result = capwap_hash_foreach_items(hash, item->left, item_foreach, param); - if (result == HASH_BREAK) { - return HASH_BREAK; - } - } - - /* */ - item->removenext = NULL; - result = item_foreach(item->data, param); - - /* Delete item */ - if ((result == HASH_DELETE_AND_BREAK) || (result == HASH_DELETE_AND_CONTINUE)) { - item->removenext = hash->removeitems; - hash->removeitems = item; - } - - /* Break */ - if ((result == HASH_BREAK) || (result == HASH_DELETE_AND_BREAK)) { - return HASH_BREAK; - } - - /* */ - if (item->right) { - result = capwap_hash_foreach_items(hash, item->right, item_foreach, param); - if (result == HASH_BREAK) { - return HASH_BREAK; - } - } - - return HASH_CONTINUE; -} - -/* */ -static struct capwap_hash_item* capwap_hash_create_item(struct capwap_hash* hash, void* data) { - struct capwap_hash_item* item; - - ASSERT(hash != NULL); - ASSERT(data != NULL); - - /* */ - item = (struct capwap_hash_item*)capwap_alloc(sizeof(struct capwap_hash_item)); - memset(item, 0, sizeof(struct capwap_hash_item)); - - item->data = data; - - return item; -} - -/* */ -static void capwap_hash_update_height(struct capwap_hash_item* item) { - ASSERT(item != NULL); - - if (item->left && item->right) { - item->height = ((item->left->height > item->right->height) ? item->left->height + 1 : item->right->height + 1); - } else if (item->left) { - item->height = item->left->height + 1; - } else if (item->right) { - item->height = item->right->height + 1; - } else { - item->height = 0; - } -} - -/* */ -static void capwap_hash_set_left_item(struct capwap_hash_item* item, struct capwap_hash_item* child) { - ASSERT(item != NULL); - - if (child) { - child->parent = item; - } - - item->left = child; - capwap_hash_update_height(item); -} - -/* */ -static void capwap_hash_set_right_item(struct capwap_hash_item* item, struct capwap_hash_item* child) { - ASSERT(item != NULL); - - if (child) { - child->parent = item; - } - - item->right = child; - capwap_hash_update_height(item); -} - -/* */ -static void capwap_hash_rotate_left(struct capwap_hash_item* item, struct capwap_hash_item** root) { - int parentside; - struct capwap_hash_item* right; - struct capwap_hash_item* parent; - - ASSERT(item != NULL); - - /* Check parent */ - parent = item->parent; - if (parent) { - parentside = ((parent->left == item) ? 1 : 0); - } - - /* Rotate */ - right = item->right; - capwap_hash_set_right_item(item, right->left); - capwap_hash_set_left_item(right, item); - - /* Update parent */ - if (parent) { - if (parentside) { - capwap_hash_set_left_item(parent, right); - } else { - capwap_hash_set_right_item(parent, right); - } - } else { - right->parent = NULL; - *root = right; - } -} - -/* */ -static void capwap_hash_rotate_right(struct capwap_hash_item* item, struct capwap_hash_item** root) { - int parentside; - struct capwap_hash_item* left; - struct capwap_hash_item* parent; - - ASSERT(item != NULL); - - /* Check parent */ - parent = item->parent; - if (parent) { - parentside = ((parent->left == item) ? 1 : 0); - } - - /* Rotate */ - left = item->left; - capwap_hash_set_left_item(item, left->right); - capwap_hash_set_right_item(left, item); - - /* Update parent */ - if (parent) { - if (parentside) { - capwap_hash_set_left_item(parent, left); - } else { - capwap_hash_set_right_item(parent, left); - } - } else { - left->parent = NULL; - *root = left; - } -} - -/* */ -static int capwap_hash_get_balance_item(struct capwap_hash_item* item) { - ASSERT(item != NULL); - - if (item->left && item->right) { - return item->left->height - item->right->height; - } else if (item->left) { - return item->left->height + 1; - } else if (item->right) { - return -(item->right->height + 1); - } - - return 0; -} - -/* */ -static void capwap_hash_balance_tree(struct capwap_hash_item* item, struct capwap_hash_item** root) { - int result; - - ASSERT(item != NULL); - - result = capwap_hash_get_balance_item(item); - if (result > 1) { - if (capwap_hash_get_balance_item(item->left) < 0) { - capwap_hash_rotate_left(item->left, root); - } - - capwap_hash_rotate_right(item, root); - } else if (result < -1) { - if (capwap_hash_get_balance_item(item->right) > 0) { - capwap_hash_rotate_right(item->right, root); - } - - capwap_hash_rotate_left(item, root); - } -} - -/* */ -static void capwap_hash_deleteitem(struct capwap_hash* hash, const void* key, struct capwap_hash_item* search, unsigned long hashvalue) { - struct capwap_hash_item* parent; - - ASSERT(hash != NULL); - ASSERT(key != NULL); - ASSERT(search != NULL); - ASSERT(hashvalue < hash->hashsize); - - /* Rebalancing tree */ - parent = search->parent; - if (!search->left && !search->right) { - if (parent) { - if (parent->left == search) { - capwap_hash_set_left_item(parent, NULL); - } else { - capwap_hash_set_right_item(parent, NULL); - } - - /* */ - capwap_hash_balance_tree(parent, &hash->items[hashvalue]); - } else { - hash->items[hashvalue] = NULL; - } - } else if (!search->right) { - if (parent) { - if (parent->left == search) { - capwap_hash_set_left_item(parent, search->left); - } else { - capwap_hash_set_right_item(parent, search->left); - } - - /* */ - capwap_hash_balance_tree(parent, &hash->items[hashvalue]); - } else { - search->left->parent = NULL; - hash->items[hashvalue] = search->left; - } - } else if (!search->left) { - if (parent) { - if (parent->left == search) { - capwap_hash_set_left_item(parent, search->right); - } else { - capwap_hash_set_right_item(parent, search->right); - } - - /* */ - capwap_hash_balance_tree(parent, &hash->items[hashvalue]); - } else { - search->right->parent = NULL; - hash->items[hashvalue] = search->right; - } - } else { - struct capwap_hash_item* replacement = NULL; - - if (capwap_hash_get_balance_item(search) > 0) { - if (!search->left->right) { - replacement = search->left; - capwap_hash_set_right_item(replacement, search->right); - } else { - replacement = search->left->right; - while (replacement->right) { - replacement = replacement->right; - } - - capwap_hash_set_right_item(replacement->parent, replacement->left); - capwap_hash_set_left_item(replacement, search->left); - capwap_hash_set_right_item(replacement, search->right); - } - } else { - if (!search->right->left) { - replacement = search->right; - capwap_hash_set_left_item(replacement, search->left); - } else { - replacement = search->right->left; - while (replacement->left) { - replacement = replacement->left; - } - - capwap_hash_set_left_item(replacement->parent, replacement->right); - capwap_hash_set_left_item(replacement, search->left); - capwap_hash_set_right_item(replacement, search->right); - } - } - - if (parent) { - if (parent->left == search) { - capwap_hash_set_left_item(parent, replacement); - } else { - capwap_hash_set_right_item(parent, replacement); - } - } else { - replacement->parent = NULL; - hash->items[hashvalue] = replacement; - } - - capwap_hash_balance_tree(replacement, &hash->items[hashvalue]); - } - - /* Free node */ - hash->count--; - capwap_hash_free_item(hash, search); -} - -/* */ -struct capwap_hash* capwap_hash_create(unsigned long hashsize) { - unsigned long size; - struct capwap_hash* hash; - - ASSERT(hashsize > 0); - - /* */ - hash = (struct capwap_hash*)capwap_alloc(sizeof(struct capwap_hash)); - hash->hashsize = hashsize; - hash->count = 0; - - size = sizeof(struct capwap_hash_item*) * hashsize; - hash->items = (struct capwap_hash_item**)capwap_alloc(size); - memset(hash->items, 0, size); - - return hash; -} - -/* */ -void capwap_hash_free(struct capwap_hash* hash) { - ASSERT(hash != NULL); - - /* Delete all items */ - capwap_hash_deleteall(hash); - - /* Free */ - capwap_free(hash->items); - capwap_free(hash); -} - -/* */ -void capwap_hash_add(struct capwap_hash* hash, void* data) { - int result; - const void* key; - unsigned long hashvalue; - struct capwap_hash_item* search; - struct capwap_hash_item* item = NULL; - - ASSERT(data != NULL); - ASSERT(hash != NULL); - ASSERT(hash->item_gethash != NULL); - ASSERT(hash->item_getkey != NULL); - ASSERT(hash->item_cmp != NULL); - - /* */ - key = hash->item_getkey(data); - hashvalue = hash->item_gethash(key, hash->hashsize); - ASSERT(hashvalue < hash->hashsize); - - /* Search position where insert item */ - search = hash->items[hashvalue]; - if (!search) { - hash->count++; - hash->items[hashvalue] = capwap_hash_create_item(hash, data); - } else { - while (search) { - result = hash->item_cmp(key, hash->item_getkey(search->data)); - if (!result) { - /* Free old element and update data value without create new item */ - if (search->data && hash->item_free) { - hash->item_free(search->data); - } - - search->data = data; - break; - } else if (result < 0) { - if (search->left) { - search = search->left; - } else { - hash->count++; - item = capwap_hash_create_item(hash, data); - capwap_hash_set_left_item(search, item); - break; - } - } else if (result > 0) { - if (search->right) { - search = search->right; - } else { - hash->count++; - item = capwap_hash_create_item(hash, data); - capwap_hash_set_right_item(search, item); - break; - } - } - } - - /* Rebalancing tree */ - while (item) { - capwap_hash_update_height(item); - capwap_hash_balance_tree(item, &hash->items[hashvalue]); - - /* Rebalancing parent */ - item = item->parent; - } - } -} - -/* */ -void capwap_hash_delete(struct capwap_hash* hash, const void* key) { - unsigned long hashvalue; - struct capwap_hash_item* search; - - ASSERT(hash != NULL); - ASSERT(key != NULL); - - /* */ - hashvalue = hash->item_gethash(key, hash->hashsize); - ASSERT(hashvalue < hash->hashsize); - if (!hash->items[hashvalue]) { - return; - } - - /* */ - search = capwap_hash_search_items(hash, hash->items[hashvalue], key); - if (!search) { - return; - } - - /* */ - capwap_hash_deleteitem(hash, key, search, hashvalue); -} - -/* */ -void capwap_hash_deleteall(struct capwap_hash* hash) { - unsigned long i; - - ASSERT(hash != NULL); - - for (i = 0; i < hash->hashsize; i++) { - if (hash->items[i]) { - capwap_hash_free_items(hash, hash->items[i]); - hash->items[i] = NULL; - } - } - - /* */ - hash->count = 0; -} - -/* */ -void* capwap_hash_search(struct capwap_hash* hash, const void* key) { - unsigned long hashvalue; - struct capwap_hash_item* items; - struct capwap_hash_item* result; - - ASSERT(hash != NULL); - ASSERT(key != NULL); - - /* Search item */ - hashvalue = hash->item_gethash(key, hash->hashsize); - items = hash->items[hashvalue]; - if (!items) { - return NULL; - } - - /* */ - result = capwap_hash_search_items(hash, items, key); - if (!result) { - return NULL; - } - - return result->data; -} - -/* */ -void capwap_hash_foreach(struct capwap_hash* hash, capwap_hash_item_foreach item_foreach, void* param) { - int result; - unsigned long i; - - ASSERT(hash != NULL); - ASSERT(item_foreach != NULL); - - /* */ - hash->removeitems = NULL; - - /* */ - for (i = 0; i < hash->hashsize; i++) { - if (hash->items[i]) { - result = capwap_hash_foreach_items(hash, hash->items[i], item_foreach, param); - if (result == HASH_BREAK) { - break; - } - } - } - - /* Delete marked items */ - while (hash->removeitems) { - struct capwap_hash_item* item = hash->removeitems; - const void* key = hash->item_getkey(item->data); - - /* */ - hash->removeitems = item->removenext; - capwap_hash_deleteitem(hash, key, item, hash->item_gethash(key, hash->hashsize)); - } -} +#include "capwap.h" +#include "capwap_hash.h" + +/* */ +static void capwap_hash_free_item(struct capwap_hash* hash, struct capwap_hash_item* item) { + ASSERT(hash != NULL); + ASSERT(item != NULL); + + if (item->data && hash->item_free) { + hash->item_free(item->data); + } + + capwap_free(item); +} + +/* */ +static void capwap_hash_free_items(struct capwap_hash* hash, struct capwap_hash_item* item) { + ASSERT(hash != NULL); + ASSERT(item != NULL); + + /* Free child */ + if (item->left) { + capwap_hash_free_items(hash, item->left); + } + + if (item->right) { + capwap_hash_free_items(hash, item->right); + } + + /* */ + capwap_hash_free_item(hash, item); +} + +/* */ +static struct capwap_hash_item* capwap_hash_search_items(struct capwap_hash* hash, struct capwap_hash_item* item, const void* key) { + int result; + struct capwap_hash_item* search; + + ASSERT(hash != NULL); + ASSERT(key != NULL); + + search = item; + while (search) { + result = hash->item_cmp(key, hash->item_getkey(search->data)); + + if (!result) { + return search; + } else if (result < 0) { + search = item->left; + } else if (result > 0) { + search = item->right; + } + } + + return NULL; +} + +/* */ +static int capwap_hash_foreach_items(struct capwap_hash* hash, struct capwap_hash_item* item, capwap_hash_item_foreach item_foreach, void* param) { + int result; + + ASSERT(hash != NULL); + ASSERT(item_foreach != NULL); + ASSERT(item != NULL); + + /* */ + if (item->left) { + result = capwap_hash_foreach_items(hash, item->left, item_foreach, param); + if (result == HASH_BREAK) { + return HASH_BREAK; + } + } + + /* */ + item->removenext = NULL; + result = item_foreach(item->data, param); + + /* Delete item */ + if ((result == HASH_DELETE_AND_BREAK) || (result == HASH_DELETE_AND_CONTINUE)) { + item->removenext = hash->removeitems; + hash->removeitems = item; + } + + /* Break */ + if ((result == HASH_BREAK) || (result == HASH_DELETE_AND_BREAK)) { + return HASH_BREAK; + } + + /* */ + if (item->right) { + result = capwap_hash_foreach_items(hash, item->right, item_foreach, param); + if (result == HASH_BREAK) { + return HASH_BREAK; + } + } + + return HASH_CONTINUE; +} + +/* */ +static struct capwap_hash_item* capwap_hash_create_item(struct capwap_hash* hash, void* data) { + struct capwap_hash_item* item; + + ASSERT(hash != NULL); + ASSERT(data != NULL); + + /* */ + item = (struct capwap_hash_item*)capwap_alloc(sizeof(struct capwap_hash_item)); + memset(item, 0, sizeof(struct capwap_hash_item)); + + item->data = data; + + return item; +} + +/* */ +static void capwap_hash_update_height(struct capwap_hash_item* item) { + ASSERT(item != NULL); + + if (item->left && item->right) { + item->height = ((item->left->height > item->right->height) ? item->left->height + 1 : item->right->height + 1); + } else if (item->left) { + item->height = item->left->height + 1; + } else if (item->right) { + item->height = item->right->height + 1; + } else { + item->height = 0; + } +} + +/* */ +static void capwap_hash_set_left_item(struct capwap_hash_item* item, struct capwap_hash_item* child) { + ASSERT(item != NULL); + + if (child) { + child->parent = item; + } + + item->left = child; + capwap_hash_update_height(item); +} + +/* */ +static void capwap_hash_set_right_item(struct capwap_hash_item* item, struct capwap_hash_item* child) { + ASSERT(item != NULL); + + if (child) { + child->parent = item; + } + + item->right = child; + capwap_hash_update_height(item); +} + +/* */ +static void capwap_hash_rotate_left(struct capwap_hash_item* item, struct capwap_hash_item** root) { + int parentside; + struct capwap_hash_item* right; + struct capwap_hash_item* parent; + + ASSERT(item != NULL); + + /* Check parent */ + parent = item->parent; + if (parent) { + parentside = ((parent->left == item) ? 1 : 0); + } + + /* Rotate */ + right = item->right; + capwap_hash_set_right_item(item, right->left); + capwap_hash_set_left_item(right, item); + + /* Update parent */ + if (parent) { + if (parentside) { + capwap_hash_set_left_item(parent, right); + } else { + capwap_hash_set_right_item(parent, right); + } + } else { + right->parent = NULL; + *root = right; + } +} + +/* */ +static void capwap_hash_rotate_right(struct capwap_hash_item* item, struct capwap_hash_item** root) { + int parentside; + struct capwap_hash_item* left; + struct capwap_hash_item* parent; + + ASSERT(item != NULL); + + /* Check parent */ + parent = item->parent; + if (parent) { + parentside = ((parent->left == item) ? 1 : 0); + } + + /* Rotate */ + left = item->left; + capwap_hash_set_left_item(item, left->right); + capwap_hash_set_right_item(left, item); + + /* Update parent */ + if (parent) { + if (parentside) { + capwap_hash_set_left_item(parent, left); + } else { + capwap_hash_set_right_item(parent, left); + } + } else { + left->parent = NULL; + *root = left; + } +} + +/* */ +static int capwap_hash_get_balance_item(struct capwap_hash_item* item) { + ASSERT(item != NULL); + + if (item->left && item->right) { + return item->left->height - item->right->height; + } else if (item->left) { + return item->left->height + 1; + } else if (item->right) { + return -(item->right->height + 1); + } + + return 0; +} + +/* */ +static void capwap_hash_balance_tree(struct capwap_hash_item* item, struct capwap_hash_item** root) { + int result; + + ASSERT(item != NULL); + + result = capwap_hash_get_balance_item(item); + if (result > 1) { + if (capwap_hash_get_balance_item(item->left) < 0) { + capwap_hash_rotate_left(item->left, root); + } + + capwap_hash_rotate_right(item, root); + } else if (result < -1) { + if (capwap_hash_get_balance_item(item->right) > 0) { + capwap_hash_rotate_right(item->right, root); + } + + capwap_hash_rotate_left(item, root); + } +} + +/* */ +static void capwap_hash_deleteitem(struct capwap_hash* hash, const void* key, struct capwap_hash_item* search, unsigned long hashvalue) { + struct capwap_hash_item* parent; + + ASSERT(hash != NULL); + ASSERT(key != NULL); + ASSERT(search != NULL); + ASSERT(hashvalue < hash->hashsize); + + /* Rebalancing tree */ + parent = search->parent; + if (!search->left && !search->right) { + if (parent) { + if (parent->left == search) { + capwap_hash_set_left_item(parent, NULL); + } else { + capwap_hash_set_right_item(parent, NULL); + } + + /* */ + capwap_hash_balance_tree(parent, &hash->items[hashvalue]); + } else { + hash->items[hashvalue] = NULL; + } + } else if (!search->right) { + if (parent) { + if (parent->left == search) { + capwap_hash_set_left_item(parent, search->left); + } else { + capwap_hash_set_right_item(parent, search->left); + } + + /* */ + capwap_hash_balance_tree(parent, &hash->items[hashvalue]); + } else { + search->left->parent = NULL; + hash->items[hashvalue] = search->left; + } + } else if (!search->left) { + if (parent) { + if (parent->left == search) { + capwap_hash_set_left_item(parent, search->right); + } else { + capwap_hash_set_right_item(parent, search->right); + } + + /* */ + capwap_hash_balance_tree(parent, &hash->items[hashvalue]); + } else { + search->right->parent = NULL; + hash->items[hashvalue] = search->right; + } + } else { + struct capwap_hash_item* replacement = NULL; + + if (capwap_hash_get_balance_item(search) > 0) { + if (!search->left->right) { + replacement = search->left; + capwap_hash_set_right_item(replacement, search->right); + } else { + replacement = search->left->right; + while (replacement->right) { + replacement = replacement->right; + } + + capwap_hash_set_right_item(replacement->parent, replacement->left); + capwap_hash_set_left_item(replacement, search->left); + capwap_hash_set_right_item(replacement, search->right); + } + } else { + if (!search->right->left) { + replacement = search->right; + capwap_hash_set_left_item(replacement, search->left); + } else { + replacement = search->right->left; + while (replacement->left) { + replacement = replacement->left; + } + + capwap_hash_set_left_item(replacement->parent, replacement->right); + capwap_hash_set_left_item(replacement, search->left); + capwap_hash_set_right_item(replacement, search->right); + } + } + + if (parent) { + if (parent->left == search) { + capwap_hash_set_left_item(parent, replacement); + } else { + capwap_hash_set_right_item(parent, replacement); + } + } else { + replacement->parent = NULL; + hash->items[hashvalue] = replacement; + } + + capwap_hash_balance_tree(replacement, &hash->items[hashvalue]); + } + + /* Free node */ + hash->count--; + capwap_hash_free_item(hash, search); +} + +/* */ +struct capwap_hash* capwap_hash_create(unsigned long hashsize) { + unsigned long size; + struct capwap_hash* hash; + + ASSERT(hashsize > 0); + + /* */ + hash = (struct capwap_hash*)capwap_alloc(sizeof(struct capwap_hash)); + hash->hashsize = hashsize; + hash->count = 0; + + size = sizeof(struct capwap_hash_item*) * hashsize; + hash->items = (struct capwap_hash_item**)capwap_alloc(size); + memset(hash->items, 0, size); + + return hash; +} + +/* */ +void capwap_hash_free(struct capwap_hash* hash) { + ASSERT(hash != NULL); + + /* Delete all items */ + capwap_hash_deleteall(hash); + + /* Free */ + capwap_free(hash->items); + capwap_free(hash); +} + +/* */ +void capwap_hash_add(struct capwap_hash* hash, void* data) { + int result; + const void* key; + unsigned long hashvalue; + struct capwap_hash_item* search; + struct capwap_hash_item* item = NULL; + + ASSERT(data != NULL); + ASSERT(hash != NULL); + ASSERT(hash->item_gethash != NULL); + ASSERT(hash->item_getkey != NULL); + ASSERT(hash->item_cmp != NULL); + + /* */ + key = hash->item_getkey(data); + hashvalue = hash->item_gethash(key, hash->hashsize); + ASSERT(hashvalue < hash->hashsize); + + /* Search position where insert item */ + search = hash->items[hashvalue]; + if (!search) { + hash->count++; + hash->items[hashvalue] = capwap_hash_create_item(hash, data); + } else { + while (search) { + result = hash->item_cmp(key, hash->item_getkey(search->data)); + if (!result) { + /* Free old element and update data value without create new item */ + if (search->data && hash->item_free) { + hash->item_free(search->data); + } + + search->data = data; + break; + } else if (result < 0) { + if (search->left) { + search = search->left; + } else { + hash->count++; + item = capwap_hash_create_item(hash, data); + capwap_hash_set_left_item(search, item); + break; + } + } else if (result > 0) { + if (search->right) { + search = search->right; + } else { + hash->count++; + item = capwap_hash_create_item(hash, data); + capwap_hash_set_right_item(search, item); + break; + } + } + } + + /* Rebalancing tree */ + while (item) { + capwap_hash_update_height(item); + capwap_hash_balance_tree(item, &hash->items[hashvalue]); + + /* Rebalancing parent */ + item = item->parent; + } + } +} + +/* */ +void capwap_hash_delete(struct capwap_hash* hash, const void* key) { + unsigned long hashvalue; + struct capwap_hash_item* search; + + ASSERT(hash != NULL); + ASSERT(key != NULL); + + /* */ + hashvalue = hash->item_gethash(key, hash->hashsize); + ASSERT(hashvalue < hash->hashsize); + if (!hash->items[hashvalue]) { + return; + } + + /* */ + search = capwap_hash_search_items(hash, hash->items[hashvalue], key); + if (!search) { + return; + } + + /* */ + capwap_hash_deleteitem(hash, key, search, hashvalue); +} + +/* */ +void capwap_hash_deleteall(struct capwap_hash* hash) { + unsigned long i; + + ASSERT(hash != NULL); + + for (i = 0; i < hash->hashsize; i++) { + if (hash->items[i]) { + capwap_hash_free_items(hash, hash->items[i]); + hash->items[i] = NULL; + } + } + + /* */ + hash->count = 0; +} + +/* */ +void* capwap_hash_search(struct capwap_hash* hash, const void* key) { + unsigned long hashvalue; + struct capwap_hash_item* items; + struct capwap_hash_item* result; + + ASSERT(hash != NULL); + ASSERT(key != NULL); + + /* Search item */ + hashvalue = hash->item_gethash(key, hash->hashsize); + items = hash->items[hashvalue]; + if (!items) { + return NULL; + } + + /* */ + result = capwap_hash_search_items(hash, items, key); + if (!result) { + return NULL; + } + + return result->data; +} + +/* */ +void capwap_hash_foreach(struct capwap_hash* hash, capwap_hash_item_foreach item_foreach, void* param) { + int result; + unsigned long i; + + ASSERT(hash != NULL); + ASSERT(item_foreach != NULL); + + /* */ + hash->removeitems = NULL; + + /* */ + for (i = 0; i < hash->hashsize; i++) { + if (hash->items[i]) { + result = capwap_hash_foreach_items(hash, hash->items[i], item_foreach, param); + if (result == HASH_BREAK) { + break; + } + } + } + + /* Delete marked items */ + while (hash->removeitems) { + struct capwap_hash_item* item = hash->removeitems; + const void* key = hash->item_getkey(item->data); + + /* */ + hash->removeitems = item->removenext; + capwap_hash_deleteitem(hash, key, item, hash->item_gethash(key, hash->hashsize)); + } +} diff --git a/src/common/capwap_hash.h b/src/common/capwap_hash.h index 9e6940e..c47b0ee 100644 --- a/src/common/capwap_hash.h +++ b/src/common/capwap_hash.h @@ -1,54 +1,54 @@ -#ifndef __CAPWAP_HASH_HEADER__ -#define __CAPWAP_HASH_HEADER__ - -typedef unsigned long (*capwap_hash_item_gethash)(const void* key, unsigned long hashsize); -typedef const void* (*capwap_hash_item_getkey)(const void* data); -typedef int (*capwap_hash_item_cmp)(const void* key1, const void* key2); -typedef void (*capwap_hash_item_free)(void* data); - -#define HASH_BREAK 0 -#define HASH_CONTINUE 1 -#define HASH_DELETE_AND_BREAK 2 -#define HASH_DELETE_AND_CONTINUE 3 -typedef int (*capwap_hash_item_foreach)(void* data, void* param); - -struct capwap_hash_item { - void* data; - - int height; - - struct capwap_hash_item* parent; - struct capwap_hash_item* left; - struct capwap_hash_item* right; - - struct capwap_hash_item* removenext; -}; - -struct capwap_hash { - struct capwap_hash_item** items; - unsigned long hashsize; - - /* */ - unsigned long count; - - /* */ - struct capwap_hash_item* removeitems; - - /* Callback functions */ - capwap_hash_item_gethash item_gethash; - capwap_hash_item_getkey item_getkey; - capwap_hash_item_cmp item_cmp; - capwap_hash_item_free item_free; -}; - -struct capwap_hash* capwap_hash_create(unsigned long hashsize); -void capwap_hash_free(struct capwap_hash* hash); - -void capwap_hash_add(struct capwap_hash* hash, void* data); -void capwap_hash_delete(struct capwap_hash* hash, const void* key); -void capwap_hash_deleteall(struct capwap_hash* hash); - -void* capwap_hash_search(struct capwap_hash* hash, const void* key); -void capwap_hash_foreach(struct capwap_hash* hash, capwap_hash_item_foreach item_foreach, void* param); - -#endif /* __CAPWAP_HASH_HEADER__ */ +#ifndef __CAPWAP_HASH_HEADER__ +#define __CAPWAP_HASH_HEADER__ + +typedef unsigned long (*capwap_hash_item_gethash)(const void* key, unsigned long hashsize); +typedef const void* (*capwap_hash_item_getkey)(const void* data); +typedef int (*capwap_hash_item_cmp)(const void* key1, const void* key2); +typedef void (*capwap_hash_item_free)(void* data); + +#define HASH_BREAK 0 +#define HASH_CONTINUE 1 +#define HASH_DELETE_AND_BREAK 2 +#define HASH_DELETE_AND_CONTINUE 3 +typedef int (*capwap_hash_item_foreach)(void* data, void* param); + +struct capwap_hash_item { + void* data; + + int height; + + struct capwap_hash_item* parent; + struct capwap_hash_item* left; + struct capwap_hash_item* right; + + struct capwap_hash_item* removenext; +}; + +struct capwap_hash { + struct capwap_hash_item** items; + unsigned long hashsize; + + /* */ + unsigned long count; + + /* */ + struct capwap_hash_item* removeitems; + + /* Callback functions */ + capwap_hash_item_gethash item_gethash; + capwap_hash_item_getkey item_getkey; + capwap_hash_item_cmp item_cmp; + capwap_hash_item_free item_free; +}; + +struct capwap_hash* capwap_hash_create(unsigned long hashsize); +void capwap_hash_free(struct capwap_hash* hash); + +void capwap_hash_add(struct capwap_hash* hash, void* data); +void capwap_hash_delete(struct capwap_hash* hash, const void* key); +void capwap_hash_deleteall(struct capwap_hash* hash); + +void* capwap_hash_search(struct capwap_hash* hash, const void* key); +void capwap_hash_foreach(struct capwap_hash* hash, capwap_hash_item_foreach item_foreach, void* param); + +#endif /* __CAPWAP_HASH_HEADER__ */ diff --git a/src/common/capwap_rfc.h b/src/common/capwap_rfc.h index 4dca1a2..08898d5 100644 --- a/src/common/capwap_rfc.h +++ b/src/common/capwap_rfc.h @@ -1,236 +1,236 @@ -#ifndef __CAPWAP_RFC_HEADER__ -#define __CAPWAP_RFC_HEADER__ - -#include - -#ifndef STRUCT_PACKED -#define STRUCT_PACKED __attribute__((__packed__)) -#endif - -#define CAPWAP_PROTOCOL_VERSION 0 - -#define CAPWAP_MTU_DEFAULT 1400 -#define CAPWAP_DONT_FRAGMENT 0 - -/* Capwap preamble */ -#define CAPWAP_PREAMBLE_HEADER 0 -#define CAPWAP_PREAMBLE_DTLS_HEADER 1 - -struct capwap_preamble { -#ifdef CAPWAP_BIG_ENDIAN - uint8_t version : 4; - uint8_t type : 4; -#else - uint8_t type : 4; - uint8_t version : 4; -#endif -} STRUCT_PACKED; - -/* Capwap DTLS header */ -struct capwap_dtls_header { - struct capwap_preamble preamble; - uint8_t reserved1; - uint8_t reserved2; - uint8_t reserved3; -} STRUCT_PACKED; - -/* Capwap header: 8 (header) + 12 (radio mac) + 256 (wireless info) */ -#define CAPWAP_HEADER_MAX_SIZE 276 -struct capwap_header { - struct capwap_preamble preamble; -#ifdef CAPWAP_BIG_ENDIAN - uint16_t hlen : 5; - uint16_t rid : 5; - uint16_t wbid : 5; - uint16_t flag_t : 1; - uint8_t flag_f : 1; - uint8_t flag_l : 1; - uint8_t flag_w : 1; - uint8_t flag_m : 1; - uint8_t flag_k : 1; - uint8_t flag_res : 3; -#else - uint16_t _rid_hi : 3; - uint16_t hlen : 5; - uint16_t flag_t : 1; - uint16_t wbid : 5; - uint16_t _rid_lo : 2; - uint8_t flag_res : 3; - uint8_t flag_k : 1; - uint8_t flag_m : 1; - uint8_t flag_w : 1; - uint8_t flag_l : 1; - uint8_t flag_f : 1; -#endif - uint16_t frag_id; - uint16_t frag_off; /* Only first 13 bit */ -} STRUCT_PACKED; - -#define FRAGMENT_OFFSET_MASK 0xfff8 - -/* Mac Address */ -struct capwap_mac_address { - uint8_t length; - uint8_t address[0]; -} STRUCT_PACKED; - -/* Wireless Information */ -struct capwap_wireless_information { - uint8_t length; - uint8_t data[0]; -} STRUCT_PACKED; - -/* IEEE802.11 Wireless Information */ -struct capwap_ieee80211_frame_info { - uint8_t rssi; - uint8_t snr; - uint16_t rate; -} STRUCT_PACKED; - -/* Message element */ -struct capwap_message_element { - uint16_t type; - uint16_t length; - uint8_t data[0]; -} STRUCT_PACKED; - -/* Control Message Type */ -#define CAPWAP_FIRST_MESSAGE_TYPE 1 -#define CAPWAP_DISCOVERY_REQUEST 1 -#define CAPWAP_DISCOVERY_RESPONSE 2 -#define CAPWAP_JOIN_REQUEST 3 -#define CAPWAP_JOIN_RESPONSE 4 -#define CAPWAP_CONFIGURATION_STATUS_REQUEST 5 -#define CAPWAP_CONFIGURATION_STATUS_RESPONSE 6 -#define CAPWAP_CONFIGURATION_UPDATE_REQUEST 7 -#define CAPWAP_CONFIGURATION_UPDATE_RESPONSE 8 -#define CAPWAP_WTP_EVENT_REQUEST 9 -#define CAPWAP_WTP_EVENT_RESPONSE 10 -#define CAPWAP_CHANGE_STATE_EVENT_REQUEST 11 -#define CAPWAP_CHANGE_STATE_EVENT_RESPONSE 12 -#define CAPWAP_ECHO_REQUEST 13 -#define CAPWAP_ECHO_RESPONSE 14 -#define CAPWAP_IMAGE_DATA_REQUEST 15 -#define CAPWAP_IMAGE_DATA_RESPONSE 16 -#define CAPWAP_RESET_REQUEST 17 -#define CAPWAP_RESET_RESPONSE 18 -#define CAPWAP_PRIMARY_DISCOVERY_REQUEST 19 -#define CAPWAP_PRIMARY_DISCOVERY_RESPONSE 20 -#define CAPWAP_DATA_TRANSFER_REQUEST 21 -#define CAPWAP_DATA_TRANSFER_RESPONSE 22 -#define CAPWAP_CLEAR_CONFIGURATION_REQUEST 23 -#define CAPWAP_CLEAR_CONFIGURATION_RESPONSE 24 -#define CAPWAP_STATION_CONFIGURATION_REQUEST 25 -#define CAPWAP_STATION_CONFIGURATION_RESPONSE 26 -#define CAPWAP_LAST_MESSAGE_TYPE 26 -#define CAPWAP_VALID_MESSAGE_TYPE(x) (((x) >= CAPWAP_FIRST_MESSAGE_TYPE) && ((x) <= CAPWAP_LAST_MESSAGE_TYPE)) - -#define CAPWAP_IEEE80211_FIRST_MESSAGE_TYPE 3398913 -#define CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST 3398913 -#define CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE 3398914 -#define CAPWAP_IEEE80211_LAST_MESSAGE_TYPE 3398914 -#define CAPWAP_VALID_IEEE80211_MESSAGE_TYPE(x) (((x) >= CAPWAP_IEEE80211_FIRST_MESSAGE_TYPE) && ((x) <= CAPWAP_IEEE80211_LAST_MESSAGE_TYPE)) - -/* Control Message */ -#define CAPWAP_CONTROL_MESSAGE_MIN_LENGTH 3 - -struct capwap_control_message { - uint32_t type; - uint8_t seq; - uint16_t length; - uint8_t flags; - uint8_t elements[0]; -} STRUCT_PACKED; - -/* Data Message Keep-Alive*/ -#define CAPWAP_DATA_MESSAGE_KEEPALIVE_MIN_LENGTH 2 - -struct capwap_data_message { - uint16_t length; - uint8_t elements[0]; -} STRUCT_PACKED; - -/* Capwap dtls header helper */ -#define GET_DTLS_BODY(x) (void*)(((uint8_t*)(x)) + sizeof(struct capwap_dtls_header)) - -/* Capwap header helper */ -#define GET_VERSION_HEADER(x) ((x)->preamble.version) -#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y)) -#define GET_TYPE_HEADER(x) ((x)->preamble.type) -#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y)) - -#define GET_HLEN_HEADER(x) ((x)->hlen) -#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y)) -#ifdef CAPWAP_BIG_ENDIAN - #define GET_RID_HEADER(x) ((uint8_t)((x)->rid)) - #define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y)) -#else - #define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo))) - #define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); }) -#endif -#define GET_WBID_HEADER(x) ((x)->wbid) -#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y)) - -#define IS_FLAG_T_HEADER(x) ((x)->flag_t) -#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0)) -#define IS_FLAG_F_HEADER(x) ((x)->flag_f) -#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0)) -#define IS_FLAG_L_HEADER(x) ((x)->flag_l) -#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0)) -#define IS_FLAG_W_HEADER(x) ((x)->flag_w) -#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0)) -#define IS_FLAG_M_HEADER(x) ((x)->flag_m) -#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0)) -#define IS_FLAG_K_HEADER(x) ((x)->flag_k) -#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0)) - -#define GET_FRAGMENT_ID_HEADER(x) (ntohs((x)->frag_id)) -#define SET_FRAGMENT_ID_HEADER(x, y) ((x)->frag_id = htons((uint16_t)(y))) -#define GET_FRAGMENT_OFFSET_HEADER(x) (ntohs((x)->frag_off) & FRAGMENT_OFFSET_MASK) -#define SET_FRAGMENT_OFFSET_HEADER(x, y) ((x)->frag_off &= ~FRAGMENT_OFFSET_MASK, (x)->frag_off |= htons((uint16_t)(y) & FRAGMENT_OFFSET_MASK)) - -#define GET_RADIO_MAC_ADDRESS_STRUCT(x) ((struct capwap_mac_address*)(((uint8_t*)(x)) + sizeof(struct capwap_header))) -#define GET_WIRELESS_INFORMATION_STRUCT(x) ((struct capwap_wireless_information*)(((uint8_t*)(x)) + sizeof(struct capwap_header) + (IS_FLAG_M_HEADER(x) ? (((GET_RADIO_MAC_ADDRESS_STRUCT(x)->length + sizeof(struct capwap_mac_address)) + 3) / 4) * 4 : 0))) -#define GET_PAYLOAD_HEADER(x) ((void*)(((uint8_t*)(x)) + GET_HLEN_HEADER(x) * 4)) - -#define IS_SEQUENCE_SMALLER(s1, s2) (((((s1) < (s2)) && (((s2) - (s1)) < 128)) || (((s1) > (s2)) && (((s1) - (s2)) > 128))) ? 1 : 0) - -/* */ -#define MACADDRESS_NONE_LENGTH 0 - -/* */ -#define MACADDRESS_EUI48_LENGTH 6 -struct capwap_macaddress_eui48 { - uint8_t macaddress[MACADDRESS_EUI48_LENGTH]; -} STRUCT_PACKED; - -/* */ -#define MACADDRESS_EUI64_LENGTH 8 -struct capwap_macaddress_eui64 { - uint8_t macaddress[MACADDRESS_EUI64_LENGTH]; -} STRUCT_PACKED; - -#define IS_VALID_MACADDRESS_LENGTH(x) ((x == MACADDRESS_EUI48_LENGTH) || (x == MACADDRESS_EUI64_LENGTH)) - -#define RADIOID_MAX_COUNT 31 -#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= RADIOID_MAX_COUNT)) - -#define WLANID_MAX_COUNT 16 -#define IS_VALID_WLANID(x) ((x >= 1) && (x <= WLANID_MAX_COUNT)) - -/* Standard message elements 1 -> 52 (1 - 1023) */ -#define CAPWAP_MESSAGE_ELEMENTS_START 1 -#define CAPWAP_MESSAGE_ELEMENTS_STOP 53 -#define CAPWAP_MESSAGE_ELEMENTS_COUNT ((CAPWAP_MESSAGE_ELEMENTS_STOP - CAPWAP_MESSAGE_ELEMENTS_START) + 1) -#define IS_MESSAGE_ELEMENTS(x) (((x >= CAPWAP_MESSAGE_ELEMENTS_START) && (x <= CAPWAP_MESSAGE_ELEMENTS_STOP)) ? 1 : 0) - -/* 802.11 message elements 1024 -> 1024 (1024 - 2047) */ -#define CAPWAP_80211_MESSAGE_ELEMENTS_START 1024 -#define CAPWAP_80211_MESSAGE_ELEMENTS_STOP 1048 -#define CAPWAP_80211_MESSAGE_ELEMENTS_COUNT ((CAPWAP_80211_MESSAGE_ELEMENTS_STOP - CAPWAP_80211_MESSAGE_ELEMENTS_START) + 1) -#define IS_80211_MESSAGE_ELEMENTS(x) (((x >= CAPWAP_80211_MESSAGE_ELEMENTS_START) && (x <= CAPWAP_80211_MESSAGE_ELEMENTS_STOP)) ? 1 : 0) - -/* */ -#define IS_VALID_MESSAGE_ELEMENTS(x) (IS_MESSAGE_ELEMENTS(x) || IS_80211_MESSAGE_ELEMENTS(x)) - -#endif /* __CAPWAP_RFC_HEADER__ */ +#ifndef __CAPWAP_RFC_HEADER__ +#define __CAPWAP_RFC_HEADER__ + +#include + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED __attribute__((__packed__)) +#endif + +#define CAPWAP_PROTOCOL_VERSION 0 + +#define CAPWAP_MTU_DEFAULT 1400 +#define CAPWAP_DONT_FRAGMENT 0 + +/* Capwap preamble */ +#define CAPWAP_PREAMBLE_HEADER 0 +#define CAPWAP_PREAMBLE_DTLS_HEADER 1 + +struct capwap_preamble { +#ifdef CAPWAP_BIG_ENDIAN + uint8_t version : 4; + uint8_t type : 4; +#else + uint8_t type : 4; + uint8_t version : 4; +#endif +} STRUCT_PACKED; + +/* Capwap DTLS header */ +struct capwap_dtls_header { + struct capwap_preamble preamble; + uint8_t reserved1; + uint8_t reserved2; + uint8_t reserved3; +} STRUCT_PACKED; + +/* Capwap header: 8 (header) + 12 (radio mac) + 256 (wireless info) */ +#define CAPWAP_HEADER_MAX_SIZE 276 +struct capwap_header { + struct capwap_preamble preamble; +#ifdef CAPWAP_BIG_ENDIAN + uint16_t hlen : 5; + uint16_t rid : 5; + uint16_t wbid : 5; + uint16_t flag_t : 1; + uint8_t flag_f : 1; + uint8_t flag_l : 1; + uint8_t flag_w : 1; + uint8_t flag_m : 1; + uint8_t flag_k : 1; + uint8_t flag_res : 3; +#else + uint16_t _rid_hi : 3; + uint16_t hlen : 5; + uint16_t flag_t : 1; + uint16_t wbid : 5; + uint16_t _rid_lo : 2; + uint8_t flag_res : 3; + uint8_t flag_k : 1; + uint8_t flag_m : 1; + uint8_t flag_w : 1; + uint8_t flag_l : 1; + uint8_t flag_f : 1; +#endif + uint16_t frag_id; + uint16_t frag_off; /* Only first 13 bit */ +} STRUCT_PACKED; + +#define FRAGMENT_OFFSET_MASK 0xfff8 + +/* Mac Address */ +struct capwap_mac_address { + uint8_t length; + uint8_t address[0]; +} STRUCT_PACKED; + +/* Wireless Information */ +struct capwap_wireless_information { + uint8_t length; + uint8_t data[0]; +} STRUCT_PACKED; + +/* IEEE802.11 Wireless Information */ +struct capwap_ieee80211_frame_info { + uint8_t rssi; + uint8_t snr; + uint16_t rate; +} STRUCT_PACKED; + +/* Message element */ +struct capwap_message_element { + uint16_t type; + uint16_t length; + uint8_t data[0]; +} STRUCT_PACKED; + +/* Control Message Type */ +#define CAPWAP_FIRST_MESSAGE_TYPE 1 +#define CAPWAP_DISCOVERY_REQUEST 1 +#define CAPWAP_DISCOVERY_RESPONSE 2 +#define CAPWAP_JOIN_REQUEST 3 +#define CAPWAP_JOIN_RESPONSE 4 +#define CAPWAP_CONFIGURATION_STATUS_REQUEST 5 +#define CAPWAP_CONFIGURATION_STATUS_RESPONSE 6 +#define CAPWAP_CONFIGURATION_UPDATE_REQUEST 7 +#define CAPWAP_CONFIGURATION_UPDATE_RESPONSE 8 +#define CAPWAP_WTP_EVENT_REQUEST 9 +#define CAPWAP_WTP_EVENT_RESPONSE 10 +#define CAPWAP_CHANGE_STATE_EVENT_REQUEST 11 +#define CAPWAP_CHANGE_STATE_EVENT_RESPONSE 12 +#define CAPWAP_ECHO_REQUEST 13 +#define CAPWAP_ECHO_RESPONSE 14 +#define CAPWAP_IMAGE_DATA_REQUEST 15 +#define CAPWAP_IMAGE_DATA_RESPONSE 16 +#define CAPWAP_RESET_REQUEST 17 +#define CAPWAP_RESET_RESPONSE 18 +#define CAPWAP_PRIMARY_DISCOVERY_REQUEST 19 +#define CAPWAP_PRIMARY_DISCOVERY_RESPONSE 20 +#define CAPWAP_DATA_TRANSFER_REQUEST 21 +#define CAPWAP_DATA_TRANSFER_RESPONSE 22 +#define CAPWAP_CLEAR_CONFIGURATION_REQUEST 23 +#define CAPWAP_CLEAR_CONFIGURATION_RESPONSE 24 +#define CAPWAP_STATION_CONFIGURATION_REQUEST 25 +#define CAPWAP_STATION_CONFIGURATION_RESPONSE 26 +#define CAPWAP_LAST_MESSAGE_TYPE 26 +#define CAPWAP_VALID_MESSAGE_TYPE(x) (((x) >= CAPWAP_FIRST_MESSAGE_TYPE) && ((x) <= CAPWAP_LAST_MESSAGE_TYPE)) + +#define CAPWAP_IEEE80211_FIRST_MESSAGE_TYPE 3398913 +#define CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST 3398913 +#define CAPWAP_IEEE80211_WLAN_CONFIGURATION_RESPONSE 3398914 +#define CAPWAP_IEEE80211_LAST_MESSAGE_TYPE 3398914 +#define CAPWAP_VALID_IEEE80211_MESSAGE_TYPE(x) (((x) >= CAPWAP_IEEE80211_FIRST_MESSAGE_TYPE) && ((x) <= CAPWAP_IEEE80211_LAST_MESSAGE_TYPE)) + +/* Control Message */ +#define CAPWAP_CONTROL_MESSAGE_MIN_LENGTH 3 + +struct capwap_control_message { + uint32_t type; + uint8_t seq; + uint16_t length; + uint8_t flags; + uint8_t elements[0]; +} STRUCT_PACKED; + +/* Data Message Keep-Alive*/ +#define CAPWAP_DATA_MESSAGE_KEEPALIVE_MIN_LENGTH 2 + +struct capwap_data_message { + uint16_t length; + uint8_t elements[0]; +} STRUCT_PACKED; + +/* Capwap dtls header helper */ +#define GET_DTLS_BODY(x) (void*)(((uint8_t*)(x)) + sizeof(struct capwap_dtls_header)) + +/* Capwap header helper */ +#define GET_VERSION_HEADER(x) ((x)->preamble.version) +#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y)) +#define GET_TYPE_HEADER(x) ((x)->preamble.type) +#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y)) + +#define GET_HLEN_HEADER(x) ((x)->hlen) +#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y)) +#ifdef CAPWAP_BIG_ENDIAN + #define GET_RID_HEADER(x) ((uint8_t)((x)->rid)) + #define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y)) +#else + #define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo))) + #define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); }) +#endif +#define GET_WBID_HEADER(x) ((x)->wbid) +#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y)) + +#define IS_FLAG_T_HEADER(x) ((x)->flag_t) +#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0)) +#define IS_FLAG_F_HEADER(x) ((x)->flag_f) +#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0)) +#define IS_FLAG_L_HEADER(x) ((x)->flag_l) +#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0)) +#define IS_FLAG_W_HEADER(x) ((x)->flag_w) +#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0)) +#define IS_FLAG_M_HEADER(x) ((x)->flag_m) +#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0)) +#define IS_FLAG_K_HEADER(x) ((x)->flag_k) +#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0)) + +#define GET_FRAGMENT_ID_HEADER(x) (ntohs((x)->frag_id)) +#define SET_FRAGMENT_ID_HEADER(x, y) ((x)->frag_id = htons((uint16_t)(y))) +#define GET_FRAGMENT_OFFSET_HEADER(x) (ntohs((x)->frag_off) & FRAGMENT_OFFSET_MASK) +#define SET_FRAGMENT_OFFSET_HEADER(x, y) ((x)->frag_off &= ~FRAGMENT_OFFSET_MASK, (x)->frag_off |= htons((uint16_t)(y) & FRAGMENT_OFFSET_MASK)) + +#define GET_RADIO_MAC_ADDRESS_STRUCT(x) ((struct capwap_mac_address*)(((uint8_t*)(x)) + sizeof(struct capwap_header))) +#define GET_WIRELESS_INFORMATION_STRUCT(x) ((struct capwap_wireless_information*)(((uint8_t*)(x)) + sizeof(struct capwap_header) + (IS_FLAG_M_HEADER(x) ? (((GET_RADIO_MAC_ADDRESS_STRUCT(x)->length + sizeof(struct capwap_mac_address)) + 3) / 4) * 4 : 0))) +#define GET_PAYLOAD_HEADER(x) ((void*)(((uint8_t*)(x)) + GET_HLEN_HEADER(x) * 4)) + +#define IS_SEQUENCE_SMALLER(s1, s2) (((((s1) < (s2)) && (((s2) - (s1)) < 128)) || (((s1) > (s2)) && (((s1) - (s2)) > 128))) ? 1 : 0) + +/* */ +#define MACADDRESS_NONE_LENGTH 0 + +/* */ +#define MACADDRESS_EUI48_LENGTH 6 +struct capwap_macaddress_eui48 { + uint8_t macaddress[MACADDRESS_EUI48_LENGTH]; +} STRUCT_PACKED; + +/* */ +#define MACADDRESS_EUI64_LENGTH 8 +struct capwap_macaddress_eui64 { + uint8_t macaddress[MACADDRESS_EUI64_LENGTH]; +} STRUCT_PACKED; + +#define IS_VALID_MACADDRESS_LENGTH(x) ((x == MACADDRESS_EUI48_LENGTH) || (x == MACADDRESS_EUI64_LENGTH)) + +#define RADIOID_MAX_COUNT 31 +#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= RADIOID_MAX_COUNT)) + +#define WLANID_MAX_COUNT 16 +#define IS_VALID_WLANID(x) ((x >= 1) && (x <= WLANID_MAX_COUNT)) + +/* Standard message elements 1 -> 52 (1 - 1023) */ +#define CAPWAP_MESSAGE_ELEMENTS_START 1 +#define CAPWAP_MESSAGE_ELEMENTS_STOP 53 +#define CAPWAP_MESSAGE_ELEMENTS_COUNT ((CAPWAP_MESSAGE_ELEMENTS_STOP - CAPWAP_MESSAGE_ELEMENTS_START) + 1) +#define IS_MESSAGE_ELEMENTS(x) (((x >= CAPWAP_MESSAGE_ELEMENTS_START) && (x <= CAPWAP_MESSAGE_ELEMENTS_STOP)) ? 1 : 0) + +/* 802.11 message elements 1024 -> 1024 (1024 - 2047) */ +#define CAPWAP_80211_MESSAGE_ELEMENTS_START 1024 +#define CAPWAP_80211_MESSAGE_ELEMENTS_STOP 1048 +#define CAPWAP_80211_MESSAGE_ELEMENTS_COUNT ((CAPWAP_80211_MESSAGE_ELEMENTS_STOP - CAPWAP_80211_MESSAGE_ELEMENTS_START) + 1) +#define IS_80211_MESSAGE_ELEMENTS(x) (((x >= CAPWAP_80211_MESSAGE_ELEMENTS_START) && (x <= CAPWAP_80211_MESSAGE_ELEMENTS_STOP)) ? 1 : 0) + +/* */ +#define IS_VALID_MESSAGE_ELEMENTS(x) (IS_MESSAGE_ELEMENTS(x) || IS_80211_MESSAGE_ELEMENTS(x)) + +#endif /* __CAPWAP_RFC_HEADER__ */ diff --git a/src/common/capwap_socket.c b/src/common/capwap_socket.c index 5e8478e..6650788 100644 --- a/src/common/capwap_socket.c +++ b/src/common/capwap_socket.c @@ -1,388 +1,388 @@ -#include "capwap.h" -#include "capwap_network.h" -#include "capwap_socket.h" - -#include -#include - -/* */ -static int capwap_socket_nonblocking(int sock, int nonblocking) { - int flags; - - ASSERT(sock >= 0); - - /* Retrieve file descriptor flags */ - flags = fcntl(sock, F_GETFL, NULL); - if (flags < 0) { - return 0; - } - - if (nonblocking) { - flags |= O_NONBLOCK; - } else { - flags &= ~O_NONBLOCK; - } - - if(fcntl(sock, F_SETFL, flags) < 0) { - return 0; - } - - return 1; -} - -/* */ -int capwap_socket_connect(int sock, union sockaddr_capwap* address, int timeout) { - int result; - struct pollfd fds; - socklen_t size; - - ASSERT(sock >= 0); - ASSERT(address != NULL); - - /* Non blocking socket */ - if (!capwap_socket_nonblocking(sock, 1)) { - return 0; - } - - /* */ - result = connect(sock, &address->sa, sizeof(union sockaddr_capwap)); - if (result < 0) { - if (errno == EINPROGRESS) { - /* Wait to connection complete */ - for (;;) { - memset(&fds, 0, sizeof(struct pollfd)); - fds.fd = sock; - fds.events = POLLOUT; - - result = poll(&fds, 1, timeout); - if (!result || ((result < 0) && (errno != EINTR))) { - return 0; - } else if (result > 0) { - /* Check connection status */ - size = sizeof(int); - if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&result, &size) < 0) { - return 0; - } - - if (result) { - return 0; - } - - /* Connection complete */ - break; - } - } - } else { - /* Unable to connect to remote host */ - return 0; - } - } - - return 1; -} - -/* */ -static int capwap_socket_crypto_verifycertificate(int preverify, CYASSL_X509_STORE_CTX* store) { - return preverify; -} - -/* */ -void* capwap_socket_crypto_createcontext(char* calist, char* cert, char* privatekey) { - CYASSL_CTX* context = NULL; - - ASSERT(calist != NULL); - ASSERT(cert != NULL); - ASSERT(privatekey != NULL); - - /* Create SSL context */ - context = CyaSSL_CTX_new(CyaTLSv1_2_client_method()); - if (context) { - /* Public certificate */ - if (!CyaSSL_CTX_use_certificate_file(context, cert, SSL_FILETYPE_PEM)) { - capwap_logging_debug("Error to load certificate file"); - capwap_socket_crypto_freecontext(context); - return NULL; - } - - /* Private key */ - if (!CyaSSL_CTX_use_PrivateKey_file(context, privatekey, SSL_FILETYPE_PEM)) { - capwap_logging_debug("Error to load private key file"); - capwap_socket_crypto_freecontext(context); - return NULL; - } - - if (!CyaSSL_CTX_check_private_key(context)) { - capwap_logging_debug("Error to check private key"); - capwap_socket_crypto_freecontext(context); - return NULL; - } - - /* Certificate Authority */ - if (!CyaSSL_CTX_load_verify_locations(context, calist, NULL)) { - capwap_logging_debug("Error to load ca file"); - capwap_socket_crypto_freecontext(context); - return NULL; - } - - /* Verify certificate callback */ - CyaSSL_CTX_set_verify(context, SSL_VERIFY_PEER, capwap_socket_crypto_verifycertificate); - - /* Set only high security cipher list */ - if (!CyaSSL_CTX_set_cipher_list(context, "AES256-SHA")) { - capwap_logging_debug("Error to select cipher list"); - capwap_socket_crypto_freecontext(context); - return NULL; - } - } - - return (void*)context; -} - -/* */ -void capwap_socket_crypto_freecontext(void* context) { - CYASSL_CTX* sslcontext = (CYASSL_CTX*)context; - - if (sslcontext) { - CyaSSL_CTX_free(sslcontext); - } -} - -/* */ -struct capwap_socket_ssl* capwap_socket_ssl_connect(int sock, void* sslcontext, int timeout) { - int result; - struct pollfd fds; - struct capwap_socket_ssl* sslsock; - - ASSERT(sock >= 0); - ASSERT(sslcontext != NULL); - - /* Create SSL session */ - sslsock = capwap_alloc(sizeof(struct capwap_socket_ssl)); - sslsock->sock = sock; - sslsock->sslcontext = sslcontext; - sslsock->sslsession = (void*)CyaSSL_new((CYASSL_CTX*)sslcontext); - if (!sslsock->sslsession) { - capwap_free(sslsock); - return NULL; - } - - /* Set socket to SSL session */ - if (!CyaSSL_set_fd((CYASSL*)sslsock->sslsession, sock)) { - CyaSSL_free((CYASSL*)sslsock->sslsession); - capwap_free(sslsock); - return NULL; - } - - /* */ - CyaSSL_set_using_nonblock((CYASSL*)sslsock->sslsession, 1); - - /* Establish SSL connection */ - for (;;) { - result = CyaSSL_connect((CYASSL*)sslsock->sslsession); - if (result == SSL_SUCCESS) { - break; /* Connection complete */ - } else { - int error = CyaSSL_get_error((CYASSL*)sslsock->sslsession, 0); - if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) { - memset(&fds, 0, sizeof(struct pollfd)); - fds.fd = sock; - fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT); - - result = poll(&fds, 1, timeout); - if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) { - CyaSSL_free((CYASSL*)sslsock->sslsession); - capwap_free(sslsock); - return NULL; - } - } else { - CyaSSL_free((CYASSL*)sslsock->sslsession); - capwap_free(sslsock); - return NULL; - } - } - } - - return sslsock; -} - -/* */ -int capwap_socket_crypto_send(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout) { - int result; - - ASSERT(sslsock != NULL); - ASSERT(sslsock->sslsession != NULL); - ASSERT(sslsock->sock >= 0); - ASSERT(buffer != NULL); - ASSERT(length > 0); - - result = CyaSSL_write((CYASSL*)sslsock->sslsession, buffer, length); - if (result != length) { - return -1; - } - - return length; -} - -/* */ -int capwap_socket_crypto_recv(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout) { - int result; - struct pollfd fds; - - ASSERT(sslsock != NULL); - ASSERT(sslsock->sslsession != NULL); - ASSERT(sslsock->sock >= 0); - ASSERT(buffer != NULL); - ASSERT(length > 0); - - for (;;) { - result = CyaSSL_read((CYASSL*)sslsock->sslsession, buffer, length); - if (result >= 0) { - return result; - } else { - int error = CyaSSL_get_error((CYASSL*)sslsock->sslsession, 0); - if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) { - memset(&fds, 0, sizeof(struct pollfd)); - fds.fd = sslsock->sock; - fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT); - - result = poll(&fds, 1, timeout); - if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) { - break; - } - } else { - break; - } - } - } - - return -1; -} - -/* */ -void capwap_socket_ssl_shutdown(struct capwap_socket_ssl* sslsock, int timeout) { - int result; - struct pollfd fds; - - ASSERT(sslsock != NULL); - ASSERT(sslsock->sslsession != NULL); - ASSERT(sslsock->sock >= 0); - - /* */ - for (;;) { - result = CyaSSL_shutdown((CYASSL*)sslsock->sslsession); - if (result >= 0) { - break; /* Shutdown complete */ - } else { - int error = CyaSSL_get_error((CYASSL*)sslsock->sslsession, 0); - if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) { - memset(&fds, 0, sizeof(struct pollfd)); - fds.fd = sslsock->sock; - fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT); - - result = poll(&fds, 1, timeout); - if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) { - break; /* Shutdown error */ - } - } else { - break; /* Shutdown error */ - } - } - } -} - -/* */ -void capwap_socket_ssl_close(struct capwap_socket_ssl* sslsock) { - ASSERT(sslsock != NULL); - ASSERT(sslsock->sslsession != NULL); - - CyaSSL_free((CYASSL*)sslsock->sslsession); - sslsock->sslsession = NULL; -} - -/* */ -void capwap_socket_shutdown(int sock) { - ASSERT(sock >= 0); - - shutdown(sock, SHUT_RDWR); -} - -/* */ -void capwap_socket_close(int sock) { - ASSERT(sock >= 0); - - capwap_socket_shutdown(sock); - capwap_socket_nonblocking(sock, 0); - close(sock); -} - -/* */ -int capwap_socket_send(int sock, void* buffer, size_t length, int timeout) { - int result; - struct pollfd fds; - size_t sendlength; - - ASSERT(sock >= 0); - ASSERT(buffer != NULL); - ASSERT(length > 0); - - sendlength = 0; - while (sendlength < length) { - memset(&fds, 0, sizeof(struct pollfd)); - fds.fd = sock; - fds.events = POLLOUT; - - result = poll(&fds, 1, timeout); - if ((result < 0) && (errno != EINTR)) { - return -1; - } else if (result > 0) { - if (fds.revents == POLLOUT) { - size_t leftlength = length - sendlength; - - result = send(sock, &((char*)buffer)[sendlength], leftlength, 0); - if ((result < 0) && (errno != EINTR)) { - return -1; - } else if (result > 0) { - sendlength += result; - } - } else { - return -1; - } - } - } - - return sendlength; -} - -/* */ -int capwap_socket_recv(int sock, void* buffer, size_t length, int timeout) { - int result; - struct pollfd fds; - - ASSERT(sock >= 0); - ASSERT(buffer != NULL); - ASSERT(length > 0); - - for (;;) { - memset(&fds, 0, sizeof(struct pollfd)); - fds.fd = sock; - fds.events = POLLIN; - - result = poll(&fds, 1, timeout); - if ((result < 0) && (errno != EINTR)) { - break; - } else if (result > 0) { - if (fds.revents == POLLIN) { - result = recv(sock, buffer, length, 0); - if ((result < 0) && (errno != EINTR)) { - break; - } else if (result >= 0) { - return result; - } - } else { - break; - } - } - } - - return -1; -} +#include "capwap.h" +#include "capwap_network.h" +#include "capwap_socket.h" + +#include +#include + +/* */ +static int capwap_socket_nonblocking(int sock, int nonblocking) { + int flags; + + ASSERT(sock >= 0); + + /* Retrieve file descriptor flags */ + flags = fcntl(sock, F_GETFL, NULL); + if (flags < 0) { + return 0; + } + + if (nonblocking) { + flags |= O_NONBLOCK; + } else { + flags &= ~O_NONBLOCK; + } + + if(fcntl(sock, F_SETFL, flags) < 0) { + return 0; + } + + return 1; +} + +/* */ +int capwap_socket_connect(int sock, union sockaddr_capwap* address, int timeout) { + int result; + struct pollfd fds; + socklen_t size; + + ASSERT(sock >= 0); + ASSERT(address != NULL); + + /* Non blocking socket */ + if (!capwap_socket_nonblocking(sock, 1)) { + return 0; + } + + /* */ + result = connect(sock, &address->sa, sizeof(union sockaddr_capwap)); + if (result < 0) { + if (errno == EINPROGRESS) { + /* Wait to connection complete */ + for (;;) { + memset(&fds, 0, sizeof(struct pollfd)); + fds.fd = sock; + fds.events = POLLOUT; + + result = poll(&fds, 1, timeout); + if (!result || ((result < 0) && (errno != EINTR))) { + return 0; + } else if (result > 0) { + /* Check connection status */ + size = sizeof(int); + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&result, &size) < 0) { + return 0; + } + + if (result) { + return 0; + } + + /* Connection complete */ + break; + } + } + } else { + /* Unable to connect to remote host */ + return 0; + } + } + + return 1; +} + +/* */ +static int capwap_socket_crypto_verifycertificate(int preverify, CYASSL_X509_STORE_CTX* store) { + return preverify; +} + +/* */ +void* capwap_socket_crypto_createcontext(char* calist, char* cert, char* privatekey) { + CYASSL_CTX* context = NULL; + + ASSERT(calist != NULL); + ASSERT(cert != NULL); + ASSERT(privatekey != NULL); + + /* Create SSL context */ + context = CyaSSL_CTX_new(CyaTLSv1_2_client_method()); + if (context) { + /* Public certificate */ + if (!CyaSSL_CTX_use_certificate_file(context, cert, SSL_FILETYPE_PEM)) { + capwap_logging_debug("Error to load certificate file"); + capwap_socket_crypto_freecontext(context); + return NULL; + } + + /* Private key */ + if (!CyaSSL_CTX_use_PrivateKey_file(context, privatekey, SSL_FILETYPE_PEM)) { + capwap_logging_debug("Error to load private key file"); + capwap_socket_crypto_freecontext(context); + return NULL; + } + + if (!CyaSSL_CTX_check_private_key(context)) { + capwap_logging_debug("Error to check private key"); + capwap_socket_crypto_freecontext(context); + return NULL; + } + + /* Certificate Authority */ + if (!CyaSSL_CTX_load_verify_locations(context, calist, NULL)) { + capwap_logging_debug("Error to load ca file"); + capwap_socket_crypto_freecontext(context); + return NULL; + } + + /* Verify certificate callback */ + CyaSSL_CTX_set_verify(context, SSL_VERIFY_PEER, capwap_socket_crypto_verifycertificate); + + /* Set only high security cipher list */ + if (!CyaSSL_CTX_set_cipher_list(context, "AES256-SHA")) { + capwap_logging_debug("Error to select cipher list"); + capwap_socket_crypto_freecontext(context); + return NULL; + } + } + + return (void*)context; +} + +/* */ +void capwap_socket_crypto_freecontext(void* context) { + CYASSL_CTX* sslcontext = (CYASSL_CTX*)context; + + if (sslcontext) { + CyaSSL_CTX_free(sslcontext); + } +} + +/* */ +struct capwap_socket_ssl* capwap_socket_ssl_connect(int sock, void* sslcontext, int timeout) { + int result; + struct pollfd fds; + struct capwap_socket_ssl* sslsock; + + ASSERT(sock >= 0); + ASSERT(sslcontext != NULL); + + /* Create SSL session */ + sslsock = capwap_alloc(sizeof(struct capwap_socket_ssl)); + sslsock->sock = sock; + sslsock->sslcontext = sslcontext; + sslsock->sslsession = (void*)CyaSSL_new((CYASSL_CTX*)sslcontext); + if (!sslsock->sslsession) { + capwap_free(sslsock); + return NULL; + } + + /* Set socket to SSL session */ + if (!CyaSSL_set_fd((CYASSL*)sslsock->sslsession, sock)) { + CyaSSL_free((CYASSL*)sslsock->sslsession); + capwap_free(sslsock); + return NULL; + } + + /* */ + CyaSSL_set_using_nonblock((CYASSL*)sslsock->sslsession, 1); + + /* Establish SSL connection */ + for (;;) { + result = CyaSSL_connect((CYASSL*)sslsock->sslsession); + if (result == SSL_SUCCESS) { + break; /* Connection complete */ + } else { + int error = CyaSSL_get_error((CYASSL*)sslsock->sslsession, 0); + if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) { + memset(&fds, 0, sizeof(struct pollfd)); + fds.fd = sock; + fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT); + + result = poll(&fds, 1, timeout); + if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) { + CyaSSL_free((CYASSL*)sslsock->sslsession); + capwap_free(sslsock); + return NULL; + } + } else { + CyaSSL_free((CYASSL*)sslsock->sslsession); + capwap_free(sslsock); + return NULL; + } + } + } + + return sslsock; +} + +/* */ +int capwap_socket_crypto_send(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout) { + int result; + + ASSERT(sslsock != NULL); + ASSERT(sslsock->sslsession != NULL); + ASSERT(sslsock->sock >= 0); + ASSERT(buffer != NULL); + ASSERT(length > 0); + + result = CyaSSL_write((CYASSL*)sslsock->sslsession, buffer, length); + if (result != length) { + return -1; + } + + return length; +} + +/* */ +int capwap_socket_crypto_recv(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout) { + int result; + struct pollfd fds; + + ASSERT(sslsock != NULL); + ASSERT(sslsock->sslsession != NULL); + ASSERT(sslsock->sock >= 0); + ASSERT(buffer != NULL); + ASSERT(length > 0); + + for (;;) { + result = CyaSSL_read((CYASSL*)sslsock->sslsession, buffer, length); + if (result >= 0) { + return result; + } else { + int error = CyaSSL_get_error((CYASSL*)sslsock->sslsession, 0); + if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) { + memset(&fds, 0, sizeof(struct pollfd)); + fds.fd = sslsock->sock; + fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT); + + result = poll(&fds, 1, timeout); + if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) { + break; + } + } else { + break; + } + } + } + + return -1; +} + +/* */ +void capwap_socket_ssl_shutdown(struct capwap_socket_ssl* sslsock, int timeout) { + int result; + struct pollfd fds; + + ASSERT(sslsock != NULL); + ASSERT(sslsock->sslsession != NULL); + ASSERT(sslsock->sock >= 0); + + /* */ + for (;;) { + result = CyaSSL_shutdown((CYASSL*)sslsock->sslsession); + if (result >= 0) { + break; /* Shutdown complete */ + } else { + int error = CyaSSL_get_error((CYASSL*)sslsock->sslsession, 0); + if ((error == SSL_ERROR_WANT_READ) || (error == SSL_ERROR_WANT_WRITE)) { + memset(&fds, 0, sizeof(struct pollfd)); + fds.fd = sslsock->sock; + fds.events = ((error == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT); + + result = poll(&fds, 1, timeout); + if (((result < 0) && (errno != EINTR)) || ((result > 0) && (fds.events != fds.revents))) { + break; /* Shutdown error */ + } + } else { + break; /* Shutdown error */ + } + } + } +} + +/* */ +void capwap_socket_ssl_close(struct capwap_socket_ssl* sslsock) { + ASSERT(sslsock != NULL); + ASSERT(sslsock->sslsession != NULL); + + CyaSSL_free((CYASSL*)sslsock->sslsession); + sslsock->sslsession = NULL; +} + +/* */ +void capwap_socket_shutdown(int sock) { + ASSERT(sock >= 0); + + shutdown(sock, SHUT_RDWR); +} + +/* */ +void capwap_socket_close(int sock) { + ASSERT(sock >= 0); + + capwap_socket_shutdown(sock); + capwap_socket_nonblocking(sock, 0); + close(sock); +} + +/* */ +int capwap_socket_send(int sock, void* buffer, size_t length, int timeout) { + int result; + struct pollfd fds; + size_t sendlength; + + ASSERT(sock >= 0); + ASSERT(buffer != NULL); + ASSERT(length > 0); + + sendlength = 0; + while (sendlength < length) { + memset(&fds, 0, sizeof(struct pollfd)); + fds.fd = sock; + fds.events = POLLOUT; + + result = poll(&fds, 1, timeout); + if ((result < 0) && (errno != EINTR)) { + return -1; + } else if (result > 0) { + if (fds.revents == POLLOUT) { + size_t leftlength = length - sendlength; + + result = send(sock, &((char*)buffer)[sendlength], leftlength, 0); + if ((result < 0) && (errno != EINTR)) { + return -1; + } else if (result > 0) { + sendlength += result; + } + } else { + return -1; + } + } + } + + return sendlength; +} + +/* */ +int capwap_socket_recv(int sock, void* buffer, size_t length, int timeout) { + int result; + struct pollfd fds; + + ASSERT(sock >= 0); + ASSERT(buffer != NULL); + ASSERT(length > 0); + + for (;;) { + memset(&fds, 0, sizeof(struct pollfd)); + fds.fd = sock; + fds.events = POLLIN; + + result = poll(&fds, 1, timeout); + if ((result < 0) && (errno != EINTR)) { + break; + } else if (result > 0) { + if (fds.revents == POLLIN) { + result = recv(sock, buffer, length, 0); + if ((result < 0) && (errno != EINTR)) { + break; + } else if (result >= 0) { + return result; + } + } else { + break; + } + } + } + + return -1; +} diff --git a/src/common/capwap_socket.h b/src/common/capwap_socket.h index 0544df7..371fd9c 100644 --- a/src/common/capwap_socket.h +++ b/src/common/capwap_socket.h @@ -1,30 +1,30 @@ -#ifndef __CAPWAP_SOCKET_HEADER__ -#define __CAPWAP_SOCKET_HEADER__ - -/* */ -int capwap_socket_connect(int sock, union sockaddr_capwap* address, int timeout); -void capwap_socket_shutdown(int sock); -void capwap_socket_close(int sock); - -/* Plain send/recv */ -int capwap_socket_send(int sock, void* buffer, size_t length, int timeout); -int capwap_socket_recv(int sock, void* buffer, size_t length, int timeout); - -/* SSL send/recv */ -struct capwap_socket_ssl { - int sock; - void* sslcontext; - void* sslsession; -}; - -void* capwap_socket_crypto_createcontext(char* calist, char* cert, char* privatekey); -void capwap_socket_crypto_freecontext(void* context); - -int capwap_socket_crypto_send(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout); -int capwap_socket_crypto_recv(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout); - -struct capwap_socket_ssl* capwap_socket_ssl_connect(int sock, void* sslcontext, int timeout); -void capwap_socket_ssl_shutdown(struct capwap_socket_ssl* sslsock, int timeout); -void capwap_socket_ssl_close(struct capwap_socket_ssl* sslsock); - -#endif /* __CAPWAP_SOCKET_HEADER__ */ +#ifndef __CAPWAP_SOCKET_HEADER__ +#define __CAPWAP_SOCKET_HEADER__ + +/* */ +int capwap_socket_connect(int sock, union sockaddr_capwap* address, int timeout); +void capwap_socket_shutdown(int sock); +void capwap_socket_close(int sock); + +/* Plain send/recv */ +int capwap_socket_send(int sock, void* buffer, size_t length, int timeout); +int capwap_socket_recv(int sock, void* buffer, size_t length, int timeout); + +/* SSL send/recv */ +struct capwap_socket_ssl { + int sock; + void* sslcontext; + void* sslsession; +}; + +void* capwap_socket_crypto_createcontext(char* calist, char* cert, char* privatekey); +void capwap_socket_crypto_freecontext(void* context); + +int capwap_socket_crypto_send(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout); +int capwap_socket_crypto_recv(struct capwap_socket_ssl* sslsock, void* buffer, size_t length, int timeout); + +struct capwap_socket_ssl* capwap_socket_ssl_connect(int sock, void* sslcontext, int timeout); +void capwap_socket_ssl_shutdown(struct capwap_socket_ssl* sslsock, int timeout); +void capwap_socket_ssl_close(struct capwap_socket_ssl* sslsock); + +#endif /* __CAPWAP_SOCKET_HEADER__ */ diff --git a/src/common/capwap_timeout.c b/src/common/capwap_timeout.c index 4f2774e..cad8be5 100644 --- a/src/common/capwap_timeout.c +++ b/src/common/capwap_timeout.c @@ -1,342 +1,342 @@ -#include "capwap.h" - -/* */ -#define CAPWAP_TIMEOUT_HASH_COUNT 128 - -/* */ -/* #define CAPWAP_TIMEOUT_LOGGING_DEBUG 1 */ - -/* */ -static unsigned long capwap_timeout_hash_item_gethash(const void* key, unsigned long hashsize) { - return (*((unsigned long*)key) % hashsize); -} - -/* */ -static const void* capwap_timeout_hash_item_getkey(const void* data) { - return (const void*)&((struct capwap_timeout_item*)((struct capwap_list_item*)data)->item)->index; -} - -/* */ -static int capwap_timeout_hash_item_cmp(const void* key1, const void* key2) { - unsigned long value1 = *(unsigned long*)key1; - unsigned long value2 = *(unsigned long*)key2; - - return ((value1 == value2) ? 0 : ((value1 < value2) ? -1 : 1)); -} - -/* */ -static long capwap_timeout_getdelta(struct timeval* time1, struct timeval* time2) { - return (time1->tv_sec - time2->tv_sec) * 1000 + (time1->tv_usec - time2->tv_usec) / 1000; -} - -/* */ -static unsigned long capwap_timeout_set_bitfield(struct capwap_timeout* timeout) { - int i, j; - - ASSERT(timeout != NULL); - - /* Search free bitfield */ - for (i = 0; i < CAPWAP_TIMEOUT_BITFIELD_SIZE; i++) { - if (timeout->timeoutbitfield[i] != 0xffffffff) { - uint32_t bitfield = timeout->timeoutbitfield[i]; - - for (j = 0; j < 32; j++) { - if (!(bitfield & (1 << j))) { - timeout->timeoutbitfield[i] |= (1 << j); - return (i * 32 + j + 1); - } - } - } - } - - return CAPWAP_TIMEOUT_INDEX_NO_SET; -} - -/* */ -static void capwap_timeout_clear_bitfield(struct capwap_timeout* timeout, unsigned long value) { - ASSERT(timeout != NULL); - ASSERT(value > 0); - - timeout->timeoutbitfield[(value - 1) / 32] &= ~(1 << ((value - 1) % 32)); -} - -/* */ -static void capwap_timeout_additem(struct capwap_list* itemstimeout, struct capwap_list_item* itemlist) { - struct capwap_list_item* search; - struct capwap_list_item* last = NULL; - struct capwap_timeout_item* item = (struct capwap_timeout_item*)itemlist->item; - - /* */ - search = itemstimeout->first; - while (search) { - struct capwap_timeout_item* itemsearch = (struct capwap_timeout_item*)search->item; - - if (capwap_timeout_getdelta(&item->expire, &itemsearch->expire) < 0) { - capwap_itemlist_insert_before(itemstimeout, last, itemlist); - break; - } - - /* Next */ - last = search; - search = search->next; - } - - /* */ - if (!search) { - capwap_itemlist_insert_after(itemstimeout, NULL, itemlist); - } -} - -/* */ -static void capwap_timeout_setexpire(long durate, struct timeval* now, struct timeval* expire) { - expire->tv_sec = now->tv_sec + durate / 1000; - expire->tv_usec = now->tv_usec + durate % 1000; - if (expire->tv_usec >= 1000000) { - expire->tv_sec++; - expire->tv_usec -= 1000000; - } -} - -/* */ -struct capwap_timeout* capwap_timeout_init(void) { - struct capwap_timeout* timeout; - - /* */ - timeout = (struct capwap_timeout*)capwap_alloc(sizeof(struct capwap_timeout)); - memset(timeout, 0, sizeof(struct capwap_timeout)); - - /* */ - timeout->itemsreference = capwap_hash_create(CAPWAP_TIMEOUT_HASH_COUNT); - timeout->itemsreference->item_gethash = capwap_timeout_hash_item_gethash; - timeout->itemsreference->item_getkey = capwap_timeout_hash_item_getkey; - timeout->itemsreference->item_cmp = capwap_timeout_hash_item_cmp; - - timeout->itemstimeout = capwap_list_create(); - - return timeout; -} - -/* */ -void capwap_timeout_free(struct capwap_timeout* timeout) { - ASSERT(timeout != NULL); - - capwap_hash_free(timeout->itemsreference); - capwap_list_free(timeout->itemstimeout); - capwap_free(timeout); -} - -/* */ -unsigned long capwap_timeout_createtimer(struct capwap_timeout* timeout) { - unsigned long index; - - ASSERT(timeout != NULL); - - /* Create new timeout index */ - index = capwap_timeout_set_bitfield(timeout); - -#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG - capwap_logging_debug("Create new timer: %lu", index); -#endif - - return index; -} - -/* */ -void capwap_timeout_deletetimer(struct capwap_timeout* timeout, unsigned long index) { - ASSERT(timeout != NULL); - - if (index != CAPWAP_TIMEOUT_INDEX_NO_SET) { -#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG - capwap_logging_debug("Delete timer: %lu", index); -#endif - - /* Unset timeout timer */ - capwap_timeout_unset(timeout, index); - - /* Release timer index */ - capwap_timeout_clear_bitfield(timeout, index); - } -} - -/* */ -unsigned long capwap_timeout_set(struct capwap_timeout* timeout, unsigned long index, long durate, capwap_timeout_expire callback, void* context, void* param) { - struct capwap_list_item* itemlist; - struct capwap_timeout_item* item; - struct timeval now; - - ASSERT(timeout != NULL); - ASSERT(durate >= 0); - - gettimeofday(&now, NULL); - - if (index == CAPWAP_TIMEOUT_INDEX_NO_SET) { - index = capwap_timeout_createtimer(timeout); - } else { - /* Check can update timeout timer */ - itemlist = (struct capwap_list_item*)capwap_hash_search(timeout->itemsreference, &index); - if (itemlist) { - /* Remove from timeout list */ - capwap_itemlist_remove(timeout->itemstimeout, itemlist); - - /* Update timeout */ - item = (struct capwap_timeout_item*)itemlist->item; - item->durate = durate; - capwap_timeout_setexpire(item->durate, &now, &item->expire); - item->callback = callback; - item->context = context; - item->param = param; - -#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG - capwap_logging_debug("Update timeout: %lu %ld", item->index, item->durate); -#endif - - /* Add itemlist into order list */ - capwap_timeout_additem(timeout->itemstimeout, itemlist); - return index; - } - } - - /* Create new timeout timer */ - itemlist = capwap_itemlist_create(sizeof(struct capwap_timeout_item)); - item = (struct capwap_timeout_item*)itemlist->item; - - /* */ - item->index = index; - item->durate = durate; - capwap_timeout_setexpire(item->durate, &now, &item->expire); - item->callback = callback; - item->context = context; - item->param = param; - -#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG - capwap_logging_debug("Set timeout: %lu %ld", item->index, item->durate); -#endif - - /* Add itemlist into hash for rapid searching */ - capwap_hash_add(timeout->itemsreference, (void*)itemlist); - - /* Add itemlist into order list */ - capwap_timeout_additem(timeout->itemstimeout, itemlist); - - return item->index; -} - -/* */ -void capwap_timeout_unset(struct capwap_timeout* timeout, unsigned long index) { - struct capwap_list_item* itemlist; - - ASSERT(timeout != NULL); - - if (index != CAPWAP_TIMEOUT_INDEX_NO_SET) { - itemlist = (struct capwap_list_item*)capwap_hash_search(timeout->itemsreference, &index); - if (itemlist) { -#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG - capwap_logging_debug("Unset timeout: %lu", index); -#endif - - /* */ - capwap_hash_delete(timeout->itemsreference, &index); - capwap_itemlist_free(capwap_itemlist_remove(timeout->itemstimeout, itemlist)); - } - } -} - -/* */ -void capwap_timeout_unsetall(struct capwap_timeout* timeout) { - capwap_hash_deleteall(timeout->itemsreference); - capwap_list_flush(timeout->itemstimeout); -} - -/* */ -long capwap_timeout_getcoming(struct capwap_timeout* timeout) { - long delta; - struct timeval now; - struct capwap_list_item* search; - struct capwap_timeout_item* item; - - ASSERT(timeout != NULL); - - /* */ - search = timeout->itemstimeout->first; - if (!search) { - return CAPWAP_TIMEOUT_INFINITE; - } - - /* */ - gettimeofday(&now, NULL); - item = (struct capwap_timeout_item*)search->item; - delta = capwap_timeout_getdelta(&item->expire, &now); - - if (delta <= 0) { - return 0; - } else if (delta <= item->durate) { - return delta; - } - - /* Recalculate all timeouts because delta > item->durate */ - while (search) { - struct capwap_timeout_item* itemsearch = (struct capwap_timeout_item*)search->item; - - capwap_timeout_setexpire(itemsearch->durate, &now, &itemsearch->expire); - search = search->next; - } - - return item->durate; -} - -/* */ -unsigned long capwap_timeout_hasexpired(struct capwap_timeout* timeout) { - long delta; - struct capwap_timeout_item* item; - struct capwap_list_item* itemlist; - unsigned long index; - capwap_timeout_expire callback; - void* context; - void* param; - - ASSERT(timeout != NULL); - - /* */ - delta = capwap_timeout_getcoming(timeout); - if ((delta > 0) || (delta == CAPWAP_TIMEOUT_INFINITE)) { - return 0; - } - - /* */ - itemlist = capwap_itemlist_remove_head(timeout->itemstimeout); - item = (struct capwap_timeout_item*)itemlist->item; - -#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG - capwap_logging_debug("Expired timeout: %lu", item->index); -#endif - - /* Cache callback before release timeout timer */ - index = item->index; - callback = item->callback; - context = item->context; - param = item->param; - - /* Free memory */ - capwap_hash_delete(timeout->itemsreference, &index); - capwap_itemlist_free(itemlist); - - /* */ - if (callback) { - callback(timeout, index, context, param); - } - - return index; -} - -/* */ -int capwap_timeout_wait(long durate) { - if (durate < 0) { - return -1; - } else if (durate > 0) { - if (usleep((useconds_t)durate * 1000)) { - return ((errno == EINTR) ? 0 : -1); - } - } - - return 1; -} +#include "capwap.h" + +/* */ +#define CAPWAP_TIMEOUT_HASH_COUNT 128 + +/* */ +/* #define CAPWAP_TIMEOUT_LOGGING_DEBUG 1 */ + +/* */ +static unsigned long capwap_timeout_hash_item_gethash(const void* key, unsigned long hashsize) { + return (*((unsigned long*)key) % hashsize); +} + +/* */ +static const void* capwap_timeout_hash_item_getkey(const void* data) { + return (const void*)&((struct capwap_timeout_item*)((struct capwap_list_item*)data)->item)->index; +} + +/* */ +static int capwap_timeout_hash_item_cmp(const void* key1, const void* key2) { + unsigned long value1 = *(unsigned long*)key1; + unsigned long value2 = *(unsigned long*)key2; + + return ((value1 == value2) ? 0 : ((value1 < value2) ? -1 : 1)); +} + +/* */ +static long capwap_timeout_getdelta(struct timeval* time1, struct timeval* time2) { + return (time1->tv_sec - time2->tv_sec) * 1000 + (time1->tv_usec - time2->tv_usec) / 1000; +} + +/* */ +static unsigned long capwap_timeout_set_bitfield(struct capwap_timeout* timeout) { + int i, j; + + ASSERT(timeout != NULL); + + /* Search free bitfield */ + for (i = 0; i < CAPWAP_TIMEOUT_BITFIELD_SIZE; i++) { + if (timeout->timeoutbitfield[i] != 0xffffffff) { + uint32_t bitfield = timeout->timeoutbitfield[i]; + + for (j = 0; j < 32; j++) { + if (!(bitfield & (1 << j))) { + timeout->timeoutbitfield[i] |= (1 << j); + return (i * 32 + j + 1); + } + } + } + } + + return CAPWAP_TIMEOUT_INDEX_NO_SET; +} + +/* */ +static void capwap_timeout_clear_bitfield(struct capwap_timeout* timeout, unsigned long value) { + ASSERT(timeout != NULL); + ASSERT(value > 0); + + timeout->timeoutbitfield[(value - 1) / 32] &= ~(1 << ((value - 1) % 32)); +} + +/* */ +static void capwap_timeout_additem(struct capwap_list* itemstimeout, struct capwap_list_item* itemlist) { + struct capwap_list_item* search; + struct capwap_list_item* last = NULL; + struct capwap_timeout_item* item = (struct capwap_timeout_item*)itemlist->item; + + /* */ + search = itemstimeout->first; + while (search) { + struct capwap_timeout_item* itemsearch = (struct capwap_timeout_item*)search->item; + + if (capwap_timeout_getdelta(&item->expire, &itemsearch->expire) < 0) { + capwap_itemlist_insert_before(itemstimeout, last, itemlist); + break; + } + + /* Next */ + last = search; + search = search->next; + } + + /* */ + if (!search) { + capwap_itemlist_insert_after(itemstimeout, NULL, itemlist); + } +} + +/* */ +static void capwap_timeout_setexpire(long durate, struct timeval* now, struct timeval* expire) { + expire->tv_sec = now->tv_sec + durate / 1000; + expire->tv_usec = now->tv_usec + durate % 1000; + if (expire->tv_usec >= 1000000) { + expire->tv_sec++; + expire->tv_usec -= 1000000; + } +} + +/* */ +struct capwap_timeout* capwap_timeout_init(void) { + struct capwap_timeout* timeout; + + /* */ + timeout = (struct capwap_timeout*)capwap_alloc(sizeof(struct capwap_timeout)); + memset(timeout, 0, sizeof(struct capwap_timeout)); + + /* */ + timeout->itemsreference = capwap_hash_create(CAPWAP_TIMEOUT_HASH_COUNT); + timeout->itemsreference->item_gethash = capwap_timeout_hash_item_gethash; + timeout->itemsreference->item_getkey = capwap_timeout_hash_item_getkey; + timeout->itemsreference->item_cmp = capwap_timeout_hash_item_cmp; + + timeout->itemstimeout = capwap_list_create(); + + return timeout; +} + +/* */ +void capwap_timeout_free(struct capwap_timeout* timeout) { + ASSERT(timeout != NULL); + + capwap_hash_free(timeout->itemsreference); + capwap_list_free(timeout->itemstimeout); + capwap_free(timeout); +} + +/* */ +unsigned long capwap_timeout_createtimer(struct capwap_timeout* timeout) { + unsigned long index; + + ASSERT(timeout != NULL); + + /* Create new timeout index */ + index = capwap_timeout_set_bitfield(timeout); + +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG + capwap_logging_debug("Create new timer: %lu", index); +#endif + + return index; +} + +/* */ +void capwap_timeout_deletetimer(struct capwap_timeout* timeout, unsigned long index) { + ASSERT(timeout != NULL); + + if (index != CAPWAP_TIMEOUT_INDEX_NO_SET) { +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG + capwap_logging_debug("Delete timer: %lu", index); +#endif + + /* Unset timeout timer */ + capwap_timeout_unset(timeout, index); + + /* Release timer index */ + capwap_timeout_clear_bitfield(timeout, index); + } +} + +/* */ +unsigned long capwap_timeout_set(struct capwap_timeout* timeout, unsigned long index, long durate, capwap_timeout_expire callback, void* context, void* param) { + struct capwap_list_item* itemlist; + struct capwap_timeout_item* item; + struct timeval now; + + ASSERT(timeout != NULL); + ASSERT(durate >= 0); + + gettimeofday(&now, NULL); + + if (index == CAPWAP_TIMEOUT_INDEX_NO_SET) { + index = capwap_timeout_createtimer(timeout); + } else { + /* Check can update timeout timer */ + itemlist = (struct capwap_list_item*)capwap_hash_search(timeout->itemsreference, &index); + if (itemlist) { + /* Remove from timeout list */ + capwap_itemlist_remove(timeout->itemstimeout, itemlist); + + /* Update timeout */ + item = (struct capwap_timeout_item*)itemlist->item; + item->durate = durate; + capwap_timeout_setexpire(item->durate, &now, &item->expire); + item->callback = callback; + item->context = context; + item->param = param; + +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG + capwap_logging_debug("Update timeout: %lu %ld", item->index, item->durate); +#endif + + /* Add itemlist into order list */ + capwap_timeout_additem(timeout->itemstimeout, itemlist); + return index; + } + } + + /* Create new timeout timer */ + itemlist = capwap_itemlist_create(sizeof(struct capwap_timeout_item)); + item = (struct capwap_timeout_item*)itemlist->item; + + /* */ + item->index = index; + item->durate = durate; + capwap_timeout_setexpire(item->durate, &now, &item->expire); + item->callback = callback; + item->context = context; + item->param = param; + +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG + capwap_logging_debug("Set timeout: %lu %ld", item->index, item->durate); +#endif + + /* Add itemlist into hash for rapid searching */ + capwap_hash_add(timeout->itemsreference, (void*)itemlist); + + /* Add itemlist into order list */ + capwap_timeout_additem(timeout->itemstimeout, itemlist); + + return item->index; +} + +/* */ +void capwap_timeout_unset(struct capwap_timeout* timeout, unsigned long index) { + struct capwap_list_item* itemlist; + + ASSERT(timeout != NULL); + + if (index != CAPWAP_TIMEOUT_INDEX_NO_SET) { + itemlist = (struct capwap_list_item*)capwap_hash_search(timeout->itemsreference, &index); + if (itemlist) { +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG + capwap_logging_debug("Unset timeout: %lu", index); +#endif + + /* */ + capwap_hash_delete(timeout->itemsreference, &index); + capwap_itemlist_free(capwap_itemlist_remove(timeout->itemstimeout, itemlist)); + } + } +} + +/* */ +void capwap_timeout_unsetall(struct capwap_timeout* timeout) { + capwap_hash_deleteall(timeout->itemsreference); + capwap_list_flush(timeout->itemstimeout); +} + +/* */ +long capwap_timeout_getcoming(struct capwap_timeout* timeout) { + long delta; + struct timeval now; + struct capwap_list_item* search; + struct capwap_timeout_item* item; + + ASSERT(timeout != NULL); + + /* */ + search = timeout->itemstimeout->first; + if (!search) { + return CAPWAP_TIMEOUT_INFINITE; + } + + /* */ + gettimeofday(&now, NULL); + item = (struct capwap_timeout_item*)search->item; + delta = capwap_timeout_getdelta(&item->expire, &now); + + if (delta <= 0) { + return 0; + } else if (delta <= item->durate) { + return delta; + } + + /* Recalculate all timeouts because delta > item->durate */ + while (search) { + struct capwap_timeout_item* itemsearch = (struct capwap_timeout_item*)search->item; + + capwap_timeout_setexpire(itemsearch->durate, &now, &itemsearch->expire); + search = search->next; + } + + return item->durate; +} + +/* */ +unsigned long capwap_timeout_hasexpired(struct capwap_timeout* timeout) { + long delta; + struct capwap_timeout_item* item; + struct capwap_list_item* itemlist; + unsigned long index; + capwap_timeout_expire callback; + void* context; + void* param; + + ASSERT(timeout != NULL); + + /* */ + delta = capwap_timeout_getcoming(timeout); + if ((delta > 0) || (delta == CAPWAP_TIMEOUT_INFINITE)) { + return 0; + } + + /* */ + itemlist = capwap_itemlist_remove_head(timeout->itemstimeout); + item = (struct capwap_timeout_item*)itemlist->item; + +#ifdef CAPWAP_TIMEOUT_LOGGING_DEBUG + capwap_logging_debug("Expired timeout: %lu", item->index); +#endif + + /* Cache callback before release timeout timer */ + index = item->index; + callback = item->callback; + context = item->context; + param = item->param; + + /* Free memory */ + capwap_hash_delete(timeout->itemsreference, &index); + capwap_itemlist_free(itemlist); + + /* */ + if (callback) { + callback(timeout, index, context, param); + } + + return index; +} + +/* */ +int capwap_timeout_wait(long durate) { + if (durate < 0) { + return -1; + } else if (durate > 0) { + if (usleep((useconds_t)durate * 1000)) { + return ((errno == EINTR) ? 0 : -1); + } + } + + return 1; +} diff --git a/src/common/capwap_timeout.h b/src/common/capwap_timeout.h index 06fbfcc..5b625ec 100644 --- a/src/common/capwap_timeout.h +++ b/src/common/capwap_timeout.h @@ -1,49 +1,49 @@ -#ifndef __CAPWAP_TIMEOUT_HEADER__ -#define __CAPWAP_TIMEOUT_HEADER__ - -#include "capwap_hash.h" -#include "capwap_list.h" - -/* */ -#define CAPWAP_TIMEOUT_BITFIELD_SIZE 128 -#define CAPWAP_TIMEOUT_INFINITE -1 -#define CAPWAP_TIMEOUT_INDEX_NO_SET 0 - -/* */ -struct capwap_timeout { - uint32_t timeoutbitfield[CAPWAP_TIMEOUT_BITFIELD_SIZE]; - struct capwap_hash* itemsreference; - struct capwap_list* itemstimeout; -}; - -/* */ -typedef void (*capwap_timeout_expire)(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); - -struct capwap_timeout_item { - unsigned long index; - long durate; - struct timeval expire; - capwap_timeout_expire callback; - void* context; - void* param; -}; - -/* */ -struct capwap_timeout* capwap_timeout_init(void); -void capwap_timeout_free(struct capwap_timeout* timeout); - -/* */ -unsigned long capwap_timeout_createtimer(struct capwap_timeout* timeout); -void capwap_timeout_deletetimer(struct capwap_timeout* timeout, unsigned long index); - -/* */ -unsigned long capwap_timeout_set(struct capwap_timeout* timeout, unsigned long index, long durate, capwap_timeout_expire callback, void* context, void* param); -void capwap_timeout_unset(struct capwap_timeout* timeout, unsigned long index); -void capwap_timeout_unsetall(struct capwap_timeout* timeout); - -long capwap_timeout_getcoming(struct capwap_timeout* timeout); -unsigned long capwap_timeout_hasexpired(struct capwap_timeout* timeout); - -int capwap_timeout_wait(long durate); - -#endif /* __CAPWAP_TIMEOUT_HEADER__ */ +#ifndef __CAPWAP_TIMEOUT_HEADER__ +#define __CAPWAP_TIMEOUT_HEADER__ + +#include "capwap_hash.h" +#include "capwap_list.h" + +/* */ +#define CAPWAP_TIMEOUT_BITFIELD_SIZE 128 +#define CAPWAP_TIMEOUT_INFINITE -1 +#define CAPWAP_TIMEOUT_INDEX_NO_SET 0 + +/* */ +struct capwap_timeout { + uint32_t timeoutbitfield[CAPWAP_TIMEOUT_BITFIELD_SIZE]; + struct capwap_hash* itemsreference; + struct capwap_list* itemstimeout; +}; + +/* */ +typedef void (*capwap_timeout_expire)(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); + +struct capwap_timeout_item { + unsigned long index; + long durate; + struct timeval expire; + capwap_timeout_expire callback; + void* context; + void* param; +}; + +/* */ +struct capwap_timeout* capwap_timeout_init(void); +void capwap_timeout_free(struct capwap_timeout* timeout); + +/* */ +unsigned long capwap_timeout_createtimer(struct capwap_timeout* timeout); +void capwap_timeout_deletetimer(struct capwap_timeout* timeout, unsigned long index); + +/* */ +unsigned long capwap_timeout_set(struct capwap_timeout* timeout, unsigned long index, long durate, capwap_timeout_expire callback, void* context, void* param); +void capwap_timeout_unset(struct capwap_timeout* timeout, unsigned long index); +void capwap_timeout_unsetall(struct capwap_timeout* timeout); + +long capwap_timeout_getcoming(struct capwap_timeout* timeout); +unsigned long capwap_timeout_hasexpired(struct capwap_timeout* timeout); + +int capwap_timeout_wait(long durate); + +#endif /* __CAPWAP_TIMEOUT_HEADER__ */ diff --git a/src/wtp/binding/ieee80211/netlink_link.c b/src/wtp/binding/ieee80211/netlink_link.c index f469427..7ccc1b0 100644 --- a/src/wtp/binding/ieee80211/netlink_link.c +++ b/src/wtp/binding/ieee80211/netlink_link.c @@ -1,155 +1,155 @@ -#include "capwap.h" -#include "capwap_network.h" -#include -#include "wifi_drivers.h" -#include "netlink_link.h" - -/* */ -struct netlink_request { - struct nlmsghdr hdr; - struct ifinfomsg ifinfo; - char opts[16]; -}; - -/* */ -struct netlink* netlink_init(void) { - int sock; - struct sockaddr_nl local; - struct netlink* netlinkhandle; - - /* Create netlink socket */ - sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (sock < 0) { - return NULL; - } - - /* Bind to kernel */ - memset(&local, 0, sizeof(struct sockaddr_nl)); - local.nl_family = AF_NETLINK; - local.nl_groups = RTMGRP_LINK; - if (bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_nl)) < 0) { - close(sock); - return NULL; - } - - /* Netlink reference */ - netlinkhandle = (struct netlink*)capwap_alloc(sizeof(struct netlink)); - netlinkhandle->sock = sock; - netlinkhandle->nl_sequence = 1; - - return netlinkhandle; -} - -/* */ -void netlink_free(struct netlink* netlinkhandle) { - ASSERT(netlinkhandle != NULL); - ASSERT(netlinkhandle->sock >= 0); - - /* */ - close(netlinkhandle->sock); - capwap_free(netlinkhandle); -} - -/* */ -void netlink_event_receive(int fd, void** params, int paramscount) { - int result; - struct netlink* netlinkhandle; - struct sockaddr_nl from; - socklen_t fromlen; - char buffer[8192]; - struct nlmsghdr* message; - - ASSERT(fd >= 0); - ASSERT(params != NULL); - ASSERT(paramscount == 2); - - /* */ - netlinkhandle = (struct netlink*)params[0]; - - /* Retrieve all netlink message */ - for (;;) { - /* Get message */ - fromlen = sizeof(struct sockaddr_nl); - result = recvfrom(netlinkhandle->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&from, &fromlen); - if (result <= 0) { - if (errno == EINTR) { - continue; - } - - /* */ - break; - } - - /* Parsing message */ - message = (struct nlmsghdr*)buffer; - while (NLMSG_OK(message, result)) { - switch (message->nlmsg_type) { - case RTM_NEWLINK: { - if (netlinkhandle->newlink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { - netlinkhandle->newlink_event((wifi_global_handle)params[1], NLMSG_DATA(message), (uint8_t*)(NLMSG_DATA(message) + NLMSG_ALIGN(sizeof(struct ifinfomsg))), NLMSG_PAYLOAD(message, sizeof(struct ifinfomsg))); - } - - break; - } - - case RTM_DELLINK: { - if (netlinkhandle->dellink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { - netlinkhandle->dellink_event((wifi_global_handle)params[1], NLMSG_DATA(message), (uint8_t*)(NLMSG_DATA(message) + NLMSG_ALIGN(sizeof(struct ifinfomsg))), NLMSG_PAYLOAD(message, sizeof(struct ifinfomsg))); - } - - break; - } - } - - /* */ - message = NLMSG_NEXT(message, result); - } - } -} - -int netlink_set_link_status(struct netlink* netlinkhandle, int ifindex, int linkmode, int operstate) { - char* data; - struct rtattr* rta; - struct netlink_request request; - - ASSERT(netlinkhandle != NULL); - ASSERT(ifindex >= 0); - - /* */ - memset(&request, 0, sizeof(struct netlink_request)); - request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - request.hdr.nlmsg_type = RTM_SETLINK; - request.hdr.nlmsg_flags = NLM_F_REQUEST; - request.hdr.nlmsg_seq = netlinkhandle->nl_sequence++; - request.hdr.nlmsg_pid = 0; - request.ifinfo.ifi_family = AF_UNSPEC; - request.ifinfo.ifi_type = 0; - request.ifinfo.ifi_index = ifindex; - request.ifinfo.ifi_flags = 0; - request.ifinfo.ifi_change = 0; - - if (linkmode != -1) { - rta = (struct rtattr*)((char*)&request + NLMSG_ALIGN(request.hdr.nlmsg_len)); - rta->rta_type = IFLA_LINKMODE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - data = (char*)RTA_DATA(rta); - *data = (char)linkmode; - request.hdr.nlmsg_len = NLMSG_ALIGN(request.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); - } - - if (operstate != -1) { - rta = (struct rtattr*)((char*)&request + NLMSG_ALIGN(request.hdr.nlmsg_len)); - rta->rta_type = IFLA_OPERSTATE; - rta->rta_len = RTA_LENGTH(sizeof(char)); - data = (char*)RTA_DATA(rta); - *data = (char)operstate; - request.hdr.nlmsg_len = NLMSG_ALIGN(request.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); - } - - /* Send new interface operation state */ - if (send(netlinkhandle->sock, &request, request.hdr.nlmsg_len, 0) < 0) { - return -1; - } - - return 0; -} +#include "capwap.h" +#include "capwap_network.h" +#include +#include "wifi_drivers.h" +#include "netlink_link.h" + +/* */ +struct netlink_request { + struct nlmsghdr hdr; + struct ifinfomsg ifinfo; + char opts[16]; +}; + +/* */ +struct netlink* netlink_init(void) { + int sock; + struct sockaddr_nl local; + struct netlink* netlinkhandle; + + /* Create netlink socket */ + sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock < 0) { + return NULL; + } + + /* Bind to kernel */ + memset(&local, 0, sizeof(struct sockaddr_nl)); + local.nl_family = AF_NETLINK; + local.nl_groups = RTMGRP_LINK; + if (bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_nl)) < 0) { + close(sock); + return NULL; + } + + /* Netlink reference */ + netlinkhandle = (struct netlink*)capwap_alloc(sizeof(struct netlink)); + netlinkhandle->sock = sock; + netlinkhandle->nl_sequence = 1; + + return netlinkhandle; +} + +/* */ +void netlink_free(struct netlink* netlinkhandle) { + ASSERT(netlinkhandle != NULL); + ASSERT(netlinkhandle->sock >= 0); + + /* */ + close(netlinkhandle->sock); + capwap_free(netlinkhandle); +} + +/* */ +void netlink_event_receive(int fd, void** params, int paramscount) { + int result; + struct netlink* netlinkhandle; + struct sockaddr_nl from; + socklen_t fromlen; + char buffer[8192]; + struct nlmsghdr* message; + + ASSERT(fd >= 0); + ASSERT(params != NULL); + ASSERT(paramscount == 2); + + /* */ + netlinkhandle = (struct netlink*)params[0]; + + /* Retrieve all netlink message */ + for (;;) { + /* Get message */ + fromlen = sizeof(struct sockaddr_nl); + result = recvfrom(netlinkhandle->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&from, &fromlen); + if (result <= 0) { + if (errno == EINTR) { + continue; + } + + /* */ + break; + } + + /* Parsing message */ + message = (struct nlmsghdr*)buffer; + while (NLMSG_OK(message, result)) { + switch (message->nlmsg_type) { + case RTM_NEWLINK: { + if (netlinkhandle->newlink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { + netlinkhandle->newlink_event((wifi_global_handle)params[1], NLMSG_DATA(message), (uint8_t*)(NLMSG_DATA(message) + NLMSG_ALIGN(sizeof(struct ifinfomsg))), NLMSG_PAYLOAD(message, sizeof(struct ifinfomsg))); + } + + break; + } + + case RTM_DELLINK: { + if (netlinkhandle->dellink_event && NLMSG_PAYLOAD(message, 0) >= sizeof(struct ifinfomsg)) { + netlinkhandle->dellink_event((wifi_global_handle)params[1], NLMSG_DATA(message), (uint8_t*)(NLMSG_DATA(message) + NLMSG_ALIGN(sizeof(struct ifinfomsg))), NLMSG_PAYLOAD(message, sizeof(struct ifinfomsg))); + } + + break; + } + } + + /* */ + message = NLMSG_NEXT(message, result); + } + } +} + +int netlink_set_link_status(struct netlink* netlinkhandle, int ifindex, int linkmode, int operstate) { + char* data; + struct rtattr* rta; + struct netlink_request request; + + ASSERT(netlinkhandle != NULL); + ASSERT(ifindex >= 0); + + /* */ + memset(&request, 0, sizeof(struct netlink_request)); + request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + request.hdr.nlmsg_type = RTM_SETLINK; + request.hdr.nlmsg_flags = NLM_F_REQUEST; + request.hdr.nlmsg_seq = netlinkhandle->nl_sequence++; + request.hdr.nlmsg_pid = 0; + request.ifinfo.ifi_family = AF_UNSPEC; + request.ifinfo.ifi_type = 0; + request.ifinfo.ifi_index = ifindex; + request.ifinfo.ifi_flags = 0; + request.ifinfo.ifi_change = 0; + + if (linkmode != -1) { + rta = (struct rtattr*)((char*)&request + NLMSG_ALIGN(request.hdr.nlmsg_len)); + rta->rta_type = IFLA_LINKMODE; + rta->rta_len = RTA_LENGTH(sizeof(char)); + data = (char*)RTA_DATA(rta); + *data = (char)linkmode; + request.hdr.nlmsg_len = NLMSG_ALIGN(request.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); + } + + if (operstate != -1) { + rta = (struct rtattr*)((char*)&request + NLMSG_ALIGN(request.hdr.nlmsg_len)); + rta->rta_type = IFLA_OPERSTATE; + rta->rta_len = RTA_LENGTH(sizeof(char)); + data = (char*)RTA_DATA(rta); + *data = (char)operstate; + request.hdr.nlmsg_len = NLMSG_ALIGN(request.hdr.nlmsg_len) + RTA_LENGTH(sizeof(char)); + } + + /* Send new interface operation state */ + if (send(netlinkhandle->sock, &request, request.hdr.nlmsg_len, 0) < 0) { + return -1; + } + + return 0; +} diff --git a/src/wtp/binding/ieee80211/netlink_link.h b/src/wtp/binding/ieee80211/netlink_link.h index e388ae8..b5c7597 100644 --- a/src/wtp/binding/ieee80211/netlink_link.h +++ b/src/wtp/binding/ieee80211/netlink_link.h @@ -1,59 +1,59 @@ -#ifndef __NETLINK_LINK_HEADER__ -#define __NETLINK_LINK_HEADER__ - -#include -#include - -/* */ -#ifndef IFLA_IFNAME -#define IFLA_IFNAME 3 -#endif - -#ifndef IFLA_WIRELESS -#define IFLA_WIRELESS 11 -#endif - -#ifndef IFLA_OPERSTATE -#define IFLA_OPERSTATE 16 -#endif - -#ifndef IFLA_LINKMODE -#define IFLA_LINKMODE 17 -#endif - -#ifndef IF_OPER_DORMANT -#define IF_OPER_DORMANT 5 -#endif - -#ifndef IF_OPER_UP -#define IF_OPER_UP 6 -#endif - -#ifndef IFF_LOWER_UP -#define IFF_LOWER_UP 0x10000 -#endif - -#ifndef IFF_DORMANT -#define IFF_DORMANT 0x20000 -#endif - -/* */ -struct netlink { - int sock; - void (*newlink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length); - void (*dellink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length); - - int nl_sequence; -}; - -/* */ -struct netlink* netlink_init(void); -void netlink_free(struct netlink* netlinkhandle); - -/* */ -int netlink_set_link_status(struct netlink* netlinkhandle, int ifindex, int linkmode, int operstate); - -/* */ -void netlink_event_receive(int fd, void** params, int paramscount); - -#endif /* __NETLINK_LINK_HEADER__ */ +#ifndef __NETLINK_LINK_HEADER__ +#define __NETLINK_LINK_HEADER__ + +#include +#include + +/* */ +#ifndef IFLA_IFNAME +#define IFLA_IFNAME 3 +#endif + +#ifndef IFLA_WIRELESS +#define IFLA_WIRELESS 11 +#endif + +#ifndef IFLA_OPERSTATE +#define IFLA_OPERSTATE 16 +#endif + +#ifndef IFLA_LINKMODE +#define IFLA_LINKMODE 17 +#endif + +#ifndef IF_OPER_DORMANT +#define IF_OPER_DORMANT 5 +#endif + +#ifndef IF_OPER_UP +#define IF_OPER_UP 6 +#endif + +#ifndef IFF_LOWER_UP +#define IFF_LOWER_UP 0x10000 +#endif + +#ifndef IFF_DORMANT +#define IFF_DORMANT 0x20000 +#endif + +/* */ +struct netlink { + int sock; + void (*newlink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length); + void (*dellink_event)(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length); + + int nl_sequence; +}; + +/* */ +struct netlink* netlink_init(void); +void netlink_free(struct netlink* netlinkhandle); + +/* */ +int netlink_set_link_status(struct netlink* netlinkhandle, int ifindex, int linkmode, int operstate); + +/* */ +void netlink_event_receive(int fd, void** params, int paramscount); + +#endif /* __NETLINK_LINK_HEADER__ */ diff --git a/src/wtp/binding/ieee80211/wifi_drivers.c b/src/wtp/binding/ieee80211/wifi_drivers.c index be175aa..20a2e33 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.c +++ b/src/wtp/binding/ieee80211/wifi_drivers.c @@ -1,1836 +1,1836 @@ -#include "wtp.h" -#include "capwap_list.h" -#include "capwap_element.h" -#include "wifi_drivers.h" -#include "wtp_radio.h" -#include "wtp_kmod.h" - -/* Declare enable wifi driver */ -#ifdef ENABLE_WIFI_DRIVERS_NL80211 -extern struct wifi_driver_ops wifi_driver_nl80211_ops; -#endif - -static struct wifi_driver_instance wifi_driver[] = { -#ifdef ENABLE_WIFI_DRIVERS_NL80211 - { &wifi_driver_nl80211_ops, NULL }, -#endif - { NULL, NULL } -}; - -/* */ -#define WIFI_STATIONS_HASH_SIZE 256 - -/* Wifi Manager */ -static struct wifi_global g_wifiglobal; -static uint8_t g_bufferIEEE80211[IEEE80211_MTU]; - -/* */ -static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); -static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation); - -/* */ -static void wifi_wlan_getrates(struct wifi_device* device, uint8_t* rates, int ratescount, struct device_setrates_params* device_params) { - int i, j, w; - int radiotype; - uint32_t mode = 0; - const struct wifi_capability* capability; - - ASSERT(device != NULL); - ASSERT(rates != NULL); - ASSERT(ratescount > 0); - ASSERT(device_params != NULL); - - /* */ - memset(device_params, 0, sizeof(struct device_setrates_params)); - - /* Retrieve capability */ - capability = wifi_device_getcapability(device); - if (!capability) { - return; - } - - /* Get radio type for basic rate */ - radiotype = wifi_frequency_to_radiotype(device->currentfrequency.frequency); - if (radiotype < 0) { - return; - } - - /* Check type of rate mode */ - for (i = 0; i < ratescount; i++) { - if (device->currentfrequency.band == WIFI_BAND_2GHZ) { - if (IS_IEEE80211_RATE_B(rates[i])) { - mode |= CAPWAP_RADIO_TYPE_80211B; - } else if (IS_IEEE80211_RATE_G(rates[i])) { - mode |= CAPWAP_RADIO_TYPE_80211G; - } else if (IS_IEEE80211_RATE_N(rates[i])) { - mode |= CAPWAP_RADIO_TYPE_80211N; - } - } else if (device->currentfrequency.band == WIFI_BAND_5GHZ) { - if (IS_IEEE80211_RATE_A(rates[i])) { - mode |= CAPWAP_RADIO_TYPE_80211A; - } else if (IS_IEEE80211_RATE_N(rates[i])) { - mode |= CAPWAP_RADIO_TYPE_80211N; - } - } - } - - /* Add implicit 802.11b rate with only 802.11g rate */ - if ((device->currentfrequency.band == WIFI_BAND_2GHZ) && !(mode & CAPWAP_RADIO_TYPE_80211B) && (device->currentfrequency.mode & CAPWAP_RADIO_TYPE_80211B)) { - device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_1M; - device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_2M; - device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_5_5M; - device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_11M; - } - - /* Filter band */ - for (i = 0; i < capability->bands->count; i++) { - struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, i); - - if (bandcap->band == device->currentfrequency.band) { - for (j = 0; j < bandcap->rate->count; j++) { - struct wifi_rate_capability* ratecapability = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, j); - - /* Validate rate */ - for (w = 0; w < ratescount; w++) { - if (rates[w] == ratecapability->bitrate) { - device_params->supportedrates[device_params->supportedratescount++] = ratecapability->bitrate; - break; - } - } - } - - break; - } - } - - /* Apply basic rate */ - for (i = 0; i < device_params->supportedratescount; i++) { - if (radiotype == CAPWAP_RADIO_TYPE_80211A) { - if (IS_IEEE80211_BASICRATE_A(device_params->supportedrates[i])) { - device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; - device_params->supportedrates[i] |= IEEE80211_BASICRATE; - } - } else if (radiotype == CAPWAP_RADIO_TYPE_80211B) { - if (IS_IEEE80211_BASICRATE_B(device_params->supportedrates[i])) { - device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; - device_params->supportedrates[i] |= IEEE80211_BASICRATE; - } - } else if (radiotype == CAPWAP_RADIO_TYPE_80211G) { - if (IS_IEEE80211_BASICRATE_G(device_params->supportedrates[i])) { - device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; - device_params->supportedrates[i] |= IEEE80211_BASICRATE; - } - } - } - - /* Add implicit 802.11n rate with only 802.11a/g rate */ - if (!(mode & CAPWAP_RADIO_TYPE_80211N) && (device->currentfrequency.mode & CAPWAP_RADIO_TYPE_80211N)) { - device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_80211N; - } -} - -/* */ -static unsigned long wifi_hash_station_gethash(const void* key, unsigned long hashsize) { - uint8_t* macaddress = (uint8_t*)key; - - return ((unsigned long)macaddress[3] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]); -} - -/* */ -static const void* wifi_hash_station_getkey(const void* data) { - return (const void*)((struct wifi_station*)data)->address; -} - -/* */ -static int wifi_hash_station_cmp(const void* key1, const void* key2) { - return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); -} - -/* */ -static void wifi_hash_station_free(void* data) { - struct wifi_station* station = (struct wifi_station*)data; - - ASSERT(data != NULL); - - /* */ - capwap_logging_info("Destroy station: %s", station->addrtext); - capwap_free(station); -} - -/* */ -static struct wifi_station* wifi_station_get(struct wifi_wlan* wlan, const uint8_t* address) { - struct wifi_station* station; - - ASSERT(address != NULL); - - /* Get station */ - station = (struct wifi_station*)capwap_hash_search(g_wifiglobal.stations, address); - if (station && wlan && (station->wlan != wlan)) { - return NULL; - } - - return station; -} - -/* */ -static void wifi_station_clean(struct wifi_station* station) { - int updatebeacons = 0; - - ASSERT(station != NULL); - - if (station->wlan) { - struct wifi_wlan* wlan = station->wlan; - - /* Delete station into wireless driver */ - if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { - wlan->device->instance->ops->station_deauthorize(wlan, station->address); - } - - if (station->aid && (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { - ieee80211_aid_free(wlan->aidbitfield, station->aid); - station->aid = 0; - } - - if (station->flags & WIFI_STATION_FLAGS_NON_ERP) { - wlan->device->stationsnonerpcount--; - if (!wlan->device->stationsnonerpcount) { - updatebeacons = 1; - } - } - - if (station->flags & WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME) { - wlan->device->stationsnoshortslottimecount--; - if (!wlan->device->stationsnoshortslottimecount && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { - updatebeacons = 1; - } - } - - if (station->flags & WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE) { - wlan->device->stationsnoshortpreamblecount--; - if (!wlan->device->stationsnoshortpreamblecount && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { - updatebeacons = 1; - } - } - - /* Update beacons */ - if (updatebeacons) { - wlan->device->instance->ops->device_updatebeacons(wlan->device); - } - - /* Disconnet from WLAN */ - wlan->stationscount--; - station->wlan = NULL; - } - - /* Remove timers */ - if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) { - capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout); - station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; - } - - /* */ - station->flags = 0; - station->supportedratescount = 0; -} - -/* */ -static void wifi_station_delete(struct wifi_station* station) { - ASSERT(station != NULL); - - /* */ - capwap_logging_info("Delete station: %s", station->addrtext); - - /* */ - wifi_station_clean(station); - - /* Delay delete station */ - station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DELETE; - station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED, wifi_station_timeout, station, NULL); -} - -/* */ -static struct wifi_station* wifi_station_create(struct wifi_wlan* wlan, const uint8_t* address) { - struct wifi_station* station; - char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; - - ASSERT(wlan != NULL); - ASSERT(address != NULL); - - /* */ - capwap_printf_macaddress(buffer, address, MACADDRESS_EUI48_LENGTH); - - /* */ - station = wifi_station_get(NULL, address); - if (station) { - if (station->wlan && (station->wlan != wlan)) { - capwap_logging_info("Roaming station: %s", buffer); - wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 1); - } else { - capwap_logging_info("Reuse station: %s", buffer); - wifi_station_clean(station); - } - } - - /* Checks if it has reached the maximum number of stations */ - if (wlan->stationscount >= wlan->maxstationscount) { - capwap_logging_warning("Unable create station: reached the maximum number of stations"); - return NULL; - } - - /* Create new station */ - if (!station) { - capwap_logging_info("Create new station: %s", buffer); - - /* */ - station = (struct wifi_station*)capwap_alloc(sizeof(struct wifi_station)); - memset(station, 0, sizeof(struct wifi_station)); - - /* Initialize station */ - memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); - capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH); - station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; - - /* Add to pool */ - capwap_hash_add(g_wifiglobal.stations, station); - } - - /* Set station to WLAN */ - station->wlan = wlan; - wlan->stationscount++; - - return station; -} - -/* */ -static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const uint8_t* station, uint16_t reasoncode) { - int responselength; - struct ieee80211_deauthentication_params ieee80211_params; - char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; - - /* */ - capwap_printf_macaddress(stationaddress, station, MACADDRESS_EUI48_LENGTH); - - /* Create deauthentication packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_deauthentication_params)); - memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); - memcpy(ieee80211_params.station, station, ETH_ALEN); - ieee80211_params.reasoncode = reasoncode; - - responselength = ieee80211_create_deauthentication(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); - if (responselength > 0) { - if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { - capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress); - - /* Forwards the station deauthentication also to AC */ - wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); - } else { - capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress); - } - } else { - capwap_logging_warning("Unable to create IEEE802.11 Deauthentication to %s station", stationaddress); - } -} - -/* */ -static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation) { - ASSERT(wlan != NULL); - ASSERT(station != NULL); - - /* Send deauthentication message */ - if (station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) { - wifi_wlan_send_mgmt_deauthentication(wlan, station->address, reasoncode); - } - - /* Clean station */ - if (reusestation) { - wifi_station_clean(station); - } else { - wifi_station_delete(station); - } -} - -/* */ -static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { - struct wifi_station* station = (struct wifi_station*)context; - - ASSERT(station != NULL); - - if (station->idtimeout == index) { - switch (station->timeoutaction) { - case WIFI_STATION_TIMEOUT_ACTION_DELETE: { - /* Free station into hash callback function */ - wifi_station_clean(station); - capwap_hash_delete(g_wifiglobal.stations, station->address); - break; - } - - case WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: { - capwap_logging_warning("The %s station has not completed the association in time", station->addrtext); - wifi_wlan_deauthentication_station((struct wifi_wlan*)param, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - break; - } - } - } -} - -/* */ -static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int ielength; - int ssidcheck; - int nowaitack; - int responselength; - struct ieee80211_ie_items ieitems; - struct ieee80211_probe_response_params ieee80211_params; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->proberequest)); - if (ielength < 0) { - return; - } - - /* Parsing Information Elements */ - if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->proberequest.ie[0], ielength)) { - return; - } - - /* Validate Probe Request Packet */ - if (!ieitems.ssid || !ieitems.supported_rates) { - return; - } - - /* Verify the SSID */ - ssidcheck = ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, ieitems.ssid_list); - if (ssidcheck == IEEE80211_WRONG_SSID) { - return; - } - - /* Create probe response */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_probe_response_params)); - memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); - memcpy(ieee80211_params.station, frame->sa, MACADDRESS_EUI48_LENGTH); - ieee80211_params.beaconperiod = wlan->device->beaconperiod; - ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); - ieee80211_params.ssid = wlan->ssid; - memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); - ieee80211_params.supportedratescount = wlan->device->supportedratescount; - ieee80211_params.mode = wlan->device->currentfrequency.mode; - ieee80211_params.erpinfo = ieee80211_get_erpinfo(wlan->device->currentfrequency.mode, wlan->device->olbc, wlan->device->stationsnonerpcount, wlan->device->stationsnoshortpreamblecount, wlan->device->shortpreamble); - ieee80211_params.channel = wlan->device->currentfrequency.channel; - - responselength = ieee80211_create_probe_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); - if (responselength < 0) { - return; - } - - /* Send probe response */ - nowaitack = ((ssidcheck == IEEE80211_WILDCARD_SSID) && ieee80211_is_broadcast_addr(frame->da) ? 1 : 0); - if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) { - /* If enable Split Mac send the probe request message to AC */ - if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); - } - } else { - capwap_logging_warning("Unable to send IEEE802.11 Probe Response"); - } -} - -/* */ -static void wifi_wlan_management_legacy_station(struct wifi_wlan* wlan, struct wifi_station* station) { - int updatebeacons = 0; - - /* Check NON ERP */ - if (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) { - int i; - int stationnonerp = 1; - - for (i = 0; i < station->supportedratescount; i++) { - if (IS_IEEE80211_RATE_G(station->supportedrates[i])) { - stationnonerp = 0; - break; - } - } - - if (stationnonerp) { - station->flags |= WIFI_STATION_FLAGS_NON_ERP; - wlan->device->stationsnonerpcount++; - if (wlan->device->stationsnonerpcount == 1) { - updatebeacons = 1; - } - } - } - - /* Check short slot capability */ - if (!(station->capability & IEEE80211_CAPABILITY_SHORTSLOTTIME)) { - station->flags |= WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME; - wlan->device->stationsnoshortslottimecount++; - if ((wlan->device->stationsnoshortslottimecount == 1) && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { - updatebeacons = 1; - } - } - - /* Check short preamble capability */ - if (!(station->capability & IEEE80211_CAPABILITY_SHORTPREAMBLE)) { - station->flags |= WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE; - wlan->device->stationsnoshortpreamblecount++; - if ((wlan->device->stationsnoshortpreamblecount == 1) && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { - updatebeacons = 1; - } - } - - /* Update beacon */ - if (updatebeacons) { - wlan->device->instance->ops->device_updatebeacons(wlan->device); - } -} - -/* */ -static int wifi_wlan_get_station_rates(struct wifi_station* station, struct ieee80211_ie_items* ieitems) { - if (!ieitems->supported_rates) { - return -1; - } else if ((ieitems->supported_rates->len + (ieitems->extended_supported_rates ? ieitems->extended_supported_rates->len : 0)) > sizeof(station->supportedrates)) { - return -1; - } - - /* */ - station->supportedratescount = ieitems->supported_rates->len; - memcpy(station->supportedrates, ieitems->supported_rates->rates, ieitems->supported_rates->len); - if (ieitems->extended_supported_rates) { - station->supportedratescount += ieitems->extended_supported_rates->len; - memcpy(&station->supportedrates[ieitems->supported_rates->len], ieitems->extended_supported_rates->rates, ieitems->extended_supported_rates->len); - } - - return 0; -} - -/* */ -static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int acl; - int ielength; - struct ieee80211_ie_items ieitems; - int responselength; - struct ieee80211_authentication_params ieee80211_params; - struct wifi_station* station; - char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; - uint16_t responsestatuscode; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); - if (ielength < 0) { - capwap_logging_info("Receive invalid IEEE802.11 Authentication Request"); - return; - } - - /* Ignore authentication packet from same AP */ - if (!memcmp(frame->sa, wlan->address, MACADDRESS_EUI48_LENGTH)) { - capwap_logging_info("Ignore IEEE802.11 Authentication Request from same AP"); - return; - } - - /* */ - capwap_printf_macaddress(stationaddress, frame->sa, MACADDRESS_EUI48_LENGTH); - - /* Get ACL Station */ - acl = wtp_radio_acl_station(frame->sa); - if (acl == WTP_RADIO_ACL_STATION_DENY) { - capwap_logging_info("Denied IEEE802.11 Authentication Request from %s station", stationaddress); - return; - } - - /* Parsing Information Elements */ - if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->authetication.ie[0], ielength)) { - capwap_logging_info("Invalid IEEE802.11 Authentication Request from %s station", stationaddress); - return; - } - - /* */ - capwap_logging_info("Receive IEEE802.11 Authentication Request from %s station", stationaddress); - - /* Create station reference */ - station = wifi_station_create(wlan, frame->sa); - if (station) { - /* A station is removed if the association does not complete within a given period of time */ - station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; - station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE, wifi_station_timeout, station, wlan); - responsestatuscode = IEEE80211_STATUS_SUCCESS; - } else { - responsestatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - } - - /* */ - if ((responsestatuscode != IEEE80211_STATUS_SUCCESS) || (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { - uint16_t algorithm = __le16_to_cpu(frame->authetication.algorithm); - uint16_t transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); - - /* Check authentication algorithm */ - if (responsestatuscode == IEEE80211_STATUS_SUCCESS) { - responsestatuscode = IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM; - if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_OPEN)) { - if (transactionseqnumber == 1) { - responsestatuscode = IEEE80211_STATUS_SUCCESS; - station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; - } else { - responsestatuscode = IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION; - } - } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP)) { - /* TODO */ - } - } - - /* Create authentication packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); - memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); - memcpy(ieee80211_params.station, frame->sa, MACADDRESS_EUI48_LENGTH); - ieee80211_params.algorithm = algorithm; - ieee80211_params.transactionseqnumber = transactionseqnumber + 1; - ieee80211_params.statuscode = responsestatuscode; - - responselength = ieee80211_create_authentication_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); - if (responselength > 0) { - /* Send authentication response */ - if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { - capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", stationaddress, (int)responsestatuscode); - - /* Notify authentication request message also to AC */ - wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); - - /* Forwards the authentication response message also to AC */ - wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); - } else if (station) { - capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress); - wifi_station_delete(station); - } - } else if (station) { - capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", stationaddress); - wifi_station_delete(station); - } - } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); - } -} - -/* */ -static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int ielength; - int responselength; - struct ieee80211_ie_items ieitems; - struct ieee80211_associationresponse_params ieee80211_params; - struct wifi_station* station; - uint16_t resultstatuscode; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationrequest)); - if (ielength < 0) { - capwap_logging_info("Receive invalid IEEE802.11 Association Request"); - return; - } - - /* Get station reference */ - station = wifi_station_get(wlan, frame->sa); - if (!station) { - char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; - - /* Invalid station, send deauthentication message */ - capwap_logging_info("Receive IEEE802.11 Association Request from %s unknown station", capwap_printf_macaddress(buffer, frame->sa, MACADDRESS_EUI48_LENGTH)); - wifi_wlan_send_mgmt_deauthentication(wlan, frame->sa, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); - return; - } - - /* */ - if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED)) { - /* Invalid station, send deauthentication message */ - capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext); - wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA, 0); - return; - } - - /* Parsing Information Elements */ - if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->associationrequest.ie[0], ielength)) { - capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext); - wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - return; - } - - /* */ - capwap_logging_info("Receive IEEE802.11 Association Request from %s station", station->addrtext); - - /* */ - if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { - /* Verify SSID */ - if (ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, NULL) == IEEE80211_VALID_SSID) { - station->capability = __le16_to_cpu(frame->associationrequest.capability); - station->listeninterval = __le16_to_cpu(frame->associationrequest.listeninterval); - if (!ieee80211_aid_create(wlan->aidbitfield, &station->aid)) { - /* Get supported rates */ - if (!wifi_wlan_get_station_rates(station, &ieitems)) { - wifi_wlan_management_legacy_station(wlan, station); - resultstatuscode = IEEE80211_STATUS_SUCCESS; - } else { - resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; - } - } else { - resultstatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; - } - } else { - resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; - } - - /* Create association response packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); - memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); - memcpy(ieee80211_params.station, frame->sa, ETH_ALEN); - ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); - ieee80211_params.statuscode = resultstatuscode; - ieee80211_params.aid = IEEE80211_AID_FIELD | station->aid; - memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); - ieee80211_params.supportedratescount = wlan->device->supportedratescount; - - responselength = ieee80211_create_associationresponse_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); - if (responselength > 0) { - if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { - capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); - - /* Notify association request message also to AC */ - wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); - - /* Forwards the association response message also to AC */ - wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); - } else { - capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); - wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - } - } else { - capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext); - wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - } - } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); - - /* Station information */ - station->capability = __le16_to_cpu(frame->associationresponse.capability); - station->listeninterval = __le16_to_cpu(frame->associationrequest.listeninterval); - } -} - -/* */ -static void wifi_wlan_receive_station_mgmt_reassociation_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int ielength; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->reassociationrequest)); - if (ielength < 0) { - return; - } - - /* TODO */ -} - -/* */ -static void wifi_wlan_receive_station_mgmt_disassociation(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int ielength; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->disassociation)); - if (ielength < 0) { - return; - } - - /* TODO */ - - /* Notify disassociation message also to AC */ - wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); -} - -/* */ -static void wifi_wlan_receive_station_mgmt_deauthentication(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int ielength; - struct wifi_station* station; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->deauthetication)); - if (ielength < 0) { - return; - } - - /* Delete station */ - station = wifi_station_get(wlan, frame->sa); - if (station) { - wifi_station_delete(station); - } - - /* Notify deauthentication message also to AC */ - wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); -} - -/* */ -static void wifi_wlan_receive_station_mgmt_frame(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate) { - int broadcast; - - /* Check frequency */ - if (frequency && (wlan->device->currentfrequency.frequency != frequency)) { - return; - } - - /* Check if sent packet to correct AP */ - broadcast = ieee80211_is_broadcast_addr(frame->bssid); - if (!broadcast && memcmp(frame->bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { - return; - } - - /* */ - if (framecontrol_subtype == IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST) { - wifi_wlan_receive_station_mgmt_probe_request(wlan, frame, length, rssi, snr, rate); - } else if (!memcmp(frame->da, wlan->address, MACADDRESS_EUI48_LENGTH)) { - switch (framecontrol_subtype) { - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { - wifi_wlan_receive_station_mgmt_authentication(wlan, frame, length, rssi, snr, rate); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { - wifi_wlan_receive_station_mgmt_association_request(wlan, frame, length, rssi, snr, rate); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { - wifi_wlan_receive_station_mgmt_reassociation_request(wlan, frame, length, rssi, snr, rate); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { - wifi_wlan_receive_station_mgmt_disassociation(wlan, frame, length, rssi, snr, rate); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { - wifi_wlan_receive_station_mgmt_deauthentication(wlan, frame, length, rssi, snr, rate); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION: { - /* TODO */ - break; - } - } - } -} - -/* */ -static void wifi_wlan_receive_station_mgmt_authentication_ack(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, int ack) { - uint16_t algorithm; - uint16_t transactionseqnumber; - uint16_t statuscode; - struct wifi_station* station; - - /* Check packet */ - if (!ack || (length < (sizeof(struct ieee80211_header) + sizeof(frame->authetication)))) { - return; - } - - /* Get station information */ - station = wifi_station_get(wlan, frame->da); - if (!station) { - return; - } - - /* */ - statuscode = __le16_to_cpu(frame->authetication.statuscode); - if (statuscode == IEEE80211_STATUS_SUCCESS) { - algorithm = __le16_to_cpu(frame->authetication.algorithm); - transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); - - /* Check if authenticate */ - if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { - capwap_logging_info("IEEE802.11 Authentication complete to %s station", station->addrtext); - station->flags |= WIFI_STATION_FLAGS_AUTHENTICATED; - } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { - /* TODO */ - } - } -} - -/* */ -static void wifi_wlan_receive_station_mgmt_association_response_ack(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, int ack) { - uint16_t statuscode; - struct wifi_station* station; - - /* Check packet */ - if (!ack || (length < (sizeof(struct ieee80211_header) + sizeof(frame->associationresponse)))) { - return; - } - - /* Get station information */ - station = wifi_station_get(wlan, frame->da); - if (!station) { - return; - } - - /* */ - statuscode = __le16_to_cpu(frame->associationresponse.statuscode); - if (statuscode == IEEE80211_STATUS_SUCCESS) { - capwap_logging_info("IEEE802.11 Association complete to %s station", station->addrtext); - - /* */ - station->flags |= WIFI_STATION_FLAGS_ASSOCIATE; - if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { - /* Apply authorization if Station already authorized */ - if (wlan->device->instance->ops->station_authorize(wlan, station)) { - wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - } - } - } -} - -/* */ -static void wifi_wlan_receive_station_mgmt_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype, int ack) { - /* Ignore packet if not sent to AP */ - if (memcmp(frame->bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { - return; - } - - /* */ - switch (framecontrol_subtype) { - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { - wifi_wlan_receive_station_mgmt_authentication_ack(wlan, frame, length, ack); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { - wifi_wlan_receive_station_mgmt_association_response_ack(wlan, frame, length, ack); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { - /* TODO */ - break; - } - } -} - -/* */ -static int wifi_wlan_receive_ac_mgmt_authentication(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { - int ielength; - struct wifi_station* station; - int forwardframe = 0; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); - if (ielength >= 0) { - if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - station = wifi_station_get(wlan, frame->da); - if (station) { - uint16_t statuscode = __le16_to_cpu(frame->authetication.statuscode); - - if (statuscode == IEEE80211_STATUS_SUCCESS) { - uint16_t algorithm = __le16_to_cpu(frame->authetication.algorithm); - uint16_t transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); - - /* Get authentication algorithm */ - if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { - station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; - } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { - station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY; - } - } - - /* */ - forwardframe = 1; - } - } - } - - return forwardframe; -} - -/* */ -static int wifi_wlan_receive_ac_mgmt_association_response(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { - int ielength; - struct ieee80211_ie_items ieitems; - struct wifi_station* station; - int forwardframe = 0; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationresponse)); - if (ielength >= 0) { - station = wifi_station_get(wlan, frame->da); - if (station) { - if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { - if (frame->associationresponse.statuscode != IEEE80211_STATUS_SUCCESS) { - capwap_logging_info("AC request deauthentication of station: %s", station->addrtext); - wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - } - } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - uint16_t statuscode = __le16_to_cpu(frame->associationresponse.statuscode); - - if ((statuscode == IEEE80211_STATUS_SUCCESS) && !ieee80211_retrieve_information_elements_position(&ieitems, &frame->associationresponse.ie[0], ielength)) { - /* Station information */ - station->aid = (__le16_to_cpu(frame->associationresponse.aid) & ~IEEE80211_AID_FIELD); - - /* Get supported rates */ - wifi_wlan_get_station_rates(station, &ieitems); - - /* */ - wifi_wlan_management_legacy_station(wlan, station); - - /* Assign valid WLAN capability */ - frame->associationresponse.capability = __cpu_to_le16(wifi_wlan_check_capability(wlan, wlan->capability)); - } - - /* */ - forwardframe = 1; - } - } - } - - return forwardframe; -} - -/* */ -static int wifi_wlan_receive_ac_mgmt_reassociation_response(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { - int ielength; - struct wifi_station* station; - int forwardframe = 0; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->reassociationresponse)); - if (ielength >= 0) { - if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - station = wifi_station_get(wlan, frame->da); - if (station) { - /* TODO */ - } - } - } - - return forwardframe; -} - -/* */ -static int wifi_wlan_receive_ac_mgmt_disassociation(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { - int ielength; - struct wifi_station* station; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->disassociation)); - if (ielength < 0) { - return 0; - } - - /* */ - station = wifi_station_get(wlan, frame->da); - if (station) { - /* Deautherize station */ - if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { - station->flags &= ~WIFI_STATION_FLAGS_AUTHORIZED; - wlan->device->instance->ops->station_deauthorize(wlan, station->address); - } - - /* Deassociate station */ - station->flags &= ~WIFI_STATION_FLAGS_ASSOCIATE; - } - - return 1; -} - -/* */ -static int wifi_wlan_receive_ac_mgmt_deauthentication(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { - int ielength; - struct wifi_station* station; - - /* Information Elements packet length */ - ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->deauthetication)); - if (ielength < 0) { - return 0; - } - - /* Delete station */ - station = wifi_station_get(wlan, frame->da); - if (station) { - wifi_station_delete(station); - } - - return 1; -} - -/* */ -static int wifi_wlan_receive_ac_mgmt_frame(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype) { - int forwardframe = 0; - - switch (framecontrol_subtype) { - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { - forwardframe = wifi_wlan_receive_ac_mgmt_authentication(wlan, frame, length); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { - forwardframe = wifi_wlan_receive_ac_mgmt_association_response(wlan, frame, length); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: { - forwardframe = wifi_wlan_receive_ac_mgmt_reassociation_response(wlan, frame, length); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { - forwardframe = wifi_wlan_receive_ac_mgmt_disassociation(wlan, frame, length); - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { - forwardframe = wifi_wlan_receive_ac_mgmt_deauthentication(wlan, frame, length); - break; - } - } - - return forwardframe; -} - -/* */ -int wifi_driver_init(struct capwap_timeout* timeout) { - int i; - - ASSERT(timeout != NULL); - - /* Socket utils */ - memset(&g_wifiglobal, 0, sizeof(struct wifi_global)); - g_wifiglobal.sock_util = socket(AF_PACKET, SOCK_RAW, 0); - if (g_wifiglobal.sock_util < 0) { - return -1; - } - - /* Initialize driver */ - for (i = 0; wifi_driver[i].ops != NULL; i++) { - wifi_driver[i].handle = wifi_driver[i].ops->global_init(); - if (!wifi_driver[i].handle) { - close(g_wifiglobal.sock_util); - return -1; - } - } - - /* */ - g_wifiglobal.timeout = timeout; - g_wifiglobal.devices = capwap_list_create(); - g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE); - g_wifiglobal.stations->item_gethash = wifi_hash_station_gethash; - g_wifiglobal.stations->item_getkey = wifi_hash_station_getkey; - g_wifiglobal.stations->item_cmp = wifi_hash_station_cmp; - g_wifiglobal.stations->item_free = wifi_hash_station_free; - - return 0; -} - -/* */ -void wifi_driver_free(void) { - int i; - struct capwap_list_item* itemdevice; - - /* Free devices */ - if (g_wifiglobal.devices) { - for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { - struct wifi_device* device = (struct wifi_device*)itemdevice->item; - - /* Free WLANS */ - if (device->wlans) { - while (device->wlans->first) { - wifi_wlan_destroy((struct wifi_wlan*)device->wlans->first->item); - } - - capwap_list_free(device->wlans); - } - - /* */ - if (device->handle) { - device->instance->ops->device_deinit(device); - } - - /* Free capability */ - if (device->capability) { - if (device->capability->bands) { - for (i = 0; i < device->capability->bands->count; i++) { - struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(device->capability->bands, i); - - if (bandcap->freq) { - capwap_array_free(bandcap->freq); - } - - if (bandcap->rate) { - capwap_array_free(bandcap->rate); - } - } - - capwap_array_free(device->capability->bands); - } - - if (device->capability->ciphers) { - capwap_array_free(device->capability->ciphers); - } - - capwap_free(device->capability); - } - } - - capwap_list_free(g_wifiglobal.devices); - } - - /* Free stations */ - if (g_wifiglobal.stations) { - capwap_hash_free(g_wifiglobal.stations); - } - - /* Free driver */ - for (i = 0; wifi_driver[i].ops != NULL; i++) { - wifi_driver[i].ops->global_deinit(wifi_driver[i].handle); - } - - /* */ - close(g_wifiglobal.sock_util); -} - -/* */ -int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count) { - int i; - int result = 0; - struct capwap_list_item* itemdevice; - struct capwap_list_item* itemwlan; - - if ((count > 0) && (!fds || !events)) { - return -1; - } - - /* Get from driver */ - for (i = 0; wifi_driver[i].ops != NULL; i++) { - result += wifi_driver[i].ops->global_getfdevent(wifi_driver[i].handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); - } - - /* Get from device */ - for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { - struct wifi_device* device = (struct wifi_device*)itemdevice->item; - if (device->handle) { - result += device->instance->ops->device_getfdevent(device, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); - - /* Get from wlan */ - if (device->wlans) { - for (itemwlan = device->wlans->first; itemwlan != NULL; itemwlan = itemwlan->next) { - struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; - - if (wlan->handle) { - result += device->instance->ops->wlan_getfdevent(wlan, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); - } - } - } - } - } - - return result; -} - -/* */ -struct wifi_wlan* wifi_get_wlan(uint32_t ifindex) { - struct capwap_list_item* itemdevice; - struct capwap_list_item* itemwlan; - - ASSERT(g_wifiglobal.devices != NULL); - ASSERT(ifindex > 0); - - /* Search device */ - for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { - struct wifi_device* device = (struct wifi_device*)itemdevice->item; - - /* Search wlan */ - if (device->wlans) { - for (itemwlan = device->wlans->first; itemwlan != NULL; itemwlan = itemwlan->next) { - struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; - - if (wlan->virtindex == ifindex) { - return wlan; - } - } - } - } - - return NULL; -} - -/* */ -struct wifi_device* wifi_device_connect(const char* ifname, const char* driver) { - int i; - int length; - struct capwap_list_item* itemdevice; - struct wifi_device* device = NULL; - - ASSERT(ifname != NULL); - ASSERT(driver != NULL); - - /* Check */ - length = strlen(ifname); - if ((length <= 0) || (length >= IFNAMSIZ)) { - capwap_logging_warning("Wifi device name error: %s", ifname); - return NULL; - } - - /* Search driver */ - for (i = 0; wifi_driver[i].ops != NULL; i++) { - if (!strcmp(driver, wifi_driver[i].ops->name)) { - itemdevice = capwap_itemlist_create(sizeof(struct wifi_device)); - device = (struct wifi_device*)itemdevice->item; - memset(device, 0, sizeof(struct wifi_device)); - - /* */ - device->global = &g_wifiglobal; - device->instance = &wifi_driver[i]; - strcpy(device->phyname, ifname); - - /* Device init */ - if (!wifi_driver[i].ops->device_init(wifi_driver[i].handle, device)) { - /* Registered new device */ - device->wlans = capwap_list_create(); - - /* Device capability */ - device->capability = (struct wifi_capability*)capwap_alloc(sizeof(struct wifi_capability)); - memset(device->capability, 0, sizeof(struct wifi_capability)); - device->capability->bands = capwap_array_create(sizeof(struct wifi_band_capability), 0, 1); - device->capability->ciphers = capwap_array_create(sizeof(struct wifi_cipher_capability), 0, 1); - - /* Retrieve device capability */ - device->instance->ops->device_getcapability(device, device->capability); - - /* Appent to device list */ - capwap_itemlist_insert_after(g_wifiglobal.devices, NULL, itemdevice); - } else { - capwap_itemlist_free(itemdevice); - device = NULL; - } - - break; - } - } - - return device; -} - -/* */ -const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device) { - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - - return device->capability; -} - -/* */ -int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params) { - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - ASSERT(params != NULL); - - /* */ - device->flags |= WIFI_DEVICE_SET_CONFIGURATION; - device->beaconperiod = params->beaconperiod; - device->dtimperiod = params->dtimperiod; - device->shortpreamble = (params->shortpreamble ? 1 : 0); - - /* Update beacons */ - if (device->wlans->count) { - device->instance->ops->device_updatebeacons(device); - } - - return 0; -} - -/* */ -int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel) { - int i, j; - int result = -1; - const struct wifi_capability* capability; - uint32_t frequency = 0; - - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - - /* Capability device */ - capability = wifi_device_getcapability(device); - if (!capability || !(capability->flags & WIFI_CAPABILITY_RADIOTYPE) || !(capability->flags & WIFI_CAPABILITY_BANDS)) { - return -1; - } - - /* Search frequency */ - for (i = 0; (i < capability->bands->count) && !frequency; i++) { - struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, i); - - if (bandcap->band == band) { - for (j = 0; j < bandcap->freq->count; j++) { - struct wifi_freq_capability* freqcap = (struct wifi_freq_capability*)capwap_array_get_item_pointer(bandcap->freq, j); - if (freqcap->channel == channel) { - frequency = freqcap->frequency; - break; - } - } - } - } - - /* Configure frequency */ - if (frequency) { - device->currentfrequency.band = band; - device->currentfrequency.mode = mode; - device->currentfrequency.channel = channel; - device->currentfrequency.frequency = frequency; - - /* According to the selected band remove the invalid mode */ - if (device->currentfrequency.band == WIFI_BAND_2GHZ) { - device->currentfrequency.mode &= ~CAPWAP_RADIO_TYPE_80211A; - } else if (device->currentfrequency.band == WIFI_BAND_5GHZ) { - device->currentfrequency.mode &= ~(CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G); - } - - /* Set frequency */ - device->flags |= WIFI_DEVICE_SET_FREQUENCY; - result = device->instance->ops->device_setfrequency(device); - } - - /* */ - return result; -} - -/* */ -int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount) { - struct device_setrates_params buildrate; - - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - ASSERT(rates != NULL); - ASSERT(ratescount > 0); - - /* */ - wifi_wlan_getrates(device, rates, ratescount, &buildrate); - if (!buildrate.supportedratescount || (buildrate.supportedratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { - return -1; - } else if (!buildrate.basicratescount || (buildrate.basicratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { - return -1; - } - - /* Set new rates */ - device->flags |= WIFI_DEVICE_SET_RATES; - memcpy(device->supportedrates, buildrate.supportedrates, buildrate.supportedratescount); - device->supportedratescount = buildrate.supportedratescount; - memcpy(device->basicrates, buildrate.basicrates, buildrate.basicratescount); - device->basicratescount = buildrate.basicratescount; - - /* Update beacons */ - if (device->wlans->count) { - device->instance->ops->device_updatebeacons(device); - } - - return 0; -} - -/* */ -struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname) { - int length; - struct wifi_wlan* wlan; - struct capwap_list_item* itemwlan; - - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - ASSERT(ifname != NULL); - - /* Check */ - length = strlen(ifname); - if ((length <= 0) || (length >= IFNAMSIZ)) { - capwap_logging_warning("Wifi device name error: %s", ifname); - return NULL; - } - - /* Create new WLAN */ - itemwlan = capwap_itemlist_create(sizeof(struct wifi_wlan)); - wlan = (struct wifi_wlan*)itemwlan->item; - memset(wlan, 0, sizeof(struct wifi_wlan)); - - /* */ - wlan->device = device; - strcpy(wlan->virtname, ifname); - wlan->maxstationscount = IEEE80211_MAX_STATIONS; - - /* Appent to wlan list */ - capwap_itemlist_insert_after(device->wlans, NULL, itemwlan); - - /* Create interface */ - wlan->handle = device->instance->ops->wlan_create(device, wlan); - if (!wlan->handle) { - capwap_logging_warning("Unable to create virtual interface: %s", ifname); - wifi_wlan_destroy(wlan); - return NULL; - } - - /* Interface info */ - wlan->virtindex = wifi_iface_index(ifname); - if (wifi_iface_hwaddr(g_wifiglobal.sock_util, wlan->virtname, wlan->address)) { - capwap_logging_warning("Unable to get macaddress: %s", ifname); - wifi_wlan_destroy(wlan); - return NULL; - } - - return wlan; -} - -/* */ -int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params) { - int result; - - ASSERT(wlan != NULL); - ASSERT(wlan->device != NULL); - ASSERT(params != NULL); - - /* Check device */ - if ((wlan->flags & WIFI_WLAN_RUNNING) || ((wlan->device->flags & WIFI_DEVICE_REQUIRED_FOR_BSS) != WIFI_DEVICE_REQUIRED_FOR_BSS)) { - return -1; - } - - /* Save configuration */ - strcpy(wlan->ssid, params->ssid); - wlan->ssid_hidden = params->ssid_hidden; - wlan->capability = params->capability; - wlan->authmode = params->authmode; - wlan->macmode = params->macmode; - wlan->tunnelmode = params->tunnelmode; - wlan->radioid = params->radioid; - wlan->wlanid = params->wlanid; - - /* Start AP */ - result = wlan->device->instance->ops->wlan_startap(wlan); - if (!result) { - wlan->device->wlanactive++; - capwap_logging_info("Configured interface: %s, SSID: '%s'", wlan->virtname, wlan->ssid); - } else { - wifi_wlan_stopap(wlan); - } - - return result; -} - -/* */ -void wifi_wlan_stopap(struct wifi_wlan* wlan) { - ASSERT(wlan != NULL); - ASSERT(wlan->device != NULL); - - /* Stop AP */ - wlan->device->instance->ops->wlan_stopap(wlan); - - /* */ - if (wlan->flags & WIFI_WLAN_RUNNING) { - wlan->device->wlanactive--; - } - - /* */ - wlan->flags = 0; - - /* TODO: Remove all stations from hash */ -} - -/* */ -int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid) { - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - ASSERT(bssid != NULL); - - memcpy(bssid, wlan->address, MACADDRESS_EUI48_LENGTH); - return 0; -} - -/* */ -uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability) { - uint16_t result = capability; - - /* Force ESS capability */ - result |= IEEE80211_CAPABILITY_ESS; - - /* Check short preamble capability */ - if (wlan->device->shortpreamble && !wlan->device->stationsnoshortpreamblecount) { - result |= IEEE80211_CAPABILITY_SHORTPREAMBLE; - } else { - result &= ~IEEE80211_CAPABILITY_SHORTPREAMBLE; - } - - /* Check privacy capability */ - /* TODO */ - - /* Check short slot time capability */ - if ((wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) && !wlan->device->stationsnoshortslottimecount) { - result |= IEEE80211_CAPABILITY_SHORTSLOTTIME; - } else { - result &= ~IEEE80211_CAPABILITY_SHORTSLOTTIME; - } - - return result; -} - -/* */ -void wifi_wlan_destroy(struct wifi_wlan* wlan) { - struct capwap_list_item* itemwlan; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - /* Terminate service */ - wifi_wlan_stopap(wlan); - - /* */ - wlan->device->instance->ops->wlan_delete(wlan); - - /* Remove wlan from device's list */ - for (itemwlan = wlan->device->wlans->first; itemwlan; itemwlan = itemwlan->next) { - if (wlan == (struct wifi_wlan*)itemwlan->item) { - capwap_itemlist_free(capwap_itemlist_remove(wlan->device->wlans, itemwlan)); - break; - } - } -} - -/* */ -void wifi_wlan_receive_station_frame(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate) { - uint16_t framecontrol; - uint16_t framecontrol_type; - uint16_t framecontrol_subtype; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - /* Check frame */ - if (!frame || (length < sizeof(struct ieee80211_header))) { - return; - } - - /* Get type frame */ - framecontrol = __le16_to_cpu(frame->framecontrol); - framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); - framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); - - /* Parsing frame */ - if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - wifi_wlan_receive_station_mgmt_frame(wlan, (const struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype, frequency, rssi, snr, rate); - } -} - -/* */ -void wifi_wlan_receive_station_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, int ack) { - uint16_t framecontrol; - uint16_t framecontrol_type; - uint16_t framecontrol_subtype; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - /* Check frame */ - if (!frame || (length < sizeof(struct ieee80211_header))) { - return; - } - - /* Get type frame */ - framecontrol = __le16_to_cpu(frame->framecontrol); - framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); - framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); - - /* Parsing frame */ - if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - wifi_wlan_receive_station_mgmt_ackframe(wlan, (const struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype, ack); - } -} - -/* */ -void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* frame, int length) { - int forwardframe = 1; - uint16_t framecontrol; - uint16_t framecontrol_type; - uint16_t framecontrol_subtype; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - /* Check frame */ - if (!frame || (length < sizeof(struct ieee80211_header))) { - return; - } - - /* Get type frame */ - framecontrol = __le16_to_cpu(frame->framecontrol); - framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); - framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); - - /* Parsing frame */ - if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - forwardframe = wifi_wlan_receive_ac_mgmt_frame(wlan, (struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype); - } - - /* Forward frame */ - if (forwardframe) { - int nowaitack = (ieee80211_is_broadcast_addr(ieee80211_get_da_addr(frame)) ? 1 : 0); - wlan->device->instance->ops->wlan_sendframe(wlan, (uint8_t*)frame, length, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack); - } -} - -/* */ -int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int result; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - if (!data || (length <= 0)) { - return -1; - } - - /* Send packet to AC */ - result = wtp_kmod_send_data(wlan->radioid, data, length, rssi, snr, rate); - if (result) { - capwap_logging_warning("Unable to sent packet to AC: %d error code", result); - } - - return result; -} - -/* */ -int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params) { - int result; - struct wifi_station* station; - - ASSERT(wlan != NULL); - ASSERT(wlan->device != NULL); - ASSERT(params != NULL); - - /* Get station */ - station = wifi_station_get(wlan, params->address); - if (!station) { - return -1; - } else if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { - return 0; - } - - /* */ - capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout); - station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; - - /* Station is authorized only after Authentication and Association */ - station->flags |= WIFI_STATION_FLAGS_AUTHORIZED; - if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) || !(station->flags & WIFI_STATION_FLAGS_ASSOCIATE)) { - return 0; - } - - /* Station authorized */ - result = wlan->device->instance->ops->station_authorize(wlan, station); - if (result) { - wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - } - - return result; -} - -/* */ -void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) { - struct wifi_station* station; - - ASSERT(device != NULL); - ASSERT(address != NULL); - - /* */ - station = wifi_station_get(NULL, address); - if (station && station->wlan) { - wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); - } -} - -/* */ -uint32_t wifi_iface_index(const char* ifname) { - if (!ifname || !*ifname) { - return 0; - } - - return if_nametoindex(ifname); -} - -/* */ -int wifi_iface_getstatus(int sock, const char* ifname) { - struct ifreq ifreq; - - ASSERT(sock > 0); - ASSERT(ifname != NULL); - ASSERT(*ifname != 0); - - /* Change link state of interface */ - memset(&ifreq, 0, sizeof(ifreq)); - strcpy(ifreq.ifr_name, ifname); - if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { - return ((ifreq.ifr_flags & IFF_UP) ? 1: 0); - } - - return -1; -} - -/* */ -int wifi_iface_updown(int sock, const char* ifname, int up) { - struct ifreq ifreq; - - ASSERT(sock > 0); - ASSERT(ifname != NULL); - ASSERT(*ifname != 0); - - /* Change link state of interface */ - memset(&ifreq, 0, sizeof(ifreq)); - strcpy(ifreq.ifr_name, ifname); - if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { - /* Set flag */ - if (up) { - if (ifreq.ifr_flags & IFF_UP) { - return 0; /* Flag is already set */ - } - - ifreq.ifr_flags |= IFF_UP; - } else { - if (!(ifreq.ifr_flags & IFF_UP)) { - return 0; /* Flag is already unset */ - } - - ifreq.ifr_flags &= ~IFF_UP; - } - - if (!ioctl(sock, SIOCSIFFLAGS, &ifreq)) { - return 0; - } - } - - return -1; -} - -/* */ -int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr) { - struct ifreq ifreq; - - ASSERT(sock > 0); - ASSERT(ifname != NULL); - ASSERT(*ifname != 0); - ASSERT(hwaddr != NULL); - - /* Get mac address of interface */ - memset(&ifreq, 0, sizeof(ifreq)); - strcpy(ifreq.ifr_name, ifname); - if (!ioctl(sock, SIOCGIFHWADDR, &ifreq)) { - if (ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) { - memcpy(hwaddr, ifreq.ifr_hwaddr.sa_data, MACADDRESS_EUI48_LENGTH); - return 0; - } - } - - return -1; -} - -/* */ -int wifi_frequency_to_radiotype(uint32_t freq) { - if ((freq >= 2412) && (freq <= 2472)) { - return CAPWAP_RADIO_TYPE_80211G; - } else if (freq == 2484) { - return CAPWAP_RADIO_TYPE_80211B; - } else if ((freq >= 4915) && (freq <= 4980)) { - return CAPWAP_RADIO_TYPE_80211A; - } else if ((freq >= 5035) && (freq <= 5825)) { - return CAPWAP_RADIO_TYPE_80211A; - } - - return -1; -} +#include "wtp.h" +#include "capwap_list.h" +#include "capwap_element.h" +#include "wifi_drivers.h" +#include "wtp_radio.h" +#include "wtp_kmod.h" + +/* Declare enable wifi driver */ +#ifdef ENABLE_WIFI_DRIVERS_NL80211 +extern struct wifi_driver_ops wifi_driver_nl80211_ops; +#endif + +static struct wifi_driver_instance wifi_driver[] = { +#ifdef ENABLE_WIFI_DRIVERS_NL80211 + { &wifi_driver_nl80211_ops, NULL }, +#endif + { NULL, NULL } +}; + +/* */ +#define WIFI_STATIONS_HASH_SIZE 256 + +/* Wifi Manager */ +static struct wifi_global g_wifiglobal; +static uint8_t g_bufferIEEE80211[IEEE80211_MTU]; + +/* */ +static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param); +static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation); + +/* */ +static void wifi_wlan_getrates(struct wifi_device* device, uint8_t* rates, int ratescount, struct device_setrates_params* device_params) { + int i, j, w; + int radiotype; + uint32_t mode = 0; + const struct wifi_capability* capability; + + ASSERT(device != NULL); + ASSERT(rates != NULL); + ASSERT(ratescount > 0); + ASSERT(device_params != NULL); + + /* */ + memset(device_params, 0, sizeof(struct device_setrates_params)); + + /* Retrieve capability */ + capability = wifi_device_getcapability(device); + if (!capability) { + return; + } + + /* Get radio type for basic rate */ + radiotype = wifi_frequency_to_radiotype(device->currentfrequency.frequency); + if (radiotype < 0) { + return; + } + + /* Check type of rate mode */ + for (i = 0; i < ratescount; i++) { + if (device->currentfrequency.band == WIFI_BAND_2GHZ) { + if (IS_IEEE80211_RATE_B(rates[i])) { + mode |= CAPWAP_RADIO_TYPE_80211B; + } else if (IS_IEEE80211_RATE_G(rates[i])) { + mode |= CAPWAP_RADIO_TYPE_80211G; + } else if (IS_IEEE80211_RATE_N(rates[i])) { + mode |= CAPWAP_RADIO_TYPE_80211N; + } + } else if (device->currentfrequency.band == WIFI_BAND_5GHZ) { + if (IS_IEEE80211_RATE_A(rates[i])) { + mode |= CAPWAP_RADIO_TYPE_80211A; + } else if (IS_IEEE80211_RATE_N(rates[i])) { + mode |= CAPWAP_RADIO_TYPE_80211N; + } + } + } + + /* Add implicit 802.11b rate with only 802.11g rate */ + if ((device->currentfrequency.band == WIFI_BAND_2GHZ) && !(mode & CAPWAP_RADIO_TYPE_80211B) && (device->currentfrequency.mode & CAPWAP_RADIO_TYPE_80211B)) { + device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_1M; + device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_2M; + device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_5_5M; + device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_11M; + } + + /* Filter band */ + for (i = 0; i < capability->bands->count; i++) { + struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, i); + + if (bandcap->band == device->currentfrequency.band) { + for (j = 0; j < bandcap->rate->count; j++) { + struct wifi_rate_capability* ratecapability = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, j); + + /* Validate rate */ + for (w = 0; w < ratescount; w++) { + if (rates[w] == ratecapability->bitrate) { + device_params->supportedrates[device_params->supportedratescount++] = ratecapability->bitrate; + break; + } + } + } + + break; + } + } + + /* Apply basic rate */ + for (i = 0; i < device_params->supportedratescount; i++) { + if (radiotype == CAPWAP_RADIO_TYPE_80211A) { + if (IS_IEEE80211_BASICRATE_A(device_params->supportedrates[i])) { + device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; + device_params->supportedrates[i] |= IEEE80211_BASICRATE; + } + } else if (radiotype == CAPWAP_RADIO_TYPE_80211B) { + if (IS_IEEE80211_BASICRATE_B(device_params->supportedrates[i])) { + device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; + device_params->supportedrates[i] |= IEEE80211_BASICRATE; + } + } else if (radiotype == CAPWAP_RADIO_TYPE_80211G) { + if (IS_IEEE80211_BASICRATE_G(device_params->supportedrates[i])) { + device_params->basicrates[device_params->basicratescount++] = device_params->supportedrates[i]; + device_params->supportedrates[i] |= IEEE80211_BASICRATE; + } + } + } + + /* Add implicit 802.11n rate with only 802.11a/g rate */ + if (!(mode & CAPWAP_RADIO_TYPE_80211N) && (device->currentfrequency.mode & CAPWAP_RADIO_TYPE_80211N)) { + device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_80211N; + } +} + +/* */ +static unsigned long wifi_hash_station_gethash(const void* key, unsigned long hashsize) { + uint8_t* macaddress = (uint8_t*)key; + + return ((unsigned long)macaddress[3] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]); +} + +/* */ +static const void* wifi_hash_station_getkey(const void* data) { + return (const void*)((struct wifi_station*)data)->address; +} + +/* */ +static int wifi_hash_station_cmp(const void* key1, const void* key2) { + return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); +} + +/* */ +static void wifi_hash_station_free(void* data) { + struct wifi_station* station = (struct wifi_station*)data; + + ASSERT(data != NULL); + + /* */ + capwap_logging_info("Destroy station: %s", station->addrtext); + capwap_free(station); +} + +/* */ +static struct wifi_station* wifi_station_get(struct wifi_wlan* wlan, const uint8_t* address) { + struct wifi_station* station; + + ASSERT(address != NULL); + + /* Get station */ + station = (struct wifi_station*)capwap_hash_search(g_wifiglobal.stations, address); + if (station && wlan && (station->wlan != wlan)) { + return NULL; + } + + return station; +} + +/* */ +static void wifi_station_clean(struct wifi_station* station) { + int updatebeacons = 0; + + ASSERT(station != NULL); + + if (station->wlan) { + struct wifi_wlan* wlan = station->wlan; + + /* Delete station into wireless driver */ + if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { + wlan->device->instance->ops->station_deauthorize(wlan, station->address); + } + + if (station->aid && (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { + ieee80211_aid_free(wlan->aidbitfield, station->aid); + station->aid = 0; + } + + if (station->flags & WIFI_STATION_FLAGS_NON_ERP) { + wlan->device->stationsnonerpcount--; + if (!wlan->device->stationsnonerpcount) { + updatebeacons = 1; + } + } + + if (station->flags & WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME) { + wlan->device->stationsnoshortslottimecount--; + if (!wlan->device->stationsnoshortslottimecount && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + if (station->flags & WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE) { + wlan->device->stationsnoshortpreamblecount--; + if (!wlan->device->stationsnoshortpreamblecount && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + /* Update beacons */ + if (updatebeacons) { + wlan->device->instance->ops->device_updatebeacons(wlan->device); + } + + /* Disconnet from WLAN */ + wlan->stationscount--; + station->wlan = NULL; + } + + /* Remove timers */ + if (station->idtimeout != CAPWAP_TIMEOUT_INDEX_NO_SET) { + capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout); + station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; + } + + /* */ + station->flags = 0; + station->supportedratescount = 0; +} + +/* */ +static void wifi_station_delete(struct wifi_station* station) { + ASSERT(station != NULL); + + /* */ + capwap_logging_info("Delete station: %s", station->addrtext); + + /* */ + wifi_station_clean(station); + + /* Delay delete station */ + station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DELETE; + station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED, wifi_station_timeout, station, NULL); +} + +/* */ +static struct wifi_station* wifi_station_create(struct wifi_wlan* wlan, const uint8_t* address) { + struct wifi_station* station; + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; + + ASSERT(wlan != NULL); + ASSERT(address != NULL); + + /* */ + capwap_printf_macaddress(buffer, address, MACADDRESS_EUI48_LENGTH); + + /* */ + station = wifi_station_get(NULL, address); + if (station) { + if (station->wlan && (station->wlan != wlan)) { + capwap_logging_info("Roaming station: %s", buffer); + wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 1); + } else { + capwap_logging_info("Reuse station: %s", buffer); + wifi_station_clean(station); + } + } + + /* Checks if it has reached the maximum number of stations */ + if (wlan->stationscount >= wlan->maxstationscount) { + capwap_logging_warning("Unable create station: reached the maximum number of stations"); + return NULL; + } + + /* Create new station */ + if (!station) { + capwap_logging_info("Create new station: %s", buffer); + + /* */ + station = (struct wifi_station*)capwap_alloc(sizeof(struct wifi_station)); + memset(station, 0, sizeof(struct wifi_station)); + + /* Initialize station */ + memcpy(station->address, address, MACADDRESS_EUI48_LENGTH); + capwap_printf_macaddress(station->addrtext, address, MACADDRESS_EUI48_LENGTH); + station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; + + /* Add to pool */ + capwap_hash_add(g_wifiglobal.stations, station); + } + + /* Set station to WLAN */ + station->wlan = wlan; + wlan->stationscount++; + + return station; +} + +/* */ +static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const uint8_t* station, uint16_t reasoncode) { + int responselength; + struct ieee80211_deauthentication_params ieee80211_params; + char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; + + /* */ + capwap_printf_macaddress(stationaddress, station, MACADDRESS_EUI48_LENGTH); + + /* Create deauthentication packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_deauthentication_params)); + memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); + memcpy(ieee80211_params.station, station, ETH_ALEN); + ieee80211_params.reasoncode = reasoncode; + + responselength = ieee80211_create_deauthentication(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); + if (responselength > 0) { + if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { + capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress); + + /* Forwards the station deauthentication also to AC */ + wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); + } else { + capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress); + } + } else { + capwap_logging_warning("Unable to create IEEE802.11 Deauthentication to %s station", stationaddress); + } +} + +/* */ +static void wifi_wlan_deauthentication_station(struct wifi_wlan* wlan, struct wifi_station* station, uint16_t reasoncode, int reusestation) { + ASSERT(wlan != NULL); + ASSERT(station != NULL); + + /* Send deauthentication message */ + if (station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) { + wifi_wlan_send_mgmt_deauthentication(wlan, station->address, reasoncode); + } + + /* Clean station */ + if (reusestation) { + wifi_station_clean(station); + } else { + wifi_station_delete(station); + } +} + +/* */ +static void wifi_station_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) { + struct wifi_station* station = (struct wifi_station*)context; + + ASSERT(station != NULL); + + if (station->idtimeout == index) { + switch (station->timeoutaction) { + case WIFI_STATION_TIMEOUT_ACTION_DELETE: { + /* Free station into hash callback function */ + wifi_station_clean(station); + capwap_hash_delete(g_wifiglobal.stations, station->address); + break; + } + + case WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE: { + capwap_logging_warning("The %s station has not completed the association in time", station->addrtext); + wifi_wlan_deauthentication_station((struct wifi_wlan*)param, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + break; + } + } + } +} + +/* */ +static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int ielength; + int ssidcheck; + int nowaitack; + int responselength; + struct ieee80211_ie_items ieitems; + struct ieee80211_probe_response_params ieee80211_params; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->proberequest)); + if (ielength < 0) { + return; + } + + /* Parsing Information Elements */ + if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->proberequest.ie[0], ielength)) { + return; + } + + /* Validate Probe Request Packet */ + if (!ieitems.ssid || !ieitems.supported_rates) { + return; + } + + /* Verify the SSID */ + ssidcheck = ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, ieitems.ssid_list); + if (ssidcheck == IEEE80211_WRONG_SSID) { + return; + } + + /* Create probe response */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_probe_response_params)); + memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); + memcpy(ieee80211_params.station, frame->sa, MACADDRESS_EUI48_LENGTH); + ieee80211_params.beaconperiod = wlan->device->beaconperiod; + ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); + ieee80211_params.ssid = wlan->ssid; + memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); + ieee80211_params.supportedratescount = wlan->device->supportedratescount; + ieee80211_params.mode = wlan->device->currentfrequency.mode; + ieee80211_params.erpinfo = ieee80211_get_erpinfo(wlan->device->currentfrequency.mode, wlan->device->olbc, wlan->device->stationsnonerpcount, wlan->device->stationsnoshortpreamblecount, wlan->device->shortpreamble); + ieee80211_params.channel = wlan->device->currentfrequency.channel; + + responselength = ieee80211_create_probe_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); + if (responselength < 0) { + return; + } + + /* Send probe response */ + nowaitack = ((ssidcheck == IEEE80211_WILDCARD_SSID) && ieee80211_is_broadcast_addr(frame->da) ? 1 : 0); + if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) { + /* If enable Split Mac send the probe request message to AC */ + if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); + } + } else { + capwap_logging_warning("Unable to send IEEE802.11 Probe Response"); + } +} + +/* */ +static void wifi_wlan_management_legacy_station(struct wifi_wlan* wlan, struct wifi_station* station) { + int updatebeacons = 0; + + /* Check NON ERP */ + if (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) { + int i; + int stationnonerp = 1; + + for (i = 0; i < station->supportedratescount; i++) { + if (IS_IEEE80211_RATE_G(station->supportedrates[i])) { + stationnonerp = 0; + break; + } + } + + if (stationnonerp) { + station->flags |= WIFI_STATION_FLAGS_NON_ERP; + wlan->device->stationsnonerpcount++; + if (wlan->device->stationsnonerpcount == 1) { + updatebeacons = 1; + } + } + } + + /* Check short slot capability */ + if (!(station->capability & IEEE80211_CAPABILITY_SHORTSLOTTIME)) { + station->flags |= WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME; + wlan->device->stationsnoshortslottimecount++; + if ((wlan->device->stationsnoshortslottimecount == 1) && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + /* Check short preamble capability */ + if (!(station->capability & IEEE80211_CAPABILITY_SHORTPREAMBLE)) { + station->flags |= WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE; + wlan->device->stationsnoshortpreamblecount++; + if ((wlan->device->stationsnoshortpreamblecount == 1) && (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + /* Update beacon */ + if (updatebeacons) { + wlan->device->instance->ops->device_updatebeacons(wlan->device); + } +} + +/* */ +static int wifi_wlan_get_station_rates(struct wifi_station* station, struct ieee80211_ie_items* ieitems) { + if (!ieitems->supported_rates) { + return -1; + } else if ((ieitems->supported_rates->len + (ieitems->extended_supported_rates ? ieitems->extended_supported_rates->len : 0)) > sizeof(station->supportedrates)) { + return -1; + } + + /* */ + station->supportedratescount = ieitems->supported_rates->len; + memcpy(station->supportedrates, ieitems->supported_rates->rates, ieitems->supported_rates->len); + if (ieitems->extended_supported_rates) { + station->supportedratescount += ieitems->extended_supported_rates->len; + memcpy(&station->supportedrates[ieitems->supported_rates->len], ieitems->extended_supported_rates->rates, ieitems->extended_supported_rates->len); + } + + return 0; +} + +/* */ +static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int acl; + int ielength; + struct ieee80211_ie_items ieitems; + int responselength; + struct ieee80211_authentication_params ieee80211_params; + struct wifi_station* station; + char stationaddress[CAPWAP_MACADDRESS_EUI48_BUFFER]; + uint16_t responsestatuscode; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); + if (ielength < 0) { + capwap_logging_info("Receive invalid IEEE802.11 Authentication Request"); + return; + } + + /* Ignore authentication packet from same AP */ + if (!memcmp(frame->sa, wlan->address, MACADDRESS_EUI48_LENGTH)) { + capwap_logging_info("Ignore IEEE802.11 Authentication Request from same AP"); + return; + } + + /* */ + capwap_printf_macaddress(stationaddress, frame->sa, MACADDRESS_EUI48_LENGTH); + + /* Get ACL Station */ + acl = wtp_radio_acl_station(frame->sa); + if (acl == WTP_RADIO_ACL_STATION_DENY) { + capwap_logging_info("Denied IEEE802.11 Authentication Request from %s station", stationaddress); + return; + } + + /* Parsing Information Elements */ + if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->authetication.ie[0], ielength)) { + capwap_logging_info("Invalid IEEE802.11 Authentication Request from %s station", stationaddress); + return; + } + + /* */ + capwap_logging_info("Receive IEEE802.11 Authentication Request from %s station", stationaddress); + + /* Create station reference */ + station = wifi_station_create(wlan, frame->sa); + if (station) { + /* A station is removed if the association does not complete within a given period of time */ + station->timeoutaction = WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE; + station->idtimeout = capwap_timeout_set(g_wifiglobal.timeout, station->idtimeout, WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE, wifi_station_timeout, station, wlan); + responsestatuscode = IEEE80211_STATUS_SUCCESS; + } else { + responsestatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + } + + /* */ + if ((responsestatuscode != IEEE80211_STATUS_SUCCESS) || (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL)) { + uint16_t algorithm = __le16_to_cpu(frame->authetication.algorithm); + uint16_t transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); + + /* Check authentication algorithm */ + if (responsestatuscode == IEEE80211_STATUS_SUCCESS) { + responsestatuscode = IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM; + if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_OPEN)) { + if (transactionseqnumber == 1) { + responsestatuscode = IEEE80211_STATUS_SUCCESS; + station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; + } else { + responsestatuscode = IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION; + } + } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP)) { + /* TODO */ + } + } + + /* Create authentication packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); + memcpy(ieee80211_params.bssid, wlan->address, MACADDRESS_EUI48_LENGTH); + memcpy(ieee80211_params.station, frame->sa, MACADDRESS_EUI48_LENGTH); + ieee80211_params.algorithm = algorithm; + ieee80211_params.transactionseqnumber = transactionseqnumber + 1; + ieee80211_params.statuscode = responsestatuscode; + + responselength = ieee80211_create_authentication_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); + if (responselength > 0) { + /* Send authentication response */ + if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { + capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", stationaddress, (int)responsestatuscode); + + /* Notify authentication request message also to AC */ + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); + + /* Forwards the authentication response message also to AC */ + wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); + } else if (station) { + capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress); + wifi_station_delete(station); + } + } else if (station) { + capwap_logging_warning("Unable to create IEEE802.11 Authentication Response to %s station", stationaddress); + wifi_station_delete(station); + } + } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); + } +} + +/* */ +static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int ielength; + int responselength; + struct ieee80211_ie_items ieitems; + struct ieee80211_associationresponse_params ieee80211_params; + struct wifi_station* station; + uint16_t resultstatuscode; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationrequest)); + if (ielength < 0) { + capwap_logging_info("Receive invalid IEEE802.11 Association Request"); + return; + } + + /* Get station reference */ + station = wifi_station_get(wlan, frame->sa); + if (!station) { + char buffer[CAPWAP_MACADDRESS_EUI48_BUFFER]; + + /* Invalid station, send deauthentication message */ + capwap_logging_info("Receive IEEE802.11 Association Request from %s unknown station", capwap_printf_macaddress(buffer, frame->sa, MACADDRESS_EUI48_LENGTH)); + wifi_wlan_send_mgmt_deauthentication(wlan, frame->sa, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); + return; + } + + /* */ + if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED)) { + /* Invalid station, send deauthentication message */ + capwap_logging_info("Receive IEEE802.11 Association Request from %s unauthorized station", station->addrtext); + wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA, 0); + return; + } + + /* Parsing Information Elements */ + if (ieee80211_retrieve_information_elements_position(&ieitems, &frame->associationrequest.ie[0], ielength)) { + capwap_logging_info("Invalid IEEE802.11 Association Request from %s station", station->addrtext); + wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + return; + } + + /* */ + capwap_logging_info("Receive IEEE802.11 Association Request from %s station", station->addrtext); + + /* */ + if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { + /* Verify SSID */ + if (ieee80211_is_valid_ssid(wlan->ssid, ieitems.ssid, NULL) == IEEE80211_VALID_SSID) { + station->capability = __le16_to_cpu(frame->associationrequest.capability); + station->listeninterval = __le16_to_cpu(frame->associationrequest.listeninterval); + if (!ieee80211_aid_create(wlan->aidbitfield, &station->aid)) { + /* Get supported rates */ + if (!wifi_wlan_get_station_rates(station, &ieitems)) { + wifi_wlan_management_legacy_station(wlan, station); + resultstatuscode = IEEE80211_STATUS_SUCCESS; + } else { + resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; + } + } else { + resultstatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + } + } else { + resultstatuscode = IEEE80211_STATUS_UNSPECIFIED_FAILURE; + } + + /* Create association response packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); + memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); + memcpy(ieee80211_params.station, frame->sa, ETH_ALEN); + ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); + ieee80211_params.statuscode = resultstatuscode; + ieee80211_params.aid = IEEE80211_AID_FIELD | station->aid; + memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); + ieee80211_params.supportedratescount = wlan->device->supportedratescount; + + responselength = ieee80211_create_associationresponse_response(g_bufferIEEE80211, sizeof(g_bufferIEEE80211), &ieee80211_params); + if (responselength > 0) { + if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, 0)) { + capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); + + /* Notify association request message also to AC */ + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); + + /* Forwards the association response message also to AC */ + wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0); + } else { + capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); + wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + } + } else { + capwap_logging_warning("Unable to create IEEE802.11 Association Response to %s station", station->addrtext); + wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + } + } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); + + /* Station information */ + station->capability = __le16_to_cpu(frame->associationresponse.capability); + station->listeninterval = __le16_to_cpu(frame->associationrequest.listeninterval); + } +} + +/* */ +static void wifi_wlan_receive_station_mgmt_reassociation_request(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int ielength; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->reassociationrequest)); + if (ielength < 0) { + return; + } + + /* TODO */ +} + +/* */ +static void wifi_wlan_receive_station_mgmt_disassociation(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int ielength; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->disassociation)); + if (ielength < 0) { + return; + } + + /* TODO */ + + /* Notify disassociation message also to AC */ + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); +} + +/* */ +static void wifi_wlan_receive_station_mgmt_deauthentication(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int ielength; + struct wifi_station* station; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->deauthetication)); + if (ielength < 0) { + return; + } + + /* Delete station */ + station = wifi_station_get(wlan, frame->sa); + if (station) { + wifi_station_delete(station); + } + + /* Notify deauthentication message also to AC */ + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate); +} + +/* */ +static void wifi_wlan_receive_station_mgmt_frame(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate) { + int broadcast; + + /* Check frequency */ + if (frequency && (wlan->device->currentfrequency.frequency != frequency)) { + return; + } + + /* Check if sent packet to correct AP */ + broadcast = ieee80211_is_broadcast_addr(frame->bssid); + if (!broadcast && memcmp(frame->bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { + return; + } + + /* */ + if (framecontrol_subtype == IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST) { + wifi_wlan_receive_station_mgmt_probe_request(wlan, frame, length, rssi, snr, rate); + } else if (!memcmp(frame->da, wlan->address, MACADDRESS_EUI48_LENGTH)) { + switch (framecontrol_subtype) { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { + wifi_wlan_receive_station_mgmt_authentication(wlan, frame, length, rssi, snr, rate); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { + wifi_wlan_receive_station_mgmt_association_request(wlan, frame, length, rssi, snr, rate); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { + wifi_wlan_receive_station_mgmt_reassociation_request(wlan, frame, length, rssi, snr, rate); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { + wifi_wlan_receive_station_mgmt_disassociation(wlan, frame, length, rssi, snr, rate); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { + wifi_wlan_receive_station_mgmt_deauthentication(wlan, frame, length, rssi, snr, rate); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION: { + /* TODO */ + break; + } + } + } +} + +/* */ +static void wifi_wlan_receive_station_mgmt_authentication_ack(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, int ack) { + uint16_t algorithm; + uint16_t transactionseqnumber; + uint16_t statuscode; + struct wifi_station* station; + + /* Check packet */ + if (!ack || (length < (sizeof(struct ieee80211_header) + sizeof(frame->authetication)))) { + return; + } + + /* Get station information */ + station = wifi_station_get(wlan, frame->da); + if (!station) { + return; + } + + /* */ + statuscode = __le16_to_cpu(frame->authetication.statuscode); + if (statuscode == IEEE80211_STATUS_SUCCESS) { + algorithm = __le16_to_cpu(frame->authetication.algorithm); + transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); + + /* Check if authenticate */ + if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { + capwap_logging_info("IEEE802.11 Authentication complete to %s station", station->addrtext); + station->flags |= WIFI_STATION_FLAGS_AUTHENTICATED; + } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { + /* TODO */ + } + } +} + +/* */ +static void wifi_wlan_receive_station_mgmt_association_response_ack(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, int ack) { + uint16_t statuscode; + struct wifi_station* station; + + /* Check packet */ + if (!ack || (length < (sizeof(struct ieee80211_header) + sizeof(frame->associationresponse)))) { + return; + } + + /* Get station information */ + station = wifi_station_get(wlan, frame->da); + if (!station) { + return; + } + + /* */ + statuscode = __le16_to_cpu(frame->associationresponse.statuscode); + if (statuscode == IEEE80211_STATUS_SUCCESS) { + capwap_logging_info("IEEE802.11 Association complete to %s station", station->addrtext); + + /* */ + station->flags |= WIFI_STATION_FLAGS_ASSOCIATE; + if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { + /* Apply authorization if Station already authorized */ + if (wlan->device->instance->ops->station_authorize(wlan, station)) { + wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + } + } + } +} + +/* */ +static void wifi_wlan_receive_station_mgmt_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype, int ack) { + /* Ignore packet if not sent to AP */ + if (memcmp(frame->bssid, wlan->address, MACADDRESS_EUI48_LENGTH)) { + return; + } + + /* */ + switch (framecontrol_subtype) { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { + wifi_wlan_receive_station_mgmt_authentication_ack(wlan, frame, length, ack); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { + wifi_wlan_receive_station_mgmt_association_response_ack(wlan, frame, length, ack); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { + /* TODO */ + break; + } + } +} + +/* */ +static int wifi_wlan_receive_ac_mgmt_authentication(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { + int ielength; + struct wifi_station* station; + int forwardframe = 0; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->authetication)); + if (ielength >= 0) { + if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + station = wifi_station_get(wlan, frame->da); + if (station) { + uint16_t statuscode = __le16_to_cpu(frame->authetication.statuscode); + + if (statuscode == IEEE80211_STATUS_SUCCESS) { + uint16_t algorithm = __le16_to_cpu(frame->authetication.algorithm); + uint16_t transactionseqnumber = __le16_to_cpu(frame->authetication.transactionseqnumber); + + /* Get authentication algorithm */ + if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { + station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_OPEN; + } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { + station->authalgorithm = IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY; + } + } + + /* */ + forwardframe = 1; + } + } + } + + return forwardframe; +} + +/* */ +static int wifi_wlan_receive_ac_mgmt_association_response(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { + int ielength; + struct ieee80211_ie_items ieitems; + struct wifi_station* station; + int forwardframe = 0; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->associationresponse)); + if (ielength >= 0) { + station = wifi_station_get(wlan, frame->da); + if (station) { + if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) { + if (frame->associationresponse.statuscode != IEEE80211_STATUS_SUCCESS) { + capwap_logging_info("AC request deauthentication of station: %s", station->addrtext); + wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + } + } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + uint16_t statuscode = __le16_to_cpu(frame->associationresponse.statuscode); + + if ((statuscode == IEEE80211_STATUS_SUCCESS) && !ieee80211_retrieve_information_elements_position(&ieitems, &frame->associationresponse.ie[0], ielength)) { + /* Station information */ + station->aid = (__le16_to_cpu(frame->associationresponse.aid) & ~IEEE80211_AID_FIELD); + + /* Get supported rates */ + wifi_wlan_get_station_rates(station, &ieitems); + + /* */ + wifi_wlan_management_legacy_station(wlan, station); + + /* Assign valid WLAN capability */ + frame->associationresponse.capability = __cpu_to_le16(wifi_wlan_check_capability(wlan, wlan->capability)); + } + + /* */ + forwardframe = 1; + } + } + } + + return forwardframe; +} + +/* */ +static int wifi_wlan_receive_ac_mgmt_reassociation_response(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { + int ielength; + struct wifi_station* station; + int forwardframe = 0; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->reassociationresponse)); + if (ielength >= 0) { + if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { + station = wifi_station_get(wlan, frame->da); + if (station) { + /* TODO */ + } + } + } + + return forwardframe; +} + +/* */ +static int wifi_wlan_receive_ac_mgmt_disassociation(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { + int ielength; + struct wifi_station* station; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->disassociation)); + if (ielength < 0) { + return 0; + } + + /* */ + station = wifi_station_get(wlan, frame->da); + if (station) { + /* Deautherize station */ + if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { + station->flags &= ~WIFI_STATION_FLAGS_AUTHORIZED; + wlan->device->instance->ops->station_deauthorize(wlan, station->address); + } + + /* Deassociate station */ + station->flags &= ~WIFI_STATION_FLAGS_ASSOCIATE; + } + + return 1; +} + +/* */ +static int wifi_wlan_receive_ac_mgmt_deauthentication(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length) { + int ielength; + struct wifi_station* station; + + /* Information Elements packet length */ + ielength = length - (sizeof(struct ieee80211_header) + sizeof(frame->deauthetication)); + if (ielength < 0) { + return 0; + } + + /* Delete station */ + station = wifi_station_get(wlan, frame->da); + if (station) { + wifi_station_delete(station); + } + + return 1; +} + +/* */ +static int wifi_wlan_receive_ac_mgmt_frame(struct wifi_wlan* wlan, struct ieee80211_header_mgmt* frame, int length, uint16_t framecontrol_subtype) { + int forwardframe = 0; + + switch (framecontrol_subtype) { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { + forwardframe = wifi_wlan_receive_ac_mgmt_authentication(wlan, frame, length); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { + forwardframe = wifi_wlan_receive_ac_mgmt_association_response(wlan, frame, length); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_RESPONSE: { + forwardframe = wifi_wlan_receive_ac_mgmt_reassociation_response(wlan, frame, length); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { + forwardframe = wifi_wlan_receive_ac_mgmt_disassociation(wlan, frame, length); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { + forwardframe = wifi_wlan_receive_ac_mgmt_deauthentication(wlan, frame, length); + break; + } + } + + return forwardframe; +} + +/* */ +int wifi_driver_init(struct capwap_timeout* timeout) { + int i; + + ASSERT(timeout != NULL); + + /* Socket utils */ + memset(&g_wifiglobal, 0, sizeof(struct wifi_global)); + g_wifiglobal.sock_util = socket(AF_PACKET, SOCK_RAW, 0); + if (g_wifiglobal.sock_util < 0) { + return -1; + } + + /* Initialize driver */ + for (i = 0; wifi_driver[i].ops != NULL; i++) { + wifi_driver[i].handle = wifi_driver[i].ops->global_init(); + if (!wifi_driver[i].handle) { + close(g_wifiglobal.sock_util); + return -1; + } + } + + /* */ + g_wifiglobal.timeout = timeout; + g_wifiglobal.devices = capwap_list_create(); + g_wifiglobal.stations = capwap_hash_create(WIFI_STATIONS_HASH_SIZE); + g_wifiglobal.stations->item_gethash = wifi_hash_station_gethash; + g_wifiglobal.stations->item_getkey = wifi_hash_station_getkey; + g_wifiglobal.stations->item_cmp = wifi_hash_station_cmp; + g_wifiglobal.stations->item_free = wifi_hash_station_free; + + return 0; +} + +/* */ +void wifi_driver_free(void) { + int i; + struct capwap_list_item* itemdevice; + + /* Free devices */ + if (g_wifiglobal.devices) { + for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { + struct wifi_device* device = (struct wifi_device*)itemdevice->item; + + /* Free WLANS */ + if (device->wlans) { + while (device->wlans->first) { + wifi_wlan_destroy((struct wifi_wlan*)device->wlans->first->item); + } + + capwap_list_free(device->wlans); + } + + /* */ + if (device->handle) { + device->instance->ops->device_deinit(device); + } + + /* Free capability */ + if (device->capability) { + if (device->capability->bands) { + for (i = 0; i < device->capability->bands->count; i++) { + struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(device->capability->bands, i); + + if (bandcap->freq) { + capwap_array_free(bandcap->freq); + } + + if (bandcap->rate) { + capwap_array_free(bandcap->rate); + } + } + + capwap_array_free(device->capability->bands); + } + + if (device->capability->ciphers) { + capwap_array_free(device->capability->ciphers); + } + + capwap_free(device->capability); + } + } + + capwap_list_free(g_wifiglobal.devices); + } + + /* Free stations */ + if (g_wifiglobal.stations) { + capwap_hash_free(g_wifiglobal.stations); + } + + /* Free driver */ + for (i = 0; wifi_driver[i].ops != NULL; i++) { + wifi_driver[i].ops->global_deinit(wifi_driver[i].handle); + } + + /* */ + close(g_wifiglobal.sock_util); +} + +/* */ +int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count) { + int i; + int result = 0; + struct capwap_list_item* itemdevice; + struct capwap_list_item* itemwlan; + + if ((count > 0) && (!fds || !events)) { + return -1; + } + + /* Get from driver */ + for (i = 0; wifi_driver[i].ops != NULL; i++) { + result += wifi_driver[i].ops->global_getfdevent(wifi_driver[i].handle, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + + /* Get from device */ + for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { + struct wifi_device* device = (struct wifi_device*)itemdevice->item; + if (device->handle) { + result += device->instance->ops->device_getfdevent(device, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + + /* Get from wlan */ + if (device->wlans) { + for (itemwlan = device->wlans->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; + + if (wlan->handle) { + result += device->instance->ops->wlan_getfdevent(wlan, (count ? &fds[result] : NULL), (count ? &events[result] : NULL)); + } + } + } + } + } + + return result; +} + +/* */ +struct wifi_wlan* wifi_get_wlan(uint32_t ifindex) { + struct capwap_list_item* itemdevice; + struct capwap_list_item* itemwlan; + + ASSERT(g_wifiglobal.devices != NULL); + ASSERT(ifindex > 0); + + /* Search device */ + for (itemdevice = g_wifiglobal.devices->first; itemdevice != NULL; itemdevice = itemdevice->next) { + struct wifi_device* device = (struct wifi_device*)itemdevice->item; + + /* Search wlan */ + if (device->wlans) { + for (itemwlan = device->wlans->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wifi_wlan* wlan = (struct wifi_wlan*)itemwlan->item; + + if (wlan->virtindex == ifindex) { + return wlan; + } + } + } + } + + return NULL; +} + +/* */ +struct wifi_device* wifi_device_connect(const char* ifname, const char* driver) { + int i; + int length; + struct capwap_list_item* itemdevice; + struct wifi_device* device = NULL; + + ASSERT(ifname != NULL); + ASSERT(driver != NULL); + + /* Check */ + length = strlen(ifname); + if ((length <= 0) || (length >= IFNAMSIZ)) { + capwap_logging_warning("Wifi device name error: %s", ifname); + return NULL; + } + + /* Search driver */ + for (i = 0; wifi_driver[i].ops != NULL; i++) { + if (!strcmp(driver, wifi_driver[i].ops->name)) { + itemdevice = capwap_itemlist_create(sizeof(struct wifi_device)); + device = (struct wifi_device*)itemdevice->item; + memset(device, 0, sizeof(struct wifi_device)); + + /* */ + device->global = &g_wifiglobal; + device->instance = &wifi_driver[i]; + strcpy(device->phyname, ifname); + + /* Device init */ + if (!wifi_driver[i].ops->device_init(wifi_driver[i].handle, device)) { + /* Registered new device */ + device->wlans = capwap_list_create(); + + /* Device capability */ + device->capability = (struct wifi_capability*)capwap_alloc(sizeof(struct wifi_capability)); + memset(device->capability, 0, sizeof(struct wifi_capability)); + device->capability->bands = capwap_array_create(sizeof(struct wifi_band_capability), 0, 1); + device->capability->ciphers = capwap_array_create(sizeof(struct wifi_cipher_capability), 0, 1); + + /* Retrieve device capability */ + device->instance->ops->device_getcapability(device, device->capability); + + /* Appent to device list */ + capwap_itemlist_insert_after(g_wifiglobal.devices, NULL, itemdevice); + } else { + capwap_itemlist_free(itemdevice); + device = NULL; + } + + break; + } + } + + return device; +} + +/* */ +const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device) { + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + + return device->capability; +} + +/* */ +int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params) { + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(params != NULL); + + /* */ + device->flags |= WIFI_DEVICE_SET_CONFIGURATION; + device->beaconperiod = params->beaconperiod; + device->dtimperiod = params->dtimperiod; + device->shortpreamble = (params->shortpreamble ? 1 : 0); + + /* Update beacons */ + if (device->wlans->count) { + device->instance->ops->device_updatebeacons(device); + } + + return 0; +} + +/* */ +int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel) { + int i, j; + int result = -1; + const struct wifi_capability* capability; + uint32_t frequency = 0; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + + /* Capability device */ + capability = wifi_device_getcapability(device); + if (!capability || !(capability->flags & WIFI_CAPABILITY_RADIOTYPE) || !(capability->flags & WIFI_CAPABILITY_BANDS)) { + return -1; + } + + /* Search frequency */ + for (i = 0; (i < capability->bands->count) && !frequency; i++) { + struct wifi_band_capability* bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, i); + + if (bandcap->band == band) { + for (j = 0; j < bandcap->freq->count; j++) { + struct wifi_freq_capability* freqcap = (struct wifi_freq_capability*)capwap_array_get_item_pointer(bandcap->freq, j); + if (freqcap->channel == channel) { + frequency = freqcap->frequency; + break; + } + } + } + } + + /* Configure frequency */ + if (frequency) { + device->currentfrequency.band = band; + device->currentfrequency.mode = mode; + device->currentfrequency.channel = channel; + device->currentfrequency.frequency = frequency; + + /* According to the selected band remove the invalid mode */ + if (device->currentfrequency.band == WIFI_BAND_2GHZ) { + device->currentfrequency.mode &= ~CAPWAP_RADIO_TYPE_80211A; + } else if (device->currentfrequency.band == WIFI_BAND_5GHZ) { + device->currentfrequency.mode &= ~(CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G); + } + + /* Set frequency */ + device->flags |= WIFI_DEVICE_SET_FREQUENCY; + result = device->instance->ops->device_setfrequency(device); + } + + /* */ + return result; +} + +/* */ +int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount) { + struct device_setrates_params buildrate; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(rates != NULL); + ASSERT(ratescount > 0); + + /* */ + wifi_wlan_getrates(device, rates, ratescount, &buildrate); + if (!buildrate.supportedratescount || (buildrate.supportedratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { + return -1; + } else if (!buildrate.basicratescount || (buildrate.basicratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { + return -1; + } + + /* Set new rates */ + device->flags |= WIFI_DEVICE_SET_RATES; + memcpy(device->supportedrates, buildrate.supportedrates, buildrate.supportedratescount); + device->supportedratescount = buildrate.supportedratescount; + memcpy(device->basicrates, buildrate.basicrates, buildrate.basicratescount); + device->basicratescount = buildrate.basicratescount; + + /* Update beacons */ + if (device->wlans->count) { + device->instance->ops->device_updatebeacons(device); + } + + return 0; +} + +/* */ +struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname) { + int length; + struct wifi_wlan* wlan; + struct capwap_list_item* itemwlan; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(ifname != NULL); + + /* Check */ + length = strlen(ifname); + if ((length <= 0) || (length >= IFNAMSIZ)) { + capwap_logging_warning("Wifi device name error: %s", ifname); + return NULL; + } + + /* Create new WLAN */ + itemwlan = capwap_itemlist_create(sizeof(struct wifi_wlan)); + wlan = (struct wifi_wlan*)itemwlan->item; + memset(wlan, 0, sizeof(struct wifi_wlan)); + + /* */ + wlan->device = device; + strcpy(wlan->virtname, ifname); + wlan->maxstationscount = IEEE80211_MAX_STATIONS; + + /* Appent to wlan list */ + capwap_itemlist_insert_after(device->wlans, NULL, itemwlan); + + /* Create interface */ + wlan->handle = device->instance->ops->wlan_create(device, wlan); + if (!wlan->handle) { + capwap_logging_warning("Unable to create virtual interface: %s", ifname); + wifi_wlan_destroy(wlan); + return NULL; + } + + /* Interface info */ + wlan->virtindex = wifi_iface_index(ifname); + if (wifi_iface_hwaddr(g_wifiglobal.sock_util, wlan->virtname, wlan->address)) { + capwap_logging_warning("Unable to get macaddress: %s", ifname); + wifi_wlan_destroy(wlan); + return NULL; + } + + return wlan; +} + +/* */ +int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params) { + int result; + + ASSERT(wlan != NULL); + ASSERT(wlan->device != NULL); + ASSERT(params != NULL); + + /* Check device */ + if ((wlan->flags & WIFI_WLAN_RUNNING) || ((wlan->device->flags & WIFI_DEVICE_REQUIRED_FOR_BSS) != WIFI_DEVICE_REQUIRED_FOR_BSS)) { + return -1; + } + + /* Save configuration */ + strcpy(wlan->ssid, params->ssid); + wlan->ssid_hidden = params->ssid_hidden; + wlan->capability = params->capability; + wlan->authmode = params->authmode; + wlan->macmode = params->macmode; + wlan->tunnelmode = params->tunnelmode; + wlan->radioid = params->radioid; + wlan->wlanid = params->wlanid; + + /* Start AP */ + result = wlan->device->instance->ops->wlan_startap(wlan); + if (!result) { + wlan->device->wlanactive++; + capwap_logging_info("Configured interface: %s, SSID: '%s'", wlan->virtname, wlan->ssid); + } else { + wifi_wlan_stopap(wlan); + } + + return result; +} + +/* */ +void wifi_wlan_stopap(struct wifi_wlan* wlan) { + ASSERT(wlan != NULL); + ASSERT(wlan->device != NULL); + + /* Stop AP */ + wlan->device->instance->ops->wlan_stopap(wlan); + + /* */ + if (wlan->flags & WIFI_WLAN_RUNNING) { + wlan->device->wlanactive--; + } + + /* */ + wlan->flags = 0; + + /* TODO: Remove all stations from hash */ +} + +/* */ +int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid) { + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + ASSERT(bssid != NULL); + + memcpy(bssid, wlan->address, MACADDRESS_EUI48_LENGTH); + return 0; +} + +/* */ +uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability) { + uint16_t result = capability; + + /* Force ESS capability */ + result |= IEEE80211_CAPABILITY_ESS; + + /* Check short preamble capability */ + if (wlan->device->shortpreamble && !wlan->device->stationsnoshortpreamblecount) { + result |= IEEE80211_CAPABILITY_SHORTPREAMBLE; + } else { + result &= ~IEEE80211_CAPABILITY_SHORTPREAMBLE; + } + + /* Check privacy capability */ + /* TODO */ + + /* Check short slot time capability */ + if ((wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) && !wlan->device->stationsnoshortslottimecount) { + result |= IEEE80211_CAPABILITY_SHORTSLOTTIME; + } else { + result &= ~IEEE80211_CAPABILITY_SHORTSLOTTIME; + } + + return result; +} + +/* */ +void wifi_wlan_destroy(struct wifi_wlan* wlan) { + struct capwap_list_item* itemwlan; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* Terminate service */ + wifi_wlan_stopap(wlan); + + /* */ + wlan->device->instance->ops->wlan_delete(wlan); + + /* Remove wlan from device's list */ + for (itemwlan = wlan->device->wlans->first; itemwlan; itemwlan = itemwlan->next) { + if (wlan == (struct wifi_wlan*)itemwlan->item) { + capwap_itemlist_free(capwap_itemlist_remove(wlan->device->wlans, itemwlan)); + break; + } + } +} + +/* */ +void wifi_wlan_receive_station_frame(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate) { + uint16_t framecontrol; + uint16_t framecontrol_type; + uint16_t framecontrol_subtype; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* Check frame */ + if (!frame || (length < sizeof(struct ieee80211_header))) { + return; + } + + /* Get type frame */ + framecontrol = __le16_to_cpu(frame->framecontrol); + framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); + framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); + + /* Parsing frame */ + if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { + wifi_wlan_receive_station_mgmt_frame(wlan, (const struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype, frequency, rssi, snr, rate); + } +} + +/* */ +void wifi_wlan_receive_station_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, int ack) { + uint16_t framecontrol; + uint16_t framecontrol_type; + uint16_t framecontrol_subtype; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* Check frame */ + if (!frame || (length < sizeof(struct ieee80211_header))) { + return; + } + + /* Get type frame */ + framecontrol = __le16_to_cpu(frame->framecontrol); + framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); + framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); + + /* Parsing frame */ + if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { + wifi_wlan_receive_station_mgmt_ackframe(wlan, (const struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype, ack); + } +} + +/* */ +void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* frame, int length) { + int forwardframe = 1; + uint16_t framecontrol; + uint16_t framecontrol_type; + uint16_t framecontrol_subtype; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* Check frame */ + if (!frame || (length < sizeof(struct ieee80211_header))) { + return; + } + + /* Get type frame */ + framecontrol = __le16_to_cpu(frame->framecontrol); + framecontrol_type = IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol); + framecontrol_subtype = IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol); + + /* Parsing frame */ + if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { + forwardframe = wifi_wlan_receive_ac_mgmt_frame(wlan, (struct ieee80211_header_mgmt*)frame, length, framecontrol_subtype); + } + + /* Forward frame */ + if (forwardframe) { + int nowaitack = (ieee80211_is_broadcast_addr(ieee80211_get_da_addr(frame)) ? 1 : 0); + wlan->device->instance->ops->wlan_sendframe(wlan, (uint8_t*)frame, length, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack); + } +} + +/* */ +int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int result; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + if (!data || (length <= 0)) { + return -1; + } + + /* Send packet to AC */ + result = wtp_kmod_send_data(wlan->radioid, data, length, rssi, snr, rate); + if (result) { + capwap_logging_warning("Unable to sent packet to AC: %d error code", result); + } + + return result; +} + +/* */ +int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params) { + int result; + struct wifi_station* station; + + ASSERT(wlan != NULL); + ASSERT(wlan->device != NULL); + ASSERT(params != NULL); + + /* Get station */ + station = wifi_station_get(wlan, params->address); + if (!station) { + return -1; + } else if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { + return 0; + } + + /* */ + capwap_timeout_deletetimer(g_wifiglobal.timeout, station->idtimeout); + station->idtimeout = CAPWAP_TIMEOUT_INDEX_NO_SET; + + /* Station is authorized only after Authentication and Association */ + station->flags |= WIFI_STATION_FLAGS_AUTHORIZED; + if (!(station->flags & WIFI_STATION_FLAGS_AUTHENTICATED) || !(station->flags & WIFI_STATION_FLAGS_ASSOCIATE)) { + return 0; + } + + /* Station authorized */ + result = wlan->device->instance->ops->station_authorize(wlan, station); + if (result) { + wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + } + + return result; +} + +/* */ +void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) { + struct wifi_station* station; + + ASSERT(device != NULL); + ASSERT(address != NULL); + + /* */ + station = wifi_station_get(NULL, address); + if (station && station->wlan) { + wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); + } +} + +/* */ +uint32_t wifi_iface_index(const char* ifname) { + if (!ifname || !*ifname) { + return 0; + } + + return if_nametoindex(ifname); +} + +/* */ +int wifi_iface_getstatus(int sock, const char* ifname) { + struct ifreq ifreq; + + ASSERT(sock > 0); + ASSERT(ifname != NULL); + ASSERT(*ifname != 0); + + /* Change link state of interface */ + memset(&ifreq, 0, sizeof(ifreq)); + strcpy(ifreq.ifr_name, ifname); + if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { + return ((ifreq.ifr_flags & IFF_UP) ? 1: 0); + } + + return -1; +} + +/* */ +int wifi_iface_updown(int sock, const char* ifname, int up) { + struct ifreq ifreq; + + ASSERT(sock > 0); + ASSERT(ifname != NULL); + ASSERT(*ifname != 0); + + /* Change link state of interface */ + memset(&ifreq, 0, sizeof(ifreq)); + strcpy(ifreq.ifr_name, ifname); + if (!ioctl(sock, SIOCGIFFLAGS, &ifreq)) { + /* Set flag */ + if (up) { + if (ifreq.ifr_flags & IFF_UP) { + return 0; /* Flag is already set */ + } + + ifreq.ifr_flags |= IFF_UP; + } else { + if (!(ifreq.ifr_flags & IFF_UP)) { + return 0; /* Flag is already unset */ + } + + ifreq.ifr_flags &= ~IFF_UP; + } + + if (!ioctl(sock, SIOCSIFFLAGS, &ifreq)) { + return 0; + } + } + + return -1; +} + +/* */ +int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr) { + struct ifreq ifreq; + + ASSERT(sock > 0); + ASSERT(ifname != NULL); + ASSERT(*ifname != 0); + ASSERT(hwaddr != NULL); + + /* Get mac address of interface */ + memset(&ifreq, 0, sizeof(ifreq)); + strcpy(ifreq.ifr_name, ifname); + if (!ioctl(sock, SIOCGIFHWADDR, &ifreq)) { + if (ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) { + memcpy(hwaddr, ifreq.ifr_hwaddr.sa_data, MACADDRESS_EUI48_LENGTH); + return 0; + } + } + + return -1; +} + +/* */ +int wifi_frequency_to_radiotype(uint32_t freq) { + if ((freq >= 2412) && (freq <= 2472)) { + return CAPWAP_RADIO_TYPE_80211G; + } else if (freq == 2484) { + return CAPWAP_RADIO_TYPE_80211B; + } else if ((freq >= 4915) && (freq <= 4980)) { + return CAPWAP_RADIO_TYPE_80211A; + } else if ((freq >= 5035) && (freq <= 5825)) { + return CAPWAP_RADIO_TYPE_80211A; + } + + return -1; +} diff --git a/src/wtp/binding/ieee80211/wifi_drivers.h b/src/wtp/binding/ieee80211/wifi_drivers.h index 61ea2b6..9a244b5 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.h +++ b/src/wtp/binding/ieee80211/wifi_drivers.h @@ -1,436 +1,436 @@ -#ifndef __WIFI_DRIVERS_HEADER__ -#define __WIFI_DRIVERS_HEADER__ - -#include -#include -#include "ieee80211.h" - -/* */ -#define WIFI_DRIVER_NAME_SIZE 16 - -/* */ -#define WIFI_BAND_UNKNOWN 0 -#define WIFI_BAND_2GHZ 1 -#define WIFI_BAND_5GHZ 2 - -/* */ -#define WIFI_CAPABILITY_RADIOSUPPORTED 0x00000001 -#define WIFI_CAPABILITY_RADIOTYPE 0x00000002 -#define WIFI_CAPABILITY_BANDS 0x00000004 -#define WIFI_CAPABILITY_CIPHERS 0x00000008 -#define WIFI_CAPABILITY_ANTENNA_MASK 0x00000010 -#define WIFI_CAPABILITY_MAX_SCAN_SSIDS 0x00000020 -#define WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS 0x00000040 -#define WIFI_CAPABILITY_MAX_MATCH_SETS 0x00000080 -#define WIFI_CAPABILITY_MAX_ACL_MACADDRESS 0x00000100 - -/* */ -#define WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK 0x00000001 -#define WIFI_CAPABILITY_FLAGS_ROAM_SUPPORT 0x00000002 -#define WIFI_CAPABILITY_FLAGS_SUPPORT_AP_UAPSD 0x00000004 -#define WIFI_CAPABILITY_FLAGS_DEVICE_AP_SME 0x00000008 -#define WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD 0x00000010 - -/* */ -#define WIFI_CAPABILITY_AP_SUPPORTED 0x00000001 -#define WIFI_CAPABILITY_AP_VLAN_SUPPORTED 0x00000002 -#define WIFI_CAPABILITY_ADHOC_SUPPORTED 0x00000004 -#define WIFI_CAPABILITY_MONITOR_SUPPORTED 0x00000008 -#define WIFI_CAPABILITY_WDS_SUPPORTED 0x00000010 - -#define FREQ_CAPABILITY_DISABLED 0x00000001 -#define FREQ_CAPABILITY_PASSIVE_SCAN 0x00000002 -#define FREQ_CAPABILITY_NO_IBBS 0x00000004 -#define FREQ_CAPABILITY_RADAR 0x00000008 -#define FREQ_CAPABILITY_DFS_STATE 0x00000010 -#define FREQ_CAPABILITY_DFS_TIME 0x00000020 - -#define RATE_CAPABILITY_SHORTPREAMBLE 0x00000001 - -#define CIPHER_CAPABILITY_UNKNOWN 0 -#define CIPHER_CAPABILITY_WEP40 1 -#define CIPHER_CAPABILITY_WEP104 2 -#define CIPHER_CAPABILITY_TKIP 3 -#define CIPHER_CAPABILITY_CCMP 4 -#define CIPHER_CAPABILITY_CMAC 5 -#define CIPHER_CAPABILITY_GCMP 6 -#define CIPHER_CAPABILITY_WPI_SMS4 7 - -#define IEEE80211_DFS_USABLE 0 -#define IEEE80211_DFS_UNAVAILABLE 1 -#define IEEE80211_DFS_AVAILABLE 2 - -#define WLAN_INTERFACE_AP 1 - -/* */ -DECLARE_OPAQUE_TYPE(wifi_global_handle); -DECLARE_OPAQUE_TYPE(wifi_device_handle); -DECLARE_OPAQUE_TYPE(wifi_wlan_handle); - -/* */ -struct device_setrates_params { - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - int basicratescount; - uint8_t basicrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; -}; - -/* */ -#define WIFI_COUNTRY_LENGTH 4 -struct device_setconfiguration_params { - int shortpreamble; - uint8_t maxbssid; - uint8_t dtimperiod; - uint8_t bssid[MACADDRESS_EUI48_LENGTH]; - uint16_t beaconperiod; - uint8_t country[WIFI_COUNTRY_LENGTH]; -}; - -/* */ -typedef int (*send_frame_to_ac)(void* param, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate); - -struct wlan_startap_params { - uint8_t radioid; - uint8_t wlanid; - - const char* ssid; - uint8_t ssid_hidden; - uint16_t capability; - uint8_t qos; - uint8_t authmode; - uint8_t macmode; - uint8_t tunnelmode; -}; - - -/* */ -struct wlan_send_frame_params { - uint8_t* packet; - int length; - - uint32_t frequency; - uint32_t duration; - int offchannel_tx_ok; - int no_cck_rate; - int no_wait_ack; - - uint64_t cookie; -}; - -/* */ -struct station_add_params { - uint8_t* address; -}; - -/* Interface capability */ -struct wifi_freq_capability { - unsigned long flags; - - unsigned long frequency; /* MHz */ - unsigned long channel; - - unsigned long maxtxpower; /* mBm = 100 * dBm */ - - unsigned long dfsstate; - unsigned long dfstime; /* ms */ -}; - -/* */ -struct wifi_rate_capability { - unsigned long flags; - - uint8_t bitrate; -}; - -/* */ -struct wifi_band_capability { - unsigned long band; - - unsigned long htcapability; - - struct capwap_array* freq; - struct capwap_array* rate; -}; - -/* */ -struct wifi_cipher_capability { - unsigned long cipher; -}; - -/* */ -struct wifi_capability { - struct wifi_device* device; - - unsigned long flags; - unsigned long capability; - - /* WIFI_CAPABILITY_RADIOSUPPORTED */ - unsigned long radiosupported; - - /* WIFI_CAPABILITY_RADIOTYPE */ - unsigned long radiotype; - - /* WIFI_CAPABILITY_ANTENNA_MASK */ - unsigned long txantennamask; - unsigned long rxantennamask; - - /* WIFI_CAPABILITY_BANDS */ - struct capwap_array* bands; - - /* WIFI_CAPABILITY_CIPHERS */ - struct capwap_array* ciphers; - - /* WIFI_CAPABILITY_MAX_SCAN_SSIDS */ - uint8_t maxscanssids; - - /* WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS */ - uint8_t maxschedscanssids; - - /* WIFI_CAPABILITY_MAX_MATCH_SETS */ - uint8_t maxmatchsets; - - /* WIFI_CAPABILITY_MAX_ACL_MACADDRESS */ - uint8_t maxaclmacaddress; -}; - -/* Frequency configuration */ -struct wifi_frequency { - uint32_t band; - uint32_t mode; - uint8_t channel; - uint32_t frequency; -}; - -/* */ -#define WIFI_EVENT_MAX_ITEMS 2 -struct wifi_event { - void (*event_handler)(int fd, void** params, int paramscount); - int paramscount; - void* params[WIFI_EVENT_MAX_ITEMS]; -}; - -/* */ -struct wifi_driver_instance { - struct wifi_driver_ops* ops; /* Driver functions */ - wifi_global_handle handle; /* Global instance handle */ -}; - -/* */ -struct wifi_global { - int sock_util; - struct capwap_list* devices; - - /* Timeout */ - struct capwap_timeout* timeout; - - /* Stations */ - struct capwap_hash* stations; -}; - -/* Device handle */ -#define WIFI_DEVICE_SET_FREQUENCY 0x00000001 -#define WIFI_DEVICE_SET_RATES 0x00000002 -#define WIFI_DEVICE_SET_CONFIGURATION 0x00000004 -#define WIFI_DEVICE_REQUIRED_FOR_BSS (WIFI_DEVICE_SET_FREQUENCY | WIFI_DEVICE_SET_RATES | WIFI_DEVICE_SET_CONFIGURATION) - -struct wifi_device { - struct wifi_global* global; - - wifi_device_handle handle; /* Device handle */ - struct wifi_driver_instance* instance; /* Driver instance */ - - uint32_t phyindex; - char phyname[IFNAMSIZ]; - - unsigned long flags; - - /* */ - struct capwap_list* wlans; - unsigned long wlanactive; - - /* Current frequency */ - struct wifi_frequency currentfrequency; - - /* */ - uint16_t beaconperiod; - uint8_t dtimperiod; - int shortpreamble; - - /* Cached capability */ - struct wifi_capability* capability; - - /* Rates */ - unsigned long supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - unsigned long basicratescount; - uint8_t basicrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - - /* ERP Information */ - int olbc; - unsigned long stationsnonerpcount; - unsigned long stationsnoshortslottimecount; - unsigned long stationsnoshortpreamblecount; -}; - -/* WLAN handle */ -#define WIFI_WLAN_RUNNING 0x00000001 -#define WIFI_WLAN_SET_BEACON 0x00000002 -#define WIFI_WLAN_OPERSTATE_RUNNING 0x00000004 - -struct wifi_wlan { - wifi_wlan_handle handle; - struct wifi_device* device; - - unsigned long flags; - - uint32_t virtindex; - char virtname[IFNAMSIZ]; - - uint8_t address[MACADDRESS_EUI48_LENGTH]; - - /* */ - uint8_t radioid; - uint8_t wlanid; - - /* WLAN information */ - char ssid[IEEE80211_SSID_MAX_LENGTH + 1]; - uint8_t ssid_hidden; - uint16_t capability; - - /* Tunnel */ - uint8_t macmode; - uint8_t tunnelmode; - - /* Authentication */ - uint8_t authmode; - - /* Station information */ - unsigned long stationscount; - unsigned long maxstationscount; - - uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE]; -}; - -/* Station handle */ -#define WIFI_STATION_FLAGS_AUTHENTICATED 0x00000001 -#define WIFI_STATION_FLAGS_ASSOCIATE 0x00000002 -#define WIFI_STATION_FLAGS_NON_ERP 0x00000004 -#define WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME 0x00000008 -#define WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE 0x00000010 -#define WIFI_STATION_FLAGS_WMM 0x00000020 -#define WIFI_STATION_FLAGS_AUTHORIZED 0x00000040 - -/* */ -#define WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE 30000 -#define WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED 5000 - -/* */ -#define WIFI_STATION_TIMEOUT_ACTION_DELETE 0x00000001 -#define WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE 0x00000002 - -struct wifi_station { - uint8_t address[MACADDRESS_EUI48_LENGTH]; - char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER]; - - /* */ - struct wifi_wlan* wlan; - - /* */ - unsigned long flags; - - /* Timers */ - int timeoutaction; - unsigned long idtimeout; - - /* */ - uint16_t capability; - uint16_t listeninterval; - uint16_t aid; - - /* */ - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - - /* Authentication */ - uint16_t authalgorithm; -}; - -/* */ -struct wifi_driver_ops { - const char* name; /* Name of wifi driver */ - const char* description; /* Description of wifi driver */ - - /* Global initialize driver */ - wifi_global_handle (*global_init)(void); - int (*global_getfdevent)(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events); - void (*global_deinit)(wifi_global_handle handle); - - /* Device functions */ - int (*device_init)(wifi_global_handle handle, struct wifi_device* device); - int (*device_getfdevent)(struct wifi_device* device, struct pollfd* fds, struct wifi_event* events); - int (*device_getcapability)(struct wifi_device* device, struct wifi_capability* capability); - void (*device_updatebeacons)(struct wifi_device* device); - int (*device_setfrequency)(struct wifi_device* device); - void (*device_deinit)(struct wifi_device* device); - - /* WLAN functions */ - wifi_wlan_handle (*wlan_create)(struct wifi_device* device, struct wifi_wlan* wlan); - int (*wlan_getfdevent)(struct wifi_wlan* wlan, struct pollfd* fds, struct wifi_event* events); - int (*wlan_startap)(struct wifi_wlan* wlan); - void (*wlan_stopap)(struct wifi_wlan* wlan); - int (*wlan_sendframe)(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack); - void (*wlan_delete)(struct wifi_wlan* wlan); - - /* Stations functions */ - int (*station_authorize)(struct wifi_wlan* wlan, struct wifi_station* station); - int (*station_deauthorize)(struct wifi_wlan* wlan, const uint8_t* address); -}; - -/* Initialize wifi driver engine */ -int wifi_driver_init(struct capwap_timeout* timeout); -void wifi_driver_free(void); - -/* Get File Descriptor Event */ -int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count); - -/* */ -struct wifi_wlan* wifi_get_wlan(uint32_t ifindex); - -/* Device management */ -struct wifi_device* wifi_device_connect(const char* ifname, const char* driver); -const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device); -int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params); -int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel); -int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount); - -/* WLAN management */ -struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname); -int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params); -void wifi_wlan_stopap(struct wifi_wlan* wlan); -int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid); -uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability); -int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate); -void wifi_wlan_destroy(struct wifi_wlan* wlan); - -/* WLAN packet management */ -void wifi_wlan_receive_station_frame(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate); -void wifi_wlan_receive_station_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, int ack); -void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* frame, int length); - -/* Station management */ -int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params); -void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address); - -/* Util functions */ -uint32_t wifi_iface_index(const char* ifname); -int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr); - -int wifi_frequency_to_radiotype(uint32_t freq); - -/* */ -int wifi_iface_getstatus(int sock, const char* ifname); -int wifi_iface_updown(int sock, const char* ifname, int up); -#define wifi_iface_up(sock, ifname) wifi_iface_updown(sock, ifname, 1) -#define wifi_iface_down(sock, ifname) wifi_iface_updown(sock, ifname, 0) - -#endif /* __WIFI_DRIVERS_HEADER__ */ +#ifndef __WIFI_DRIVERS_HEADER__ +#define __WIFI_DRIVERS_HEADER__ + +#include +#include +#include "ieee80211.h" + +/* */ +#define WIFI_DRIVER_NAME_SIZE 16 + +/* */ +#define WIFI_BAND_UNKNOWN 0 +#define WIFI_BAND_2GHZ 1 +#define WIFI_BAND_5GHZ 2 + +/* */ +#define WIFI_CAPABILITY_RADIOSUPPORTED 0x00000001 +#define WIFI_CAPABILITY_RADIOTYPE 0x00000002 +#define WIFI_CAPABILITY_BANDS 0x00000004 +#define WIFI_CAPABILITY_CIPHERS 0x00000008 +#define WIFI_CAPABILITY_ANTENNA_MASK 0x00000010 +#define WIFI_CAPABILITY_MAX_SCAN_SSIDS 0x00000020 +#define WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS 0x00000040 +#define WIFI_CAPABILITY_MAX_MATCH_SETS 0x00000080 +#define WIFI_CAPABILITY_MAX_ACL_MACADDRESS 0x00000100 + +/* */ +#define WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK 0x00000001 +#define WIFI_CAPABILITY_FLAGS_ROAM_SUPPORT 0x00000002 +#define WIFI_CAPABILITY_FLAGS_SUPPORT_AP_UAPSD 0x00000004 +#define WIFI_CAPABILITY_FLAGS_DEVICE_AP_SME 0x00000008 +#define WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD 0x00000010 + +/* */ +#define WIFI_CAPABILITY_AP_SUPPORTED 0x00000001 +#define WIFI_CAPABILITY_AP_VLAN_SUPPORTED 0x00000002 +#define WIFI_CAPABILITY_ADHOC_SUPPORTED 0x00000004 +#define WIFI_CAPABILITY_MONITOR_SUPPORTED 0x00000008 +#define WIFI_CAPABILITY_WDS_SUPPORTED 0x00000010 + +#define FREQ_CAPABILITY_DISABLED 0x00000001 +#define FREQ_CAPABILITY_PASSIVE_SCAN 0x00000002 +#define FREQ_CAPABILITY_NO_IBBS 0x00000004 +#define FREQ_CAPABILITY_RADAR 0x00000008 +#define FREQ_CAPABILITY_DFS_STATE 0x00000010 +#define FREQ_CAPABILITY_DFS_TIME 0x00000020 + +#define RATE_CAPABILITY_SHORTPREAMBLE 0x00000001 + +#define CIPHER_CAPABILITY_UNKNOWN 0 +#define CIPHER_CAPABILITY_WEP40 1 +#define CIPHER_CAPABILITY_WEP104 2 +#define CIPHER_CAPABILITY_TKIP 3 +#define CIPHER_CAPABILITY_CCMP 4 +#define CIPHER_CAPABILITY_CMAC 5 +#define CIPHER_CAPABILITY_GCMP 6 +#define CIPHER_CAPABILITY_WPI_SMS4 7 + +#define IEEE80211_DFS_USABLE 0 +#define IEEE80211_DFS_UNAVAILABLE 1 +#define IEEE80211_DFS_AVAILABLE 2 + +#define WLAN_INTERFACE_AP 1 + +/* */ +DECLARE_OPAQUE_TYPE(wifi_global_handle); +DECLARE_OPAQUE_TYPE(wifi_device_handle); +DECLARE_OPAQUE_TYPE(wifi_wlan_handle); + +/* */ +struct device_setrates_params { + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + int basicratescount; + uint8_t basicrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; +}; + +/* */ +#define WIFI_COUNTRY_LENGTH 4 +struct device_setconfiguration_params { + int shortpreamble; + uint8_t maxbssid; + uint8_t dtimperiod; + uint8_t bssid[MACADDRESS_EUI48_LENGTH]; + uint16_t beaconperiod; + uint8_t country[WIFI_COUNTRY_LENGTH]; +}; + +/* */ +typedef int (*send_frame_to_ac)(void* param, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate); + +struct wlan_startap_params { + uint8_t radioid; + uint8_t wlanid; + + const char* ssid; + uint8_t ssid_hidden; + uint16_t capability; + uint8_t qos; + uint8_t authmode; + uint8_t macmode; + uint8_t tunnelmode; +}; + + +/* */ +struct wlan_send_frame_params { + uint8_t* packet; + int length; + + uint32_t frequency; + uint32_t duration; + int offchannel_tx_ok; + int no_cck_rate; + int no_wait_ack; + + uint64_t cookie; +}; + +/* */ +struct station_add_params { + uint8_t* address; +}; + +/* Interface capability */ +struct wifi_freq_capability { + unsigned long flags; + + unsigned long frequency; /* MHz */ + unsigned long channel; + + unsigned long maxtxpower; /* mBm = 100 * dBm */ + + unsigned long dfsstate; + unsigned long dfstime; /* ms */ +}; + +/* */ +struct wifi_rate_capability { + unsigned long flags; + + uint8_t bitrate; +}; + +/* */ +struct wifi_band_capability { + unsigned long band; + + unsigned long htcapability; + + struct capwap_array* freq; + struct capwap_array* rate; +}; + +/* */ +struct wifi_cipher_capability { + unsigned long cipher; +}; + +/* */ +struct wifi_capability { + struct wifi_device* device; + + unsigned long flags; + unsigned long capability; + + /* WIFI_CAPABILITY_RADIOSUPPORTED */ + unsigned long radiosupported; + + /* WIFI_CAPABILITY_RADIOTYPE */ + unsigned long radiotype; + + /* WIFI_CAPABILITY_ANTENNA_MASK */ + unsigned long txantennamask; + unsigned long rxantennamask; + + /* WIFI_CAPABILITY_BANDS */ + struct capwap_array* bands; + + /* WIFI_CAPABILITY_CIPHERS */ + struct capwap_array* ciphers; + + /* WIFI_CAPABILITY_MAX_SCAN_SSIDS */ + uint8_t maxscanssids; + + /* WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS */ + uint8_t maxschedscanssids; + + /* WIFI_CAPABILITY_MAX_MATCH_SETS */ + uint8_t maxmatchsets; + + /* WIFI_CAPABILITY_MAX_ACL_MACADDRESS */ + uint8_t maxaclmacaddress; +}; + +/* Frequency configuration */ +struct wifi_frequency { + uint32_t band; + uint32_t mode; + uint8_t channel; + uint32_t frequency; +}; + +/* */ +#define WIFI_EVENT_MAX_ITEMS 2 +struct wifi_event { + void (*event_handler)(int fd, void** params, int paramscount); + int paramscount; + void* params[WIFI_EVENT_MAX_ITEMS]; +}; + +/* */ +struct wifi_driver_instance { + struct wifi_driver_ops* ops; /* Driver functions */ + wifi_global_handle handle; /* Global instance handle */ +}; + +/* */ +struct wifi_global { + int sock_util; + struct capwap_list* devices; + + /* Timeout */ + struct capwap_timeout* timeout; + + /* Stations */ + struct capwap_hash* stations; +}; + +/* Device handle */ +#define WIFI_DEVICE_SET_FREQUENCY 0x00000001 +#define WIFI_DEVICE_SET_RATES 0x00000002 +#define WIFI_DEVICE_SET_CONFIGURATION 0x00000004 +#define WIFI_DEVICE_REQUIRED_FOR_BSS (WIFI_DEVICE_SET_FREQUENCY | WIFI_DEVICE_SET_RATES | WIFI_DEVICE_SET_CONFIGURATION) + +struct wifi_device { + struct wifi_global* global; + + wifi_device_handle handle; /* Device handle */ + struct wifi_driver_instance* instance; /* Driver instance */ + + uint32_t phyindex; + char phyname[IFNAMSIZ]; + + unsigned long flags; + + /* */ + struct capwap_list* wlans; + unsigned long wlanactive; + + /* Current frequency */ + struct wifi_frequency currentfrequency; + + /* */ + uint16_t beaconperiod; + uint8_t dtimperiod; + int shortpreamble; + + /* Cached capability */ + struct wifi_capability* capability; + + /* Rates */ + unsigned long supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + unsigned long basicratescount; + uint8_t basicrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + /* ERP Information */ + int olbc; + unsigned long stationsnonerpcount; + unsigned long stationsnoshortslottimecount; + unsigned long stationsnoshortpreamblecount; +}; + +/* WLAN handle */ +#define WIFI_WLAN_RUNNING 0x00000001 +#define WIFI_WLAN_SET_BEACON 0x00000002 +#define WIFI_WLAN_OPERSTATE_RUNNING 0x00000004 + +struct wifi_wlan { + wifi_wlan_handle handle; + struct wifi_device* device; + + unsigned long flags; + + uint32_t virtindex; + char virtname[IFNAMSIZ]; + + uint8_t address[MACADDRESS_EUI48_LENGTH]; + + /* */ + uint8_t radioid; + uint8_t wlanid; + + /* WLAN information */ + char ssid[IEEE80211_SSID_MAX_LENGTH + 1]; + uint8_t ssid_hidden; + uint16_t capability; + + /* Tunnel */ + uint8_t macmode; + uint8_t tunnelmode; + + /* Authentication */ + uint8_t authmode; + + /* Station information */ + unsigned long stationscount; + unsigned long maxstationscount; + + uint32_t aidbitfield[IEEE80211_AID_BITFIELD_SIZE]; +}; + +/* Station handle */ +#define WIFI_STATION_FLAGS_AUTHENTICATED 0x00000001 +#define WIFI_STATION_FLAGS_ASSOCIATE 0x00000002 +#define WIFI_STATION_FLAGS_NON_ERP 0x00000004 +#define WIFI_STATION_FLAGS_NO_SHORT_SLOT_TIME 0x00000008 +#define WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE 0x00000010 +#define WIFI_STATION_FLAGS_WMM 0x00000020 +#define WIFI_STATION_FLAGS_AUTHORIZED 0x00000040 + +/* */ +#define WIFI_STATION_TIMEOUT_ASSOCIATION_COMPLETE 30000 +#define WIFI_STATION_TIMEOUT_AFTER_DEAUTHENTICATED 5000 + +/* */ +#define WIFI_STATION_TIMEOUT_ACTION_DELETE 0x00000001 +#define WIFI_STATION_TIMEOUT_ACTION_DEAUTHENTICATE 0x00000002 + +struct wifi_station { + uint8_t address[MACADDRESS_EUI48_LENGTH]; + char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER]; + + /* */ + struct wifi_wlan* wlan; + + /* */ + unsigned long flags; + + /* Timers */ + int timeoutaction; + unsigned long idtimeout; + + /* */ + uint16_t capability; + uint16_t listeninterval; + uint16_t aid; + + /* */ + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + /* Authentication */ + uint16_t authalgorithm; +}; + +/* */ +struct wifi_driver_ops { + const char* name; /* Name of wifi driver */ + const char* description; /* Description of wifi driver */ + + /* Global initialize driver */ + wifi_global_handle (*global_init)(void); + int (*global_getfdevent)(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events); + void (*global_deinit)(wifi_global_handle handle); + + /* Device functions */ + int (*device_init)(wifi_global_handle handle, struct wifi_device* device); + int (*device_getfdevent)(struct wifi_device* device, struct pollfd* fds, struct wifi_event* events); + int (*device_getcapability)(struct wifi_device* device, struct wifi_capability* capability); + void (*device_updatebeacons)(struct wifi_device* device); + int (*device_setfrequency)(struct wifi_device* device); + void (*device_deinit)(struct wifi_device* device); + + /* WLAN functions */ + wifi_wlan_handle (*wlan_create)(struct wifi_device* device, struct wifi_wlan* wlan); + int (*wlan_getfdevent)(struct wifi_wlan* wlan, struct pollfd* fds, struct wifi_event* events); + int (*wlan_startap)(struct wifi_wlan* wlan); + void (*wlan_stopap)(struct wifi_wlan* wlan); + int (*wlan_sendframe)(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack); + void (*wlan_delete)(struct wifi_wlan* wlan); + + /* Stations functions */ + int (*station_authorize)(struct wifi_wlan* wlan, struct wifi_station* station); + int (*station_deauthorize)(struct wifi_wlan* wlan, const uint8_t* address); +}; + +/* Initialize wifi driver engine */ +int wifi_driver_init(struct capwap_timeout* timeout); +void wifi_driver_free(void); + +/* Get File Descriptor Event */ +int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count); + +/* */ +struct wifi_wlan* wifi_get_wlan(uint32_t ifindex); + +/* Device management */ +struct wifi_device* wifi_device_connect(const char* ifname, const char* driver); +const struct wifi_capability* wifi_device_getcapability(struct wifi_device* device); +int wifi_device_setconfiguration(struct wifi_device* device, struct device_setconfiguration_params* params); +int wifi_device_setfrequency(struct wifi_device* device, uint32_t band, uint32_t mode, uint8_t channel); +int wifi_device_updaterates(struct wifi_device* device, uint8_t* rates, int ratescount); + +/* WLAN management */ +struct wifi_wlan* wifi_wlan_create(struct wifi_device* device, const char* ifname); +int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params); +void wifi_wlan_stopap(struct wifi_wlan* wlan); +int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid); +uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability); +int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate); +void wifi_wlan_destroy(struct wifi_wlan* wlan); + +/* WLAN packet management */ +void wifi_wlan_receive_station_frame(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, uint32_t frequency, uint8_t rssi, uint8_t snr, uint16_t rate); +void wifi_wlan_receive_station_ackframe(struct wifi_wlan* wlan, const struct ieee80211_header* frame, int length, int ack); +void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* frame, int length); + +/* Station management */ +int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params); +void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address); + +/* Util functions */ +uint32_t wifi_iface_index(const char* ifname); +int wifi_iface_hwaddr(int sock, const char* ifname, uint8_t* hwaddr); + +int wifi_frequency_to_radiotype(uint32_t freq); + +/* */ +int wifi_iface_getstatus(int sock, const char* ifname); +int wifi_iface_updown(int sock, const char* ifname, int up); +#define wifi_iface_up(sock, ifname) wifi_iface_updown(sock, ifname, 1) +#define wifi_iface_down(sock, ifname) wifi_iface_updown(sock, ifname, 0) + +#endif /* __WIFI_DRIVERS_HEADER__ */ diff --git a/src/wtp/binding/ieee80211/wifi_nl80211.c b/src/wtp/binding/ieee80211/wifi_nl80211.c index 062fd14..ece4c0f 100644 --- a/src/wtp/binding/ieee80211/wifi_nl80211.c +++ b/src/wtp/binding/ieee80211/wifi_nl80211.c @@ -1,1755 +1,1755 @@ -#include "wtp.h" -#include "capwap_array.h" -#include "capwap_list.h" -#include "capwap_element.h" -#include -#include -#include -#include "wtp_kmod.h" - -/* Local version of nl80211 with all feature to remove the problem of frag version of nl80211 */ -#include "nl80211_v3_10.h" - -#include "wifi_drivers.h" -#include "wifi_nl80211.h" - -/* Physical device info */ -struct nl80211_phydevice_item { - uint32_t index; - char name[IFNAMSIZ]; -}; - -/* Virtual device info */ -struct nl80211_virtdevice_item { - uint32_t phyindex; - uint32_t virtindex; - char virtname[IFNAMSIZ]; -}; - -/* */ -static const int g_stypes[] = { - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST -}; - -/* */ -struct family_data { - int id; - const char* group; -}; - -/* Compatibility functions */ -#ifdef HAVE_LIBNL_10 -static uint32_t g_portbitmap[32] = { 0 }; - -static struct nl_sock* nl_socket_alloc_cb(void* cb) { - int i; - struct nl_sock* handle; - uint32_t pid = getpid() & 0x3FFFFF; - - handle = nl_handle_alloc_cb(cb); - for (i = 0; i < 1024; i++) { - if (g_portbitmap[i / 32] & (1 << (i % 32))) { - continue; - } - - g_portbitmap[i / 32] |= 1 << (i % 32); - pid += i << 22; - break; - } - - nl_socket_set_local_port(handle, pid); - return handle; -} - -static void nl_socket_free(struct nl_sock* handle) { - uint32_t port = nl_socket_get_local_port(handle); - - port >>= 22; - g_portbitmap[port / 32] &= ~(1 << (port % 32)); - - nl_handle_destroy(handle); -} -#endif - -/* */ -static struct nl_sock* nl_create_handle(struct nl_cb* cb) { - struct nl_sock* handle; - - handle = nl_socket_alloc_cb(cb); - if (!handle) { - return NULL; - } - - if (genl_connect(handle)) { - nl_socket_free(handle); - return NULL; - } - - return handle; -} - -/* */ -static int nl80211_no_seq_check(struct nl_msg* msg, void* arg) { - return NL_OK; -} - -/* */ -static int nl80211_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) { - *((int*)arg) = err->error; - return NL_STOP; -} - -/* */ -static int nl80211_finish_handler(struct nl_msg* msg, void* arg) { - *((int*)arg) = 0; - return NL_SKIP; -} - -/* */ -static int nl80211_ack_handler(struct nl_msg* msg, void* arg) { - *((int*)arg) = 0; - return NL_STOP; -} - -/* */ -static int nl80211_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) { - int result; - struct nl_cb* cb; - - /* Clone netlink callback */ - cb = nl_cb_clone(nl_cb); - if (!cb) { - return -1; - } - - /* Complete send message */ - result = nl_send_auto_complete(nl, msg); - if (result < 0) { - nl_cb_put(cb); - return -1; - } - - /* Customize message callback */ - nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_handler, &result); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_finish_handler, &result); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_ack_handler, &result); - - if (valid_cb) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data); - } - - result = 1; - while (result > 0) { - nl_recvmsgs(nl, cb); - } - - nl_cb_put(cb); - return result; -} - -/* */ -static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) { - return nl80211_send_and_recv(globalhandle->nl, globalhandle->nl_cb, msg, valid_cb, data); -} - -/* */ -static int cb_family_handler(struct nl_msg* msg, void* data) { - int i; - struct nlattr* mcast_group; - struct nlattr* tb_msg[CTRL_ATTR_MAX + 1]; - struct nlattr* tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct family_data* resource = (struct family_data*)data; - - nla_parse(tb_msg, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[CTRL_ATTR_MCAST_GROUPS]) { - nla_for_each_nested(mcast_group, tb_msg[CTRL_ATTR_MCAST_GROUPS], i) { - nla_parse(tb_msg_mcast_group, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcast_group), nla_len(mcast_group), NULL); - - if (tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_NAME] && tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_ID]) { - if (!strncmp(nla_data(tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]), resource->group, nla_len(tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]))) { - resource->id = nla_get_u32(tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_ID]); - break; - } - } - } - } - - return NL_SKIP; -} - -/* */ -static int nl80211_get_multicast_id(struct nl80211_global_handle* globalhandle, const char* family, const char* group) { - int result; - struct nl_msg* msg; - struct family_data resource = { -1, group }; - - ASSERT(globalhandle != NULL); - ASSERT(family != NULL); - ASSERT(group != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, genl_ctrl_resolve(globalhandle->nl, "nlctrl"), 0, 0, CTRL_CMD_GETFAMILY, 0); - nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family); - - /* */ - result = nl80211_send_and_recv_msg(globalhandle, msg, cb_family_handler, &resource); - if (!result) { - result = resource.id; - } else { - capwap_logging_error("Unable get multicast id, error code: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static int nl80211_wlan_set_type(struct wifi_wlan* wlan, uint32_t type) { - int result; - struct nl_msg* msg; - struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_INTERFACE, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - nla_put_u32(msg, NL80211_ATTR_IFTYPE, type); - - /* */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable set type, error code: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static int cb_get_type(struct nl_msg* msg, void* data) { - struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - uint32_t* type = (uint32_t*)data; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_IFTYPE]) { - *type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]); - } - - return NL_SKIP; -} - -/* */ -static uint32_t nl80211_wlan_get_type(struct wifi_wlan* wlan) { - int result; - struct nl_msg* msg; - uint32_t type = NL80211_IFTYPE_UNSPECIFIED; - struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return NL80211_IFTYPE_UNSPECIFIED; - } - - /* */ - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_INTERFACE, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - - /* */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, cb_get_type, &type); - if (result) { - capwap_logging_error("Unable get type, error code: %d", result); - type = NL80211_IFTYPE_UNSPECIFIED; - } - - /* */ - nlmsg_free(msg); - return type; -} - -/* */ -static int nl80211_wlan_set_profile(struct wifi_wlan* wlan, uint32_t type) { - int result; - - /* Change interface type */ - result = nl80211_wlan_set_type(wlan, type); - if (result && (type == nl80211_wlan_get_type(wlan))) { - result = 0; /* No error */ - } - - /* */ - if (result) { - if (result == -ENODEV) { - return -1; - } - - /* TODO */ - } - - return result; -} - -/* */ -static int nl80211_device_changefrequency(struct wifi_device* device, struct wifi_frequency* freq) { - int result; - struct nl_msg* msg; - struct capwap_list_item* wlansearch; - struct nl80211_device_handle* devicehandle; - struct wifi_wlan* wlan = NULL; - - ASSERT(device != NULL); - ASSERT(freq != NULL); - - /* Search a valid interface */ - for (wlansearch = device->wlans->first; wlansearch; wlansearch = wlansearch->next) { - struct wifi_wlan* element = (struct wifi_wlan*)wlansearch->item; - - if (element->flags & WIFI_WLAN_RUNNING) { - wlan = element; - break; - } - } - - /* */ - if (!wlan) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* Set frequecy using device index of first BSS */ - devicehandle = (struct nl80211_device_handle*)device->handle; - genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_WIPHY, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->frequency); - - /* Set wifi frequency */ - result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); - if (!result) { - capwap_logging_info("Change %s frequency %d", wlan->virtname, (int)freq->frequency); - } else { - capwap_logging_error("Unable set frequency %d, error code: %d", (int)freq->frequency, result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static int nl80211_wlan_event(struct wifi_wlan* wlan, struct genlmsghdr* gnlh, struct nlattr** tb_msg) { - switch (gnlh->cmd) { - case NL80211_CMD_FRAME: { - if (tb_msg[NL80211_ATTR_FRAME]) { - uint32_t frequency = (tb_msg[NL80211_ATTR_WIPHY_FREQ] ? nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]) : 0); - uint8_t rssi = (tb_msg[NL80211_ATTR_RX_SIGNAL_DBM] ? (uint8_t)nla_get_u32(tb_msg[NL80211_ATTR_RX_SIGNAL_DBM]) : 0); - - /* */ - wifi_wlan_receive_station_frame(wlan, (struct ieee80211_header*)nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), frequency, rssi, 0, 0); - } - - break; - } - - case NL80211_CMD_FRAME_TX_STATUS: { - if (tb_msg[NL80211_ATTR_FRAME] && tb_msg[NL80211_ATTR_COOKIE]) { - struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - uint64_t cookie = nla_get_u64(tb_msg[NL80211_ATTR_COOKIE]); - - if (wlanhandle->last_cookie == cookie) { - wlanhandle->last_cookie = 0; - wifi_wlan_receive_station_ackframe(wlan, (struct ieee80211_header*)nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), (tb_msg[NL80211_ATTR_ACK] ? 1 : 0)); - } - } - - break; - } - - case NL80211_CMD_TRIGGER_SCAN: { - break; - } - - case NL80211_CMD_NEW_SCAN_RESULTS: { - break; - } - - case NL80211_CMD_NEW_STATION: { - break; - } - - case NL80211_CMD_DEL_STATION: { - break; - } - - default: { - capwap_logging_debug("*** nl80211_wlan_event: %d", (int)gnlh->cmd); - break; - } - } - - return NL_SKIP; -} - -/* */ -static int nl80211_wlan_valid_handler(struct nl_msg* msg, void* arg) { - struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - return nl80211_wlan_event((struct wifi_wlan*)arg, gnlh, tb_msg); -} - -/* */ -static int nl80211_wlan_registerframe(struct wifi_wlan* wlan, uint16_t type, const uint8_t* match, int lengthmatch) { - int result; - struct nl_msg* msg; - struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_REGISTER_FRAME, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type); - nla_put(msg, NL80211_ATTR_FRAME_MATCH, lengthmatch, match); - - /* Destroy virtual device */ - result = nl80211_send_and_recv(wlanhandle->nl, wlanhandle->nl_cb, msg, NULL, NULL); - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static int nl80211_global_destroy_virtdevice(struct nl80211_global_handle* globalhandle, uint32_t virtindex) { - int result; - struct nl_msg* msg; - - ASSERT(globalhandle != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, 0, NL80211_CMD_DEL_INTERFACE, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, virtindex); - - /* Destroy virtual device */ - result = nl80211_send_and_recv_msg(globalhandle, msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable destroy interface, error code: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static int cb_global_destroy_all_virtdevice(struct nl_msg* msg, void* data) { - struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct capwap_list* list = (struct capwap_list*)data; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_WIPHY] && tb_msg[NL80211_ATTR_IFNAME] && tb_msg[NL80211_ATTR_IFINDEX]) { - struct capwap_list_item* item = capwap_itemlist_create(sizeof(struct nl80211_virtdevice_item)); - struct nl80211_virtdevice_item* virtitem = (struct nl80211_virtdevice_item*)item->item; - - /* Add virtual device info */ - virtitem->phyindex = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); - virtitem->virtindex = nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]); - strcpy(virtitem->virtname, nla_get_string(tb_msg[NL80211_ATTR_IFNAME])); - capwap_itemlist_insert_after(list, NULL, item); - } - - return NL_SKIP; -} - -/* */ -static void nl80211_global_destroy_all_virtdevice(struct nl80211_global_handle* globalhandle, uint32_t phyindex) { - int result; - struct nl_msg* msg; - struct capwap_list* list; - struct capwap_list_item* itemsearch; - - ASSERT(globalhandle != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return; - } - - genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0); - nla_put_u32(msg, NL80211_ATTR_WIPHY, phyindex); - - /* Retrieve all virtual interface */ - list = capwap_list_create(); - result = nl80211_send_and_recv_msg(globalhandle, msg, cb_global_destroy_all_virtdevice, list); - if (!result) { - for (itemsearch = list->first; itemsearch; itemsearch = itemsearch->next) { - struct nl80211_virtdevice_item* virtitem = (struct nl80211_virtdevice_item*)itemsearch->item; - - /* Destroy virtual device */ - if (virtitem->phyindex == phyindex) { - wifi_iface_down(globalhandle->sock_util, virtitem->virtname); - result = nl80211_global_destroy_virtdevice(globalhandle, virtitem->virtindex); - if (result) { - capwap_logging_error("Unable to destroy virtual device, error code: %d", result); - } - } - } - } else { - /* Error get virtual devices */ - capwap_logging_error("Unable retrieve virtual device info, error code: %d", result); - } - - /* */ - nlmsg_free(msg); - capwap_list_free(list); -} - -/* */ -static wifi_wlan_handle nl80211_wlan_create(struct wifi_device* device, struct wifi_wlan* wlan) { - int result; - struct nl_msg* msg; - struct nl80211_wlan_handle* wlanhandle; - struct nl80211_device_handle* devicehandle; - - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - ASSERT(wlan != NULL); - - /* */ - devicehandle = (struct nl80211_device_handle*)device->handle; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return NULL; - } - - /* Create wlan interface */ - genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_NEW_INTERFACE, 0); - nla_put_u32(msg, NL80211_ATTR_WIPHY, device->phyindex); - nla_put_u32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION); - nla_put_string(msg, NL80211_ATTR_IFNAME, wlan->virtname); - - /* */ - result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); - nlmsg_free(msg); - - /* Check interface */ - if (result || !wifi_iface_index(wlan->virtname)) { - capwap_logging_error("Unable create interface %s, error code: %d", wlan->virtname, result); - return NULL; - } - - /* Init wlan */ - wlanhandle = (struct nl80211_wlan_handle*)capwap_alloc(sizeof(struct nl80211_wlan_handle)); - memset(wlanhandle, 0, sizeof(struct nl80211_wlan_handle)); - - wlanhandle->devicehandle = devicehandle; - wlanhandle->nl_fd = -1; - - return (wifi_wlan_handle)wlanhandle; -} - -/* */ -static void nl80211_event_receive(int fd, void** params, int paramscount) { - int res; - - ASSERT(fd >= 0); - ASSERT(params != NULL); - ASSERT(paramscount == 2); - - /* */ - res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); - if (res) { - capwap_logging_warning("Receive nl80211 message failed: %d", res); - } -} - -/* */ -static int nl80211_wlan_getfdevent(struct wifi_wlan* wlan, struct pollfd* fds, struct wifi_event* events) { - struct nl80211_wlan_handle* wlanhandle; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - /* */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - if (!(wlan->flags & WIFI_WLAN_RUNNING) || (wlanhandle->nl_fd < 0)) { - return 0; - } - - if (fds) { - fds[0].fd = wlanhandle->nl_fd; - fds[0].events = POLLIN | POLLERR | POLLHUP; - } - - if (events) { - events[0].event_handler = nl80211_event_receive; - events[0].params[0] = (void*)wlanhandle->nl; - events[0].params[1] = (void*)wlanhandle->nl_cb; - events[0].paramscount = 2; - } - - return 1; -} - -/* */ -static int nl80211_wlan_setbeacon(struct wifi_wlan* wlan) { - int result; - struct nl_msg* msg; - struct nl80211_wlan_handle* wlanhandle; - struct ieee80211_beacon_params ieee80211_params; - uint8_t buffer[IEEE80211_MTU]; - - /* */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - - /* Create beacon packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_beacon_params)); - memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); - ieee80211_params.beaconperiod = wlan->device->beaconperiod; - ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); - ieee80211_params.ssid = wlan->ssid; - ieee80211_params.ssid_hidden = wlan->ssid_hidden; - memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); - ieee80211_params.supportedratescount = wlan->device->supportedratescount; - ieee80211_params.mode = wlan->device->currentfrequency.mode; - ieee80211_params.erpinfo = ieee80211_get_erpinfo(wlan->device->currentfrequency.mode, wlan->device->olbc, wlan->device->stationsnonerpcount, wlan->device->stationsnoshortpreamblecount, wlan->device->shortpreamble); - ieee80211_params.channel = wlan->device->currentfrequency.channel; - - /* Enable probe response offload only in CAPWAP Local Mac */ - if ((wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) && (wlan->device->capability->capability & WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD)) { - ieee80211_params.flags |= IEEE80221_CREATE_BEACON_FLAGS_PROBE_RESPONSE_OFFLOAD; - } - - /* */ - result = ieee80211_create_beacon(buffer, sizeof(buffer), &ieee80211_params); - if (result < 0) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, ((wlan->flags & WIFI_WLAN_SET_BEACON) ? NL80211_CMD_SET_BEACON : NL80211_CMD_START_AP), 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - nla_put(msg, NL80211_ATTR_BEACON_HEAD, ieee80211_params.headbeaconlength, ieee80211_params.headbeacon); - nla_put(msg, NL80211_ATTR_BEACON_TAIL, ieee80211_params.tailbeaconlength, ieee80211_params.tailbeacon); - nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL, wlan->device->beaconperiod); - nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, wlan->device->dtimperiod); - nla_put(msg, NL80211_ATTR_SSID, strlen(wlan->ssid), wlan->ssid); - nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID, (wlan->ssid_hidden ? NL80211_HIDDEN_SSID_ZERO_LEN : NL80211_HIDDEN_SSID_NOT_IN_USE)); - nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, ((wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM)); - nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); - - if ((wlan->device->capability->capability & WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD) && (ieee80211_params.proberesponseoffloadlength > 0)) { - nla_put(msg, NL80211_ATTR_PROBE_RESP, ieee80211_params.proberesponseoffloadlength, ieee80211_params.proberesponseoffload); - } - - /* Start AP */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - if (result) { - capwap_logging_error("Unable set beacon, error code: %d", result); - } - - nlmsg_free(msg); - - /* Configure AP */ - if (!result) { - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_BSS, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - - /* */ - nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, ((ieee80211_params.erpinfo & IEEE80211_ERP_INFO_USE_PROTECTION) ? 1 : 0)); - nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, ((!wlan->device->stationsnoshortpreamblecount && wlan->device->shortpreamble) ? 1 : 0)); - //nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ???); - //nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ???); - - if (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) { - nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, (!wlan->device->stationsnoshortslottimecount ? 1 : 0)); - } - - if (wlan->device->basicratescount > 0) { - nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, wlan->device->basicratescount, wlan->device->basicrates); - } - - /* */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - if (!result) { - wlan->flags |= WIFI_WLAN_SET_BEACON; - } else { - capwap_logging_error("Unable set BSS, error code: %d", result); - } - - nlmsg_free(msg); - } - - return result; -} - -/* */ -static int nl80211_wlan_startap(struct wifi_wlan* wlan) { - int i; - int result; - struct nl80211_wlan_handle* wlanhandle; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - /* Configure interface with AP profile */ - if (nl80211_wlan_set_profile(wlan, NL80211_IFTYPE_AP)) { - return -1; - } - - /* Socket management */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - wlanhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!wlanhandle->nl_cb) { - return -1; - } - - /* */ - nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); - nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wlan_valid_handler, (void*)wlan); - - wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb); - if (wlanhandle->nl) { - wlanhandle->nl_fd = nl_socket_get_fd(wlanhandle->nl); - } else { - return -1; - } - - /* Register frames */ - for (i = 0; i < sizeof(g_stypes) / sizeof(g_stypes[0]); i++) { - result = nl80211_wlan_registerframe(wlan, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (g_stypes[i] << 4), NULL, 0); - if (result) { - capwap_logging_error("Unable to register frame %d, error code: %d", g_stypes[i], result); - return -1; - } - } - - /* Enable interface */ - wlan->flags |= WIFI_WLAN_RUNNING; - if (wifi_iface_up(wlanhandle->devicehandle->globalhandle->sock_util, wlan->virtname)) { - return -1; - } - - /* Configure device if first BSS device */ - if (!wlan->device->wlanactive) { - /* Set device frequency */ - nl80211_device_changefrequency(wlan->device, &wlan->device->currentfrequency); - /* TODO Get current frequency */ - } - - /* Set beacon */ - if (nl80211_wlan_setbeacon(wlan)) { - return -1; - } - - /* */ - if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { - /* Join interface in kernel module */ - uint32_t flags = ((wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211) ? WTP_KMOD_FLAGS_TUNNEL_NATIVE : WTP_KMOD_FLAGS_TUNNEL_8023); - - if (!wtp_kmod_join_mac80211_device(wlan, flags)) { - capwap_logging_info("Joined the interface %d in kernel mode ", wlan->virtindex); - } else { - capwap_logging_error("Unable to join the interface %d in kernel mode ", wlan->virtindex); - return -1; - } - } - - /* Enable operation status */ - wlan->flags |= WIFI_WLAN_OPERSTATE_RUNNING; - netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP); - - return 0; -} - -/* */ -static void nl80211_wlan_stopap(struct wifi_wlan* wlan) { - struct nl_msg* msg; - struct nl80211_wlan_handle* wlanhandle; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - - /* */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - - /* */ - if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { - /* Leave interface from kernel module */ - wtp_kmod_leave_mac80211_device(wlan); - } - - /* */ - if (wlan->flags & WIFI_WLAN_SET_BEACON) { - msg = nlmsg_alloc(); - if (msg) { - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_STOP_AP, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - - /* Stop AP */ - nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - nlmsg_free(msg); - } - } - - /* Disable interface */ - wifi_iface_down(wlanhandle->devicehandle->globalhandle->sock_util, wlan->virtname); - - /* Configure interface with station profile */ - nl80211_wlan_set_profile(wlan, NL80211_IFTYPE_STATION); - - /* */ - if (wlanhandle->nl) { - nl_socket_free(wlanhandle->nl); - wlanhandle->nl = NULL; - wlanhandle->nl_fd = -1; - } - - if (wlanhandle->nl_cb) { - nl_cb_put(wlanhandle->nl_cb); - wlanhandle->nl_cb = NULL; - } -} - -/* */ -static int cb_wlan_send_frame(struct nl_msg* msg, void* arg) { - struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - - /* */ - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - if (tb_msg[NL80211_ATTR_COOKIE]) { - *(uint64_t*)arg = nla_get_u64(tb_msg[NL80211_ATTR_COOKIE]); - } - - return NL_SKIP; -} - -/* */ -static int nl80211_wlan_sendframe(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack) { - int result; - uint64_t cookie; - struct nl_msg* msg; - struct nl80211_wlan_handle* wlanhandle; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - ASSERT(frame != NULL); - ASSERT(length > 0); - - /* */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_FRAME, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - - if (frequency) { - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, frequency); - } - - if (duration) { - nla_put_u32(msg, NL80211_ATTR_DURATION, duration); - } - - if (offchannel_tx_ok && (wlan->device->capability->capability & WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK)) { - nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); - } - - if (no_cck_rate) { - nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE); - } - - if (no_wait_ack) { - nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK); - } - - nla_put(msg, NL80211_ATTR_FRAME, length, frame); - - /* Send frame */ - cookie = 0; - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, cb_wlan_send_frame, &cookie); - if (result) { - capwap_logging_error("Unable send frame, error code: %d", result); - } - - nlmsg_free(msg); - - wlanhandle->last_cookie = (result || no_wait_ack ? 0 : cookie); - return result; -} - -/* */ -static void nl80211_wlan_delete(struct wifi_wlan* wlan) { - struct nl80211_wlan_handle* wlanhandle; - - ASSERT(wlan != NULL); - - /* */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - if (wlanhandle) { - if (wlan->virtindex) { - nl80211_global_destroy_virtdevice(wlanhandle->devicehandle->globalhandle, wlan->virtindex); - } - - capwap_free(wlanhandle); - } -} - -/* */ -static uint32_t nl80211_station_get_flags(struct wifi_station* station) { - uint32_t result = 0; - - ASSERT(station != NULL); - - if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { - result |= 1 << NL80211_STA_FLAG_AUTHORIZED; - } - - if (!(station->flags & WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE)) { - result |= 1 << NL80211_STA_FLAG_SHORT_PREAMBLE; - } - - if (station->flags & WIFI_STATION_FLAGS_WMM) { - result |= 1 << NL80211_STA_FLAG_WME; - } - - return result; -} - -/* */ -int nl80211_station_authorize(struct wifi_wlan* wlan, struct wifi_station* station) { - int result; - struct nl_msg* msg; - struct nl80211_sta_flag_update flagstation; - struct nl80211_wlan_handle* wlanhandle; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - ASSERT(station != NULL); - ASSERT(wlan == station->wlan); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_NEW_STATION, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, station->address); - nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES, station->supportedratescount, station->supportedrates); - nla_put_u16(msg, NL80211_ATTR_STA_AID, station->aid); - nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, station->listeninterval); - nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY, station->capability); - - /* */ - memset(&flagstation, 0, sizeof(struct nl80211_sta_flag_update)); - flagstation.mask = nl80211_station_get_flags(station); - flagstation.set = flagstation.mask; - nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(struct nl80211_sta_flag_update), &flagstation); - - /* */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - if (result) { - if (result == -EEXIST) { - result = 0; - } else { - capwap_logging_error("Unable to authorized station, error code: %d", result); - } - } - - /* */ - if (!result) { - capwap_logging_info("Authorized station: %s", station->addrtext); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int nl80211_station_deauthorize(struct wifi_wlan* wlan, const uint8_t* address) { - int result; - struct nl_msg* msg; - struct nl80211_wlan_handle* wlanhandle; - - ASSERT(wlan != NULL); - ASSERT(wlan->handle != NULL); - ASSERT(address != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_DEL_STATION, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); - nla_put(msg, NL80211_ATTR_MAC, MACADDRESS_EUI48_LENGTH, address); - - /* */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - if (result) { - if (result == -ENOENT) { - result = 0; - } else { - capwap_logging_error("Unable delete station, error code: %d", result); - } - } - - /* */ - if (!result) { - char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER]; - capwap_logging_info("Deauthorize station: %s", capwap_printf_macaddress(addrtext, address, MACADDRESS_EUI48_LENGTH)); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static int cb_device_init(struct nl_msg* msg, void* data) { - struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct capwap_list* list = (struct capwap_list*)data; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_WIPHY_NAME] && tb_msg[NL80211_ATTR_WIPHY]) { - struct capwap_list_item* item = capwap_itemlist_create(sizeof(struct nl80211_phydevice_item)); - struct nl80211_phydevice_item* phyitem = (struct nl80211_phydevice_item*)item->item; - - /* Add physical device info */ - phyitem->index = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); - strcpy(phyitem->name, nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME])); - capwap_itemlist_insert_after(list, NULL, item); - } - - return NL_SKIP; -} - -/* */ -int nl80211_device_init(wifi_global_handle handle, struct wifi_device* device) { - int result; - struct nl_msg* msg; - struct capwap_list* list; - struct capwap_list_item* item; - struct nl80211_device_handle* devicehandle = NULL; - struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; - - ASSERT(handle != NULL); - ASSERT(device != NULL); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0); - - /* Retrieve all physical interface */ - list = capwap_list_create(); - result = nl80211_send_and_recv_msg(globalhandle, msg, cb_device_init, list); - if (!result) { - for (item = list->first; item; item = item->next) { - struct nl80211_phydevice_item* phyitem = (struct nl80211_phydevice_item*)item->item; - - if (!strcmp(phyitem->name, device->phyname)) { - /* Create device */ - devicehandle = (struct nl80211_device_handle*)capwap_alloc(sizeof(struct nl80211_device_handle)); - memset(devicehandle, 0, sizeof(struct nl80211_device_handle)); - - /* */ - devicehandle->globalhandle = globalhandle; - - /* */ - device->handle = (wifi_device_handle)devicehandle; - device->phyindex = phyitem->index; - break; - } - } - } else { - /* Error get physical devices */ - capwap_logging_error("Unable retrieve physical device info, error code: %d", result); - } - - /* */ - nlmsg_free(msg); - capwap_list_free(list); - if (!devicehandle) { - return -1; - } - - /* Remove all virtual adapter from wifi device */ - nl80211_global_destroy_all_virtdevice(globalhandle, device->phyindex); - return 0; -} - -/* */ -static int nl80211_device_getfdevent(struct wifi_device* device, struct pollfd* fds, struct wifi_event* events) { - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - - return 0; -} - -/* */ -static unsigned long nl80211_get_cipher(uint32_t chiper) { - switch (chiper) { - case 0x000fac01: { - return CIPHER_CAPABILITY_WEP40; - } - - case 0x000fac05: { - return CIPHER_CAPABILITY_WEP104; - } - - case 0x000fac02: { - return CIPHER_CAPABILITY_TKIP; - } - - case 0x000fac04: { - return CIPHER_CAPABILITY_CCMP; - } - - case 0x000fac06: { - return CIPHER_CAPABILITY_CMAC; - } - - case 0x000fac08: { - return CIPHER_CAPABILITY_GCMP; - } - - case 0x00147201: { - return CIPHER_CAPABILITY_WPI_SMS4; - } - } - - return CIPHER_CAPABILITY_UNKNOWN; -} - -/* */ -static int cb_get_phydevice_capability(struct nl_msg* msg, void* data) { - int i, j; - struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct wifi_capability* capability = (struct wifi_capability*)data; - int radio80211bg = 0; - int radio80211a = 0; - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_WIPHY] && (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]) == capability->device->phyindex)) { - /* Interface supported */ - if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) { - struct nlattr* nl_mode; - - capability->flags |= WIFI_CAPABILITY_RADIOSUPPORTED; - nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], i) { - switch (nla_type(nl_mode)) { - case NL80211_IFTYPE_AP: { - capability->radiosupported |= WIFI_CAPABILITY_AP_SUPPORTED; - break; - } - - case NL80211_IFTYPE_AP_VLAN: { - capability->radiosupported |= WIFI_CAPABILITY_AP_VLAN_SUPPORTED; - break; - } - - case NL80211_IFTYPE_ADHOC: { - capability->radiosupported |= WIFI_CAPABILITY_ADHOC_SUPPORTED; - break; - } - - case NL80211_IFTYPE_WDS: { - capability->radiosupported |= WIFI_CAPABILITY_WDS_SUPPORTED; - break; - } - - case NL80211_IFTYPE_MONITOR: { - capability->radiosupported |= WIFI_CAPABILITY_MONITOR_SUPPORTED; - break; - } - } - } - } - - /* */ - if (tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) { - capability->flags |= WIFI_CAPABILITY_MAX_SCAN_SSIDS; - capability->maxscanssids = nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); - } - - if (tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) { - capability->flags |= WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS; - capability->maxschedscanssids = nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); - } - - if (tb_msg[NL80211_ATTR_MAX_MATCH_SETS]) { - capability->flags |= WIFI_CAPABILITY_MAX_MATCH_SETS; - capability->maxmatchsets = nla_get_u8(tb_msg[NL80211_ATTR_MAX_MATCH_SETS]); - } - - if (tb_msg[NL80211_ATTR_MAC_ACL_MAX]) { - capability->flags |= WIFI_CAPABILITY_MAX_ACL_MACADDRESS; - capability->maxaclmacaddress = nla_get_u8(tb_msg[NL80211_ATTR_MAC_ACL_MAX]); - } - - if (tb_msg[NL80211_ATTR_OFFCHANNEL_TX_OK]) { - capability->capability |= WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK; - } - - if (tb_msg[NL80211_ATTR_ROAM_SUPPORT]) { - capability->capability |= WIFI_CAPABILITY_FLAGS_ROAM_SUPPORT; - } - - if (tb_msg[NL80211_ATTR_SUPPORT_AP_UAPSD]) { - capability->capability |= WIFI_CAPABILITY_FLAGS_SUPPORT_AP_UAPSD; - } - - if (tb_msg[NL80211_ATTR_DEVICE_AP_SME]) { - capability->capability |= WIFI_CAPABILITY_FLAGS_DEVICE_AP_SME; - } - - if (tb_msg[NL80211_ATTR_PROBE_RESP_OFFLOAD]) { - capability->capability |= WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD; - /* TODO check offload protocol support */ - } - - /* Cipher supported */ - if (tb_msg[NL80211_ATTR_CIPHER_SUITES]) { - int count; - uint32_t* ciphers; - struct wifi_cipher_capability* ciphercap; - - /* */ - count = nla_len(tb_msg[NL80211_ATTR_CIPHER_SUITES]) / sizeof(uint32_t); - if (count > 0) { - capability->flags |= WIFI_CAPABILITY_CIPHERS; - ciphers = (uint32_t*)nla_data(tb_msg[NL80211_ATTR_CIPHER_SUITES]); - for (j = 0; j < count; j++) { - ciphercap = (struct wifi_cipher_capability*)capwap_array_get_item_pointer(capability->ciphers, capability->ciphers->count); - ciphercap->cipher = nl80211_get_cipher(ciphers[j]); - } - } - } - - /* TX/RX Antenna count */ - if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX] && tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX]) { - capability->flags |= WIFI_CAPABILITY_ANTENNA_MASK; - capability->txantennamask = (unsigned long)nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX]); - capability->rxantennamask = (unsigned long)nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX]); - } - - /* Band and datarate supported */ - if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) { - struct nlattr* nl_band; - struct nlattr* tb_band[NL80211_BAND_ATTR_MAX + 1]; - - capability->flags |= WIFI_CAPABILITY_BANDS; - nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], i) { - struct wifi_band_capability* bandcap; - - nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL); - - /* Init band */ - bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, capability->bands->count); - bandcap->freq = capwap_array_create(sizeof(struct wifi_freq_capability), 0, 1); - bandcap->rate = capwap_array_create(sizeof(struct wifi_rate_capability), 0, 1); - - /* Check High Throughput capability */ - if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { - bandcap->htcapability = (unsigned long)nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]); - capability->flags |= WIFI_CAPABILITY_RADIOTYPE; - capability->radiotype |= CAPWAP_RADIO_TYPE_80211N; - } - - /* Frequency */ - if (tb_band[NL80211_BAND_ATTR_FREQS]) { - struct nlattr* nl_freq; - struct nlattr* tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; - struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, - [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, - }; - - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], j) { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), freq_policy); - - if (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) { - unsigned long frequency = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - unsigned long band = (IS_IEEE80211_FREQ_BG(frequency) ? WIFI_BAND_2GHZ : (IS_IEEE80211_FREQ_A(frequency) ? WIFI_BAND_5GHZ : WIFI_BAND_UNKNOWN)); - - if (band != WIFI_BAND_UNKNOWN) { - struct wifi_freq_capability* freq = (struct wifi_freq_capability*)capwap_array_get_item_pointer(bandcap->freq, bandcap->freq->count); - - /* Set band */ - if (bandcap->band == WIFI_BAND_UNKNOWN) { - bandcap->band = band; - } else if (bandcap->band != band) { - capwap_logging_warning("Multiple wireless band into logical band"); - } - - /* Retrieve frequency and channel */ - freq->frequency = frequency; - freq->channel = ieee80211_frequency_to_channel(frequency); - - if (!radio80211bg && IS_IEEE80211_FREQ_BG(frequency)) { - radio80211bg = 1; - capability->flags |= WIFI_CAPABILITY_RADIOTYPE; - capability->radiotype |= (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G); - } else if (!radio80211a && IS_IEEE80211_FREQ_A(frequency)) { - radio80211a = 1; - capability->flags |= WIFI_CAPABILITY_RADIOTYPE; - capability->radiotype |= CAPWAP_RADIO_TYPE_80211A; - } - - /* Get max tx power */ - if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) { - freq->maxtxpower = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]); - } - - /* Get flags */ - if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) { - freq->flags |= FREQ_CAPABILITY_DISABLED; - } else { - if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) { - freq->flags |= FREQ_CAPABILITY_PASSIVE_SCAN; - } - - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) { - freq->flags |= FREQ_CAPABILITY_NO_IBBS; - } - - if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) { - freq->flags |= FREQ_CAPABILITY_RADAR; - } - - if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) { - freq->flags |= FREQ_CAPABILITY_DFS_STATE; - freq->dfsstate = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]); - - if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) { - freq->flags |= FREQ_CAPABILITY_DFS_TIME; - freq->dfstime = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]); - } - } - } - } - } - } - } - - /* Rate */ - if (tb_band[NL80211_BAND_ATTR_RATES]) { - struct nlattr* nl_rate; - struct nlattr* tb_rate[NL80211_FREQUENCY_ATTR_MAX + 1]; - struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { - [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, - [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, - }; - - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], j) { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), nla_len(nl_rate), rate_policy); - - if (tb_rate[NL80211_BITRATE_ATTR_RATE]) { - struct wifi_rate_capability* rate = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, bandcap->rate->count); - - /* Set bitrate into multiple of 500Kbps */ - rate->bitrate = (uint8_t)(nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]) / 5); - - if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) { - rate->flags |= RATE_CAPABILITY_SHORTPREAMBLE; - } - } - } - } - } - } - } - - return NL_SKIP; -} - -/* */ -static int nl80211_device_getcapability(struct wifi_device* device, struct wifi_capability* capability) { - int result; - struct nl_msg* msg; - struct nl80211_device_handle* devicehandle; - - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - ASSERT(capability != NULL); - - /* */ - devicehandle = (struct nl80211_device_handle*)device->handle; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_WIPHY, 0); - nla_put_u32(msg, NL80211_ATTR_WIPHY, device->phyindex); - - /* Retrieve physical device capability */ - capability->device = device; - result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, cb_get_phydevice_capability, capability); - if (result) { - capwap_logging_error("Unable retrieve physical device capability, error code: %d", result); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static void nl80211_device_updatebeacons(struct wifi_device* device) { - struct wifi_wlan* wlan; - struct capwap_list_item* wlansearch; - - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - - /* Update all wlan beacon */ - for (wlansearch = device->wlans->first; wlansearch; wlansearch = wlansearch->next) { - wlan = (struct wifi_wlan*)wlansearch->item; - if (wlan->flags & WIFI_WLAN_SET_BEACON) { - if (nl80211_wlan_setbeacon(wlan)) { - capwap_logging_warning("Unable to update beacon on interface %d", wlan->virtindex); - wifi_wlan_stopap(wlan); - } - } - } -} - -/* */ -static int nl80211_device_setfrequency(struct wifi_device* device) { - ASSERT(device != NULL); - ASSERT(device->handle != NULL); - - /* Delay request if not found BSS interface */ - if (!device->wlanactive) { - return 0; - } - - return nl80211_device_changefrequency(device, &device->currentfrequency); -} - -/* */ -static void nl80211_device_deinit(struct wifi_device* device) { - struct nl80211_device_handle* devicehandle; - - ASSERT(device != NULL); - - devicehandle = (struct nl80211_device_handle*)device->handle; - if (devicehandle) { - capwap_free(devicehandle); - device->handle = NULL; - } -} - -/* */ -static void nl80211_global_deinit(wifi_global_handle handle) { - struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; - - if (globalhandle) { - if (globalhandle->netlinkhandle) { - netlink_free(globalhandle->netlinkhandle); - } - - if (globalhandle->nl) { - nl_socket_free(globalhandle->nl); - } - - if (globalhandle->nl_event) { - nl_socket_free(globalhandle->nl_event); - } - - if (globalhandle->nl_cb) { - nl_cb_put(globalhandle->nl_cb); - } - - if (globalhandle->sock_util >= 0) { - close(globalhandle->sock_util); - } - - capwap_free(globalhandle); - } -} - -/* */ -static void nl80211_global_newlink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { - struct wifi_wlan* wlan; - struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; - - ASSERT(handle != NULL); - ASSERT(infomsg != NULL); - - /* Search device */ - wlan = wifi_get_wlan(infomsg->ifi_index); - if (wlan) { - if (!(wlan->flags & WIFI_WLAN_RUNNING)) { - if ((infomsg->ifi_flags & IFF_UP) && (wifi_iface_getstatus(globalhandle->sock_util, wlan->virtname) > 0)) { - wifi_iface_down(globalhandle->sock_util, wlan->virtname); - } - } else if (wlan->flags & WIFI_WLAN_SET_BEACON) { - if ((wlan->flags & WIFI_WLAN_OPERSTATE_RUNNING) && (infomsg->ifi_flags & IFF_LOWER_UP) && !(infomsg->ifi_flags & (IFF_RUNNING | IFF_DORMANT))) { - struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; - netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP); - } - } - } -} - -/* */ -static void nl80211_global_dellink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { -} - -/* */ -static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { - uint32_t ifindex; - struct wifi_wlan* wlan; - struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (tb_msg[NL80211_ATTR_IFINDEX]) { - ifindex = (int)nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]); - - /* Search interface */ - wlan = wifi_get_wlan(ifindex); - if (wlan) { - return nl80211_wlan_event(wlan, gnlh, tb_msg); - } - } - - return NL_SKIP; -} - -/* */ -static wifi_global_handle nl80211_global_init(void) { - int result; - struct nl80211_global_handle* globalhandle; - - /* */ - globalhandle = (struct nl80211_global_handle*)capwap_alloc(sizeof(struct nl80211_global_handle)); - memset(globalhandle, 0, sizeof(struct nl80211_global_handle)); - globalhandle->sock_util = -1; - - /* Configure global netlink callback */ - globalhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!globalhandle->nl_cb) { - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - /* Create netlink socket */ - globalhandle->nl = nl_create_handle(globalhandle->nl_cb); - if (!globalhandle->nl) { - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - /* Create netlink socket for event */ - globalhandle->nl_event = nl_create_handle(globalhandle->nl_cb); - if (globalhandle->nl_event) { - globalhandle->nl_event_fd = nl_socket_get_fd(globalhandle->nl_event); - } else { - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - /* Add membership scan events */ - result = nl80211_get_multicast_id(globalhandle, "nl80211", "scan"); - if (result >= 0) { - result = nl_socket_add_membership(globalhandle->nl_event, result); - } - - if (result < 0) { - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - /* Add membership mlme events */ - result = nl80211_get_multicast_id(globalhandle, "nl80211", "mlme"); - if (result >= 0) { - result = nl_socket_add_membership(globalhandle->nl_event, result); - } - - if (result < 0) { - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - /* Add membership regulatory events */ - result = nl80211_get_multicast_id(globalhandle, "nl80211", "regulatory"); - if (result >= 0) { - nl_socket_add_membership(globalhandle->nl_event, result); - } - - /* Get nl80211 netlink family */ - globalhandle->nl80211_id = genl_ctrl_resolve(globalhandle->nl, "nl80211"); - if (globalhandle->nl80211_id < 0) { - capwap_logging_warning("Unable to found mac80211 kernel module"); - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - /* Configure global callback function */ - nl_cb_set(globalhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); - nl_cb_set(globalhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_global_valid_handler, NULL); - - /* Netlink lisk status */ - globalhandle->netlinkhandle = netlink_init(); - if (!globalhandle->netlinkhandle) { - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - globalhandle->netlinkhandle->newlink_event = nl80211_global_newlink_event; - globalhandle->netlinkhandle->dellink_event = nl80211_global_dellink_event; - - /* Socket utils */ - globalhandle->sock_util = socket(AF_PACKET, SOCK_RAW, 0); - if (globalhandle->sock_util < 0) { - nl80211_global_deinit((wifi_global_handle)globalhandle); - return NULL; - } - - return (wifi_global_handle)globalhandle; -} - -/* */ -static int nl80211_global_getfdevent(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events) { - struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; - - ASSERT(handle != NULL); - ASSERT(globalhandle->nl_event_fd >= 0); - ASSERT(globalhandle->netlinkhandle != NULL); - ASSERT(globalhandle->netlinkhandle->sock >= 0); - - if (fds) { - fds[0].fd = globalhandle->nl_event_fd; - fds[0].events = POLLIN | POLLERR | POLLHUP; - fds[1].fd = globalhandle->netlinkhandle->sock; - fds[1].events = POLLIN | POLLERR | POLLHUP; - } - - if (events) { - events[0].event_handler = nl80211_event_receive; - events[0].params[0] = (void*)globalhandle->nl_event; - events[0].params[1] = (void*)globalhandle->nl_cb; - events[0].paramscount = 2; - events[1].event_handler = netlink_event_receive; - events[1].params[0] = (void*)globalhandle->netlinkhandle; - events[1].params[1] = (void*)globalhandle; - events[1].paramscount = 2; - } - - return 2; -} - -/* Driver function */ -const struct wifi_driver_ops wifi_driver_nl80211_ops = { - .name = "nl80211", - .description = "Linux nl80211/cfg80211", - .global_init = nl80211_global_init, - .global_getfdevent = nl80211_global_getfdevent, - .global_deinit = nl80211_global_deinit, - - .device_init = nl80211_device_init, - .device_getfdevent = nl80211_device_getfdevent, - .device_getcapability = nl80211_device_getcapability, - .device_updatebeacons = nl80211_device_updatebeacons, - .device_setfrequency = nl80211_device_setfrequency, - .device_deinit = nl80211_device_deinit, - - .wlan_create = nl80211_wlan_create, - .wlan_getfdevent = nl80211_wlan_getfdevent, - .wlan_startap = nl80211_wlan_startap, - .wlan_stopap = nl80211_wlan_stopap, - .wlan_sendframe = nl80211_wlan_sendframe, - .wlan_delete = nl80211_wlan_delete, - - .station_authorize = nl80211_station_authorize, - .station_deauthorize = nl80211_station_deauthorize -}; +#include "wtp.h" +#include "capwap_array.h" +#include "capwap_list.h" +#include "capwap_element.h" +#include +#include +#include +#include "wtp_kmod.h" + +/* Local version of nl80211 with all feature to remove the problem of frag version of nl80211 */ +#include "nl80211_v3_10.h" + +#include "wifi_drivers.h" +#include "wifi_nl80211.h" + +/* Physical device info */ +struct nl80211_phydevice_item { + uint32_t index; + char name[IFNAMSIZ]; +}; + +/* Virtual device info */ +struct nl80211_virtdevice_item { + uint32_t phyindex; + uint32_t virtindex; + char virtname[IFNAMSIZ]; +}; + +/* */ +static const int g_stypes[] = { + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST +}; + +/* */ +struct family_data { + int id; + const char* group; +}; + +/* Compatibility functions */ +#ifdef HAVE_LIBNL_10 +static uint32_t g_portbitmap[32] = { 0 }; + +static struct nl_sock* nl_socket_alloc_cb(void* cb) { + int i; + struct nl_sock* handle; + uint32_t pid = getpid() & 0x3FFFFF; + + handle = nl_handle_alloc_cb(cb); + for (i = 0; i < 1024; i++) { + if (g_portbitmap[i / 32] & (1 << (i % 32))) { + continue; + } + + g_portbitmap[i / 32] |= 1 << (i % 32); + pid += i << 22; + break; + } + + nl_socket_set_local_port(handle, pid); + return handle; +} + +static void nl_socket_free(struct nl_sock* handle) { + uint32_t port = nl_socket_get_local_port(handle); + + port >>= 22; + g_portbitmap[port / 32] &= ~(1 << (port % 32)); + + nl_handle_destroy(handle); +} +#endif + +/* */ +static struct nl_sock* nl_create_handle(struct nl_cb* cb) { + struct nl_sock* handle; + + handle = nl_socket_alloc_cb(cb); + if (!handle) { + return NULL; + } + + if (genl_connect(handle)) { + nl_socket_free(handle); + return NULL; + } + + return handle; +} + +/* */ +static int nl80211_no_seq_check(struct nl_msg* msg, void* arg) { + return NL_OK; +} + +/* */ +static int nl80211_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) { + *((int*)arg) = err->error; + return NL_STOP; +} + +/* */ +static int nl80211_finish_handler(struct nl_msg* msg, void* arg) { + *((int*)arg) = 0; + return NL_SKIP; +} + +/* */ +static int nl80211_ack_handler(struct nl_msg* msg, void* arg) { + *((int*)arg) = 0; + return NL_STOP; +} + +/* */ +static int nl80211_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) { + int result; + struct nl_cb* cb; + + /* Clone netlink callback */ + cb = nl_cb_clone(nl_cb); + if (!cb) { + return -1; + } + + /* Complete send message */ + result = nl_send_auto_complete(nl, msg); + if (result < 0) { + nl_cb_put(cb); + return -1; + } + + /* Customize message callback */ + nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_handler, &result); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_finish_handler, &result); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_ack_handler, &result); + + if (valid_cb) { + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data); + } + + result = 1; + while (result > 0) { + nl_recvmsgs(nl, cb); + } + + nl_cb_put(cb); + return result; +} + +/* */ +static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle, struct nl_msg* msg, nl_valid_cb valid_cb, void* data) { + return nl80211_send_and_recv(globalhandle->nl, globalhandle->nl_cb, msg, valid_cb, data); +} + +/* */ +static int cb_family_handler(struct nl_msg* msg, void* data) { + int i; + struct nlattr* mcast_group; + struct nlattr* tb_msg[CTRL_ATTR_MAX + 1]; + struct nlattr* tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct family_data* resource = (struct family_data*)data; + + nla_parse(tb_msg, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[CTRL_ATTR_MCAST_GROUPS]) { + nla_for_each_nested(mcast_group, tb_msg[CTRL_ATTR_MCAST_GROUPS], i) { + nla_parse(tb_msg_mcast_group, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcast_group), nla_len(mcast_group), NULL); + + if (tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_NAME] && tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_ID]) { + if (!strncmp(nla_data(tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]), resource->group, nla_len(tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_NAME]))) { + resource->id = nla_get_u32(tb_msg_mcast_group[CTRL_ATTR_MCAST_GRP_ID]); + break; + } + } + } + } + + return NL_SKIP; +} + +/* */ +static int nl80211_get_multicast_id(struct nl80211_global_handle* globalhandle, const char* family, const char* group) { + int result; + struct nl_msg* msg; + struct family_data resource = { -1, group }; + + ASSERT(globalhandle != NULL); + ASSERT(family != NULL); + ASSERT(group != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, genl_ctrl_resolve(globalhandle->nl, "nlctrl"), 0, 0, CTRL_CMD_GETFAMILY, 0); + nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family); + + /* */ + result = nl80211_send_and_recv_msg(globalhandle, msg, cb_family_handler, &resource); + if (!result) { + result = resource.id; + } else { + capwap_logging_error("Unable get multicast id, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int nl80211_wlan_set_type(struct wifi_wlan* wlan, uint32_t type) { + int result; + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + nla_put_u32(msg, NL80211_ATTR_IFTYPE, type); + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable set type, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int cb_get_type(struct nl_msg* msg, void* data) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + uint32_t* type = (uint32_t*)data; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_IFTYPE]) { + *type = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]); + } + + return NL_SKIP; +} + +/* */ +static uint32_t nl80211_wlan_get_type(struct wifi_wlan* wlan) { + int result; + struct nl_msg* msg; + uint32_t type = NL80211_IFTYPE_UNSPECIFIED; + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return NL80211_IFTYPE_UNSPECIFIED; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, cb_get_type, &type); + if (result) { + capwap_logging_error("Unable get type, error code: %d", result); + type = NL80211_IFTYPE_UNSPECIFIED; + } + + /* */ + nlmsg_free(msg); + return type; +} + +/* */ +static int nl80211_wlan_set_profile(struct wifi_wlan* wlan, uint32_t type) { + int result; + + /* Change interface type */ + result = nl80211_wlan_set_type(wlan, type); + if (result && (type == nl80211_wlan_get_type(wlan))) { + result = 0; /* No error */ + } + + /* */ + if (result) { + if (result == -ENODEV) { + return -1; + } + + /* TODO */ + } + + return result; +} + +/* */ +static int nl80211_device_changefrequency(struct wifi_device* device, struct wifi_frequency* freq) { + int result; + struct nl_msg* msg; + struct capwap_list_item* wlansearch; + struct nl80211_device_handle* devicehandle; + struct wifi_wlan* wlan = NULL; + + ASSERT(device != NULL); + ASSERT(freq != NULL); + + /* Search a valid interface */ + for (wlansearch = device->wlans->first; wlansearch; wlansearch = wlansearch->next) { + struct wifi_wlan* element = (struct wifi_wlan*)wlansearch->item; + + if (element->flags & WIFI_WLAN_RUNNING) { + wlan = element; + break; + } + } + + /* */ + if (!wlan) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* Set frequecy using device index of first BSS */ + devicehandle = (struct nl80211_device_handle*)device->handle; + genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_WIPHY, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->frequency); + + /* Set wifi frequency */ + result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); + if (!result) { + capwap_logging_info("Change %s frequency %d", wlan->virtname, (int)freq->frequency); + } else { + capwap_logging_error("Unable set frequency %d, error code: %d", (int)freq->frequency, result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int nl80211_wlan_event(struct wifi_wlan* wlan, struct genlmsghdr* gnlh, struct nlattr** tb_msg) { + switch (gnlh->cmd) { + case NL80211_CMD_FRAME: { + if (tb_msg[NL80211_ATTR_FRAME]) { + uint32_t frequency = (tb_msg[NL80211_ATTR_WIPHY_FREQ] ? nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]) : 0); + uint8_t rssi = (tb_msg[NL80211_ATTR_RX_SIGNAL_DBM] ? (uint8_t)nla_get_u32(tb_msg[NL80211_ATTR_RX_SIGNAL_DBM]) : 0); + + /* */ + wifi_wlan_receive_station_frame(wlan, (struct ieee80211_header*)nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), frequency, rssi, 0, 0); + } + + break; + } + + case NL80211_CMD_FRAME_TX_STATUS: { + if (tb_msg[NL80211_ATTR_FRAME] && tb_msg[NL80211_ATTR_COOKIE]) { + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + uint64_t cookie = nla_get_u64(tb_msg[NL80211_ATTR_COOKIE]); + + if (wlanhandle->last_cookie == cookie) { + wlanhandle->last_cookie = 0; + wifi_wlan_receive_station_ackframe(wlan, (struct ieee80211_header*)nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), (tb_msg[NL80211_ATTR_ACK] ? 1 : 0)); + } + } + + break; + } + + case NL80211_CMD_TRIGGER_SCAN: { + break; + } + + case NL80211_CMD_NEW_SCAN_RESULTS: { + break; + } + + case NL80211_CMD_NEW_STATION: { + break; + } + + case NL80211_CMD_DEL_STATION: { + break; + } + + default: { + capwap_logging_debug("*** nl80211_wlan_event: %d", (int)gnlh->cmd); + break; + } + } + + return NL_SKIP; +} + +/* */ +static int nl80211_wlan_valid_handler(struct nl_msg* msg, void* arg) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + return nl80211_wlan_event((struct wifi_wlan*)arg, gnlh, tb_msg); +} + +/* */ +static int nl80211_wlan_registerframe(struct wifi_wlan* wlan, uint16_t type, const uint8_t* match, int lengthmatch) { + int result; + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_REGISTER_FRAME, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type); + nla_put(msg, NL80211_ATTR_FRAME_MATCH, lengthmatch, match); + + /* Destroy virtual device */ + result = nl80211_send_and_recv(wlanhandle->nl, wlanhandle->nl_cb, msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int nl80211_global_destroy_virtdevice(struct nl80211_global_handle* globalhandle, uint32_t virtindex) { + int result; + struct nl_msg* msg; + + ASSERT(globalhandle != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, 0, NL80211_CMD_DEL_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, virtindex); + + /* Destroy virtual device */ + result = nl80211_send_and_recv_msg(globalhandle, msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable destroy interface, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int cb_global_destroy_all_virtdevice(struct nl_msg* msg, void* data) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct capwap_list* list = (struct capwap_list*)data; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_WIPHY] && tb_msg[NL80211_ATTR_IFNAME] && tb_msg[NL80211_ATTR_IFINDEX]) { + struct capwap_list_item* item = capwap_itemlist_create(sizeof(struct nl80211_virtdevice_item)); + struct nl80211_virtdevice_item* virtitem = (struct nl80211_virtdevice_item*)item->item; + + /* Add virtual device info */ + virtitem->phyindex = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); + virtitem->virtindex = nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]); + strcpy(virtitem->virtname, nla_get_string(tb_msg[NL80211_ATTR_IFNAME])); + capwap_itemlist_insert_after(list, NULL, item); + } + + return NL_SKIP; +} + +/* */ +static void nl80211_global_destroy_all_virtdevice(struct nl80211_global_handle* globalhandle, uint32_t phyindex) { + int result; + struct nl_msg* msg; + struct capwap_list* list; + struct capwap_list_item* itemsearch; + + ASSERT(globalhandle != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return; + } + + genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_WIPHY, phyindex); + + /* Retrieve all virtual interface */ + list = capwap_list_create(); + result = nl80211_send_and_recv_msg(globalhandle, msg, cb_global_destroy_all_virtdevice, list); + if (!result) { + for (itemsearch = list->first; itemsearch; itemsearch = itemsearch->next) { + struct nl80211_virtdevice_item* virtitem = (struct nl80211_virtdevice_item*)itemsearch->item; + + /* Destroy virtual device */ + if (virtitem->phyindex == phyindex) { + wifi_iface_down(globalhandle->sock_util, virtitem->virtname); + result = nl80211_global_destroy_virtdevice(globalhandle, virtitem->virtindex); + if (result) { + capwap_logging_error("Unable to destroy virtual device, error code: %d", result); + } + } + } + } else { + /* Error get virtual devices */ + capwap_logging_error("Unable retrieve virtual device info, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + capwap_list_free(list); +} + +/* */ +static wifi_wlan_handle nl80211_wlan_create(struct wifi_device* device, struct wifi_wlan* wlan) { + int result; + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle; + struct nl80211_device_handle* devicehandle; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(wlan != NULL); + + /* */ + devicehandle = (struct nl80211_device_handle*)device->handle; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return NULL; + } + + /* Create wlan interface */ + genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_NEW_INTERFACE, 0); + nla_put_u32(msg, NL80211_ATTR_WIPHY, device->phyindex); + nla_put_u32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION); + nla_put_string(msg, NL80211_ATTR_IFNAME, wlan->virtname); + + /* */ + result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); + nlmsg_free(msg); + + /* Check interface */ + if (result || !wifi_iface_index(wlan->virtname)) { + capwap_logging_error("Unable create interface %s, error code: %d", wlan->virtname, result); + return NULL; + } + + /* Init wlan */ + wlanhandle = (struct nl80211_wlan_handle*)capwap_alloc(sizeof(struct nl80211_wlan_handle)); + memset(wlanhandle, 0, sizeof(struct nl80211_wlan_handle)); + + wlanhandle->devicehandle = devicehandle; + wlanhandle->nl_fd = -1; + + return (wifi_wlan_handle)wlanhandle; +} + +/* */ +static void nl80211_event_receive(int fd, void** params, int paramscount) { + int res; + + ASSERT(fd >= 0); + ASSERT(params != NULL); + ASSERT(paramscount == 2); + + /* */ + res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); + if (res) { + capwap_logging_warning("Receive nl80211 message failed: %d", res); + } +} + +/* */ +static int nl80211_wlan_getfdevent(struct wifi_wlan* wlan, struct pollfd* fds, struct wifi_event* events) { + struct nl80211_wlan_handle* wlanhandle; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + if (!(wlan->flags & WIFI_WLAN_RUNNING) || (wlanhandle->nl_fd < 0)) { + return 0; + } + + if (fds) { + fds[0].fd = wlanhandle->nl_fd; + fds[0].events = POLLIN | POLLERR | POLLHUP; + } + + if (events) { + events[0].event_handler = nl80211_event_receive; + events[0].params[0] = (void*)wlanhandle->nl; + events[0].params[1] = (void*)wlanhandle->nl_cb; + events[0].paramscount = 2; + } + + return 1; +} + +/* */ +static int nl80211_wlan_setbeacon(struct wifi_wlan* wlan) { + int result; + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle; + struct ieee80211_beacon_params ieee80211_params; + uint8_t buffer[IEEE80211_MTU]; + + /* */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + + /* Create beacon packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_beacon_params)); + memcpy(ieee80211_params.bssid, wlan->address, ETH_ALEN); + ieee80211_params.beaconperiod = wlan->device->beaconperiod; + ieee80211_params.capability = wifi_wlan_check_capability(wlan, wlan->capability); + ieee80211_params.ssid = wlan->ssid; + ieee80211_params.ssid_hidden = wlan->ssid_hidden; + memcpy(ieee80211_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); + ieee80211_params.supportedratescount = wlan->device->supportedratescount; + ieee80211_params.mode = wlan->device->currentfrequency.mode; + ieee80211_params.erpinfo = ieee80211_get_erpinfo(wlan->device->currentfrequency.mode, wlan->device->olbc, wlan->device->stationsnonerpcount, wlan->device->stationsnoshortpreamblecount, wlan->device->shortpreamble); + ieee80211_params.channel = wlan->device->currentfrequency.channel; + + /* Enable probe response offload only in CAPWAP Local Mac */ + if ((wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_LOCAL) && (wlan->device->capability->capability & WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD)) { + ieee80211_params.flags |= IEEE80221_CREATE_BEACON_FLAGS_PROBE_RESPONSE_OFFLOAD; + } + + /* */ + result = ieee80211_create_beacon(buffer, sizeof(buffer), &ieee80211_params); + if (result < 0) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, ((wlan->flags & WIFI_WLAN_SET_BEACON) ? NL80211_CMD_SET_BEACON : NL80211_CMD_START_AP), 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + nla_put(msg, NL80211_ATTR_BEACON_HEAD, ieee80211_params.headbeaconlength, ieee80211_params.headbeacon); + nla_put(msg, NL80211_ATTR_BEACON_TAIL, ieee80211_params.tailbeaconlength, ieee80211_params.tailbeacon); + nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL, wlan->device->beaconperiod); + nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, wlan->device->dtimperiod); + nla_put(msg, NL80211_ATTR_SSID, strlen(wlan->ssid), wlan->ssid); + nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID, (wlan->ssid_hidden ? NL80211_HIDDEN_SSID_ZERO_LEN : NL80211_HIDDEN_SSID_NOT_IN_USE)); + nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, ((wlan->authmode == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM)); + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); + + if ((wlan->device->capability->capability & WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD) && (ieee80211_params.proberesponseoffloadlength > 0)) { + nla_put(msg, NL80211_ATTR_PROBE_RESP, ieee80211_params.proberesponseoffloadlength, ieee80211_params.proberesponseoffload); + } + + /* Start AP */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (result) { + capwap_logging_error("Unable set beacon, error code: %d", result); + } + + nlmsg_free(msg); + + /* Configure AP */ + if (!result) { + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_SET_BSS, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + + /* */ + nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, ((ieee80211_params.erpinfo & IEEE80211_ERP_INFO_USE_PROTECTION) ? 1 : 0)); + nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, ((!wlan->device->stationsnoshortpreamblecount && wlan->device->shortpreamble) ? 1 : 0)); + //nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ???); + //nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ???); + + if (wlan->device->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) { + nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, (!wlan->device->stationsnoshortslottimecount ? 1 : 0)); + } + + if (wlan->device->basicratescount > 0) { + nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, wlan->device->basicratescount, wlan->device->basicrates); + } + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (!result) { + wlan->flags |= WIFI_WLAN_SET_BEACON; + } else { + capwap_logging_error("Unable set BSS, error code: %d", result); + } + + nlmsg_free(msg); + } + + return result; +} + +/* */ +static int nl80211_wlan_startap(struct wifi_wlan* wlan) { + int i; + int result; + struct nl80211_wlan_handle* wlanhandle; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* Configure interface with AP profile */ + if (nl80211_wlan_set_profile(wlan, NL80211_IFTYPE_AP)) { + return -1; + } + + /* Socket management */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + wlanhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!wlanhandle->nl_cb) { + return -1; + } + + /* */ + nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); + nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wlan_valid_handler, (void*)wlan); + + wlanhandle->nl = nl_create_handle(wlanhandle->nl_cb); + if (wlanhandle->nl) { + wlanhandle->nl_fd = nl_socket_get_fd(wlanhandle->nl); + } else { + return -1; + } + + /* Register frames */ + for (i = 0; i < sizeof(g_stypes) / sizeof(g_stypes[0]); i++) { + result = nl80211_wlan_registerframe(wlan, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (g_stypes[i] << 4), NULL, 0); + if (result) { + capwap_logging_error("Unable to register frame %d, error code: %d", g_stypes[i], result); + return -1; + } + } + + /* Enable interface */ + wlan->flags |= WIFI_WLAN_RUNNING; + if (wifi_iface_up(wlanhandle->devicehandle->globalhandle->sock_util, wlan->virtname)) { + return -1; + } + + /* Configure device if first BSS device */ + if (!wlan->device->wlanactive) { + /* Set device frequency */ + nl80211_device_changefrequency(wlan->device, &wlan->device->currentfrequency); + /* TODO Get current frequency */ + } + + /* Set beacon */ + if (nl80211_wlan_setbeacon(wlan)) { + return -1; + } + + /* */ + if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { + /* Join interface in kernel module */ + uint32_t flags = ((wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211) ? WTP_KMOD_FLAGS_TUNNEL_NATIVE : WTP_KMOD_FLAGS_TUNNEL_8023); + + if (!wtp_kmod_join_mac80211_device(wlan, flags)) { + capwap_logging_info("Joined the interface %d in kernel mode ", wlan->virtindex); + } else { + capwap_logging_error("Unable to join the interface %d in kernel mode ", wlan->virtindex); + return -1; + } + } + + /* Enable operation status */ + wlan->flags |= WIFI_WLAN_OPERSTATE_RUNNING; + netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP); + + return 0; +} + +/* */ +static void nl80211_wlan_stopap(struct wifi_wlan* wlan) { + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + /* */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + + /* */ + if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { + /* Leave interface from kernel module */ + wtp_kmod_leave_mac80211_device(wlan); + } + + /* */ + if (wlan->flags & WIFI_WLAN_SET_BEACON) { + msg = nlmsg_alloc(); + if (msg) { + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_STOP_AP, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + + /* Stop AP */ + nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + nlmsg_free(msg); + } + } + + /* Disable interface */ + wifi_iface_down(wlanhandle->devicehandle->globalhandle->sock_util, wlan->virtname); + + /* Configure interface with station profile */ + nl80211_wlan_set_profile(wlan, NL80211_IFTYPE_STATION); + + /* */ + if (wlanhandle->nl) { + nl_socket_free(wlanhandle->nl); + wlanhandle->nl = NULL; + wlanhandle->nl_fd = -1; + } + + if (wlanhandle->nl_cb) { + nl_cb_put(wlanhandle->nl_cb); + wlanhandle->nl_cb = NULL; + } +} + +/* */ +static int cb_wlan_send_frame(struct nl_msg* msg, void* arg) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + + /* */ + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + if (tb_msg[NL80211_ATTR_COOKIE]) { + *(uint64_t*)arg = nla_get_u64(tb_msg[NL80211_ATTR_COOKIE]); + } + + return NL_SKIP; +} + +/* */ +static int nl80211_wlan_sendframe(struct wifi_wlan* wlan, uint8_t* frame, int length, uint32_t frequency, uint32_t duration, int offchannel_tx_ok, int no_cck_rate, int no_wait_ack) { + int result; + uint64_t cookie; + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + ASSERT(frame != NULL); + ASSERT(length > 0); + + /* */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_FRAME, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + + if (frequency) { + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, frequency); + } + + if (duration) { + nla_put_u32(msg, NL80211_ATTR_DURATION, duration); + } + + if (offchannel_tx_ok && (wlan->device->capability->capability & WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK)) { + nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); + } + + if (no_cck_rate) { + nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE); + } + + if (no_wait_ack) { + nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK); + } + + nla_put(msg, NL80211_ATTR_FRAME, length, frame); + + /* Send frame */ + cookie = 0; + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, cb_wlan_send_frame, &cookie); + if (result) { + capwap_logging_error("Unable send frame, error code: %d", result); + } + + nlmsg_free(msg); + + wlanhandle->last_cookie = (result || no_wait_ack ? 0 : cookie); + return result; +} + +/* */ +static void nl80211_wlan_delete(struct wifi_wlan* wlan) { + struct nl80211_wlan_handle* wlanhandle; + + ASSERT(wlan != NULL); + + /* */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + if (wlanhandle) { + if (wlan->virtindex) { + nl80211_global_destroy_virtdevice(wlanhandle->devicehandle->globalhandle, wlan->virtindex); + } + + capwap_free(wlanhandle); + } +} + +/* */ +static uint32_t nl80211_station_get_flags(struct wifi_station* station) { + uint32_t result = 0; + + ASSERT(station != NULL); + + if (station->flags & WIFI_STATION_FLAGS_AUTHORIZED) { + result |= 1 << NL80211_STA_FLAG_AUTHORIZED; + } + + if (!(station->flags & WIFI_STATION_FLAGS_NO_SHORT_PREAMBLE)) { + result |= 1 << NL80211_STA_FLAG_SHORT_PREAMBLE; + } + + if (station->flags & WIFI_STATION_FLAGS_WMM) { + result |= 1 << NL80211_STA_FLAG_WME; + } + + return result; +} + +/* */ +int nl80211_station_authorize(struct wifi_wlan* wlan, struct wifi_station* station) { + int result; + struct nl_msg* msg; + struct nl80211_sta_flag_update flagstation; + struct nl80211_wlan_handle* wlanhandle; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + ASSERT(station != NULL); + ASSERT(wlan == station->wlan); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_NEW_STATION, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, station->address); + nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES, station->supportedratescount, station->supportedrates); + nla_put_u16(msg, NL80211_ATTR_STA_AID, station->aid); + nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, station->listeninterval); + nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY, station->capability); + + /* */ + memset(&flagstation, 0, sizeof(struct nl80211_sta_flag_update)); + flagstation.mask = nl80211_station_get_flags(station); + flagstation.set = flagstation.mask; + nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(struct nl80211_sta_flag_update), &flagstation); + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (result) { + if (result == -EEXIST) { + result = 0; + } else { + capwap_logging_error("Unable to authorized station, error code: %d", result); + } + } + + /* */ + if (!result) { + capwap_logging_info("Authorized station: %s", station->addrtext); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int nl80211_station_deauthorize(struct wifi_wlan* wlan, const uint8_t* address) { + int result; + struct nl_msg* msg; + struct nl80211_wlan_handle* wlanhandle; + + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + ASSERT(address != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_DEL_STATION, 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlan->virtindex); + nla_put(msg, NL80211_ATTR_MAC, MACADDRESS_EUI48_LENGTH, address); + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + if (result) { + if (result == -ENOENT) { + result = 0; + } else { + capwap_logging_error("Unable delete station, error code: %d", result); + } + } + + /* */ + if (!result) { + char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER]; + capwap_logging_info("Deauthorize station: %s", capwap_printf_macaddress(addrtext, address, MACADDRESS_EUI48_LENGTH)); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static int cb_device_init(struct nl_msg* msg, void* data) { + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct capwap_list* list = (struct capwap_list*)data; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_WIPHY_NAME] && tb_msg[NL80211_ATTR_WIPHY]) { + struct capwap_list_item* item = capwap_itemlist_create(sizeof(struct nl80211_phydevice_item)); + struct nl80211_phydevice_item* phyitem = (struct nl80211_phydevice_item*)item->item; + + /* Add physical device info */ + phyitem->index = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); + strcpy(phyitem->name, nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME])); + capwap_itemlist_insert_after(list, NULL, item); + } + + return NL_SKIP; +} + +/* */ +int nl80211_device_init(wifi_global_handle handle, struct wifi_device* device) { + int result; + struct nl_msg* msg; + struct capwap_list* list; + struct capwap_list_item* item; + struct nl80211_device_handle* devicehandle = NULL; + struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; + + ASSERT(handle != NULL); + ASSERT(device != NULL); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, globalhandle->nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0); + + /* Retrieve all physical interface */ + list = capwap_list_create(); + result = nl80211_send_and_recv_msg(globalhandle, msg, cb_device_init, list); + if (!result) { + for (item = list->first; item; item = item->next) { + struct nl80211_phydevice_item* phyitem = (struct nl80211_phydevice_item*)item->item; + + if (!strcmp(phyitem->name, device->phyname)) { + /* Create device */ + devicehandle = (struct nl80211_device_handle*)capwap_alloc(sizeof(struct nl80211_device_handle)); + memset(devicehandle, 0, sizeof(struct nl80211_device_handle)); + + /* */ + devicehandle->globalhandle = globalhandle; + + /* */ + device->handle = (wifi_device_handle)devicehandle; + device->phyindex = phyitem->index; + break; + } + } + } else { + /* Error get physical devices */ + capwap_logging_error("Unable retrieve physical device info, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + capwap_list_free(list); + if (!devicehandle) { + return -1; + } + + /* Remove all virtual adapter from wifi device */ + nl80211_global_destroy_all_virtdevice(globalhandle, device->phyindex); + return 0; +} + +/* */ +static int nl80211_device_getfdevent(struct wifi_device* device, struct pollfd* fds, struct wifi_event* events) { + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + + return 0; +} + +/* */ +static unsigned long nl80211_get_cipher(uint32_t chiper) { + switch (chiper) { + case 0x000fac01: { + return CIPHER_CAPABILITY_WEP40; + } + + case 0x000fac05: { + return CIPHER_CAPABILITY_WEP104; + } + + case 0x000fac02: { + return CIPHER_CAPABILITY_TKIP; + } + + case 0x000fac04: { + return CIPHER_CAPABILITY_CCMP; + } + + case 0x000fac06: { + return CIPHER_CAPABILITY_CMAC; + } + + case 0x000fac08: { + return CIPHER_CAPABILITY_GCMP; + } + + case 0x00147201: { + return CIPHER_CAPABILITY_WPI_SMS4; + } + } + + return CIPHER_CAPABILITY_UNKNOWN; +} + +/* */ +static int cb_get_phydevice_capability(struct nl_msg* msg, void* data) { + int i, j; + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct wifi_capability* capability = (struct wifi_capability*)data; + int radio80211bg = 0; + int radio80211a = 0; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_WIPHY] && (nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]) == capability->device->phyindex)) { + /* Interface supported */ + if (tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) { + struct nlattr* nl_mode; + + capability->flags |= WIFI_CAPABILITY_RADIOSUPPORTED; + nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], i) { + switch (nla_type(nl_mode)) { + case NL80211_IFTYPE_AP: { + capability->radiosupported |= WIFI_CAPABILITY_AP_SUPPORTED; + break; + } + + case NL80211_IFTYPE_AP_VLAN: { + capability->radiosupported |= WIFI_CAPABILITY_AP_VLAN_SUPPORTED; + break; + } + + case NL80211_IFTYPE_ADHOC: { + capability->radiosupported |= WIFI_CAPABILITY_ADHOC_SUPPORTED; + break; + } + + case NL80211_IFTYPE_WDS: { + capability->radiosupported |= WIFI_CAPABILITY_WDS_SUPPORTED; + break; + } + + case NL80211_IFTYPE_MONITOR: { + capability->radiosupported |= WIFI_CAPABILITY_MONITOR_SUPPORTED; + break; + } + } + } + } + + /* */ + if (tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) { + capability->flags |= WIFI_CAPABILITY_MAX_SCAN_SSIDS; + capability->maxscanssids = nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); + } + + if (tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]) { + capability->flags |= WIFI_CAPABILITY_MAX_SCHED_SCAN_SSIDS; + capability->maxschedscanssids = nla_get_u8(tb_msg[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]); + } + + if (tb_msg[NL80211_ATTR_MAX_MATCH_SETS]) { + capability->flags |= WIFI_CAPABILITY_MAX_MATCH_SETS; + capability->maxmatchsets = nla_get_u8(tb_msg[NL80211_ATTR_MAX_MATCH_SETS]); + } + + if (tb_msg[NL80211_ATTR_MAC_ACL_MAX]) { + capability->flags |= WIFI_CAPABILITY_MAX_ACL_MACADDRESS; + capability->maxaclmacaddress = nla_get_u8(tb_msg[NL80211_ATTR_MAC_ACL_MAX]); + } + + if (tb_msg[NL80211_ATTR_OFFCHANNEL_TX_OK]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_OFFCHANNEL_TX_OK; + } + + if (tb_msg[NL80211_ATTR_ROAM_SUPPORT]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_ROAM_SUPPORT; + } + + if (tb_msg[NL80211_ATTR_SUPPORT_AP_UAPSD]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_SUPPORT_AP_UAPSD; + } + + if (tb_msg[NL80211_ATTR_DEVICE_AP_SME]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_DEVICE_AP_SME; + } + + if (tb_msg[NL80211_ATTR_PROBE_RESP_OFFLOAD]) { + capability->capability |= WIFI_CAPABILITY_FLAGS_PROBE_RESPONSE_OFFLOAD; + /* TODO check offload protocol support */ + } + + /* Cipher supported */ + if (tb_msg[NL80211_ATTR_CIPHER_SUITES]) { + int count; + uint32_t* ciphers; + struct wifi_cipher_capability* ciphercap; + + /* */ + count = nla_len(tb_msg[NL80211_ATTR_CIPHER_SUITES]) / sizeof(uint32_t); + if (count > 0) { + capability->flags |= WIFI_CAPABILITY_CIPHERS; + ciphers = (uint32_t*)nla_data(tb_msg[NL80211_ATTR_CIPHER_SUITES]); + for (j = 0; j < count; j++) { + ciphercap = (struct wifi_cipher_capability*)capwap_array_get_item_pointer(capability->ciphers, capability->ciphers->count); + ciphercap->cipher = nl80211_get_cipher(ciphers[j]); + } + } + } + + /* TX/RX Antenna count */ + if (tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX] && tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX]) { + capability->flags |= WIFI_CAPABILITY_ANTENNA_MASK; + capability->txantennamask = (unsigned long)nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_TX]); + capability->rxantennamask = (unsigned long)nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_ANTENNA_RX]); + } + + /* Band and datarate supported */ + if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) { + struct nlattr* nl_band; + struct nlattr* tb_band[NL80211_BAND_ATTR_MAX + 1]; + + capability->flags |= WIFI_CAPABILITY_BANDS; + nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], i) { + struct wifi_band_capability* bandcap; + + nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL); + + /* Init band */ + bandcap = (struct wifi_band_capability*)capwap_array_get_item_pointer(capability->bands, capability->bands->count); + bandcap->freq = capwap_array_create(sizeof(struct wifi_freq_capability), 0, 1); + bandcap->rate = capwap_array_create(sizeof(struct wifi_rate_capability), 0, 1); + + /* Check High Throughput capability */ + if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) { + bandcap->htcapability = (unsigned long)nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]); + capability->flags |= WIFI_CAPABILITY_RADIOTYPE; + capability->radiotype |= CAPWAP_RADIO_TYPE_80211N; + } + + /* Frequency */ + if (tb_band[NL80211_BAND_ATTR_FREQS]) { + struct nlattr* nl_freq; + struct nlattr* tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { + [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, + [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, + }; + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], j) { + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), freq_policy); + + if (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) { + unsigned long frequency = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + unsigned long band = (IS_IEEE80211_FREQ_BG(frequency) ? WIFI_BAND_2GHZ : (IS_IEEE80211_FREQ_A(frequency) ? WIFI_BAND_5GHZ : WIFI_BAND_UNKNOWN)); + + if (band != WIFI_BAND_UNKNOWN) { + struct wifi_freq_capability* freq = (struct wifi_freq_capability*)capwap_array_get_item_pointer(bandcap->freq, bandcap->freq->count); + + /* Set band */ + if (bandcap->band == WIFI_BAND_UNKNOWN) { + bandcap->band = band; + } else if (bandcap->band != band) { + capwap_logging_warning("Multiple wireless band into logical band"); + } + + /* Retrieve frequency and channel */ + freq->frequency = frequency; + freq->channel = ieee80211_frequency_to_channel(frequency); + + if (!radio80211bg && IS_IEEE80211_FREQ_BG(frequency)) { + radio80211bg = 1; + capability->flags |= WIFI_CAPABILITY_RADIOTYPE; + capability->radiotype |= (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G); + } else if (!radio80211a && IS_IEEE80211_FREQ_A(frequency)) { + radio80211a = 1; + capability->flags |= WIFI_CAPABILITY_RADIOTYPE; + capability->radiotype |= CAPWAP_RADIO_TYPE_80211A; + } + + /* Get max tx power */ + if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) { + freq->maxtxpower = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]); + } + + /* Get flags */ + if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) { + freq->flags |= FREQ_CAPABILITY_DISABLED; + } else { + if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) { + freq->flags |= FREQ_CAPABILITY_PASSIVE_SCAN; + } + + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) { + freq->flags |= FREQ_CAPABILITY_NO_IBBS; + } + + if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) { + freq->flags |= FREQ_CAPABILITY_RADAR; + } + + if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) { + freq->flags |= FREQ_CAPABILITY_DFS_STATE; + freq->dfsstate = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]); + + if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) { + freq->flags |= FREQ_CAPABILITY_DFS_TIME; + freq->dfstime = (unsigned long)nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]); + } + } + } + } + } + } + } + + /* Rate */ + if (tb_band[NL80211_BAND_ATTR_RATES]) { + struct nlattr* nl_rate; + struct nlattr* tb_rate[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = { + [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 }, + [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG }, + }; + + nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], j) { + nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate), nla_len(nl_rate), rate_policy); + + if (tb_rate[NL80211_BITRATE_ATTR_RATE]) { + struct wifi_rate_capability* rate = (struct wifi_rate_capability*)capwap_array_get_item_pointer(bandcap->rate, bandcap->rate->count); + + /* Set bitrate into multiple of 500Kbps */ + rate->bitrate = (uint8_t)(nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]) / 5); + + if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE]) { + rate->flags |= RATE_CAPABILITY_SHORTPREAMBLE; + } + } + } + } + } + } + } + + return NL_SKIP; +} + +/* */ +static int nl80211_device_getcapability(struct wifi_device* device, struct wifi_capability* capability) { + int result; + struct nl_msg* msg; + struct nl80211_device_handle* devicehandle; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + ASSERT(capability != NULL); + + /* */ + devicehandle = (struct nl80211_device_handle*)device->handle; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + genlmsg_put(msg, 0, 0, devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_GET_WIPHY, 0); + nla_put_u32(msg, NL80211_ATTR_WIPHY, device->phyindex); + + /* Retrieve physical device capability */ + capability->device = device; + result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, cb_get_phydevice_capability, capability); + if (result) { + capwap_logging_error("Unable retrieve physical device capability, error code: %d", result); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static void nl80211_device_updatebeacons(struct wifi_device* device) { + struct wifi_wlan* wlan; + struct capwap_list_item* wlansearch; + + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + + /* Update all wlan beacon */ + for (wlansearch = device->wlans->first; wlansearch; wlansearch = wlansearch->next) { + wlan = (struct wifi_wlan*)wlansearch->item; + if (wlan->flags & WIFI_WLAN_SET_BEACON) { + if (nl80211_wlan_setbeacon(wlan)) { + capwap_logging_warning("Unable to update beacon on interface %d", wlan->virtindex); + wifi_wlan_stopap(wlan); + } + } + } +} + +/* */ +static int nl80211_device_setfrequency(struct wifi_device* device) { + ASSERT(device != NULL); + ASSERT(device->handle != NULL); + + /* Delay request if not found BSS interface */ + if (!device->wlanactive) { + return 0; + } + + return nl80211_device_changefrequency(device, &device->currentfrequency); +} + +/* */ +static void nl80211_device_deinit(struct wifi_device* device) { + struct nl80211_device_handle* devicehandle; + + ASSERT(device != NULL); + + devicehandle = (struct nl80211_device_handle*)device->handle; + if (devicehandle) { + capwap_free(devicehandle); + device->handle = NULL; + } +} + +/* */ +static void nl80211_global_deinit(wifi_global_handle handle) { + struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; + + if (globalhandle) { + if (globalhandle->netlinkhandle) { + netlink_free(globalhandle->netlinkhandle); + } + + if (globalhandle->nl) { + nl_socket_free(globalhandle->nl); + } + + if (globalhandle->nl_event) { + nl_socket_free(globalhandle->nl_event); + } + + if (globalhandle->nl_cb) { + nl_cb_put(globalhandle->nl_cb); + } + + if (globalhandle->sock_util >= 0) { + close(globalhandle->sock_util); + } + + capwap_free(globalhandle); + } +} + +/* */ +static void nl80211_global_newlink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { + struct wifi_wlan* wlan; + struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; + + ASSERT(handle != NULL); + ASSERT(infomsg != NULL); + + /* Search device */ + wlan = wifi_get_wlan(infomsg->ifi_index); + if (wlan) { + if (!(wlan->flags & WIFI_WLAN_RUNNING)) { + if ((infomsg->ifi_flags & IFF_UP) && (wifi_iface_getstatus(globalhandle->sock_util, wlan->virtname) > 0)) { + wifi_iface_down(globalhandle->sock_util, wlan->virtname); + } + } else if (wlan->flags & WIFI_WLAN_SET_BEACON) { + if ((wlan->flags & WIFI_WLAN_OPERSTATE_RUNNING) && (infomsg->ifi_flags & IFF_LOWER_UP) && !(infomsg->ifi_flags & (IFF_RUNNING | IFF_DORMANT))) { + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP); + } + } + } +} + +/* */ +static void nl80211_global_dellink_event(wifi_global_handle handle, struct ifinfomsg* infomsg, uint8_t* data, int length) { +} + +/* */ +static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { + uint32_t ifindex; + struct wifi_wlan* wlan; + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_IFINDEX]) { + ifindex = (int)nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]); + + /* Search interface */ + wlan = wifi_get_wlan(ifindex); + if (wlan) { + return nl80211_wlan_event(wlan, gnlh, tb_msg); + } + } + + return NL_SKIP; +} + +/* */ +static wifi_global_handle nl80211_global_init(void) { + int result; + struct nl80211_global_handle* globalhandle; + + /* */ + globalhandle = (struct nl80211_global_handle*)capwap_alloc(sizeof(struct nl80211_global_handle)); + memset(globalhandle, 0, sizeof(struct nl80211_global_handle)); + globalhandle->sock_util = -1; + + /* Configure global netlink callback */ + globalhandle->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!globalhandle->nl_cb) { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + /* Create netlink socket */ + globalhandle->nl = nl_create_handle(globalhandle->nl_cb); + if (!globalhandle->nl) { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + /* Create netlink socket for event */ + globalhandle->nl_event = nl_create_handle(globalhandle->nl_cb); + if (globalhandle->nl_event) { + globalhandle->nl_event_fd = nl_socket_get_fd(globalhandle->nl_event); + } else { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + /* Add membership scan events */ + result = nl80211_get_multicast_id(globalhandle, "nl80211", "scan"); + if (result >= 0) { + result = nl_socket_add_membership(globalhandle->nl_event, result); + } + + if (result < 0) { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + /* Add membership mlme events */ + result = nl80211_get_multicast_id(globalhandle, "nl80211", "mlme"); + if (result >= 0) { + result = nl_socket_add_membership(globalhandle->nl_event, result); + } + + if (result < 0) { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + /* Add membership regulatory events */ + result = nl80211_get_multicast_id(globalhandle, "nl80211", "regulatory"); + if (result >= 0) { + nl_socket_add_membership(globalhandle->nl_event, result); + } + + /* Get nl80211 netlink family */ + globalhandle->nl80211_id = genl_ctrl_resolve(globalhandle->nl, "nl80211"); + if (globalhandle->nl80211_id < 0) { + capwap_logging_warning("Unable to found mac80211 kernel module"); + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + /* Configure global callback function */ + nl_cb_set(globalhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL); + nl_cb_set(globalhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_global_valid_handler, NULL); + + /* Netlink lisk status */ + globalhandle->netlinkhandle = netlink_init(); + if (!globalhandle->netlinkhandle) { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + globalhandle->netlinkhandle->newlink_event = nl80211_global_newlink_event; + globalhandle->netlinkhandle->dellink_event = nl80211_global_dellink_event; + + /* Socket utils */ + globalhandle->sock_util = socket(AF_PACKET, SOCK_RAW, 0); + if (globalhandle->sock_util < 0) { + nl80211_global_deinit((wifi_global_handle)globalhandle); + return NULL; + } + + return (wifi_global_handle)globalhandle; +} + +/* */ +static int nl80211_global_getfdevent(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events) { + struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; + + ASSERT(handle != NULL); + ASSERT(globalhandle->nl_event_fd >= 0); + ASSERT(globalhandle->netlinkhandle != NULL); + ASSERT(globalhandle->netlinkhandle->sock >= 0); + + if (fds) { + fds[0].fd = globalhandle->nl_event_fd; + fds[0].events = POLLIN | POLLERR | POLLHUP; + fds[1].fd = globalhandle->netlinkhandle->sock; + fds[1].events = POLLIN | POLLERR | POLLHUP; + } + + if (events) { + events[0].event_handler = nl80211_event_receive; + events[0].params[0] = (void*)globalhandle->nl_event; + events[0].params[1] = (void*)globalhandle->nl_cb; + events[0].paramscount = 2; + events[1].event_handler = netlink_event_receive; + events[1].params[0] = (void*)globalhandle->netlinkhandle; + events[1].params[1] = (void*)globalhandle; + events[1].paramscount = 2; + } + + return 2; +} + +/* Driver function */ +const struct wifi_driver_ops wifi_driver_nl80211_ops = { + .name = "nl80211", + .description = "Linux nl80211/cfg80211", + .global_init = nl80211_global_init, + .global_getfdevent = nl80211_global_getfdevent, + .global_deinit = nl80211_global_deinit, + + .device_init = nl80211_device_init, + .device_getfdevent = nl80211_device_getfdevent, + .device_getcapability = nl80211_device_getcapability, + .device_updatebeacons = nl80211_device_updatebeacons, + .device_setfrequency = nl80211_device_setfrequency, + .device_deinit = nl80211_device_deinit, + + .wlan_create = nl80211_wlan_create, + .wlan_getfdevent = nl80211_wlan_getfdevent, + .wlan_startap = nl80211_wlan_startap, + .wlan_stopap = nl80211_wlan_stopap, + .wlan_sendframe = nl80211_wlan_sendframe, + .wlan_delete = nl80211_wlan_delete, + + .station_authorize = nl80211_station_authorize, + .station_deauthorize = nl80211_station_deauthorize +}; diff --git a/src/wtp/binding/ieee80211/wifi_nl80211.h b/src/wtp/binding/ieee80211/wifi_nl80211.h index 6ab7c6e..a681093 100644 --- a/src/wtp/binding/ieee80211/wifi_nl80211.h +++ b/src/wtp/binding/ieee80211/wifi_nl80211.h @@ -1,45 +1,45 @@ -#ifndef __WIFI_NL80211_HEADER__ -#define __WIFI_NL80211_HEADER__ - -#include "capwap_hash.h" -#include "netlink_link.h" - -/* Compatibility functions */ -#ifdef HAVE_LIBNL_10 -#define nl_sock nl_handle -#endif - -/* */ -typedef int (*nl_valid_cb)(struct nl_msg* msg, void* data); - -/* Global handle */ -struct nl80211_global_handle { - struct nl_sock* nl; - struct nl_cb* nl_cb; - int nl80211_id; - - struct nl_sock* nl_event; - int nl_event_fd; - - struct netlink* netlinkhandle; - - int sock_util; -}; - -/* Device handle */ -struct nl80211_device_handle { - struct nl80211_global_handle* globalhandle; -}; - -/* WLAN handle */ -struct nl80211_wlan_handle { - struct nl80211_device_handle* devicehandle; - - struct nl_sock* nl; - int nl_fd; - struct nl_cb* nl_cb; - - uint64_t last_cookie; -}; - -#endif /* __WIFI_NL80211_HEADER__ */ +#ifndef __WIFI_NL80211_HEADER__ +#define __WIFI_NL80211_HEADER__ + +#include "capwap_hash.h" +#include "netlink_link.h" + +/* Compatibility functions */ +#ifdef HAVE_LIBNL_10 +#define nl_sock nl_handle +#endif + +/* */ +typedef int (*nl_valid_cb)(struct nl_msg* msg, void* data); + +/* Global handle */ +struct nl80211_global_handle { + struct nl_sock* nl; + struct nl_cb* nl_cb; + int nl80211_id; + + struct nl_sock* nl_event; + int nl_event_fd; + + struct netlink* netlinkhandle; + + int sock_util; +}; + +/* Device handle */ +struct nl80211_device_handle { + struct nl80211_global_handle* globalhandle; +}; + +/* WLAN handle */ +struct nl80211_wlan_handle { + struct nl80211_device_handle* devicehandle; + + struct nl_sock* nl; + int nl_fd; + struct nl_cb* nl_cb; + + uint64_t last_cookie; +}; + +#endif /* __WIFI_NL80211_HEADER__ */ diff --git a/src/wtp/kmod/capwap.c b/src/wtp/kmod/capwap.c index 5a5dd9f..6e4dc33 100644 --- a/src/wtp/kmod/capwap.c +++ b/src/wtp/kmod/capwap.c @@ -1,789 +1,789 @@ -#include "config.h" -#include -#include -#include -#include -#include "socket.h" -#include "capwap.h" -#include "nlsmartcapwap.h" -#include "netlinkapp.h" - -/* */ -union capwap_addr sc_localaddr; - -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char sc_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; - -/* */ -static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) { - TRACEKMOD("### sc_capwap_fragment_free\n"); - - /* */ - list_del(&fragment->lru_list); - fragment->flags = 0; - - /* Free socket buffer */ - while (fragment->fragments) { - struct sk_buff* next = fragment->fragments->next; - - kfree_skb(fragment->fragments); - fragment->fragments = next; - } -} - -/* */ -static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) { - ktime_t delta; - struct sc_capwap_fragment* fragment; - struct list_head* list = &session->fragments.lru_list; - - TRACEKMOD("### sc_capwap_defrag_evictor\n"); - - /* Light check without lock */ - if (!list_empty(list)) { - spin_lock(&session->fragments.lock); - - /* Remove last old fragment */ - if (!list_empty(list)) { - fragment = list_first_entry(list, struct sc_capwap_fragment, lru_list); - delta = ktime_sub(now, fragment->tstamp); - if ((delta.tv64 < -NSEC_PER_SEC) || (delta.tv64 > NSEC_PER_SEC)) { - TRACEKMOD("*** Expired fragment %hu (%llu %llu)\n", fragment->fragmentid, now.tv64, fragment->tstamp.tv64); - sc_capwap_fragment_free(fragment); - } - } - - spin_unlock(&session->fragments.lock); - } -} - -/* */ -static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) { - int len; - int offset; - struct sk_buff* skb; - struct sk_buff* skbfrag; - struct sc_capwap_header* header; - - TRACEKMOD("### sc_capwap_reasm\n"); - - /* */ - skbfrag = fragment->fragments; - len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; - - /* Create new packet */ - skb = alloc_skb(len + fragment->totallength, GFP_KERNEL); - if (!skb) { - return NULL; - } - - /* The first capwap header is header of reassembled packet without fragment field */ - header = (struct sc_capwap_header*)skb_put(skb, len); - memcpy(header, skbfrag->data, len); - - SET_FLAG_F_HEADER(header, 0); - SET_FLAG_L_HEADER(header, 0); - header->frag_id = (__be16)0; - header->frag_off = (__be16)0; - - /* Copy body */ - while (skbfrag) { - offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; - len = skbfrag->len - offset; - - TRACEKMOD("*** Append fragment size %d\n", len); - - /* */ - memcpy(skb_put(skb, len), skbfrag->data + offset, len); - skbfrag = skbfrag->next; - } - - TRACEKMOD("*** Assemblate capwap data packet with total size %d\n", skb->len); - - return skb; -} - -/* */ -static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) { - uint16_t headersize; - uint16_t frag_id; - struct sk_buff* prev; - struct sk_buff* next; - struct sc_capwap_fragment* fragment; - struct sc_skb_capwap_cb* cb; - struct sk_buff* skb_defrag = NULL; - struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; - - TRACEKMOD("### sc_capwap_defrag\n"); - - /* */ - headersize = GET_HLEN_HEADER(header) * 4; - if (skb->len < headersize) { - goto error; - } - - /* */ - frag_id = be16_to_cpu(header->frag_id); - - /* */ - cb = CAPWAP_SKB_CB(skb); - cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT; - cb->frag_offset = be16_to_cpu(header->frag_off); - cb->frag_length = skb->len - headersize; - - /* */ - spin_lock(&session->fragments.lock); - TRACEKMOD("*** Fragment info: id %hu offset %hu length %hu\n", frag_id, cb->frag_offset, cb->frag_length); - - /* Get fragment */ - fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE]; - if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) { - TRACEKMOD("*** Unable defrag, queue fragment busy\n"); - goto error2; /* Queue fragment busy*/ - } - - /* Init fragment */ - if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) { - fragment->flags = CAPWAP_FRAGMENT_ENABLE; - fragment->fragmentid = frag_id; - fragment->fragments = NULL; - fragment->lastfragment = NULL; - fragment->recvlength = 0; - fragment->totallength = 0; - list_add_tail(&fragment->lru_list, &session->fragments.lru_list); - } - - /* Search fragment position */ - prev = fragment->lastfragment; - if (!prev) { - next = NULL; - } else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) { - if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) <= cb->frag_offset) { - next = NULL; - } else { - sc_capwap_fragment_free(fragment); - TRACEKMOD("*** Unable defrag, overlap error\n"); - goto error2; /* Overlap error */ - } - } else { - prev = NULL; - for (next = fragment->fragments; next != NULL; next = next->next) { - struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next); - - if (next_cb->frag_offset == cb->frag_offset) { - TRACEKMOD("*** Unable defrag, duplicate packet\n"); - goto error2; /* Duplicate packet */ - } else if (next_cb->frag_offset > cb->frag_offset) { - if ((cb->frag_offset + cb->frag_length) <= next_cb->frag_offset) { - break; - } else { - sc_capwap_fragment_free(fragment); - TRACEKMOD("*** Unable defrag, overlap error\n"); - goto error2; /* Overlap error */ - } - } - - prev = next; - } - } - - /* Insert fragment */ - skb->prev = NULL; - skb->next = next; - if (!next) { - fragment->lastfragment = skb; - } - - if (prev) { - prev->next = skb; - } else { - fragment->fragments = skb; - } - - /* Update size */ - fragment->recvlength += cb->frag_length; - if (IS_FLAG_L_HEADER(header)) { - fragment->totallength = cb->frag_offset + cb->frag_length; - fragment->flags |= CAPWAP_FRAGMENT_LAST; - } - - /* Check if receive all fragment */ - if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) { - skb_defrag = sc_capwap_reasm(fragment); - - /* Free fragment complete */ - sc_capwap_fragment_free(fragment); - } else { - /* Update timeout */ - fragment->tstamp = skb->tstamp; - TRACEKMOD("*** Fragment id %hu expire at %llu\n", frag_id, fragment->tstamp.tv64); - - /* Set LRU timeout */ - if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) { - list_move_tail(&fragment->lru_list, &session->fragments.lru_list); - } - } - - spin_unlock(&session->fragments.lock); - - return skb_defrag; - -error2: - spin_unlock(&session->fragments.lock); - -error: - kfree_skb(skb); - return NULL; -} - -/* */ -static unsigned int sc_capwap_80211_hdrlen(__le16 fc) { - unsigned int hdrlen = 24; - - TRACEKMOD("### sc_capwap_80211_hdrlen\n"); - - if (ieee80211_is_data(fc)) { - if (ieee80211_has_a4(fc)) { - hdrlen = 30; - } - - if (ieee80211_is_data_qos(fc)) { - hdrlen += IEEE80211_QOS_CTL_LEN; - if (ieee80211_has_order(fc)) { - hdrlen += IEEE80211_HT_CTL_LEN; - } - } - } else if (ieee80211_is_ctl(fc)) { - if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) { - hdrlen = 10; - } else { - hdrlen = 16; - } - } - - return hdrlen; -} - -/* */ -int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid) { - uint16_t hdrlen; - int head_need; - struct ieee80211_hdr hdr; - int skip_header_bytes; - uint8_t* encaps_data; - int encaps_len; - struct ethhdr* eh = (struct ethhdr*)skb->data; - uint16_t ethertype = ntohs(eh->h_proto); - - TRACEKMOD("### sc_capwap_8023_to_80211\n"); - - /* IEEE 802.11 header */ - hdrlen = 24; - hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_FROMDS); - memcpy(hdr.addr1, eh->h_dest, ETH_ALEN); - memcpy(hdr.addr2, bssid, ETH_ALEN); - memcpy(hdr.addr3, eh->h_source, ETH_ALEN); - hdr.duration_id = 0; - hdr.seq_ctrl = 0; - - /* */ - skip_header_bytes = ETH_HLEN; - if ((ethertype == ETH_P_AARP) || (ethertype == ETH_P_IPX)) { - encaps_data = sc_bridge_tunnel_header; - encaps_len = sizeof(sc_bridge_tunnel_header); - skip_header_bytes -= 2; - } else if (ethertype >= ETH_P_802_3_MIN) { - encaps_data = sc_rfc1042_header; - encaps_len = sizeof(sc_rfc1042_header); - skip_header_bytes -= 2; - } else { - encaps_data = NULL; - encaps_len = 0; - } - - /* Remove IEEE 802.3 header */ - skb_pull(skb, skip_header_bytes); - - /* Check headroom */ - head_need = hdrlen + encaps_len - skb_headroom(skb); - if ((head_need > 0) || skb_cloned(skb)) { - head_need = max(head_need, 0); - if (head_need) { - skb_orphan(skb); - } - - TRACEKMOD("*** Expand headroom skb of: %d\n", head_need); - if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { - return -ENOMEM; - } - - skb->truesize += head_need; - } - - /* Add LLC header */ - if (encaps_data) { - memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); - } - - /* Add IEEE 802.11 header */ - memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); - skb_reset_mac_header(skb); - - return 0; -} - -/* */ -int sc_capwap_80211_to_8023(struct sk_buff* skb) { - struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; - uint16_t hdrlen; - uint16_t ethertype; - uint8_t* payload; - uint8_t dst[ETH_ALEN]; - uint8_t src[ETH_ALEN] __aligned(2); - - TRACEKMOD("### sc_capwap_80211_to_8023\n"); - - /* */ - hdrlen = sc_capwap_80211_hdrlen(hdr->frame_control); - memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); - memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); - - /* */ - if (!pskb_may_pull(skb, hdrlen + 8)) { - return -1; - } - - /* */ - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((ether_addr_equal(payload, sc_rfc1042_header) && (ethertype != ETH_P_AARP) && (ethertype != ETH_P_IPX)) || ether_addr_equal(payload, sc_bridge_tunnel_header))) { - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - struct ethhdr *ehdr; - __be16 len; - - skb_pull(skb, hdrlen); - len = htons(skb->len); - ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); - memcpy(ehdr->h_dest, dst, ETH_ALEN); - memcpy(ehdr->h_source, src, ETH_ALEN); - ehdr->h_proto = len; - } - - return 0; -} - -/* */ -int sc_capwap_bind(union capwap_addr* sockaddr) { - int ret; - - TRACEKMOD("### sc_capwap_bind\n"); - - /* */ - ret = sc_socket_bind(sockaddr); - if (ret) { - return ret; - } - - memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr)); - return 0; -} - -/* */ -void sc_capwap_initsession(struct sc_capwap_session* session) { - TRACEKMOD("### sc_capwap_initsession\n"); - - spin_lock_init(&session->fragmentid_lock); - - /* Defragment packets */ - memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue)); - INIT_LIST_HEAD(&session->fragments.lru_list); - spin_lock_init(&session->fragments.lock); -} - -/* */ -void sc_capwap_freesession(struct sc_capwap_session* session) { - struct sc_capwap_fragment* temp; - struct sc_capwap_fragment* fragment; - - TRACEKMOD("### sc_capwap_freesession\n"); - - /* Free socket buffers */ - list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) { - sc_capwap_fragment_free(fragment); - } -} - -/* */ -uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) { - uint16_t fragmentid; - - TRACEKMOD("### sc_capwap_newfragmentid\n"); - - spin_lock(&session->fragmentid_lock); - fragmentid = session->fragmentid++; - spin_unlock(&session->fragmentid_lock); - - return fragmentid; -} - -/* */ -int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) { - int length; - struct sc_capwap_header* header; - struct sc_capwap_data_message* dataheader; - struct sc_capwap_message_element* msgelement; - - TRACEKMOD("### sc_capwap_createkeepalive\n"); - - /* */ - if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) { - return -ENOMEM; - } - - /* Preamble CAPWAP header */ - header = (struct sc_capwap_header*)buffer; - length = sizeof(struct sc_capwap_header); - buffer += sizeof(struct sc_capwap_header); - - memset(header, 0, sizeof(struct sc_capwap_header)); - SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); - SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); - SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4); - SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211); - SET_FLAG_K_HEADER(header, 1); - - /* CAPWAP Data header */ - dataheader = (struct sc_capwap_data_message*)buffer; - length += sizeof(struct sc_capwap_data_message); - buffer += sizeof(struct sc_capwap_data_message); - - dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)); - - /* CAPWAP Keep-Alive Message Element */ - msgelement = (struct sc_capwap_message_element*)buffer; - length += sizeof(struct sc_capwap_message_element); - buffer += sizeof(struct sc_capwap_message_element); - - msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID); - msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element)); - - /* Session ID */ - memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element)); - length += sizeof(struct sc_capwap_sessionid_element); - - return length; -} - -/* */ -int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) { - int length; - uint16_t headersize; - struct sc_capwap_data_message* dataheader; - struct sc_capwap_message_element* message; - struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; - - TRACEKMOD("### sc_capwap_parsingpacket\n"); - - /* Linearize socket buffer */ - if (skb_linearize(skb)) { - TRACEKMOD("*** Unable to linearize packet\n"); - return -EINVAL; - } - - /* Check header */ - if (skb->len < sizeof(struct sc_capwap_header)) { - TRACEKMOD("*** Invalid capwap header length\n"); - return -EINVAL; - } else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) { - TRACEKMOD("*** Invalid capwap header version\n"); - return -EINVAL; - } else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) { - TRACEKMOD("*** Packet is encrypted\n"); - return -EINVAL; /* Accept only plain packet */ - } - - /* */ - if (IS_FLAG_K_HEADER(header)) { - /* Keep alive can not fragment */ - if (IS_FLAG_F_HEADER(header)) { - TRACEKMOD("*** Keep alive can not fragment\n"); - return -EINVAL; - } - - /* */ - length = skb->len; - headersize = GET_HLEN_HEADER(header) * 4; - if (length < (headersize + sizeof(struct sc_capwap_data_message))) { - TRACEKMOD("*** Invalid capwap data header length\n"); - return -EINVAL; - } - - /* Data message */ - length -= headersize; - dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize); - headersize = ntohs(dataheader->length); - if (length < headersize) { - TRACEKMOD("*** Capwap data header length mismatch\n"); - return -EINVAL; - } - - /* Message elements */ - headersize -= sizeof(struct sc_capwap_data_message); - message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message)); - while (headersize > 0) { - uint16_t msglength = ntohs(message->length); - if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) { - TRACEKMOD("*** Invalid capwap message element length\n"); - return -EINVAL; - } - - /* */ - if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) { - struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element)); - - if (!session) { - session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid); - if (!session) { - TRACEKMOD("*** Receive unknown keep alive without valid session\n"); - return -EINVAL; - } - } else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { - TRACEKMOD("*** Session id mismatch\n"); - return -EINVAL; - } - - /* Session found */ - sc_netlink_notify_recv_keepalive(sockaddr, sessionid); - - /* Parsing complete */ - kfree_skb(skb); - return 0; - } - - /* Next message element */ - msglength += sizeof(struct sc_capwap_message_element); - message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength); - headersize -= msglength; - } - } else if (session) { - if (!skb->tstamp.tv64) { - skb->tstamp = ktime_get(); - } - - /* Cleaning old fragments */ - sc_capwap_defrag_evictor(session, skb->tstamp); - - /* */ - if (IS_FLAG_F_HEADER(header)) { - skb = sc_capwap_defrag(session, skb); - if (!skb) { - return 0; - } - - /* Get new header info */ - header = (struct sc_capwap_header*)skb->data; - } - - /* Parsing data/management packet */ - if (!IS_FLAG_T_HEADER(header)) { - sc_capwap_parsingdatapacket(session, skb); - } else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) { - struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4); - - if (ieee80211_is_data_present(hdr->frame_control)) { - sc_capwap_parsingdatapacket(session, skb); - } else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) { - sc_capwap_parsingmgmtpacket(session, skb); - } - } - - return 0; - } - - return -EINVAL; -} - -/* */ -int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) { - int err; - int size; - int length; - int reserve; - int headroom; - int requestfragment; - __be16 fragmentid = 0; - int fragmentoffset = 0; - struct sc_capwap_header* header; - struct sk_buff* clone = NULL; - int packetlength = skb->len; - - TRACEKMOD("### sc_capwap_forwarddata\n"); - - /* Check headroom */ - headroom = skb_headroom(skb); - reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; - if (skb_is_nonlinear(skb) || (headroom < reserve)) { - TRACEKMOD("*** Copy socket buffer and expand headroom of: %d\n", (reserve - headroom)); - clone = skb_copy_expand(skb, max(headroom, reserve), skb_tailroom(skb), GFP_KERNEL); - if (!clone) { - TRACEKMOD("*** Unable to copy socket buffer\n"); - return -ENOMEM; - } - - skb = clone; - } - - /* Check MTU */ - requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0); - if (requestfragment) { - fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session)); - } - - /* */ - header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength); - while (packetlength > 0) { - memset(header, 0, sizeof(struct sc_capwap_header)); - SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); - SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); - SET_WBID_HEADER(header, binding); - SET_RID_HEADER(header, radioid); - SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1)); - - if (!fragmentoffset) { - uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header); - - if (radioaddr) { - SET_FLAG_M_HEADER(header, 1); - memcpy(headeroption, radioaddr, radioaddrlength); - headeroption += radioaddrlength; - } - - if (winfo) { - SET_FLAG_W_HEADER(header, 1); - memcpy(headeroption, winfo, winfolength); - headeroption += winfolength; - } - - size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; - SET_HLEN_HEADER(header, size / 4); - } else { - size = sizeof(struct sc_capwap_header); - SET_HLEN_HEADER(header, size / 4); - } - - /* Calculate body size */ - length = session->mtu - size; - if (packetlength <= length) { - length = packetlength; - } else if (requestfragment) { - length -= length % 8; /* Capwap fragment size is module 8 */ - } else { - break; - } - - /* Fragment options */ - if (requestfragment) { - SET_FLAG_F_HEADER(header, 1); - if (packetlength == length) { - SET_FLAG_L_HEADER(header, 1); - } - - header->frag_id = fragmentid; - header->frag_off = cpu_to_be16(fragmentoffset); - } - - /* Send packet */ - err = sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr); - TRACEKMOD("*** Send packet result: %d\n", err); - if (err < 0) { - break; - } - - /* */ - header = (struct sc_capwap_header*)(((uint8_t*)header + size + length) - sizeof(struct sc_capwap_header)); - fragmentoffset += length; - packetlength -= length; - } - - if (clone) { - kfree_skb(clone); - } - - return (!packetlength ? 0 : -EIO); -} - -/* */ -void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) { - int i; - char* pos = string; - - for (i = 0; i < 16; i++) { - snprintf(pos, 3, "%02x", sessionid->id[i]); - pos += 2; - } - - *pos = 0; -} - -/* */ -struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) { - struct sc_capwap_radio_addr* radioaddr; - struct sc_capwap_macaddress_eui48* addr; - - TRACEKMOD("### sc_capwap_setwirelessinformation\n"); - - memset(buffer, 0, size); - - radioaddr = (struct sc_capwap_radio_addr*)buffer; - radioaddr->length = MACADDRESS_EUI48_LENGTH; - - addr = (struct sc_capwap_macaddress_eui48*)radioaddr->addr; - memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH); - - return radioaddr; -} - -/* */ -struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) { - struct sc_capwap_wireless_information* winfo; - struct sc_capwap_ieee80211_frame_info* frameinfo; - - TRACEKMOD("### sc_capwap_setwinfo_frameinfo\n"); - - memset(buffer, 0, size); - - winfo = (struct sc_capwap_wireless_information*)buffer; - winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info); - - frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information)); - frameinfo->rssi = rssi; - frameinfo->snr = snr; - frameinfo->rate = cpu_to_be16(rate); - - return winfo; -} - -/* */ -struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap) { - struct sc_capwap_wireless_information* winfo; - struct sc_capwap_destination_wlans* destwlans; - - TRACEKMOD("### sc_capwap_setwinfo_destwlans\n"); - - memset(buffer, 0, size); - - winfo = (struct sc_capwap_wireless_information*)buffer; - winfo->length = sizeof(struct sc_capwap_destination_wlans); - - destwlans = (struct sc_capwap_destination_wlans*)(buffer + sizeof(struct sc_capwap_wireless_information)); - destwlans->wlanidbitmap = cpu_to_be16(wlanidbitmap); - - return winfo; -} +#include "config.h" +#include +#include +#include +#include +#include "socket.h" +#include "capwap.h" +#include "nlsmartcapwap.h" +#include "netlinkapp.h" + +/* */ +union capwap_addr sc_localaddr; + +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +static unsigned char sc_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +static unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; + +/* */ +static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) { + TRACEKMOD("### sc_capwap_fragment_free\n"); + + /* */ + list_del(&fragment->lru_list); + fragment->flags = 0; + + /* Free socket buffer */ + while (fragment->fragments) { + struct sk_buff* next = fragment->fragments->next; + + kfree_skb(fragment->fragments); + fragment->fragments = next; + } +} + +/* */ +static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) { + ktime_t delta; + struct sc_capwap_fragment* fragment; + struct list_head* list = &session->fragments.lru_list; + + TRACEKMOD("### sc_capwap_defrag_evictor\n"); + + /* Light check without lock */ + if (!list_empty(list)) { + spin_lock(&session->fragments.lock); + + /* Remove last old fragment */ + if (!list_empty(list)) { + fragment = list_first_entry(list, struct sc_capwap_fragment, lru_list); + delta = ktime_sub(now, fragment->tstamp); + if ((delta.tv64 < -NSEC_PER_SEC) || (delta.tv64 > NSEC_PER_SEC)) { + TRACEKMOD("*** Expired fragment %hu (%llu %llu)\n", fragment->fragmentid, now.tv64, fragment->tstamp.tv64); + sc_capwap_fragment_free(fragment); + } + } + + spin_unlock(&session->fragments.lock); + } +} + +/* */ +static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) { + int len; + int offset; + struct sk_buff* skb; + struct sk_buff* skbfrag; + struct sc_capwap_header* header; + + TRACEKMOD("### sc_capwap_reasm\n"); + + /* */ + skbfrag = fragment->fragments; + len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; + + /* Create new packet */ + skb = alloc_skb(len + fragment->totallength, GFP_KERNEL); + if (!skb) { + return NULL; + } + + /* The first capwap header is header of reassembled packet without fragment field */ + header = (struct sc_capwap_header*)skb_put(skb, len); + memcpy(header, skbfrag->data, len); + + SET_FLAG_F_HEADER(header, 0); + SET_FLAG_L_HEADER(header, 0); + header->frag_id = (__be16)0; + header->frag_off = (__be16)0; + + /* Copy body */ + while (skbfrag) { + offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4; + len = skbfrag->len - offset; + + TRACEKMOD("*** Append fragment size %d\n", len); + + /* */ + memcpy(skb_put(skb, len), skbfrag->data + offset, len); + skbfrag = skbfrag->next; + } + + TRACEKMOD("*** Assemblate capwap data packet with total size %d\n", skb->len); + + return skb; +} + +/* */ +static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) { + uint16_t headersize; + uint16_t frag_id; + struct sk_buff* prev; + struct sk_buff* next; + struct sc_capwap_fragment* fragment; + struct sc_skb_capwap_cb* cb; + struct sk_buff* skb_defrag = NULL; + struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; + + TRACEKMOD("### sc_capwap_defrag\n"); + + /* */ + headersize = GET_HLEN_HEADER(header) * 4; + if (skb->len < headersize) { + goto error; + } + + /* */ + frag_id = be16_to_cpu(header->frag_id); + + /* */ + cb = CAPWAP_SKB_CB(skb); + cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT; + cb->frag_offset = be16_to_cpu(header->frag_off); + cb->frag_length = skb->len - headersize; + + /* */ + spin_lock(&session->fragments.lock); + TRACEKMOD("*** Fragment info: id %hu offset %hu length %hu\n", frag_id, cb->frag_offset, cb->frag_length); + + /* Get fragment */ + fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE]; + if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) { + TRACEKMOD("*** Unable defrag, queue fragment busy\n"); + goto error2; /* Queue fragment busy*/ + } + + /* Init fragment */ + if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) { + fragment->flags = CAPWAP_FRAGMENT_ENABLE; + fragment->fragmentid = frag_id; + fragment->fragments = NULL; + fragment->lastfragment = NULL; + fragment->recvlength = 0; + fragment->totallength = 0; + list_add_tail(&fragment->lru_list, &session->fragments.lru_list); + } + + /* Search fragment position */ + prev = fragment->lastfragment; + if (!prev) { + next = NULL; + } else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) { + if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) <= cb->frag_offset) { + next = NULL; + } else { + sc_capwap_fragment_free(fragment); + TRACEKMOD("*** Unable defrag, overlap error\n"); + goto error2; /* Overlap error */ + } + } else { + prev = NULL; + for (next = fragment->fragments; next != NULL; next = next->next) { + struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next); + + if (next_cb->frag_offset == cb->frag_offset) { + TRACEKMOD("*** Unable defrag, duplicate packet\n"); + goto error2; /* Duplicate packet */ + } else if (next_cb->frag_offset > cb->frag_offset) { + if ((cb->frag_offset + cb->frag_length) <= next_cb->frag_offset) { + break; + } else { + sc_capwap_fragment_free(fragment); + TRACEKMOD("*** Unable defrag, overlap error\n"); + goto error2; /* Overlap error */ + } + } + + prev = next; + } + } + + /* Insert fragment */ + skb->prev = NULL; + skb->next = next; + if (!next) { + fragment->lastfragment = skb; + } + + if (prev) { + prev->next = skb; + } else { + fragment->fragments = skb; + } + + /* Update size */ + fragment->recvlength += cb->frag_length; + if (IS_FLAG_L_HEADER(header)) { + fragment->totallength = cb->frag_offset + cb->frag_length; + fragment->flags |= CAPWAP_FRAGMENT_LAST; + } + + /* Check if receive all fragment */ + if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) { + skb_defrag = sc_capwap_reasm(fragment); + + /* Free fragment complete */ + sc_capwap_fragment_free(fragment); + } else { + /* Update timeout */ + fragment->tstamp = skb->tstamp; + TRACEKMOD("*** Fragment id %hu expire at %llu\n", frag_id, fragment->tstamp.tv64); + + /* Set LRU timeout */ + if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) { + list_move_tail(&fragment->lru_list, &session->fragments.lru_list); + } + } + + spin_unlock(&session->fragments.lock); + + return skb_defrag; + +error2: + spin_unlock(&session->fragments.lock); + +error: + kfree_skb(skb); + return NULL; +} + +/* */ +static unsigned int sc_capwap_80211_hdrlen(__le16 fc) { + unsigned int hdrlen = 24; + + TRACEKMOD("### sc_capwap_80211_hdrlen\n"); + + if (ieee80211_is_data(fc)) { + if (ieee80211_has_a4(fc)) { + hdrlen = 30; + } + + if (ieee80211_is_data_qos(fc)) { + hdrlen += IEEE80211_QOS_CTL_LEN; + if (ieee80211_has_order(fc)) { + hdrlen += IEEE80211_HT_CTL_LEN; + } + } + } else if (ieee80211_is_ctl(fc)) { + if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) { + hdrlen = 10; + } else { + hdrlen = 16; + } + } + + return hdrlen; +} + +/* */ +int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid) { + uint16_t hdrlen; + int head_need; + struct ieee80211_hdr hdr; + int skip_header_bytes; + uint8_t* encaps_data; + int encaps_len; + struct ethhdr* eh = (struct ethhdr*)skb->data; + uint16_t ethertype = ntohs(eh->h_proto); + + TRACEKMOD("### sc_capwap_8023_to_80211\n"); + + /* IEEE 802.11 header */ + hdrlen = 24; + hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_FROMDS); + memcpy(hdr.addr1, eh->h_dest, ETH_ALEN); + memcpy(hdr.addr2, bssid, ETH_ALEN); + memcpy(hdr.addr3, eh->h_source, ETH_ALEN); + hdr.duration_id = 0; + hdr.seq_ctrl = 0; + + /* */ + skip_header_bytes = ETH_HLEN; + if ((ethertype == ETH_P_AARP) || (ethertype == ETH_P_IPX)) { + encaps_data = sc_bridge_tunnel_header; + encaps_len = sizeof(sc_bridge_tunnel_header); + skip_header_bytes -= 2; + } else if (ethertype >= ETH_P_802_3_MIN) { + encaps_data = sc_rfc1042_header; + encaps_len = sizeof(sc_rfc1042_header); + skip_header_bytes -= 2; + } else { + encaps_data = NULL; + encaps_len = 0; + } + + /* Remove IEEE 802.3 header */ + skb_pull(skb, skip_header_bytes); + + /* Check headroom */ + head_need = hdrlen + encaps_len - skb_headroom(skb); + if ((head_need > 0) || skb_cloned(skb)) { + head_need = max(head_need, 0); + if (head_need) { + skb_orphan(skb); + } + + TRACEKMOD("*** Expand headroom skb of: %d\n", head_need); + if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { + return -ENOMEM; + } + + skb->truesize += head_need; + } + + /* Add LLC header */ + if (encaps_data) { + memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); + } + + /* Add IEEE 802.11 header */ + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + skb_reset_mac_header(skb); + + return 0; +} + +/* */ +int sc_capwap_80211_to_8023(struct sk_buff* skb) { + struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; + uint16_t hdrlen; + uint16_t ethertype; + uint8_t* payload; + uint8_t dst[ETH_ALEN]; + uint8_t src[ETH_ALEN] __aligned(2); + + TRACEKMOD("### sc_capwap_80211_to_8023\n"); + + /* */ + hdrlen = sc_capwap_80211_hdrlen(hdr->frame_control); + memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); + + /* */ + if (!pskb_may_pull(skb, hdrlen + 8)) { + return -1; + } + + /* */ + payload = skb->data + hdrlen; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((ether_addr_equal(payload, sc_rfc1042_header) && (ethertype != ETH_P_AARP) && (ethertype != ETH_P_IPX)) || ether_addr_equal(payload, sc_bridge_tunnel_header))) { + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + struct ethhdr *ehdr; + __be16 len; + + skb_pull(skb, hdrlen); + len = htons(skb->len); + ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dst, ETH_ALEN); + memcpy(ehdr->h_source, src, ETH_ALEN); + ehdr->h_proto = len; + } + + return 0; +} + +/* */ +int sc_capwap_bind(union capwap_addr* sockaddr) { + int ret; + + TRACEKMOD("### sc_capwap_bind\n"); + + /* */ + ret = sc_socket_bind(sockaddr); + if (ret) { + return ret; + } + + memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr)); + return 0; +} + +/* */ +void sc_capwap_initsession(struct sc_capwap_session* session) { + TRACEKMOD("### sc_capwap_initsession\n"); + + spin_lock_init(&session->fragmentid_lock); + + /* Defragment packets */ + memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue)); + INIT_LIST_HEAD(&session->fragments.lru_list); + spin_lock_init(&session->fragments.lock); +} + +/* */ +void sc_capwap_freesession(struct sc_capwap_session* session) { + struct sc_capwap_fragment* temp; + struct sc_capwap_fragment* fragment; + + TRACEKMOD("### sc_capwap_freesession\n"); + + /* Free socket buffers */ + list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) { + sc_capwap_fragment_free(fragment); + } +} + +/* */ +uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) { + uint16_t fragmentid; + + TRACEKMOD("### sc_capwap_newfragmentid\n"); + + spin_lock(&session->fragmentid_lock); + fragmentid = session->fragmentid++; + spin_unlock(&session->fragmentid_lock); + + return fragmentid; +} + +/* */ +int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) { + int length; + struct sc_capwap_header* header; + struct sc_capwap_data_message* dataheader; + struct sc_capwap_message_element* msgelement; + + TRACEKMOD("### sc_capwap_createkeepalive\n"); + + /* */ + if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) { + return -ENOMEM; + } + + /* Preamble CAPWAP header */ + header = (struct sc_capwap_header*)buffer; + length = sizeof(struct sc_capwap_header); + buffer += sizeof(struct sc_capwap_header); + + memset(header, 0, sizeof(struct sc_capwap_header)); + SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); + SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); + SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4); + SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211); + SET_FLAG_K_HEADER(header, 1); + + /* CAPWAP Data header */ + dataheader = (struct sc_capwap_data_message*)buffer; + length += sizeof(struct sc_capwap_data_message); + buffer += sizeof(struct sc_capwap_data_message); + + dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)); + + /* CAPWAP Keep-Alive Message Element */ + msgelement = (struct sc_capwap_message_element*)buffer; + length += sizeof(struct sc_capwap_message_element); + buffer += sizeof(struct sc_capwap_message_element); + + msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID); + msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element)); + + /* Session ID */ + memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element)); + length += sizeof(struct sc_capwap_sessionid_element); + + return length; +} + +/* */ +int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) { + int length; + uint16_t headersize; + struct sc_capwap_data_message* dataheader; + struct sc_capwap_message_element* message; + struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; + + TRACEKMOD("### sc_capwap_parsingpacket\n"); + + /* Linearize socket buffer */ + if (skb_linearize(skb)) { + TRACEKMOD("*** Unable to linearize packet\n"); + return -EINVAL; + } + + /* Check header */ + if (skb->len < sizeof(struct sc_capwap_header)) { + TRACEKMOD("*** Invalid capwap header length\n"); + return -EINVAL; + } else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) { + TRACEKMOD("*** Invalid capwap header version\n"); + return -EINVAL; + } else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) { + TRACEKMOD("*** Packet is encrypted\n"); + return -EINVAL; /* Accept only plain packet */ + } + + /* */ + if (IS_FLAG_K_HEADER(header)) { + /* Keep alive can not fragment */ + if (IS_FLAG_F_HEADER(header)) { + TRACEKMOD("*** Keep alive can not fragment\n"); + return -EINVAL; + } + + /* */ + length = skb->len; + headersize = GET_HLEN_HEADER(header) * 4; + if (length < (headersize + sizeof(struct sc_capwap_data_message))) { + TRACEKMOD("*** Invalid capwap data header length\n"); + return -EINVAL; + } + + /* Data message */ + length -= headersize; + dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize); + headersize = ntohs(dataheader->length); + if (length < headersize) { + TRACEKMOD("*** Capwap data header length mismatch\n"); + return -EINVAL; + } + + /* Message elements */ + headersize -= sizeof(struct sc_capwap_data_message); + message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message)); + while (headersize > 0) { + uint16_t msglength = ntohs(message->length); + if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) { + TRACEKMOD("*** Invalid capwap message element length\n"); + return -EINVAL; + } + + /* */ + if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) { + struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element)); + + if (!session) { + session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid); + if (!session) { + TRACEKMOD("*** Receive unknown keep alive without valid session\n"); + return -EINVAL; + } + } else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) { + TRACEKMOD("*** Session id mismatch\n"); + return -EINVAL; + } + + /* Session found */ + sc_netlink_notify_recv_keepalive(sockaddr, sessionid); + + /* Parsing complete */ + kfree_skb(skb); + return 0; + } + + /* Next message element */ + msglength += sizeof(struct sc_capwap_message_element); + message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength); + headersize -= msglength; + } + } else if (session) { + if (!skb->tstamp.tv64) { + skb->tstamp = ktime_get(); + } + + /* Cleaning old fragments */ + sc_capwap_defrag_evictor(session, skb->tstamp); + + /* */ + if (IS_FLAG_F_HEADER(header)) { + skb = sc_capwap_defrag(session, skb); + if (!skb) { + return 0; + } + + /* Get new header info */ + header = (struct sc_capwap_header*)skb->data; + } + + /* Parsing data/management packet */ + if (!IS_FLAG_T_HEADER(header)) { + sc_capwap_parsingdatapacket(session, skb); + } else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) { + struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4); + + if (ieee80211_is_data_present(hdr->frame_control)) { + sc_capwap_parsingdatapacket(session, skb); + } else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) { + sc_capwap_parsingmgmtpacket(session, skb); + } + } + + return 0; + } + + return -EINVAL; +} + +/* */ +int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) { + int err; + int size; + int length; + int reserve; + int headroom; + int requestfragment; + __be16 fragmentid = 0; + int fragmentoffset = 0; + struct sc_capwap_header* header; + struct sk_buff* clone = NULL; + int packetlength = skb->len; + + TRACEKMOD("### sc_capwap_forwarddata\n"); + + /* Check headroom */ + headroom = skb_headroom(skb); + reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; + if (skb_is_nonlinear(skb) || (headroom < reserve)) { + TRACEKMOD("*** Copy socket buffer and expand headroom of: %d\n", (reserve - headroom)); + clone = skb_copy_expand(skb, max(headroom, reserve), skb_tailroom(skb), GFP_KERNEL); + if (!clone) { + TRACEKMOD("*** Unable to copy socket buffer\n"); + return -ENOMEM; + } + + skb = clone; + } + + /* Check MTU */ + requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0); + if (requestfragment) { + fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session)); + } + + /* */ + header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength); + while (packetlength > 0) { + memset(header, 0, sizeof(struct sc_capwap_header)); + SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION); + SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER); + SET_WBID_HEADER(header, binding); + SET_RID_HEADER(header, radioid); + SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1)); + + if (!fragmentoffset) { + uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header); + + if (radioaddr) { + SET_FLAG_M_HEADER(header, 1); + memcpy(headeroption, radioaddr, radioaddrlength); + headeroption += radioaddrlength; + } + + if (winfo) { + SET_FLAG_W_HEADER(header, 1); + memcpy(headeroption, winfo, winfolength); + headeroption += winfolength; + } + + size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength; + SET_HLEN_HEADER(header, size / 4); + } else { + size = sizeof(struct sc_capwap_header); + SET_HLEN_HEADER(header, size / 4); + } + + /* Calculate body size */ + length = session->mtu - size; + if (packetlength <= length) { + length = packetlength; + } else if (requestfragment) { + length -= length % 8; /* Capwap fragment size is module 8 */ + } else { + break; + } + + /* Fragment options */ + if (requestfragment) { + SET_FLAG_F_HEADER(header, 1); + if (packetlength == length) { + SET_FLAG_L_HEADER(header, 1); + } + + header->frag_id = fragmentid; + header->frag_off = cpu_to_be16(fragmentoffset); + } + + /* Send packet */ + err = sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr); + TRACEKMOD("*** Send packet result: %d\n", err); + if (err < 0) { + break; + } + + /* */ + header = (struct sc_capwap_header*)(((uint8_t*)header + size + length) - sizeof(struct sc_capwap_header)); + fragmentoffset += length; + packetlength -= length; + } + + if (clone) { + kfree_skb(clone); + } + + return (!packetlength ? 0 : -EIO); +} + +/* */ +void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) { + int i; + char* pos = string; + + for (i = 0; i < 16; i++) { + snprintf(pos, 3, "%02x", sessionid->id[i]); + pos += 2; + } + + *pos = 0; +} + +/* */ +struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) { + struct sc_capwap_radio_addr* radioaddr; + struct sc_capwap_macaddress_eui48* addr; + + TRACEKMOD("### sc_capwap_setwirelessinformation\n"); + + memset(buffer, 0, size); + + radioaddr = (struct sc_capwap_radio_addr*)buffer; + radioaddr->length = MACADDRESS_EUI48_LENGTH; + + addr = (struct sc_capwap_macaddress_eui48*)radioaddr->addr; + memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH); + + return radioaddr; +} + +/* */ +struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) { + struct sc_capwap_wireless_information* winfo; + struct sc_capwap_ieee80211_frame_info* frameinfo; + + TRACEKMOD("### sc_capwap_setwinfo_frameinfo\n"); + + memset(buffer, 0, size); + + winfo = (struct sc_capwap_wireless_information*)buffer; + winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info); + + frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information)); + frameinfo->rssi = rssi; + frameinfo->snr = snr; + frameinfo->rate = cpu_to_be16(rate); + + return winfo; +} + +/* */ +struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap) { + struct sc_capwap_wireless_information* winfo; + struct sc_capwap_destination_wlans* destwlans; + + TRACEKMOD("### sc_capwap_setwinfo_destwlans\n"); + + memset(buffer, 0, size); + + winfo = (struct sc_capwap_wireless_information*)buffer; + winfo->length = sizeof(struct sc_capwap_destination_wlans); + + destwlans = (struct sc_capwap_destination_wlans*)(buffer + sizeof(struct sc_capwap_wireless_information)); + destwlans->wlanidbitmap = cpu_to_be16(wlanidbitmap); + + return winfo; +} diff --git a/src/wtp/kmod/capwap.h b/src/wtp/kmod/capwap.h index 8b39e7b..d7087c0 100644 --- a/src/wtp/kmod/capwap.h +++ b/src/wtp/kmod/capwap.h @@ -1,124 +1,124 @@ -#ifndef __KMOD_CAPWAP_HEADER__ -#define __KMOD_CAPWAP_HEADER__ - -#include "capwap_rfc.h" -#include "socket.h" - -/* */ -#define MAX_MTU 9000 -#define DEFAULT_MTU 1450 -#define MIN_MTU 500 -#define IEEE80211_MTU 7981 - -/* */ -#define CAPWAP_FRAGMENT_QUEUE 16 - -/* */ -#define CAPWAP_FRAGMENT_ENABLE 0x0001 -#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002 -#define CAPWAP_FRAGMENT_LAST 0x0004 - -/* */ -#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001 -#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002 -#define SKB_CAPWAP_FLAG_FROM_AC_TAP 0x0004 -#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0008 - -#define SKB_CAPWAP_FLAG_SESSIONID 0x0100 -#define SKB_CAPWAP_FLAG_RADIOID 0x0200 -#define SKB_CAPWAP_FLAG_BINDING 0x0400 -#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0800 -#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000 - -struct sc_skb_capwap_cb { - uint16_t flags; - - /* Session ID */ - struct sc_capwap_sessionid_element sessionid; - - /* Capwap information */ - uint8_t radioid; - uint8_t binding; - - /* Wireless Information */ - uint8_t winfo_rssi; - uint8_t winfo_snr; - uint16_t winfo_rate; - - /* Fragment */ - uint16_t frag_offset; - uint16_t frag_length; -}; - -#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb)) - -/* */ -struct sc_capwap_fragment { - struct list_head lru_list; - - uint8_t flags; - ktime_t tstamp; - - uint16_t fragmentid; - - struct sk_buff* fragments; - struct sk_buff* lastfragment; - int recvlength; - int totallength; -}; - -/* */ -struct sc_capwap_fragment_queue { - spinlock_t lock; - - struct list_head lru_list; - struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE]; -}; - -/* */ -struct sc_capwap_session { - uint16_t mtu; - union capwap_addr peeraddr; - struct sc_capwap_sessionid_element sessionid; - - uint16_t fragmentid; - spinlock_t fragmentid_lock; - - struct sc_capwap_fragment_queue fragments; -}; - -/* */ -extern union capwap_addr sc_localaddr; - -/* Dipendent implementation function */ -void sc_capwap_recvpacket(struct sk_buff* skb); -struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid); - -void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb); -void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb); - -/* Indipendent implementation function */ -int sc_capwap_bind(union capwap_addr* sockaddr); - -void sc_capwap_initsession(struct sc_capwap_session* session); -void sc_capwap_freesession(struct sc_capwap_session* session); -uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session); - -int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid); -int sc_capwap_80211_to_8023(struct sk_buff* skb); - -void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string); - -int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size); -int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb); - -struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid); -struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate); -struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap); - -int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength); - -/* Private funciotn */ -#include "capwap_private.h" - -#endif /* __KMOD_CAPWAP_HEADER__ */ +#ifndef __KMOD_CAPWAP_HEADER__ +#define __KMOD_CAPWAP_HEADER__ + +#include "capwap_rfc.h" +#include "socket.h" + +/* */ +#define MAX_MTU 9000 +#define DEFAULT_MTU 1450 +#define MIN_MTU 500 +#define IEEE80211_MTU 7981 + +/* */ +#define CAPWAP_FRAGMENT_QUEUE 16 + +/* */ +#define CAPWAP_FRAGMENT_ENABLE 0x0001 +#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002 +#define CAPWAP_FRAGMENT_LAST 0x0004 + +/* */ +#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001 +#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002 +#define SKB_CAPWAP_FLAG_FROM_AC_TAP 0x0004 +#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0008 + +#define SKB_CAPWAP_FLAG_SESSIONID 0x0100 +#define SKB_CAPWAP_FLAG_RADIOID 0x0200 +#define SKB_CAPWAP_FLAG_BINDING 0x0400 +#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0800 +#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000 + +struct sc_skb_capwap_cb { + uint16_t flags; + + /* Session ID */ + struct sc_capwap_sessionid_element sessionid; + + /* Capwap information */ + uint8_t radioid; + uint8_t binding; + + /* Wireless Information */ + uint8_t winfo_rssi; + uint8_t winfo_snr; + uint16_t winfo_rate; + + /* Fragment */ + uint16_t frag_offset; + uint16_t frag_length; +}; + +#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb)) + +/* */ +struct sc_capwap_fragment { + struct list_head lru_list; + + uint8_t flags; + ktime_t tstamp; + + uint16_t fragmentid; + + struct sk_buff* fragments; + struct sk_buff* lastfragment; + int recvlength; + int totallength; +}; + +/* */ +struct sc_capwap_fragment_queue { + spinlock_t lock; + + struct list_head lru_list; + struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE]; +}; + +/* */ +struct sc_capwap_session { + uint16_t mtu; + union capwap_addr peeraddr; + struct sc_capwap_sessionid_element sessionid; + + uint16_t fragmentid; + spinlock_t fragmentid_lock; + + struct sc_capwap_fragment_queue fragments; +}; + +/* */ +extern union capwap_addr sc_localaddr; + +/* Dipendent implementation function */ +void sc_capwap_recvpacket(struct sk_buff* skb); +struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid); + +void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb); +void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb); + +/* Indipendent implementation function */ +int sc_capwap_bind(union capwap_addr* sockaddr); + +void sc_capwap_initsession(struct sc_capwap_session* session); +void sc_capwap_freesession(struct sc_capwap_session* session); +uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session); + +int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid); +int sc_capwap_80211_to_8023(struct sk_buff* skb); + +void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string); + +int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size); +int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb); + +struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid); +struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate); +struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap); + +int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength); + +/* Private funciotn */ +#include "capwap_private.h" + +#endif /* __KMOD_CAPWAP_HEADER__ */ diff --git a/src/wtp/kmod/capwap_private.c b/src/wtp/kmod/capwap_private.c index d9b16f9..1060e63 100644 --- a/src/wtp/kmod/capwap_private.c +++ b/src/wtp/kmod/capwap_private.c @@ -1,275 +1,275 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include "capwap.h" -#include "nlsmartcapwap.h" -#include "netlinkapp.h" - -/* */ -static struct sc_capwap_session sc_acsession; - -/* */ -int sc_capwap_init(void) { - TRACEKMOD("### sc_capwap_init\n"); - - /* Init session */ - memset(&sc_acsession, 0, sizeof(struct sc_capwap_session)); - sc_capwap_initsession(&sc_acsession); - - /* Init sockect */ - memset(&sc_localaddr, 0, sizeof(union capwap_addr)); - return sc_socket_init(); -} - -/* */ -void sc_capwap_close(void) { - TRACEKMOD("### sc_capwap_close\n"); - - /* */ - sc_socket_close(); - memset(&sc_localaddr, 0, sizeof(union capwap_addr)); - sc_capwap_freesession(&sc_acsession); -} - -/* */ -int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu) { - TRACEKMOD("### sc_capwap_connect\n"); - - if ((sc_localaddr.ss.ss_family != AF_INET) && (sc_localaddr.ss.ss_family != AF_INET6)) { - return -ENONET; - } - - /* AC address */ - if ((sockaddr->ss.ss_family == AF_INET6) && ipv6_addr_v4mapped(&sockaddr->sin6.sin6_addr)) { - return -EINVAL; - } else if ((sc_localaddr.ss.ss_family == AF_INET) && (sockaddr->ss.ss_family == AF_INET6)) { - return -EINVAL; - } - - /* */ - memcpy(&sc_acsession.peeraddr, sockaddr, sizeof(union capwap_addr)); - memcpy(&sc_acsession.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element)); - sc_acsession.mtu = mtu; - - return sc_capwap_sendkeepalive(); -} - -/* */ -void sc_capwap_resetsession(void) { - TRACEKMOD("### sc_capwap_resetsession\n"); - - /* */ - sc_capwap_freesession(&sc_acsession); - - /* Reinit session */ - memset(&sc_acsession, 0, sizeof(struct sc_capwap_session)); - sc_capwap_initsession(&sc_acsession); -} - -/* */ -int sc_capwap_sendkeepalive(void) { - int ret; - int length; - uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE]; - - TRACEKMOD("### sc_capwap_sendkeepalive\n"); - - /* Build keepalive */ - length = sc_capwap_createkeepalive(&sc_acsession.sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE); - - /* Send packet */ - ret = sc_socket_send(SOCKET_UDP, buffer, length, &sc_acsession.peeraddr); - TRACEKMOD("*** Send keep-alive result: %d\n", ret); - if (ret > 0) { - ret = 0; - } - - return ret; -} - -/* */ -struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr) { - TRACEKMOD("### sc_capwap_getsession\n"); - - if (!sockaddr) { - return &sc_acsession; - } else if (sc_acsession.peeraddr.ss.ss_family == sockaddr->ss.ss_family) { - if (sc_acsession.peeraddr.ss.ss_family == AF_INET) { - if ((sc_acsession.peeraddr.sin.sin_port == sockaddr->sin.sin_port) && (sc_acsession.peeraddr.sin.sin_addr.s_addr == sockaddr->sin.sin_addr.s_addr)) { - return &sc_acsession; - } - } else if (sc_acsession.peeraddr.ss.ss_family == AF_INET6) { - if ((sc_acsession.peeraddr.sin6.sin6_port == sockaddr->sin6.sin6_port) && !ipv6_addr_cmp(&sc_acsession.peeraddr.sin6.sin6_addr, &sockaddr->sin6.sin6_addr)) { - return &sc_acsession; - } - } - } - - return NULL; -} - -/* */ -void sc_capwap_recvpacket(struct sk_buff* skb) { - union capwap_addr peeraddr; - struct sc_capwap_session* session; - - TRACEKMOD("### sc_capwap_recvpacket\n"); - - /* Get peer address */ - if (sc_socket_getpeeraddr(skb, &peeraddr)) { - goto drop; - } - - /* Get session */ - session = sc_capwap_getsession(&peeraddr); - if (!session) { - TRACEKMOD("*** Session not found\n"); - goto drop; - } - - /* Remove UDP header */ - if (!skb_pull(skb, sizeof(struct udphdr))) { - TRACEKMOD("*** Invalid packet\n"); - goto drop; - } - - /* Parsing packet */ - if (sc_capwap_parsingpacket(session, &peeraddr, skb)) { - TRACEKMOD("*** Parsing error\n"); - goto drop; - } - - return; - -drop: - kfree_skb(skb); -} - -/* */ -struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid) { - TRACEKMOD("### sc_capwap_recvunknownkeepalive\n"); - - return NULL; -} - -/* */ -void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) { - uint8_t* pos; - uint8_t* dstaddress; - struct net_device* dev; - struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; - int is80211 = (IS_FLAG_T_HEADER(header) ? 1 : 0); - struct sc_capwap_radio_addr* radioaddr = NULL; - int radioaddrsize = 0; - struct sc_capwap_wireless_information* winfo = NULL; - struct sc_capwap_destination_wlans* destwlan = NULL; - int winfosize = 0; - - TRACEKMOD("### sc_capwap_parsingdatapacket\n"); - - /* Retrieve optional attribute */ - pos = skb->data + sizeof(struct sc_capwap_header); - if (IS_FLAG_M_HEADER(header)) { - radioaddr = (struct sc_capwap_radio_addr*)pos; - radioaddrsize = (sizeof(struct sc_capwap_radio_addr) + radioaddr->length + 3) & ~3; - pos += radioaddrsize; - } - - if (IS_FLAG_W_HEADER(header)) { - winfo = (struct sc_capwap_wireless_information*)pos; - destwlan = (struct sc_capwap_destination_wlans*)(pos + sizeof(struct sc_capwap_wireless_information)); - winfosize = (sizeof(struct sc_capwap_wireless_information) + winfo->length + 3) & ~3; - pos += winfosize; - } - - /* Body packet */ - skb_pull(skb, GET_HLEN_HEADER(header) * 4); - - dstaddress = (is80211 ? ieee80211_get_DA((struct ieee80211_hdr*)skb->data) : (uint8_t*)((struct ethhdr*)skb->data)->h_dest); - if (is_multicast_ether_addr(dstaddress)) { - /* Accept only broadcast packet with wireless information */ - if (winfo) { - uint8_t wlanid = 1; - uint16_t bitmask = be16_to_cpu(destwlan->wlanidbitmap); - while (bitmask) { - if (bitmask & 0x01) { - dev = sc_netlink_getdev_from_wlanid(GET_RID_HEADER(header), wlanid); - if (dev) { - struct sk_buff* clone = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb), GFP_KERNEL); - if (!clone) { - goto error; - } - - /* */ - if (!is80211) { - if (sc_capwap_8023_to_80211(clone, dev->dev_addr)) { - kfree_skb(clone); - goto error; - } - } - - TRACEKMOD("*** Send broadcast packet to interface: %d\n", dev->ifindex); - - /* Send packet */ - local_bh_disable(); - ieee80211_inject_xmit(clone, dev); - local_bh_enable(); - } else { - TRACEKMOD("*** Unknown wlanid: %d\n", (int)wlanid); - } - } - - /* Next */ - wlanid++; - bitmask >>= 1; - } - } else { - TRACEKMOD("*** Invalid broadcast packet\n"); - } - - /* Free broadcast packet */ - kfree_skb(skb); - } else { - /* Accept only 802.11 frame or 802.3 frame with radio address */ - if (is80211 || (radioaddr && (radioaddr->length == MACADDRESS_EUI48_LENGTH))){ - if (!is80211) { - if (sc_capwap_8023_to_80211(skb, radioaddr->addr)) { - goto error; - } - } - - /* */ - dev = sc_netlink_getdev_from_bssid(GET_RID_HEADER(header), ((struct ieee80211_hdr*)skb->data)->addr2); - if (!dev) { - goto error; - } - - TRACEKMOD("** Send packet to interface: %d\n", dev->ifindex); - - /* Send packet */ - local_bh_disable(); - ieee80211_inject_xmit(skb, dev); - local_bh_enable(); - } else { - goto error; - } - } - - return; - -error: - TRACEKMOD("*** Invalid packet\n"); - kfree_skb(skb); -} - -/* */ -void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) { - TRACEKMOD("### sc_capwap_parsingmgmtpacket\n"); - - /* Send packet with capwap header into userspace */ - sc_netlink_notify_recv_data(skb->data, skb->len); -} +#include "config.h" +#include +#include +#include +#include +#include +#include +#include "capwap.h" +#include "nlsmartcapwap.h" +#include "netlinkapp.h" + +/* */ +static struct sc_capwap_session sc_acsession; + +/* */ +int sc_capwap_init(void) { + TRACEKMOD("### sc_capwap_init\n"); + + /* Init session */ + memset(&sc_acsession, 0, sizeof(struct sc_capwap_session)); + sc_capwap_initsession(&sc_acsession); + + /* Init sockect */ + memset(&sc_localaddr, 0, sizeof(union capwap_addr)); + return sc_socket_init(); +} + +/* */ +void sc_capwap_close(void) { + TRACEKMOD("### sc_capwap_close\n"); + + /* */ + sc_socket_close(); + memset(&sc_localaddr, 0, sizeof(union capwap_addr)); + sc_capwap_freesession(&sc_acsession); +} + +/* */ +int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu) { + TRACEKMOD("### sc_capwap_connect\n"); + + if ((sc_localaddr.ss.ss_family != AF_INET) && (sc_localaddr.ss.ss_family != AF_INET6)) { + return -ENONET; + } + + /* AC address */ + if ((sockaddr->ss.ss_family == AF_INET6) && ipv6_addr_v4mapped(&sockaddr->sin6.sin6_addr)) { + return -EINVAL; + } else if ((sc_localaddr.ss.ss_family == AF_INET) && (sockaddr->ss.ss_family == AF_INET6)) { + return -EINVAL; + } + + /* */ + memcpy(&sc_acsession.peeraddr, sockaddr, sizeof(union capwap_addr)); + memcpy(&sc_acsession.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element)); + sc_acsession.mtu = mtu; + + return sc_capwap_sendkeepalive(); +} + +/* */ +void sc_capwap_resetsession(void) { + TRACEKMOD("### sc_capwap_resetsession\n"); + + /* */ + sc_capwap_freesession(&sc_acsession); + + /* Reinit session */ + memset(&sc_acsession, 0, sizeof(struct sc_capwap_session)); + sc_capwap_initsession(&sc_acsession); +} + +/* */ +int sc_capwap_sendkeepalive(void) { + int ret; + int length; + uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE]; + + TRACEKMOD("### sc_capwap_sendkeepalive\n"); + + /* Build keepalive */ + length = sc_capwap_createkeepalive(&sc_acsession.sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE); + + /* Send packet */ + ret = sc_socket_send(SOCKET_UDP, buffer, length, &sc_acsession.peeraddr); + TRACEKMOD("*** Send keep-alive result: %d\n", ret); + if (ret > 0) { + ret = 0; + } + + return ret; +} + +/* */ +struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr) { + TRACEKMOD("### sc_capwap_getsession\n"); + + if (!sockaddr) { + return &sc_acsession; + } else if (sc_acsession.peeraddr.ss.ss_family == sockaddr->ss.ss_family) { + if (sc_acsession.peeraddr.ss.ss_family == AF_INET) { + if ((sc_acsession.peeraddr.sin.sin_port == sockaddr->sin.sin_port) && (sc_acsession.peeraddr.sin.sin_addr.s_addr == sockaddr->sin.sin_addr.s_addr)) { + return &sc_acsession; + } + } else if (sc_acsession.peeraddr.ss.ss_family == AF_INET6) { + if ((sc_acsession.peeraddr.sin6.sin6_port == sockaddr->sin6.sin6_port) && !ipv6_addr_cmp(&sc_acsession.peeraddr.sin6.sin6_addr, &sockaddr->sin6.sin6_addr)) { + return &sc_acsession; + } + } + } + + return NULL; +} + +/* */ +void sc_capwap_recvpacket(struct sk_buff* skb) { + union capwap_addr peeraddr; + struct sc_capwap_session* session; + + TRACEKMOD("### sc_capwap_recvpacket\n"); + + /* Get peer address */ + if (sc_socket_getpeeraddr(skb, &peeraddr)) { + goto drop; + } + + /* Get session */ + session = sc_capwap_getsession(&peeraddr); + if (!session) { + TRACEKMOD("*** Session not found\n"); + goto drop; + } + + /* Remove UDP header */ + if (!skb_pull(skb, sizeof(struct udphdr))) { + TRACEKMOD("*** Invalid packet\n"); + goto drop; + } + + /* Parsing packet */ + if (sc_capwap_parsingpacket(session, &peeraddr, skb)) { + TRACEKMOD("*** Parsing error\n"); + goto drop; + } + + return; + +drop: + kfree_skb(skb); +} + +/* */ +struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid) { + TRACEKMOD("### sc_capwap_recvunknownkeepalive\n"); + + return NULL; +} + +/* */ +void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) { + uint8_t* pos; + uint8_t* dstaddress; + struct net_device* dev; + struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data; + int is80211 = (IS_FLAG_T_HEADER(header) ? 1 : 0); + struct sc_capwap_radio_addr* radioaddr = NULL; + int radioaddrsize = 0; + struct sc_capwap_wireless_information* winfo = NULL; + struct sc_capwap_destination_wlans* destwlan = NULL; + int winfosize = 0; + + TRACEKMOD("### sc_capwap_parsingdatapacket\n"); + + /* Retrieve optional attribute */ + pos = skb->data + sizeof(struct sc_capwap_header); + if (IS_FLAG_M_HEADER(header)) { + radioaddr = (struct sc_capwap_radio_addr*)pos; + radioaddrsize = (sizeof(struct sc_capwap_radio_addr) + radioaddr->length + 3) & ~3; + pos += radioaddrsize; + } + + if (IS_FLAG_W_HEADER(header)) { + winfo = (struct sc_capwap_wireless_information*)pos; + destwlan = (struct sc_capwap_destination_wlans*)(pos + sizeof(struct sc_capwap_wireless_information)); + winfosize = (sizeof(struct sc_capwap_wireless_information) + winfo->length + 3) & ~3; + pos += winfosize; + } + + /* Body packet */ + skb_pull(skb, GET_HLEN_HEADER(header) * 4); + + dstaddress = (is80211 ? ieee80211_get_DA((struct ieee80211_hdr*)skb->data) : (uint8_t*)((struct ethhdr*)skb->data)->h_dest); + if (is_multicast_ether_addr(dstaddress)) { + /* Accept only broadcast packet with wireless information */ + if (winfo) { + uint8_t wlanid = 1; + uint16_t bitmask = be16_to_cpu(destwlan->wlanidbitmap); + while (bitmask) { + if (bitmask & 0x01) { + dev = sc_netlink_getdev_from_wlanid(GET_RID_HEADER(header), wlanid); + if (dev) { + struct sk_buff* clone = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb), GFP_KERNEL); + if (!clone) { + goto error; + } + + /* */ + if (!is80211) { + if (sc_capwap_8023_to_80211(clone, dev->dev_addr)) { + kfree_skb(clone); + goto error; + } + } + + TRACEKMOD("*** Send broadcast packet to interface: %d\n", dev->ifindex); + + /* Send packet */ + local_bh_disable(); + ieee80211_inject_xmit(clone, dev); + local_bh_enable(); + } else { + TRACEKMOD("*** Unknown wlanid: %d\n", (int)wlanid); + } + } + + /* Next */ + wlanid++; + bitmask >>= 1; + } + } else { + TRACEKMOD("*** Invalid broadcast packet\n"); + } + + /* Free broadcast packet */ + kfree_skb(skb); + } else { + /* Accept only 802.11 frame or 802.3 frame with radio address */ + if (is80211 || (radioaddr && (radioaddr->length == MACADDRESS_EUI48_LENGTH))){ + if (!is80211) { + if (sc_capwap_8023_to_80211(skb, radioaddr->addr)) { + goto error; + } + } + + /* */ + dev = sc_netlink_getdev_from_bssid(GET_RID_HEADER(header), ((struct ieee80211_hdr*)skb->data)->addr2); + if (!dev) { + goto error; + } + + TRACEKMOD("** Send packet to interface: %d\n", dev->ifindex); + + /* Send packet */ + local_bh_disable(); + ieee80211_inject_xmit(skb, dev); + local_bh_enable(); + } else { + goto error; + } + } + + return; + +error: + TRACEKMOD("*** Invalid packet\n"); + kfree_skb(skb); +} + +/* */ +void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) { + TRACEKMOD("### sc_capwap_parsingmgmtpacket\n"); + + /* Send packet with capwap header into userspace */ + sc_netlink_notify_recv_data(skb->data, skb->len); +} diff --git a/src/wtp/kmod/capwap_private.h b/src/wtp/kmod/capwap_private.h index ad4c70a..845efbb 100644 --- a/src/wtp/kmod/capwap_private.h +++ b/src/wtp/kmod/capwap_private.h @@ -1,27 +1,27 @@ -#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__ -#define __KMOD_CAPWAP_PRIVATE_HEADER__ - -/* */ -struct sc_capwap_workthread { - struct task_struct* thread; - - struct sk_buff_head queue; - wait_queue_head_t waitevent; -}; - -/* */ -int sc_capwap_init(void); -void sc_capwap_close(void); - -/* */ -int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu); -void sc_capwap_resetsession(void); - -/* */ -struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr); - -/* */ -int sc_capwap_sendkeepalive(void); - -#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */ - +#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__ +#define __KMOD_CAPWAP_PRIVATE_HEADER__ + +/* */ +struct sc_capwap_workthread { + struct task_struct* thread; + + struct sk_buff_head queue; + wait_queue_head_t waitevent; +}; + +/* */ +int sc_capwap_init(void); +void sc_capwap_close(void); + +/* */ +int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu); +void sc_capwap_resetsession(void); + +/* */ +struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr); + +/* */ +int sc_capwap_sendkeepalive(void); + +#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */ + diff --git a/src/wtp/kmod/capwap_rfc.h b/src/wtp/kmod/capwap_rfc.h index 84b81aa..6981ac2 100644 --- a/src/wtp/kmod/capwap_rfc.h +++ b/src/wtp/kmod/capwap_rfc.h @@ -1,187 +1,187 @@ -#ifndef __KMOD_CAPWAP_RFC_HEADER__ -#define __KMOD_CAPWAP_RFC_HEADER__ - -#include -#include - -/* */ -#define CAPWAP_RADIOID_MAX_COUNT 31 -#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT)) - -#define CAPWAP_WLANID_MAX_COUNT 16 -#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT)) - -/* */ -#define CAPWAP_WIRELESS_BINDING_NONE 0 -#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 - -/* */ -#define CAPWAP_ELEMENT_SESSIONID 35 - -/* */ -#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \ - sizeof(struct sc_capwap_header) + \ - sizeof(struct sc_capwap_data_message) + \ - sizeof(struct sc_capwap_message_element) + \ - sizeof(struct sc_capwap_sessionid_element)) - -/* Preamble */ -struct sc_capwap_preamble { -#if defined(__BIG_ENDIAN_BITFIELD) - uint8_t version: 4, - type: 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - uint8_t type: 4, - version: 4; -#endif -} __packed; - -/* DTLS header */ -struct sc_capwap_dtls_header { - struct sc_capwap_preamble preamble; - uint8_t reserved[3]; -} __packed; - -/* Plain header */ -struct sc_capwap_header { - struct sc_capwap_preamble preamble; -#if defined(__BIG_ENDIAN_BITFIELD) - uint16_t hlen: 5, - rid: 5, - wbid: 5, - flag_t: 1; - uint8_t flag_f: 1, - flag_l: 1, - flag_w: 1, - flag_m: 1, - flag_k: 1, - flag_res: 3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - uint16_t _rid_hi: 3, - hlen: 5, - flag_t: 1, - wbid: 5, - _rid_lo: 2; - uint8_t flag_res: 3, - flag_k: 1, - flag_m: 1, - flag_w: 1, - flag_l: 1, - flag_f: 1; -#endif - __be16 frag_id; - __be16 frag_off; -} __packed; - -/* Mac Address */ -#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8 -#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12 -#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12 -struct sc_capwap_radio_addr { - uint8_t length; - uint8_t addr[0]; -} __packed; - -/* Wireless Information */ -#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8 -#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8 -#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8 -struct sc_capwap_wireless_information { - uint8_t length; -} __packed; - -/* IEEE802.11 Wireless Information */ -struct sc_capwap_ieee80211_frame_info { - uint8_t rssi; - uint8_t snr; - __be16 rate; -} __packed; - -/* Destination WLANs */ -struct sc_capwap_destination_wlans { - __be16 wlanidbitmap; - __be16 reserved; -} __packed; - -/* */ -#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED) - -/* Data channel message */ -struct sc_capwap_data_message { - __be16 length; -} __packed; - -/* Message element */ -struct sc_capwap_message_element { - __be16 type; - __be16 length; -} __packed; - -/* Session id message element */ -struct sc_capwap_sessionid_element { - union { - uint8_t id[16]; - uint32_t id32[4]; - }; -} __packed; - -/* */ -#define MACADDRESS_EUI48_LENGTH 6 -struct sc_capwap_macaddress_eui48 { - uint8_t addr[MACADDRESS_EUI48_LENGTH]; -} __packed; - -/* */ -#define MACADDRESS_EUI64_LENGTH 8 -struct sc_capwap_macaddress_eui64 { - uint8_t addr[MACADDRESS_EUI64_LENGTH]; -} __packed; - -/* Capwap preamble */ -#define CAPWAP_PROTOCOL_VERSION 0 -#define CAPWAP_PREAMBLE_HEADER 0 -#define CAPWAP_PREAMBLE_DTLS_HEADER 1 - -#define CAPWAP_WIRELESS_BINDING_NONE 0 -#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 - -/* */ -#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)) - -/* */ -#define GET_VERSION_HEADER(x) ((x)->preamble.version) -#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y)) -#define GET_TYPE_HEADER(x) ((x)->preamble.type) -#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y)) - -#define GET_HLEN_HEADER(x) ((x)->hlen) -#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y)) -#if defined(__BIG_ENDIAN_BITFIELD) - #define GET_RID_HEADER(x) ((uint8_t)((x)->rid)) - #define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y)) -#elif defined(__LITTLE_ENDIAN_BITFIELD) - #define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo))) - #define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); }) -#endif -#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid)) -#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y)) - -#define IS_FLAG_T_HEADER(x) ((x)->flag_t) -#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0)) -#define IS_FLAG_F_HEADER(x) ((x)->flag_f) -#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0)) -#define IS_FLAG_L_HEADER(x) ((x)->flag_l) -#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0)) -#define IS_FLAG_W_HEADER(x) ((x)->flag_w) -#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0)) -#define IS_FLAG_M_HEADER(x) ((x)->flag_m) -#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0)) -#define IS_FLAG_K_HEADER(x) ((x)->flag_k) -#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0)) - -/* IEEE 802.11 Add WLAN */ -#define CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL 0 -#define CAPWAP_ADD_WLAN_TUNNELMODE_8023 1 -#define CAPWAP_ADD_WLAN_TUNNELMODE_80211 2 - -#endif /* __KMOD_CAPWAP_RFC_HEADER__ */ +#ifndef __KMOD_CAPWAP_RFC_HEADER__ +#define __KMOD_CAPWAP_RFC_HEADER__ + +#include +#include + +/* */ +#define CAPWAP_RADIOID_MAX_COUNT 31 +#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT)) + +#define CAPWAP_WLANID_MAX_COUNT 16 +#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT)) + +/* */ +#define CAPWAP_WIRELESS_BINDING_NONE 0 +#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 + +/* */ +#define CAPWAP_ELEMENT_SESSIONID 35 + +/* */ +#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \ + sizeof(struct sc_capwap_header) + \ + sizeof(struct sc_capwap_data_message) + \ + sizeof(struct sc_capwap_message_element) + \ + sizeof(struct sc_capwap_sessionid_element)) + +/* Preamble */ +struct sc_capwap_preamble { +#if defined(__BIG_ENDIAN_BITFIELD) + uint8_t version: 4, + type: 4; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + uint8_t type: 4, + version: 4; +#endif +} __packed; + +/* DTLS header */ +struct sc_capwap_dtls_header { + struct sc_capwap_preamble preamble; + uint8_t reserved[3]; +} __packed; + +/* Plain header */ +struct sc_capwap_header { + struct sc_capwap_preamble preamble; +#if defined(__BIG_ENDIAN_BITFIELD) + uint16_t hlen: 5, + rid: 5, + wbid: 5, + flag_t: 1; + uint8_t flag_f: 1, + flag_l: 1, + flag_w: 1, + flag_m: 1, + flag_k: 1, + flag_res: 3; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + uint16_t _rid_hi: 3, + hlen: 5, + flag_t: 1, + wbid: 5, + _rid_lo: 2; + uint8_t flag_res: 3, + flag_k: 1, + flag_m: 1, + flag_w: 1, + flag_l: 1, + flag_f: 1; +#endif + __be16 frag_id; + __be16 frag_off; +} __packed; + +/* Mac Address */ +#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8 +#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12 +#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12 +struct sc_capwap_radio_addr { + uint8_t length; + uint8_t addr[0]; +} __packed; + +/* Wireless Information */ +#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8 +#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8 +#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8 +struct sc_capwap_wireless_information { + uint8_t length; +} __packed; + +/* IEEE802.11 Wireless Information */ +struct sc_capwap_ieee80211_frame_info { + uint8_t rssi; + uint8_t snr; + __be16 rate; +} __packed; + +/* Destination WLANs */ +struct sc_capwap_destination_wlans { + __be16 wlanidbitmap; + __be16 reserved; +} __packed; + +/* */ +#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED) + +/* Data channel message */ +struct sc_capwap_data_message { + __be16 length; +} __packed; + +/* Message element */ +struct sc_capwap_message_element { + __be16 type; + __be16 length; +} __packed; + +/* Session id message element */ +struct sc_capwap_sessionid_element { + union { + uint8_t id[16]; + uint32_t id32[4]; + }; +} __packed; + +/* */ +#define MACADDRESS_EUI48_LENGTH 6 +struct sc_capwap_macaddress_eui48 { + uint8_t addr[MACADDRESS_EUI48_LENGTH]; +} __packed; + +/* */ +#define MACADDRESS_EUI64_LENGTH 8 +struct sc_capwap_macaddress_eui64 { + uint8_t addr[MACADDRESS_EUI64_LENGTH]; +} __packed; + +/* Capwap preamble */ +#define CAPWAP_PROTOCOL_VERSION 0 +#define CAPWAP_PREAMBLE_HEADER 0 +#define CAPWAP_PREAMBLE_DTLS_HEADER 1 + +#define CAPWAP_WIRELESS_BINDING_NONE 0 +#define CAPWAP_WIRELESS_BINDING_IEEE80211 1 + +/* */ +#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element)) + +/* */ +#define GET_VERSION_HEADER(x) ((x)->preamble.version) +#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y)) +#define GET_TYPE_HEADER(x) ((x)->preamble.type) +#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y)) + +#define GET_HLEN_HEADER(x) ((x)->hlen) +#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y)) +#if defined(__BIG_ENDIAN_BITFIELD) + #define GET_RID_HEADER(x) ((uint8_t)((x)->rid)) + #define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y)) +#elif defined(__LITTLE_ENDIAN_BITFIELD) + #define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo))) + #define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); }) +#endif +#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid)) +#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y)) + +#define IS_FLAG_T_HEADER(x) ((x)->flag_t) +#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0)) +#define IS_FLAG_F_HEADER(x) ((x)->flag_f) +#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0)) +#define IS_FLAG_L_HEADER(x) ((x)->flag_l) +#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0)) +#define IS_FLAG_W_HEADER(x) ((x)->flag_w) +#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0)) +#define IS_FLAG_M_HEADER(x) ((x)->flag_m) +#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0)) +#define IS_FLAG_K_HEADER(x) ((x)->flag_k) +#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0)) + +/* IEEE 802.11 Add WLAN */ +#define CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL 0 +#define CAPWAP_ADD_WLAN_TUNNELMODE_8023 1 +#define CAPWAP_ADD_WLAN_TUNNELMODE_80211 2 + +#endif /* __KMOD_CAPWAP_RFC_HEADER__ */ diff --git a/src/wtp/kmod/config.h b/src/wtp/kmod/config.h index 207855b..d4c3990 100644 --- a/src/wtp/kmod/config.h +++ b/src/wtp/kmod/config.h @@ -1,13 +1,13 @@ -#ifndef __KMOD_CONFIG_HEADER__ -#define __KMOD_CONFIG_HEADER__ - -#define DEBUGKMOD 1 - -#ifdef DEBUGKMOD -#define TRACEKMOD(s, args...) printk(s, ##args) -#else -#define TRACEKMOD(s, args...) -#endif - -#endif /* __KMOD_CONFIG_HEADER__ */ - +#ifndef __KMOD_CONFIG_HEADER__ +#define __KMOD_CONFIG_HEADER__ + +#define DEBUGKMOD 1 + +#ifdef DEBUGKMOD +#define TRACEKMOD(s, args...) printk(s, ##args) +#else +#define TRACEKMOD(s, args...) +#endif + +#endif /* __KMOD_CONFIG_HEADER__ */ + diff --git a/src/wtp/kmod/netlinkapp.c b/src/wtp/kmod/netlinkapp.c index 8ddcc86..1a3cdc9 100644 --- a/src/wtp/kmod/netlinkapp.c +++ b/src/wtp/kmod/netlinkapp.c @@ -1,803 +1,803 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nlsmartcapwap.h" -#include "netlinkapp.h" -#include "capwap.h" - -/* */ -struct sc_netlink_device { - struct list_head list; - struct ieee80211_pcktunnel pcktunnel_handler; - - uint32_t ifindex; - uint8_t radioid; - uint8_t wlanid; - uint8_t binding; - struct net_device* dev; - uint32_t flags; -}; - -/* */ -static uint32_t sc_netlink_usermodeid; -static LIST_HEAD(sc_netlink_dev_list); - -/* */ -static int sc_netlink_pre_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_pre_doit\n"); - - rtnl_lock(); - return 0; -} - -/* */ -static void sc_netlink_post_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_post_doit\n"); - - rtnl_unlock(); -} - -/* Netlink Family */ -static struct genl_family sc_netlink_family = { - .id = GENL_ID_GENERATE, - .name = NLSMARTCAPWAP_GENL_NAME, - .hdrsize = 0, - .version = 1, - .maxattr = NLSMARTCAPWAP_ATTR_MAX, - .netnsok = true, - .pre_doit = sc_netlink_pre_doit, - .post_doit = sc_netlink_post_doit, -}; - -/* */ -static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) { - int ret = 0; - struct sc_netlink_device* nldev = (struct sc_netlink_device*)data; - struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; - - TRACEKMOD("### sc_netlink_handler\n"); - - /* IEEE802.11 Data Packet */ - if (ieee80211_is_data(hdr->frame_control)) { - int err; - struct sc_capwap_session* session; - uint8_t radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED]; - uint8_t winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED]; - struct sc_capwap_radio_addr* radioaddr = NULL; - struct sc_capwap_wireless_information* winfo = NULL; - - /* Drop packet */ - ret = -1; - - /* */ - session = sc_capwap_getsession(NULL); - if (!session) { - goto error; - } - - /* IEEE 802.11 into IEEE 802.3 */ - if (nldev->flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) { - if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP)) { - goto error; - } - - /* Create Radio Mac Address */ - radioaddr = sc_capwap_setradiomacaddress(radioaddrbuffer, CAPWAP_RADIO_EUI48_LENGTH_PADDED, nldev->dev->dev_addr); - } - - /* Create Wireless Information */ - if (sig_dbm || rate) { - winfo = sc_capwap_setwinfo_frameinfo(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, (uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5); - } - - /* */ - CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_IEEE80211; - - /* Forward to AC */ - err = sc_capwap_forwarddata(session, nldev->radioid, nldev->binding, skb, nldev->flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0)); - } - -error: - return ret; -} - -/* */ -static struct sc_netlink_device* sc_netlink_new_device(uint32_t ifindex, uint8_t radioid, u8 wlanid, uint8_t binding) { - struct net_device* dev; - struct sc_netlink_device* nldev; - - TRACEKMOD("### sc_netlink_new_device\n"); - - /* Retrieve device from ifindex */ - dev = dev_get_by_index(&init_net, ifindex); - if (!dev) { - return NULL; - } - - /* Check if wireless device */ - if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) { - dev_put(dev); - return NULL; - } - - /* Create device */ - nldev = (struct sc_netlink_device*)kzalloc(sizeof(struct sc_netlink_device), GFP_KERNEL); - if (!nldev) { - dev_put(dev); - return NULL; - } - - /* Initialize device */ - nldev->pcktunnel_handler.handler = sc_netlink_handler; - nldev->pcktunnel_handler.data = (void*)nldev; - nldev->ifindex = ifindex; - nldev->radioid = radioid; - nldev->wlanid = wlanid; - nldev->binding = binding; - nldev->dev = dev; - - return nldev; -} - -/* */ -static void sc_netlink_free_device(struct sc_netlink_device* nldev) { - TRACEKMOD("### sc_netlink_free_device\n"); - - /* Disconnect device from mac80211 */ - ieee80211_pcktunnel_deregister(nldev->dev, &nldev->pcktunnel_handler); - - /* */ - dev_put(nldev->dev); - - /* Free memory */ - kfree(nldev); -} - -/* */ -static struct sc_netlink_device* sc_netlink_register_device(uint32_t ifindex, uint8_t radioid, uint16_t wlanid, uint8_t binding) { - struct sc_netlink_device* nldev; - - TRACEKMOD("### sc_netlink_register_device\n"); - - ASSERT_RTNL(); - - /* */ - if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { - return NULL; - } - - /* Search device */ - list_for_each_entry(nldev, &sc_netlink_dev_list, list) { - if (nldev->ifindex == ifindex) { - return NULL; - } - } - - /* Create device */ - nldev = sc_netlink_new_device(ifindex, radioid, wlanid, binding); - if (nldev) { - list_add_rcu(&nldev->list, &sc_netlink_dev_list); - } - - return nldev; -} - -/* */ -static int sc_netlink_unregister_device(uint32_t ifindex) { - int ret = -ENODEV; - struct sc_netlink_device* nldev; - - TRACEKMOD("### sc_netlink_unregister_device\n"); - - ASSERT_RTNL(); - - /* Search device */ - list_for_each_entry(nldev, &sc_netlink_dev_list, list) { - if (nldev->ifindex == ifindex) { - /* Remove from list */ - list_del_rcu(&nldev->list); - synchronize_net(); - - /* Free device */ - ret = 0; - sc_netlink_free_device(nldev); - break; - } - } - - return ret; -} - -/* */ -static void sc_netlink_unregister_alldevice(void) { - struct sc_netlink_device* tmp; - struct sc_netlink_device* nldev; - - TRACEKMOD("### sc_netlink_unregister_alldevice\n"); - - ASSERT_RTNL(); - - /* Close all devices */ - list_for_each_entry_safe(nldev, tmp, &sc_netlink_dev_list, list) { - /* Remove from list */ - list_del_rcu(&nldev->list); - synchronize_net(); - - /* Free device */ - sc_netlink_free_device(nldev); - } -} - -/* */ -static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) { - int ret; - uint32_t portid = genl_info_snd_portid(info); - - TRACEKMOD("### sc_netlink_link\n"); - - /* */ - if (sc_netlink_usermodeid) { - TRACEKMOD("*** Busy kernel link\n"); - return -EBUSY; - } - - /* Initialize library */ - ret = sc_capwap_init(); - if (ret) { - return ret; - } - - /* Deny unload module */ - sc_netlink_usermodeid = portid; - try_module_get(THIS_MODULE); - - return 0; -} - -/* */ -static int sc_netlink_reset(struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_reset\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Close all devices */ - sc_netlink_unregister_alldevice(); - - /* Reset session */ - sc_capwap_resetsession(); - - return 0; -} - -/* */ -static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) { - struct netlink_notify* notify = (struct netlink_notify*)_notify; - - if ((state == NETLINK_URELEASE) && (sc_netlink_usermodeid == netlink_notify_portid(notify))) { - rtnl_lock(); - - sc_netlink_usermodeid = 0; - - /* Close all devices */ - sc_netlink_unregister_alldevice(); - - /* Close capwap engine */ - sc_capwap_close(); - - /* Allow unload module */ - module_put(THIS_MODULE); - - rtnl_unlock(); - } - - return NOTIFY_DONE; -} - -/* */ -static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) { - union capwap_addr sockaddr; - - TRACEKMOD("### sc_netlink_bind\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Get bind address */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) { - return -EINVAL; - } - - memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage)); - if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) { - return -EINVAL; - } - - /* Bind socket */ - return sc_capwap_bind(&sockaddr); -} - -/* */ -static int sc_netlink_connect(struct sk_buff* skb, struct genl_info* info) { - int ret; - union capwap_addr sockaddr; - struct sc_capwap_sessionid_element sessionid; - uint16_t mtu = DEFAULT_MTU; - - TRACEKMOD("### sc_netlink_connect\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Get AC address */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) { - return -EINVAL; - } - - memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage)); - if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) { - return -EINVAL; - } - - /* Get MTU */ - if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) { - mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]); - if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) { - return -EINVAL; - } - } - - /* Get Session ID */ - if (info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] && (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) == sizeof(struct sc_capwap_sessionid_element))) { - memcpy(sessionid.id, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), sizeof(struct sc_capwap_sessionid_element)); - } else { - return -EINVAL; - } - - /* Send packet */ - ret = sc_capwap_connect(&sockaddr, &sessionid, mtu); - if (ret < 0) { - return ret; - } - - return 0; -} - -/* */ -static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) { - int ret; - - TRACEKMOD("### sc_netlink_send_keepalive\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Send packet */ - ret = sc_capwap_sendkeepalive(); - if (ret < 0) { - return ret; - } - - return 0; -} - -/* */ -static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) { - int ret; - uint8_t radioid; - uint8_t binding; - uint8_t rssi = 0; - uint8_t snr = 0; - uint16_t rate = 0; - int length; - struct sk_buff* skbdata; - struct sc_capwap_session* session; - unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED]; - struct sc_capwap_wireless_information* winfo = NULL; - - TRACEKMOD("### sc_netlink_send_data\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } else if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { - return -EINVAL; - } - - /* */ - session = sc_capwap_getsession(NULL); - if (!session) { - return -ENOLINK; - } - - /* Get radioid */ - radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); - if (!IS_VALID_RADIOID(radioid) || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) { - return -EINVAL; - } - - /* Get binding */ - binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]); - - /* Get RSSI */ - if (info->attrs[NLSMARTCAPWAP_ATTR_RSSI]) { - rssi = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RSSI]); - } - - /* Get SNR */ - if (info->attrs[NLSMARTCAPWAP_ATTR_SNR]) { - snr = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_SNR]); - } - - /* Get RATE */ - if (info->attrs[NLSMARTCAPWAP_ATTR_RATE]) { - rate = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RATE]); - } - - /* Create Wireless Information */ - if (rssi || snr || rate) { - winfo = sc_capwap_setwinfo_frameinfo(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, rssi, snr, rate); - } - - /* Create socket buffer */ - length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]); - skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL); - if (!skbdata) { - return -ENOMEM; - } - - /* Reserve space for Capwap Header */ - skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH); - - /* Copy data into socket buffer */ - memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length); - - /* */ - CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE; - - /* Send packet */ - ret = sc_capwap_forwarddata(session, radioid, binding, skbdata, 0, NULL, 0, winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0)); - if (ret) { - TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n"); - } - - kfree_skb(skbdata); - return ret; -} - -/* */ -static int sc_netlink_join_mac80211_device(struct sk_buff* skb, struct genl_info* info) { - int ret; - uint32_t ifindex; - struct sc_netlink_device* nldev; - - TRACEKMOD("### sc_netlink_join_mac80211_device\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Get interface index */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) { - return -EINVAL; - } - - ifindex = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]); - if (!ifindex) { - return -EINVAL; - } - - /* Check */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) { - return -EINVAL; - } - - /* Register device */ - nldev = sc_netlink_register_device(ifindex, nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING])); - if (!nldev) { - return -EINVAL; - } - - /* */ - if (info->attrs[NLSMARTCAPWAP_ATTR_FLAGS]) { - nldev->flags = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_FLAGS]); - } - - /* Set subtype masking */ - if (info->attrs[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK]) { - nldev->pcktunnel_handler.subtype_mask[0] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK]); - } - - if (info->attrs[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK]) { - nldev->pcktunnel_handler.subtype_mask[1] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK]); - } - - if (info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]) { - nldev->pcktunnel_handler.subtype_mask[2] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]); - } - - /* Connect device to mac80211 */ - ret = ieee80211_pcktunnel_register(nldev->dev, &nldev->pcktunnel_handler); - if (ret) { - sc_netlink_unregister_device(ifindex); - } - - return ret; -} - -/* */ -static int sc_netlink_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) { - TRACEKMOD("### sc_netlink_leave_mac80211_device\n"); - - /* Check Link */ - if (!sc_netlink_usermodeid) { - return -ENOLINK; - } - - /* Get interface index */ - if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) { - return -EINVAL; - } - - /* Unregister device */ - return sc_netlink_unregister_device(nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX])); -} - -/* */ -static int sc_device_event(struct notifier_block* unused, unsigned long event, void* ptr) { - struct net_device* dev = netdev_notifier_info_to_dev(ptr); - - /* Check event only if connect with WTP userspace */ - if (!sc_netlink_usermodeid) { - return NOTIFY_DONE; - } - - /* */ - switch (event) { - case NETDEV_UNREGISTER: { - /* Try to unregister device */ - sc_netlink_unregister_device(dev->ifindex); - break; - } - } - - return NOTIFY_DONE; -} - -/* */ -static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = { - [NLSMARTCAPWAP_ATTR_IFINDEX] = { .type = NLA_U32 }, - [NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_WLANID] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 }, - [NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 }, - [NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 }, - [NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 }, - [NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) }, - [NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 }, - [NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) }, - [NLSMARTCAPWAP_ATTR_DTLS] = { .type = NLA_U16 }, - [NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MTU }, - [NLSMARTCAPWAP_ATTR_RSSI] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_SNR] = { .type = NLA_U8 }, - [NLSMARTCAPWAP_ATTR_RATE] = { .type = NLA_U16 }, - -}; - -/* Netlink Ops */ -static __genl_const struct genl_ops sc_netlink_ops[] = { - { - .cmd = NLSMARTCAPWAP_CMD_LINK, - .doit = sc_netlink_link, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_BIND, - .doit = sc_netlink_bind, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_CONNECT, - .doit = sc_netlink_connect, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_RESET, - .doit = sc_netlink_reset, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, - .doit = sc_netlink_send_keepalive, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_SEND_DATA, - .doit = sc_netlink_send_data, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, - .doit = sc_netlink_join_mac80211_device, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, - .doit = sc_netlink_leave_mac80211_device, - .policy = sc_netlink_policy, - .flags = GENL_ADMIN_PERM, - }, -}; - -/* Netlink notify */ -static struct notifier_block sc_netlink_notifier = { - .notifier_call = sc_netlink_notify, -}; - -/* Interface notify */ -struct notifier_block sc_device_notifier = { - .notifier_call = sc_device_event -}; - -/* */ -int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) { - void* msg; - struct sk_buff* sk_msg; - - TRACEKMOD("### sc_netlink_notify_recv_keepalive\n"); - - /* Alloc message */ - sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!sk_msg) { - return -ENOMEM; - } - - /* Set command */ - msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE); - if (!msg) { - nlmsg_free(sk_msg); - return -ENOMEM; - } - - /* Send message */ - genlmsg_end(sk_msg, msg); - return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); -} - -/* */ -int sc_netlink_notify_recv_data(uint8_t* packet, int length) { - void* msg; - struct sk_buff* sk_msg; - - TRACEKMOD("### sc_netlink_notify_recv_data\n"); - - /* Alloc message */ - sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (!sk_msg) { - return -ENOMEM; - } - - /* Set command */ - msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA); - if (!msg) { - goto error; - } - - /* */ - if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) { - goto error2; - } - - /* Send message */ - genlmsg_end(sk_msg, msg); - return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); - -error2: - genlmsg_cancel(sk_msg, msg); - -error: - nlmsg_free(sk_msg); - return -ENOMEM; -} - -/* */ -struct net_device* sc_netlink_getdev_from_wlanid(uint8_t radioid, uint8_t wlanid) { - struct sc_netlink_device* nldev; - - TRACEKMOD("### sc_netlink_getdev_from_wlanid\n"); - - /* Search */ - list_for_each_entry(nldev, &sc_netlink_dev_list, list) { - if ((nldev->radioid == radioid) && (nldev->wlanid == wlanid)) { - return nldev->dev; - } - } - - return NULL; -} - -/* */ -struct net_device* sc_netlink_getdev_from_bssid(uint8_t radioid, const uint8_t* addr) { - struct sc_netlink_device* nldev; - - TRACEKMOD("### sc_netlink_getdev_from_bssid\n"); - - /* Search */ - list_for_each_entry(nldev, &sc_netlink_dev_list, list) { - if ((nldev->radioid == radioid) && !memcmp(nldev->dev->dev_addr, addr, MACADDRESS_EUI48_LENGTH)) { - return nldev->dev; - } - } - - return NULL; -} - -/* */ -int sc_netlink_init(void) { - int ret; - - TRACEKMOD("### sc_netlink_init\n"); - - /* */ - sc_netlink_usermodeid = 0; - - /* Register interface event */ - ret = register_netdevice_notifier(&sc_device_notifier); - if (ret) { - goto error; - } - - /* Register netlink family */ - ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops); - if (ret) { - goto error2; - } - - /* Register netlink notifier */ - ret = netlink_register_notifier(&sc_netlink_notifier); - if (ret) { - goto error3; - } - - return 0; - -error3: - genl_unregister_family(&sc_netlink_family); -error2: - unregister_netdevice_notifier(&sc_device_notifier); -error: - return ret; -} - -/* */ -void sc_netlink_exit(void) { - TRACEKMOD("### sc_netlink_exit\n"); - - netlink_unregister_notifier(&sc_netlink_notifier); - genl_unregister_family(&sc_netlink_family); - unregister_netdevice_notifier(&sc_device_notifier); -} +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nlsmartcapwap.h" +#include "netlinkapp.h" +#include "capwap.h" + +/* */ +struct sc_netlink_device { + struct list_head list; + struct ieee80211_pcktunnel pcktunnel_handler; + + uint32_t ifindex; + uint8_t radioid; + uint8_t wlanid; + uint8_t binding; + struct net_device* dev; + uint32_t flags; +}; + +/* */ +static uint32_t sc_netlink_usermodeid; +static LIST_HEAD(sc_netlink_dev_list); + +/* */ +static int sc_netlink_pre_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_pre_doit\n"); + + rtnl_lock(); + return 0; +} + +/* */ +static void sc_netlink_post_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_post_doit\n"); + + rtnl_unlock(); +} + +/* Netlink Family */ +static struct genl_family sc_netlink_family = { + .id = GENL_ID_GENERATE, + .name = NLSMARTCAPWAP_GENL_NAME, + .hdrsize = 0, + .version = 1, + .maxattr = NLSMARTCAPWAP_ATTR_MAX, + .netnsok = true, + .pre_doit = sc_netlink_pre_doit, + .post_doit = sc_netlink_post_doit, +}; + +/* */ +static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) { + int ret = 0; + struct sc_netlink_device* nldev = (struct sc_netlink_device*)data; + struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; + + TRACEKMOD("### sc_netlink_handler\n"); + + /* IEEE802.11 Data Packet */ + if (ieee80211_is_data(hdr->frame_control)) { + int err; + struct sc_capwap_session* session; + uint8_t radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED]; + uint8_t winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED]; + struct sc_capwap_radio_addr* radioaddr = NULL; + struct sc_capwap_wireless_information* winfo = NULL; + + /* Drop packet */ + ret = -1; + + /* */ + session = sc_capwap_getsession(NULL); + if (!session) { + goto error; + } + + /* IEEE 802.11 into IEEE 802.3 */ + if (nldev->flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) { + if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP)) { + goto error; + } + + /* Create Radio Mac Address */ + radioaddr = sc_capwap_setradiomacaddress(radioaddrbuffer, CAPWAP_RADIO_EUI48_LENGTH_PADDED, nldev->dev->dev_addr); + } + + /* Create Wireless Information */ + if (sig_dbm || rate) { + winfo = sc_capwap_setwinfo_frameinfo(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, (uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5); + } + + /* */ + CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_IEEE80211; + + /* Forward to AC */ + err = sc_capwap_forwarddata(session, nldev->radioid, nldev->binding, skb, nldev->flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0)); + } + +error: + return ret; +} + +/* */ +static struct sc_netlink_device* sc_netlink_new_device(uint32_t ifindex, uint8_t radioid, u8 wlanid, uint8_t binding) { + struct net_device* dev; + struct sc_netlink_device* nldev; + + TRACEKMOD("### sc_netlink_new_device\n"); + + /* Retrieve device from ifindex */ + dev = dev_get_by_index(&init_net, ifindex); + if (!dev) { + return NULL; + } + + /* Check if wireless device */ + if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) { + dev_put(dev); + return NULL; + } + + /* Create device */ + nldev = (struct sc_netlink_device*)kzalloc(sizeof(struct sc_netlink_device), GFP_KERNEL); + if (!nldev) { + dev_put(dev); + return NULL; + } + + /* Initialize device */ + nldev->pcktunnel_handler.handler = sc_netlink_handler; + nldev->pcktunnel_handler.data = (void*)nldev; + nldev->ifindex = ifindex; + nldev->radioid = radioid; + nldev->wlanid = wlanid; + nldev->binding = binding; + nldev->dev = dev; + + return nldev; +} + +/* */ +static void sc_netlink_free_device(struct sc_netlink_device* nldev) { + TRACEKMOD("### sc_netlink_free_device\n"); + + /* Disconnect device from mac80211 */ + ieee80211_pcktunnel_deregister(nldev->dev, &nldev->pcktunnel_handler); + + /* */ + dev_put(nldev->dev); + + /* Free memory */ + kfree(nldev); +} + +/* */ +static struct sc_netlink_device* sc_netlink_register_device(uint32_t ifindex, uint8_t radioid, uint16_t wlanid, uint8_t binding) { + struct sc_netlink_device* nldev; + + TRACEKMOD("### sc_netlink_register_device\n"); + + ASSERT_RTNL(); + + /* */ + if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) { + return NULL; + } + + /* Search device */ + list_for_each_entry(nldev, &sc_netlink_dev_list, list) { + if (nldev->ifindex == ifindex) { + return NULL; + } + } + + /* Create device */ + nldev = sc_netlink_new_device(ifindex, radioid, wlanid, binding); + if (nldev) { + list_add_rcu(&nldev->list, &sc_netlink_dev_list); + } + + return nldev; +} + +/* */ +static int sc_netlink_unregister_device(uint32_t ifindex) { + int ret = -ENODEV; + struct sc_netlink_device* nldev; + + TRACEKMOD("### sc_netlink_unregister_device\n"); + + ASSERT_RTNL(); + + /* Search device */ + list_for_each_entry(nldev, &sc_netlink_dev_list, list) { + if (nldev->ifindex == ifindex) { + /* Remove from list */ + list_del_rcu(&nldev->list); + synchronize_net(); + + /* Free device */ + ret = 0; + sc_netlink_free_device(nldev); + break; + } + } + + return ret; +} + +/* */ +static void sc_netlink_unregister_alldevice(void) { + struct sc_netlink_device* tmp; + struct sc_netlink_device* nldev; + + TRACEKMOD("### sc_netlink_unregister_alldevice\n"); + + ASSERT_RTNL(); + + /* Close all devices */ + list_for_each_entry_safe(nldev, tmp, &sc_netlink_dev_list, list) { + /* Remove from list */ + list_del_rcu(&nldev->list); + synchronize_net(); + + /* Free device */ + sc_netlink_free_device(nldev); + } +} + +/* */ +static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) { + int ret; + uint32_t portid = genl_info_snd_portid(info); + + TRACEKMOD("### sc_netlink_link\n"); + + /* */ + if (sc_netlink_usermodeid) { + TRACEKMOD("*** Busy kernel link\n"); + return -EBUSY; + } + + /* Initialize library */ + ret = sc_capwap_init(); + if (ret) { + return ret; + } + + /* Deny unload module */ + sc_netlink_usermodeid = portid; + try_module_get(THIS_MODULE); + + return 0; +} + +/* */ +static int sc_netlink_reset(struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_reset\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Close all devices */ + sc_netlink_unregister_alldevice(); + + /* Reset session */ + sc_capwap_resetsession(); + + return 0; +} + +/* */ +static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) { + struct netlink_notify* notify = (struct netlink_notify*)_notify; + + if ((state == NETLINK_URELEASE) && (sc_netlink_usermodeid == netlink_notify_portid(notify))) { + rtnl_lock(); + + sc_netlink_usermodeid = 0; + + /* Close all devices */ + sc_netlink_unregister_alldevice(); + + /* Close capwap engine */ + sc_capwap_close(); + + /* Allow unload module */ + module_put(THIS_MODULE); + + rtnl_unlock(); + } + + return NOTIFY_DONE; +} + +/* */ +static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) { + union capwap_addr sockaddr; + + TRACEKMOD("### sc_netlink_bind\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Get bind address */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) { + return -EINVAL; + } + + memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage)); + if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) { + return -EINVAL; + } + + /* Bind socket */ + return sc_capwap_bind(&sockaddr); +} + +/* */ +static int sc_netlink_connect(struct sk_buff* skb, struct genl_info* info) { + int ret; + union capwap_addr sockaddr; + struct sc_capwap_sessionid_element sessionid; + uint16_t mtu = DEFAULT_MTU; + + TRACEKMOD("### sc_netlink_connect\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Get AC address */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) { + return -EINVAL; + } + + memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage)); + if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) { + return -EINVAL; + } + + /* Get MTU */ + if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) { + mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]); + if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) { + return -EINVAL; + } + } + + /* Get Session ID */ + if (info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] && (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) == sizeof(struct sc_capwap_sessionid_element))) { + memcpy(sessionid.id, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), sizeof(struct sc_capwap_sessionid_element)); + } else { + return -EINVAL; + } + + /* Send packet */ + ret = sc_capwap_connect(&sockaddr, &sessionid, mtu); + if (ret < 0) { + return ret; + } + + return 0; +} + +/* */ +static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) { + int ret; + + TRACEKMOD("### sc_netlink_send_keepalive\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Send packet */ + ret = sc_capwap_sendkeepalive(); + if (ret < 0) { + return ret; + } + + return 0; +} + +/* */ +static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) { + int ret; + uint8_t radioid; + uint8_t binding; + uint8_t rssi = 0; + uint8_t snr = 0; + uint16_t rate = 0; + int length; + struct sk_buff* skbdata; + struct sc_capwap_session* session; + unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED]; + struct sc_capwap_wireless_information* winfo = NULL; + + TRACEKMOD("### sc_netlink_send_data\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } else if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { + return -EINVAL; + } + + /* */ + session = sc_capwap_getsession(NULL); + if (!session) { + return -ENOLINK; + } + + /* Get radioid */ + radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]); + if (!IS_VALID_RADIOID(radioid) || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) { + return -EINVAL; + } + + /* Get binding */ + binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]); + + /* Get RSSI */ + if (info->attrs[NLSMARTCAPWAP_ATTR_RSSI]) { + rssi = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RSSI]); + } + + /* Get SNR */ + if (info->attrs[NLSMARTCAPWAP_ATTR_SNR]) { + snr = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_SNR]); + } + + /* Get RATE */ + if (info->attrs[NLSMARTCAPWAP_ATTR_RATE]) { + rate = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RATE]); + } + + /* Create Wireless Information */ + if (rssi || snr || rate) { + winfo = sc_capwap_setwinfo_frameinfo(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, rssi, snr, rate); + } + + /* Create socket buffer */ + length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]); + skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL); + if (!skbdata) { + return -ENOMEM; + } + + /* Reserve space for Capwap Header */ + skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH); + + /* Copy data into socket buffer */ + memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length); + + /* */ + CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE; + + /* Send packet */ + ret = sc_capwap_forwarddata(session, radioid, binding, skbdata, 0, NULL, 0, winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0)); + if (ret) { + TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n"); + } + + kfree_skb(skbdata); + return ret; +} + +/* */ +static int sc_netlink_join_mac80211_device(struct sk_buff* skb, struct genl_info* info) { + int ret; + uint32_t ifindex; + struct sc_netlink_device* nldev; + + TRACEKMOD("### sc_netlink_join_mac80211_device\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Get interface index */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) { + return -EINVAL; + } + + ifindex = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]); + if (!ifindex) { + return -EINVAL; + } + + /* Check */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) { + return -EINVAL; + } + + /* Register device */ + nldev = sc_netlink_register_device(ifindex, nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING])); + if (!nldev) { + return -EINVAL; + } + + /* */ + if (info->attrs[NLSMARTCAPWAP_ATTR_FLAGS]) { + nldev->flags = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_FLAGS]); + } + + /* Set subtype masking */ + if (info->attrs[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK]) { + nldev->pcktunnel_handler.subtype_mask[0] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK]); + } + + if (info->attrs[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK]) { + nldev->pcktunnel_handler.subtype_mask[1] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK]); + } + + if (info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]) { + nldev->pcktunnel_handler.subtype_mask[2] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]); + } + + /* Connect device to mac80211 */ + ret = ieee80211_pcktunnel_register(nldev->dev, &nldev->pcktunnel_handler); + if (ret) { + sc_netlink_unregister_device(ifindex); + } + + return ret; +} + +/* */ +static int sc_netlink_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) { + TRACEKMOD("### sc_netlink_leave_mac80211_device\n"); + + /* Check Link */ + if (!sc_netlink_usermodeid) { + return -ENOLINK; + } + + /* Get interface index */ + if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) { + return -EINVAL; + } + + /* Unregister device */ + return sc_netlink_unregister_device(nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX])); +} + +/* */ +static int sc_device_event(struct notifier_block* unused, unsigned long event, void* ptr) { + struct net_device* dev = netdev_notifier_info_to_dev(ptr); + + /* Check event only if connect with WTP userspace */ + if (!sc_netlink_usermodeid) { + return NOTIFY_DONE; + } + + /* */ + switch (event) { + case NETDEV_UNREGISTER: { + /* Try to unregister device */ + sc_netlink_unregister_device(dev->ifindex); + break; + } + } + + return NOTIFY_DONE; +} + +/* */ +static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = { + [NLSMARTCAPWAP_ATTR_IFINDEX] = { .type = NLA_U32 }, + [NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_WLANID] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 }, + [NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 }, + [NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 }, + [NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 }, + [NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) }, + [NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 }, + [NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) }, + [NLSMARTCAPWAP_ATTR_DTLS] = { .type = NLA_U16 }, + [NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MTU }, + [NLSMARTCAPWAP_ATTR_RSSI] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_SNR] = { .type = NLA_U8 }, + [NLSMARTCAPWAP_ATTR_RATE] = { .type = NLA_U16 }, + +}; + +/* Netlink Ops */ +static __genl_const struct genl_ops sc_netlink_ops[] = { + { + .cmd = NLSMARTCAPWAP_CMD_LINK, + .doit = sc_netlink_link, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_BIND, + .doit = sc_netlink_bind, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_CONNECT, + .doit = sc_netlink_connect, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_RESET, + .doit = sc_netlink_reset, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, + .doit = sc_netlink_send_keepalive, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_SEND_DATA, + .doit = sc_netlink_send_data, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, + .doit = sc_netlink_join_mac80211_device, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, + .doit = sc_netlink_leave_mac80211_device, + .policy = sc_netlink_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +/* Netlink notify */ +static struct notifier_block sc_netlink_notifier = { + .notifier_call = sc_netlink_notify, +}; + +/* Interface notify */ +struct notifier_block sc_device_notifier = { + .notifier_call = sc_device_event +}; + +/* */ +int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) { + void* msg; + struct sk_buff* sk_msg; + + TRACEKMOD("### sc_netlink_notify_recv_keepalive\n"); + + /* Alloc message */ + sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!sk_msg) { + return -ENOMEM; + } + + /* Set command */ + msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE); + if (!msg) { + nlmsg_free(sk_msg); + return -ENOMEM; + } + + /* Send message */ + genlmsg_end(sk_msg, msg); + return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); +} + +/* */ +int sc_netlink_notify_recv_data(uint8_t* packet, int length) { + void* msg; + struct sk_buff* sk_msg; + + TRACEKMOD("### sc_netlink_notify_recv_data\n"); + + /* Alloc message */ + sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!sk_msg) { + return -ENOMEM; + } + + /* Set command */ + msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA); + if (!msg) { + goto error; + } + + /* */ + if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) { + goto error2; + } + + /* Send message */ + genlmsg_end(sk_msg, msg); + return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid); + +error2: + genlmsg_cancel(sk_msg, msg); + +error: + nlmsg_free(sk_msg); + return -ENOMEM; +} + +/* */ +struct net_device* sc_netlink_getdev_from_wlanid(uint8_t radioid, uint8_t wlanid) { + struct sc_netlink_device* nldev; + + TRACEKMOD("### sc_netlink_getdev_from_wlanid\n"); + + /* Search */ + list_for_each_entry(nldev, &sc_netlink_dev_list, list) { + if ((nldev->radioid == radioid) && (nldev->wlanid == wlanid)) { + return nldev->dev; + } + } + + return NULL; +} + +/* */ +struct net_device* sc_netlink_getdev_from_bssid(uint8_t radioid, const uint8_t* addr) { + struct sc_netlink_device* nldev; + + TRACEKMOD("### sc_netlink_getdev_from_bssid\n"); + + /* Search */ + list_for_each_entry(nldev, &sc_netlink_dev_list, list) { + if ((nldev->radioid == radioid) && !memcmp(nldev->dev->dev_addr, addr, MACADDRESS_EUI48_LENGTH)) { + return nldev->dev; + } + } + + return NULL; +} + +/* */ +int sc_netlink_init(void) { + int ret; + + TRACEKMOD("### sc_netlink_init\n"); + + /* */ + sc_netlink_usermodeid = 0; + + /* Register interface event */ + ret = register_netdevice_notifier(&sc_device_notifier); + if (ret) { + goto error; + } + + /* Register netlink family */ + ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops); + if (ret) { + goto error2; + } + + /* Register netlink notifier */ + ret = netlink_register_notifier(&sc_netlink_notifier); + if (ret) { + goto error3; + } + + return 0; + +error3: + genl_unregister_family(&sc_netlink_family); +error2: + unregister_netdevice_notifier(&sc_device_notifier); +error: + return ret; +} + +/* */ +void sc_netlink_exit(void) { + TRACEKMOD("### sc_netlink_exit\n"); + + netlink_unregister_notifier(&sc_netlink_notifier); + genl_unregister_family(&sc_netlink_family); + unregister_netdevice_notifier(&sc_device_notifier); +} diff --git a/src/wtp/kmod/netlinkapp.h b/src/wtp/kmod/netlinkapp.h index b881ee9..a65630d 100644 --- a/src/wtp/kmod/netlinkapp.h +++ b/src/wtp/kmod/netlinkapp.h @@ -1,19 +1,19 @@ -#ifndef __KMOD_WTP_NETLINKAPP_HEADER__ -#define __KMOD_WTP_NETLINKAPP_HEADER__ - -#include "capwap_rfc.h" -#include "socket.h" - -/* */ -int sc_netlink_init(void); -void sc_netlink_exit(void); - -/* */ -struct net_device* sc_netlink_getdev_from_wlanid(uint8_t radioid, uint8_t wlanid); -struct net_device* sc_netlink_getdev_from_bssid(uint8_t radioid, const uint8_t* addr); - -/* */ -int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid); -int sc_netlink_notify_recv_data(uint8_t* packet, int length); - -#endif /* __KMOD_WTP_NETLINKAPP_HEADER__ */ +#ifndef __KMOD_WTP_NETLINKAPP_HEADER__ +#define __KMOD_WTP_NETLINKAPP_HEADER__ + +#include "capwap_rfc.h" +#include "socket.h" + +/* */ +int sc_netlink_init(void); +void sc_netlink_exit(void); + +/* */ +struct net_device* sc_netlink_getdev_from_wlanid(uint8_t radioid, uint8_t wlanid); +struct net_device* sc_netlink_getdev_from_bssid(uint8_t radioid, const uint8_t* addr); + +/* */ +int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid); +int sc_netlink_notify_recv_data(uint8_t* packet, int length); + +#endif /* __KMOD_WTP_NETLINKAPP_HEADER__ */ diff --git a/src/wtp/kmod/nlsmartcapwap.h b/src/wtp/kmod/nlsmartcapwap.h index 709756f..decd22f 100644 --- a/src/wtp/kmod/nlsmartcapwap.h +++ b/src/wtp/kmod/nlsmartcapwap.h @@ -1,66 +1,66 @@ -#ifndef __WTP_NLSMARTCAPWAP_HEADER__ -#define __WTP_NLSMARTCAPWAP_HEADER__ - -/* */ -#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_wtp" - -/* */ -#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001 - -/* */ -enum nlsmartcapwap_attrs { - NLSMARTCAPWAP_ATTR_UNSPEC, - - NLSMARTCAPWAP_ATTR_IFINDEX, - NLSMARTCAPWAP_ATTR_RADIOID, - NLSMARTCAPWAP_ATTR_WLANID, - NLSMARTCAPWAP_ATTR_BINDING, - - NLSMARTCAPWAP_ATTR_FLAGS, - - NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, - NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, - NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, - - NLSMARTCAPWAP_ATTR_ADDRESS, - NLSMARTCAPWAP_ATTR_MTU, - - NLSMARTCAPWAP_ATTR_SESSION_ID, - - NLSMARTCAPWAP_ATTR_DTLS, - - NLSMARTCAPWAP_ATTR_DATA_FRAME, - NLSMARTCAPWAP_ATTR_RSSI, - NLSMARTCAPWAP_ATTR_SNR, - NLSMARTCAPWAP_ATTR_RATE, - - /* Last attribute */ - __NLSMARTCAPWAP_ATTR_AFTER_LAST, - NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1 -}; - -/* */ -enum nlsmartcapwap_commands { - NLSMARTCAPWAP_CMD_UNSPEC, - - NLSMARTCAPWAP_CMD_LINK, - - NLSMARTCAPWAP_CMD_BIND, - NLSMARTCAPWAP_CMD_CONNECT, - NLSMARTCAPWAP_CMD_RESET, - - NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, - NLSMARTCAPWAP_CMD_RECV_KEEPALIVE, - - NLSMARTCAPWAP_CMD_SEND_DATA, - NLSMARTCAPWAP_CMD_RECV_DATA, - - NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, - NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, - - /* Last command */ - __NLSMARTCAPWAP_CMD_AFTER_LAST, - NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1 -}; - -#endif /* __WTP_NLSMARTCAPWAP_HEADER__ */ +#ifndef __WTP_NLSMARTCAPWAP_HEADER__ +#define __WTP_NLSMARTCAPWAP_HEADER__ + +/* */ +#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_wtp" + +/* */ +#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001 + +/* */ +enum nlsmartcapwap_attrs { + NLSMARTCAPWAP_ATTR_UNSPEC, + + NLSMARTCAPWAP_ATTR_IFINDEX, + NLSMARTCAPWAP_ATTR_RADIOID, + NLSMARTCAPWAP_ATTR_WLANID, + NLSMARTCAPWAP_ATTR_BINDING, + + NLSMARTCAPWAP_ATTR_FLAGS, + + NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, + NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, + NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, + + NLSMARTCAPWAP_ATTR_ADDRESS, + NLSMARTCAPWAP_ATTR_MTU, + + NLSMARTCAPWAP_ATTR_SESSION_ID, + + NLSMARTCAPWAP_ATTR_DTLS, + + NLSMARTCAPWAP_ATTR_DATA_FRAME, + NLSMARTCAPWAP_ATTR_RSSI, + NLSMARTCAPWAP_ATTR_SNR, + NLSMARTCAPWAP_ATTR_RATE, + + /* Last attribute */ + __NLSMARTCAPWAP_ATTR_AFTER_LAST, + NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1 +}; + +/* */ +enum nlsmartcapwap_commands { + NLSMARTCAPWAP_CMD_UNSPEC, + + NLSMARTCAPWAP_CMD_LINK, + + NLSMARTCAPWAP_CMD_BIND, + NLSMARTCAPWAP_CMD_CONNECT, + NLSMARTCAPWAP_CMD_RESET, + + NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, + NLSMARTCAPWAP_CMD_RECV_KEEPALIVE, + + NLSMARTCAPWAP_CMD_SEND_DATA, + NLSMARTCAPWAP_CMD_RECV_DATA, + + NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, + NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, + + /* Last command */ + __NLSMARTCAPWAP_CMD_AFTER_LAST, + NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1 +}; + +#endif /* __WTP_NLSMARTCAPWAP_HEADER__ */ diff --git a/src/wtp/kmod/socket.c b/src/wtp/kmod/socket.c index eba63c2..29ba410 100644 --- a/src/wtp/kmod/socket.c +++ b/src/wtp/kmod/socket.c @@ -1,227 +1,227 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "socket.h" -#include "capwap.h" - -/* Socket */ -#define SOCKET_COUNT 2 -static struct socket* sc_sockets[SOCKET_COUNT]; - -/* */ -int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) { - TRACEKMOD("### sc_socket_recvpacket\n"); - - /* */ - CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL; - - /* */ - sc_capwap_recvpacket(skb); - return 0; -} - -/* */ -static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) { - int ret; - - TRACEKMOD("### sc_socket_create\n"); - - /* Create socket */ - ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]); - if (ret) { - return ret; - } - - /* Bind to interface */ - ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr)); - if (ret) { - goto failure; - } - - /* Set callback */ - udp_sk(sc_sockets[type]->sk)->encap_type = 1; - udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket; - - /* */ - if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) { - union capwap_addr localaddr; - int localaddrsize = sizeof(union capwap_addr); - - /* Retrieve port */ - ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize); - if (ret) { - goto failure; - } - - /* */ - if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) { - sockaddr->sin.sin_port = localaddr.sin.sin_port; - } else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) { - sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port; - } else { - ret = -EFAULT; - goto failure; - } - } - - return 0; - -failure: - sock_release(sc_sockets[type]); - sc_sockets[type] = 0; - return ret; -} - -/* */ -int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) { - unsigned char* nethdr; - - TRACEKMOD("### sc_socket_getpeeraddr\n"); - - /* */ - nethdr = skb_network_header(skb); - if (!nethdr) { - return -EINVAL; - } - - /* */ - switch (ntohs(skb->protocol)) { - case ETH_P_IP: { - /* Validate IPv4 header */ - if ((nethdr[0] & 0xf0) != 0x40) { - return -EINVAL; - } - - /* Retrieve address */ - peeraddr->sin.sin_family = AF_INET; - peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr; - peeraddr->sin.sin_port = udp_hdr(skb)->source; - break; - } - - case ETH_P_IPV6: { - /* Validate IPv6 header */ - if ((nethdr[0] & 0xf0) != 0x60) { - return -EINVAL; - } - - /* Retrieve address */ - peeraddr->sin6.sin6_family = AF_INET6; - memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr)); - peeraddr->sin6.sin6_port = udp_hdr(skb)->source; - break; - } - - default: { - return -EINVAL; - } - } - - return 0; -} - -/* */ -int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) { - struct kvec vec; - struct msghdr msg; - - TRACEKMOD("### sc_socket_send\n"); - - /* */ - vec.iov_base = buffer; - vec.iov_len = length; - - /* */ - memset(&msg, 0, sizeof(struct msghdr)); - msg.msg_name = sockaddr; - msg.msg_namelen = sizeof(union capwap_addr); - msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; - - /* */ - return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length); -} - -/* */ -int sc_socket_init(void) { - TRACEKMOD("### sc_socket_init\n"); - - memset(sc_sockets, 0, sizeof(sc_sockets)); - return 0; -} - -/* */ -int sc_socket_bind(union capwap_addr* sockaddr) { - int ret; - - TRACEKMOD("### sc_socket_bind\n"); - - /* */ - if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) { - return -EBUSY; - } - - /* UDP socket */ - ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP); - if (ret) { - goto failure; - } - - /* UDPLite socket */ - ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE); - if (ret) { - goto failure; - } - - /* */ - udp_encap_enable(); - if (sockaddr->ss.ss_family == AF_INET6) { - udpv6_encap_enable(); - } - - return 0; - -failure: - sc_socket_close(); - return ret; -} - -/* */ -void sc_socket_close(void) { - TRACEKMOD("### sc_socket_close\n"); - - /* Close sockets */ - if (sc_sockets[SOCKET_UDP]) { - kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR); - sock_release(sc_sockets[SOCKET_UDP]); - } - - if (sc_sockets[SOCKET_UDPLITE]) { - kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR); - sock_release(sc_sockets[SOCKET_UDPLITE]); - } - - memset(sc_sockets, 0, sizeof(sc_sockets)); -} - -/* */ -int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) { - TRACEKMOD("### sc_addr_compare\n"); - - if (addr1->ss.ss_family == addr2->ss.ss_family) { - if (addr1->ss.ss_family == AF_INET) { - return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1); - } else if (addr1->ss.ss_family == AF_INET6) { - return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1); - } - } - - return -1; -} +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "socket.h" +#include "capwap.h" + +/* Socket */ +#define SOCKET_COUNT 2 +static struct socket* sc_sockets[SOCKET_COUNT]; + +/* */ +int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) { + TRACEKMOD("### sc_socket_recvpacket\n"); + + /* */ + CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL; + + /* */ + sc_capwap_recvpacket(skb); + return 0; +} + +/* */ +static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) { + int ret; + + TRACEKMOD("### sc_socket_create\n"); + + /* Create socket */ + ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]); + if (ret) { + return ret; + } + + /* Bind to interface */ + ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr)); + if (ret) { + goto failure; + } + + /* Set callback */ + udp_sk(sc_sockets[type]->sk)->encap_type = 1; + udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket; + + /* */ + if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) { + union capwap_addr localaddr; + int localaddrsize = sizeof(union capwap_addr); + + /* Retrieve port */ + ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize); + if (ret) { + goto failure; + } + + /* */ + if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) { + sockaddr->sin.sin_port = localaddr.sin.sin_port; + } else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) { + sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port; + } else { + ret = -EFAULT; + goto failure; + } + } + + return 0; + +failure: + sock_release(sc_sockets[type]); + sc_sockets[type] = 0; + return ret; +} + +/* */ +int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) { + unsigned char* nethdr; + + TRACEKMOD("### sc_socket_getpeeraddr\n"); + + /* */ + nethdr = skb_network_header(skb); + if (!nethdr) { + return -EINVAL; + } + + /* */ + switch (ntohs(skb->protocol)) { + case ETH_P_IP: { + /* Validate IPv4 header */ + if ((nethdr[0] & 0xf0) != 0x40) { + return -EINVAL; + } + + /* Retrieve address */ + peeraddr->sin.sin_family = AF_INET; + peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr; + peeraddr->sin.sin_port = udp_hdr(skb)->source; + break; + } + + case ETH_P_IPV6: { + /* Validate IPv6 header */ + if ((nethdr[0] & 0xf0) != 0x60) { + return -EINVAL; + } + + /* Retrieve address */ + peeraddr->sin6.sin6_family = AF_INET6; + memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr)); + peeraddr->sin6.sin6_port = udp_hdr(skb)->source; + break; + } + + default: { + return -EINVAL; + } + } + + return 0; +} + +/* */ +int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) { + struct kvec vec; + struct msghdr msg; + + TRACEKMOD("### sc_socket_send\n"); + + /* */ + vec.iov_base = buffer; + vec.iov_len = length; + + /* */ + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_name = sockaddr; + msg.msg_namelen = sizeof(union capwap_addr); + msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT; + + /* */ + return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length); +} + +/* */ +int sc_socket_init(void) { + TRACEKMOD("### sc_socket_init\n"); + + memset(sc_sockets, 0, sizeof(sc_sockets)); + return 0; +} + +/* */ +int sc_socket_bind(union capwap_addr* sockaddr) { + int ret; + + TRACEKMOD("### sc_socket_bind\n"); + + /* */ + if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) { + return -EBUSY; + } + + /* UDP socket */ + ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP); + if (ret) { + goto failure; + } + + /* UDPLite socket */ + ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE); + if (ret) { + goto failure; + } + + /* */ + udp_encap_enable(); + if (sockaddr->ss.ss_family == AF_INET6) { + udpv6_encap_enable(); + } + + return 0; + +failure: + sc_socket_close(); + return ret; +} + +/* */ +void sc_socket_close(void) { + TRACEKMOD("### sc_socket_close\n"); + + /* Close sockets */ + if (sc_sockets[SOCKET_UDP]) { + kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR); + sock_release(sc_sockets[SOCKET_UDP]); + } + + if (sc_sockets[SOCKET_UDPLITE]) { + kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR); + sock_release(sc_sockets[SOCKET_UDPLITE]); + } + + memset(sc_sockets, 0, sizeof(sc_sockets)); +} + +/* */ +int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) { + TRACEKMOD("### sc_addr_compare\n"); + + if (addr1->ss.ss_family == addr2->ss.ss_family) { + if (addr1->ss.ss_family == AF_INET) { + return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1); + } else if (addr1->ss.ss_family == AF_INET6) { + return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1); + } + } + + return -1; +} diff --git a/src/wtp/kmod/socket.h b/src/wtp/kmod/socket.h index a993b77..32a7c67 100644 --- a/src/wtp/kmod/socket.h +++ b/src/wtp/kmod/socket.h @@ -1,35 +1,35 @@ -#ifndef __KMOD_SOCKET_HEADER__ -#define __KMOD_SOCKET_HEADER__ - -#include -#include -#include -#include - -/* */ -#define SOCKET_UDP 0 -#define SOCKET_UDPLITE 1 - -/* Universal socket address */ -union capwap_addr { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - struct sockaddr_storage ss; -}; - -/* */ -int sc_socket_init(void); -void sc_socket_close(void); - -/* */ -int sc_socket_bind(union capwap_addr* sockaddr); -int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr); - -/* */ -int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr); - -/* */ -int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2); - -#endif /* __KMOD_SOCKET_HEADER__ */ +#ifndef __KMOD_SOCKET_HEADER__ +#define __KMOD_SOCKET_HEADER__ + +#include +#include +#include +#include + +/* */ +#define SOCKET_UDP 0 +#define SOCKET_UDPLITE 1 + +/* Universal socket address */ +union capwap_addr { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + struct sockaddr_storage ss; +}; + +/* */ +int sc_socket_init(void); +void sc_socket_close(void); + +/* */ +int sc_socket_bind(union capwap_addr* sockaddr); +int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr); + +/* */ +int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr); + +/* */ +int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2); + +#endif /* __KMOD_SOCKET_HEADER__ */ diff --git a/src/wtp/wtp_element_helper.c b/src/wtp/wtp_element_helper.c index 9b02b36..c4d42db 100644 --- a/src/wtp/wtp_element_helper.c +++ b/src/wtp/wtp_element_helper.c @@ -1,65 +1,65 @@ -#include "wtp.h" -#include "wtp_radio.h" - -/* */ -void wtp_create_radioopsstate_element(struct capwap_packet_txmng* txmngpacket) { - int i; - - for (i = 0; i < g_wtp.radios->count; i++) { - struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); - struct capwap_radiooprstate_element radiooprstate; - - radiooprstate.radioid = radio->radioid; - radiooprstate.state = ((radio->status == WTP_RADIO_ENABLED) ? CAPWAP_RADIO_OPERATIONAL_STATE_ENABLED : CAPWAP_RADIO_OPERATIONAL_STATE_DISABLED); - - if (radio->status == WTP_RADIO_ENABLED) { - radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_NORMAL; - } else if (radio->status == WTP_RADIO_DISABLED) { - radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_ADMINSET; - } else if (radio->status == WTP_RADIO_HWFAILURE) { - radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_RADIOFAILURE; - } else if (radio->status == WTP_RADIO_SWFAILURE) { - radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_SOFTWAREFAILURE; - } else { - /* Unknown value */ - ASSERT(0); - } - - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RADIOOPRSTATE, &radiooprstate); - } -} - -/* */ -void wtp_create_radioadmstate_element(struct capwap_packet_txmng* txmngpacket) { - int i; - - for (i = 0; i < g_wtp.radios->count; i++) { - struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); - struct capwap_radioadmstate_element radioadmstate; - - radioadmstate.radioid = radio->radioid; - radioadmstate.state = ((radio->status == WTP_RADIO_DISABLED) ? CAPWAP_RADIO_ADMIN_STATE_DISABLED : CAPWAP_RADIO_ADMIN_STATE_ENABLED); - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RADIOADMSTATE, &radioadmstate); - } -} - -/* */ -void wtp_create_80211_wtpradioinformation_element(struct capwap_packet_txmng* txmngpacket) { - int i; - struct wtp_radio* radio; - struct capwap_80211_wtpradioinformation_element element; - - for (i = 0; i < g_wtp.radios->count; i++) { - radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); - - /* Set message element */ - if (radio->status == WTP_RADIO_ENABLED) { - memcpy(&element, &radio->radioinformation, sizeof(struct capwap_80211_wtpradioinformation_element)); - } else { - memset(&element, 0, sizeof(struct capwap_80211_wtpradioinformation_element)); - element.radioid = radio->radioid; - } - - capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION, &element); - } -} +#include "wtp.h" +#include "wtp_radio.h" + +/* */ +void wtp_create_radioopsstate_element(struct capwap_packet_txmng* txmngpacket) { + int i; + + for (i = 0; i < g_wtp.radios->count; i++) { + struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); + struct capwap_radiooprstate_element radiooprstate; + + radiooprstate.radioid = radio->radioid; + radiooprstate.state = ((radio->status == WTP_RADIO_ENABLED) ? CAPWAP_RADIO_OPERATIONAL_STATE_ENABLED : CAPWAP_RADIO_OPERATIONAL_STATE_DISABLED); + + if (radio->status == WTP_RADIO_ENABLED) { + radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_NORMAL; + } else if (radio->status == WTP_RADIO_DISABLED) { + radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_ADMINSET; + } else if (radio->status == WTP_RADIO_HWFAILURE) { + radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_RADIOFAILURE; + } else if (radio->status == WTP_RADIO_SWFAILURE) { + radiooprstate.cause = CAPWAP_RADIO_OPERATIONAL_CAUSE_SOFTWAREFAILURE; + } else { + /* Unknown value */ + ASSERT(0); + } + + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RADIOOPRSTATE, &radiooprstate); + } +} + +/* */ +void wtp_create_radioadmstate_element(struct capwap_packet_txmng* txmngpacket) { + int i; + + for (i = 0; i < g_wtp.radios->count; i++) { + struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); + struct capwap_radioadmstate_element radioadmstate; + + radioadmstate.radioid = radio->radioid; + radioadmstate.state = ((radio->status == WTP_RADIO_DISABLED) ? CAPWAP_RADIO_ADMIN_STATE_DISABLED : CAPWAP_RADIO_ADMIN_STATE_ENABLED); + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_RADIOADMSTATE, &radioadmstate); + } +} + +/* */ +void wtp_create_80211_wtpradioinformation_element(struct capwap_packet_txmng* txmngpacket) { + int i; + struct wtp_radio* radio; + struct capwap_80211_wtpradioinformation_element element; + + for (i = 0; i < g_wtp.radios->count; i++) { + radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); + + /* Set message element */ + if (radio->status == WTP_RADIO_ENABLED) { + memcpy(&element, &radio->radioinformation, sizeof(struct capwap_80211_wtpradioinformation_element)); + } else { + memset(&element, 0, sizeof(struct capwap_80211_wtpradioinformation_element)); + element.radioid = radio->radioid; + } + + capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION, &element); + } +} diff --git a/src/wtp/wtp_kmod.c b/src/wtp/wtp_kmod.c index a423c96..c59d88f 100644 --- a/src/wtp/wtp_kmod.c +++ b/src/wtp/wtp_kmod.c @@ -1,591 +1,591 @@ -#include "wtp.h" -#include "wtp_dfa.h" -#include -#include -#include -#include "nlsmartcapwap.h" - -/* Compatibility functions */ -#ifdef HAVE_LIBNL_10 -static uint32_t g_portbitmap[32] = { 0 }; - -static struct nl_sock* nl_socket_alloc_cb(void* cb) { - int i; - struct nl_sock* handle; - uint32_t pid = getpid() & 0x3FFFFF; - - handle = nl_handle_alloc_cb(cb); - for (i = 0; i < 1024; i++) { - if (g_portbitmap[i / 32] & (1 << (i % 32))) { - continue; - } - - g_portbitmap[i / 32] |= 1 << (i % 32); - pid += i << 22; - break; - } - - nl_socket_set_local_port(handle, pid); - return handle; -} - -static void nl_socket_free(struct nl_sock* handle) { - uint32_t port = nl_socket_get_local_port(handle); - - port >>= 22; - g_portbitmap[port / 32] &= ~(1 << (port % 32)); - - nl_handle_destroy(handle); -} -#endif - -/* */ -typedef int (*wtp_kmod_valid_cb)(struct nl_msg* msg, void* data); - -/* */ -static struct nl_sock* nl_create_handle(struct nl_cb* cb) { - struct nl_sock* handle; - - handle = nl_socket_alloc_cb(cb); - if (!handle) { - return NULL; - } - - if (genl_connect(handle)) { - nl_socket_free(handle); - return NULL; - } - - return handle; -} - -/* */ -static int wtp_kmod_no_seq_check(struct nl_msg* msg, void* arg) { - return NL_OK; -} - -/* */ -static int wtp_kmod_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) { - *((int*)arg) = err->error; - return NL_STOP; -} - -/* */ -static int wtp_kmod_finish_handler(struct nl_msg* msg, void* arg) { - *((int*)arg) = 0; - return NL_SKIP; -} - -/* */ -static int wtp_kmod_ack_handler(struct nl_msg* msg, void* arg) { - *((int*)arg) = 0; - return NL_STOP; -} - -/* */ -static int wtp_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) { - switch (gnlh->cmd) { - case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: { - wtp_recv_data_keepalive(); - break; - } - - case NLSMARTCAPWAP_CMD_RECV_DATA: { - if (tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { - wtp_recv_data(nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME])); - } - - break; - } - } - - return NL_SKIP; -} - -/* */ -static int wtp_kmod_valid_handler(struct nl_msg* msg, void* data) { - struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1]; - struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - return wtp_kmod_event_handler(gnlh, tb_msg, data); -} - -/* */ -static int wtp_kmod_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, wtp_kmod_valid_cb valid_cb, void* data) { - int result; - struct nl_cb* cb; - - /* Clone netlink callback */ - cb = nl_cb_clone(nl_cb); - if (!cb) { - return -1; - } - - /* Complete send message */ - result = nl_send_auto_complete(nl, msg); - if (result < 0) { - nl_cb_put(cb); - return -1; - } - - /* Customize message callback */ - nl_cb_err(cb, NL_CB_CUSTOM, wtp_kmod_error_handler, &result); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wtp_kmod_finish_handler, &result); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wtp_kmod_ack_handler, &result); - - if (valid_cb) { - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data); - } - - result = 1; - while (result > 0) { - nl_recvmsgs(nl, cb); - } - - nl_cb_put(cb); - return result; -} - -/* */ -static int wtp_kmod_send_and_recv_msg(struct nl_msg* msg, wtp_kmod_valid_cb valid_cb, void* data) { - return wtp_kmod_send_and_recv(g_wtp.kmodhandle.nlmsg, g_wtp.kmodhandle.nlmsg_cb, msg, valid_cb, data); -} - -/* */ -static int wtp_kmod_link(void) { - int result; - struct nl_msg* msg; - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LINK, 0); - - /* */ - result = wtp_kmod_send_and_recv(g_wtp.kmodhandle.nl, g_wtp.kmodhandle.nl_cb, msg, NULL, NULL); - if (result) { - if (result == -EALREADY) { - result = 0; - } else { - capwap_logging_warning("Unable to connect kernel module, error code: %d", result); - } - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -static void wtp_kmod_event_receive(int fd, void** params, int paramscount) { - int res; - - ASSERT(fd >= 0); - ASSERT(params != NULL); - ASSERT(paramscount == 2); - - /* */ - res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); - if (res) { - capwap_logging_warning("Receive kernel module message failed: %d", res); - } -} - -/* */ -int wtp_kmod_bind(uint16_t family) { - int result; - struct nl_msg* msg; - struct sockaddr_storage sockaddr; - - ASSERT((family == AF_INET) || (family == AF_INET6)); - - /* */ - if (!wtp_kmod_isconnected()) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - memset(&sockaddr, 0, sizeof(struct sockaddr_storage)); - sockaddr.ss_family = family; - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr); - - /* */ - result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu) { - int result; - struct nl_msg* msg; - - ASSERT(sockaddr != NULL); - ASSERT((sockaddr->ss_family == AF_INET) || (sockaddr->ss_family == AF_INET6)); - ASSERT(sessionid != NULL); - - /* */ - if (!wtp_kmod_isconnected()) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_CONNECT, 0); - nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr); - nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu); - - /* */ - result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int wtp_kmod_send_keepalive(void) { - int result; - struct nl_msg* msg; - - /* */ - if (!wtp_kmod_isconnected()) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0); - - /* */ - result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int wtp_kmod_resetsession(void) { - int result; - struct nl_msg* msg; - - /* */ - if (!wtp_kmod_isconnected()) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_RESET, 0); - - /* */ - result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { - int result; - struct nl_msg* msg; - - /* */ - if (!wtp_kmod_isconnected()) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); - nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, frame); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding); - - if (rssi) { - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RSSI, rssi); - } - - if (snr) { - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_SNR, snr); - } - - if (rate) { - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_RATE, rate); - } - - /* */ - result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags) { - int result; - struct nl_msg* msg; - struct capwap_list_item* itemlist; - struct wtp_kmod_iface_handle* interface; - uint32_t kmodflags = 0; - - ASSERT(wlan != NULL); - - /* */ - if (!wtp_kmod_isconnected()) { - return -1; - } - - /* */ - itemlist = capwap_itemlist_create(sizeof(struct wtp_kmod_iface_handle)); - interface = (struct wtp_kmod_iface_handle*)itemlist->item; - memset(interface, 0, sizeof(struct wtp_kmod_iface_handle)); - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - capwap_itemlist_free(itemlist); - return -1; - } - - /* Set flags */ - if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) { - kmodflags |= NLSMARTCAPWAP_FLAGS_TUNNEL_8023; - } - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, 0); - nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, wlan->radioid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlan->wlanid); - nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding); - nla_put_u32(msg, NLSMARTCAPWAP_ATTR_FLAGS, kmodflags); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, 0x0000); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, 0x0000); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, 0xffff); - - /* */ - result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - if (!result) { - interface->flags = flags; - interface->wlan = wlan; - - /* */ - capwap_itemlist_insert_after(g_wtp.kmodhandle.interfaces, NULL, itemlist); - } else { - capwap_itemlist_free(itemlist); - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan) { - int result; - struct nl_msg* msg; - - ASSERT(wlan != NULL); - - /* */ - if (!wtp_kmod_isconnected()) { - return -1; - } - - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, 0); - nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex); - - /* */ - result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - if (!result) { - struct capwap_list_item* itemlist; - - for (itemlist = g_wtp.kmodhandle.interfaces->first; itemlist != NULL; itemlist = itemlist->next) { - struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item; - - if (interface->wlan == wlan) { - capwap_itemlist_free(capwap_itemlist_remove(g_wtp.kmodhandle.interfaces, itemlist)); - break; - } - } - } - - /* */ - nlmsg_free(msg); - return result; -} - -/* */ -int wtp_kmod_isconnected(void) { - return (g_wtp.kmodhandle.nlsmartcapwap_id ? 1 : 0); -} - -/* */ -int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) { - int kmodcount = (wtp_kmod_isconnected() ? 1 : 0); - - /* */ - if (!kmodcount) { - return 0; - } else if (!fds && !events && !count) { - return kmodcount; - } else if ((count > 0) && (!fds || !events)) { - return -1; - } else if (count < kmodcount) { - return -1; - } - - /* */ - fds[0].fd = g_wtp.kmodhandle.nl_fd; - fds[0].events = POLLIN | POLLERR | POLLHUP; - - /* */ - events[0].event_handler = wtp_kmod_event_receive; - events[0].params[0] = (void*)g_wtp.kmodhandle.nl; - events[0].params[1] = (void*)g_wtp.kmodhandle.nl_cb; - events[0].paramscount = 2; - - return kmodcount; -} - -/* */ -int wtp_kmod_init(void) { - int result; - - /* Configure netlink callback */ - g_wtp.kmodhandle.nl_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!g_wtp.kmodhandle.nl_cb) { - wtp_kmod_free(); - return -1; - } - - /* Create netlink socket */ - g_wtp.kmodhandle.nl = nl_create_handle(g_wtp.kmodhandle.nl_cb); - if (!g_wtp.kmodhandle.nl) { - wtp_kmod_free(); - return -1; - } - - g_wtp.kmodhandle.nl_fd = nl_socket_get_fd(g_wtp.kmodhandle.nl); - - /* Get nlsmartcapwap netlink family */ - g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME); - if (g_wtp.kmodhandle.nlsmartcapwap_id < 0) { - capwap_logging_warning("Unable to found kernel module"); - wtp_kmod_free(); - return -1; - } - - /* Configure callback function */ - nl_cb_set(g_wtp.kmodhandle.nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, wtp_kmod_no_seq_check, NULL); - nl_cb_set(g_wtp.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, wtp_kmod_valid_handler, NULL); - - /* Link to kernel module */ - result = wtp_kmod_link(); - if (result) { - wtp_kmod_free(); - return result; - } - - /* Configure netlink message socket */ - g_wtp.kmodhandle.nlmsg_cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!g_wtp.kmodhandle.nlmsg_cb) { - wtp_kmod_free(); - return -1; - } - - /* */ - g_wtp.kmodhandle.nlmsg = nl_create_handle(g_wtp.kmodhandle.nlmsg_cb); - if (!g_wtp.kmodhandle.nlmsg) { - wtp_kmod_free(); - return -1; - } - - /* */ - g_wtp.kmodhandle.interfaces = capwap_list_create(); - return 0; -} - -/* */ -void wtp_kmod_free(void) { - if (g_wtp.kmodhandle.interfaces) { - while (g_wtp.kmodhandle.interfaces->first) { - struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)g_wtp.kmodhandle.interfaces->first->item; - - if (wtp_kmod_leave_mac80211_device(interface->wlan)) { - break; - } - } - - /* */ - capwap_list_free(g_wtp.kmodhandle.interfaces); - } - - if (g_wtp.kmodhandle.nlmsg) { - nl_socket_free(g_wtp.kmodhandle.nlmsg); - } - - if (g_wtp.kmodhandle.nlmsg_cb) { - nl_cb_put(g_wtp.kmodhandle.nlmsg_cb); - } - - if (g_wtp.kmodhandle.nl) { - nl_socket_free(g_wtp.kmodhandle.nl); - } - - if (g_wtp.kmodhandle.nl_cb) { - nl_cb_put(g_wtp.kmodhandle.nl_cb); - } - - /* */ - memset(&g_wtp.kmodhandle, 0, sizeof(struct wtp_kmod_handle)); -} +#include "wtp.h" +#include "wtp_dfa.h" +#include +#include +#include +#include "nlsmartcapwap.h" + +/* Compatibility functions */ +#ifdef HAVE_LIBNL_10 +static uint32_t g_portbitmap[32] = { 0 }; + +static struct nl_sock* nl_socket_alloc_cb(void* cb) { + int i; + struct nl_sock* handle; + uint32_t pid = getpid() & 0x3FFFFF; + + handle = nl_handle_alloc_cb(cb); + for (i = 0; i < 1024; i++) { + if (g_portbitmap[i / 32] & (1 << (i % 32))) { + continue; + } + + g_portbitmap[i / 32] |= 1 << (i % 32); + pid += i << 22; + break; + } + + nl_socket_set_local_port(handle, pid); + return handle; +} + +static void nl_socket_free(struct nl_sock* handle) { + uint32_t port = nl_socket_get_local_port(handle); + + port >>= 22; + g_portbitmap[port / 32] &= ~(1 << (port % 32)); + + nl_handle_destroy(handle); +} +#endif + +/* */ +typedef int (*wtp_kmod_valid_cb)(struct nl_msg* msg, void* data); + +/* */ +static struct nl_sock* nl_create_handle(struct nl_cb* cb) { + struct nl_sock* handle; + + handle = nl_socket_alloc_cb(cb); + if (!handle) { + return NULL; + } + + if (genl_connect(handle)) { + nl_socket_free(handle); + return NULL; + } + + return handle; +} + +/* */ +static int wtp_kmod_no_seq_check(struct nl_msg* msg, void* arg) { + return NL_OK; +} + +/* */ +static int wtp_kmod_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) { + *((int*)arg) = err->error; + return NL_STOP; +} + +/* */ +static int wtp_kmod_finish_handler(struct nl_msg* msg, void* arg) { + *((int*)arg) = 0; + return NL_SKIP; +} + +/* */ +static int wtp_kmod_ack_handler(struct nl_msg* msg, void* arg) { + *((int*)arg) = 0; + return NL_STOP; +} + +/* */ +static int wtp_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) { + switch (gnlh->cmd) { + case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: { + wtp_recv_data_keepalive(); + break; + } + + case NLSMARTCAPWAP_CMD_RECV_DATA: { + if (tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) { + wtp_recv_data(nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME])); + } + + break; + } + } + + return NL_SKIP; +} + +/* */ +static int wtp_kmod_valid_handler(struct nl_msg* msg, void* data) { + struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + + nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + return wtp_kmod_event_handler(gnlh, tb_msg, data); +} + +/* */ +static int wtp_kmod_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, wtp_kmod_valid_cb valid_cb, void* data) { + int result; + struct nl_cb* cb; + + /* Clone netlink callback */ + cb = nl_cb_clone(nl_cb); + if (!cb) { + return -1; + } + + /* Complete send message */ + result = nl_send_auto_complete(nl, msg); + if (result < 0) { + nl_cb_put(cb); + return -1; + } + + /* Customize message callback */ + nl_cb_err(cb, NL_CB_CUSTOM, wtp_kmod_error_handler, &result); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wtp_kmod_finish_handler, &result); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wtp_kmod_ack_handler, &result); + + if (valid_cb) { + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data); + } + + result = 1; + while (result > 0) { + nl_recvmsgs(nl, cb); + } + + nl_cb_put(cb); + return result; +} + +/* */ +static int wtp_kmod_send_and_recv_msg(struct nl_msg* msg, wtp_kmod_valid_cb valid_cb, void* data) { + return wtp_kmod_send_and_recv(g_wtp.kmodhandle.nlmsg, g_wtp.kmodhandle.nlmsg_cb, msg, valid_cb, data); +} + +/* */ +static int wtp_kmod_link(void) { + int result; + struct nl_msg* msg; + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LINK, 0); + + /* */ + result = wtp_kmod_send_and_recv(g_wtp.kmodhandle.nl, g_wtp.kmodhandle.nl_cb, msg, NULL, NULL); + if (result) { + if (result == -EALREADY) { + result = 0; + } else { + capwap_logging_warning("Unable to connect kernel module, error code: %d", result); + } + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +static void wtp_kmod_event_receive(int fd, void** params, int paramscount) { + int res; + + ASSERT(fd >= 0); + ASSERT(params != NULL); + ASSERT(paramscount == 2); + + /* */ + res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]); + if (res) { + capwap_logging_warning("Receive kernel module message failed: %d", res); + } +} + +/* */ +int wtp_kmod_bind(uint16_t family) { + int result; + struct nl_msg* msg; + struct sockaddr_storage sockaddr; + + ASSERT((family == AF_INET) || (family == AF_INET6)); + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + memset(&sockaddr, 0, sizeof(struct sockaddr_storage)); + sockaddr.ss_family = family; + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu) { + int result; + struct nl_msg* msg; + + ASSERT(sockaddr != NULL); + ASSERT((sockaddr->ss_family == AF_INET) || (sockaddr->ss_family == AF_INET6)); + ASSERT(sessionid != NULL); + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_CONNECT, 0); + nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr); + nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_send_keepalive(void) { + int result; + struct nl_msg* msg; + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_resetsession(void) { + int result; + struct nl_msg* msg; + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_RESET, 0); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) { + int result; + struct nl_msg* msg; + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid); + nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, frame); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding); + + if (rssi) { + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RSSI, rssi); + } + + if (snr) { + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_SNR, snr); + } + + if (rate) { + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_RATE, rate); + } + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags) { + int result; + struct nl_msg* msg; + struct capwap_list_item* itemlist; + struct wtp_kmod_iface_handle* interface; + uint32_t kmodflags = 0; + + ASSERT(wlan != NULL); + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + itemlist = capwap_itemlist_create(sizeof(struct wtp_kmod_iface_handle)); + interface = (struct wtp_kmod_iface_handle*)itemlist->item; + memset(interface, 0, sizeof(struct wtp_kmod_iface_handle)); + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + capwap_itemlist_free(itemlist); + return -1; + } + + /* Set flags */ + if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) { + kmodflags |= NLSMARTCAPWAP_FLAGS_TUNNEL_8023; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, 0); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, wlan->radioid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlan->wlanid); + nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_FLAGS, kmodflags); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, 0x0000); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, 0x0000); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, 0xffff); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + if (!result) { + interface->flags = flags; + interface->wlan = wlan; + + /* */ + capwap_itemlist_insert_after(g_wtp.kmodhandle.interfaces, NULL, itemlist); + } else { + capwap_itemlist_free(itemlist); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan) { + int result; + struct nl_msg* msg; + + ASSERT(wlan != NULL); + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + return -1; + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, 0); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex); + + /* */ + result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); + if (!result) { + struct capwap_list_item* itemlist; + + for (itemlist = g_wtp.kmodhandle.interfaces->first; itemlist != NULL; itemlist = itemlist->next) { + struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item; + + if (interface->wlan == wlan) { + capwap_itemlist_free(capwap_itemlist_remove(g_wtp.kmodhandle.interfaces, itemlist)); + break; + } + } + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_isconnected(void) { + return (g_wtp.kmodhandle.nlsmartcapwap_id ? 1 : 0); +} + +/* */ +int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) { + int kmodcount = (wtp_kmod_isconnected() ? 1 : 0); + + /* */ + if (!kmodcount) { + return 0; + } else if (!fds && !events && !count) { + return kmodcount; + } else if ((count > 0) && (!fds || !events)) { + return -1; + } else if (count < kmodcount) { + return -1; + } + + /* */ + fds[0].fd = g_wtp.kmodhandle.nl_fd; + fds[0].events = POLLIN | POLLERR | POLLHUP; + + /* */ + events[0].event_handler = wtp_kmod_event_receive; + events[0].params[0] = (void*)g_wtp.kmodhandle.nl; + events[0].params[1] = (void*)g_wtp.kmodhandle.nl_cb; + events[0].paramscount = 2; + + return kmodcount; +} + +/* */ +int wtp_kmod_init(void) { + int result; + + /* Configure netlink callback */ + g_wtp.kmodhandle.nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!g_wtp.kmodhandle.nl_cb) { + wtp_kmod_free(); + return -1; + } + + /* Create netlink socket */ + g_wtp.kmodhandle.nl = nl_create_handle(g_wtp.kmodhandle.nl_cb); + if (!g_wtp.kmodhandle.nl) { + wtp_kmod_free(); + return -1; + } + + g_wtp.kmodhandle.nl_fd = nl_socket_get_fd(g_wtp.kmodhandle.nl); + + /* Get nlsmartcapwap netlink family */ + g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME); + if (g_wtp.kmodhandle.nlsmartcapwap_id < 0) { + capwap_logging_warning("Unable to found kernel module"); + wtp_kmod_free(); + return -1; + } + + /* Configure callback function */ + nl_cb_set(g_wtp.kmodhandle.nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, wtp_kmod_no_seq_check, NULL); + nl_cb_set(g_wtp.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, wtp_kmod_valid_handler, NULL); + + /* Link to kernel module */ + result = wtp_kmod_link(); + if (result) { + wtp_kmod_free(); + return result; + } + + /* Configure netlink message socket */ + g_wtp.kmodhandle.nlmsg_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!g_wtp.kmodhandle.nlmsg_cb) { + wtp_kmod_free(); + return -1; + } + + /* */ + g_wtp.kmodhandle.nlmsg = nl_create_handle(g_wtp.kmodhandle.nlmsg_cb); + if (!g_wtp.kmodhandle.nlmsg) { + wtp_kmod_free(); + return -1; + } + + /* */ + g_wtp.kmodhandle.interfaces = capwap_list_create(); + return 0; +} + +/* */ +void wtp_kmod_free(void) { + if (g_wtp.kmodhandle.interfaces) { + while (g_wtp.kmodhandle.interfaces->first) { + struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)g_wtp.kmodhandle.interfaces->first->item; + + if (wtp_kmod_leave_mac80211_device(interface->wlan)) { + break; + } + } + + /* */ + capwap_list_free(g_wtp.kmodhandle.interfaces); + } + + if (g_wtp.kmodhandle.nlmsg) { + nl_socket_free(g_wtp.kmodhandle.nlmsg); + } + + if (g_wtp.kmodhandle.nlmsg_cb) { + nl_cb_put(g_wtp.kmodhandle.nlmsg_cb); + } + + if (g_wtp.kmodhandle.nl) { + nl_socket_free(g_wtp.kmodhandle.nl); + } + + if (g_wtp.kmodhandle.nl_cb) { + nl_cb_put(g_wtp.kmodhandle.nl_cb); + } + + /* */ + memset(&g_wtp.kmodhandle, 0, sizeof(struct wtp_kmod_handle)); +} diff --git a/src/wtp/wtp_kmod.h b/src/wtp/wtp_kmod.h index 46c49e1..17d6ef3 100644 --- a/src/wtp/wtp_kmod.h +++ b/src/wtp/wtp_kmod.h @@ -1,65 +1,65 @@ -#ifndef __WTP_KMOD_HEADER__ -#define __WTP_KMOD_HEADER__ - -#include "wifi_drivers.h" - -/* */ -#ifdef HAVE_LIBNL_10 -#define nl_sock nl_handle -#endif - -/* */ -#define WTP_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000 -#define WTP_KMOD_FLAGS_TUNNEL_8023 0x00000001 - -/* */ -struct wtp_kmod_iface_handle { - uint32_t flags; - struct wifi_wlan* wlan; -}; - -/* */ -struct wtp_kmod_handle { - struct nl_sock* nl; - int nl_fd; - struct nl_cb* nl_cb; - int nlsmartcapwap_id; - - /* */ - struct nl_sock* nlmsg; - struct nl_cb* nlmsg_cb; - - /* */ - struct capwap_list* interfaces; -}; - -/* */ -#define WTP_KMOD_EVENT_MAX_ITEMS 2 -struct wtp_kmod_event { - void (*event_handler)(int fd, void** params, int paramscount); - int paramscount; - void* params[WTP_KMOD_EVENT_MAX_ITEMS]; -}; - -/* */ -int wtp_kmod_init(void); -void wtp_kmod_free(void); - -/* */ -int wtp_kmod_isconnected(void); -int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count); - -/* */ -int wtp_kmod_bind(uint16_t family); -int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu); -int wtp_kmod_resetsession(void); - -/* */ -int wtp_kmod_send_keepalive(void); -int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate); - -/* */ -int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags); -int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan); - -#endif /* __WTP_KMOD_HEADER__ */ +#ifndef __WTP_KMOD_HEADER__ +#define __WTP_KMOD_HEADER__ + +#include "wifi_drivers.h" + +/* */ +#ifdef HAVE_LIBNL_10 +#define nl_sock nl_handle +#endif + +/* */ +#define WTP_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000 +#define WTP_KMOD_FLAGS_TUNNEL_8023 0x00000001 + +/* */ +struct wtp_kmod_iface_handle { + uint32_t flags; + struct wifi_wlan* wlan; +}; + +/* */ +struct wtp_kmod_handle { + struct nl_sock* nl; + int nl_fd; + struct nl_cb* nl_cb; + int nlsmartcapwap_id; + + /* */ + struct nl_sock* nlmsg; + struct nl_cb* nlmsg_cb; + + /* */ + struct capwap_list* interfaces; +}; + +/* */ +#define WTP_KMOD_EVENT_MAX_ITEMS 2 +struct wtp_kmod_event { + void (*event_handler)(int fd, void** params, int paramscount); + int paramscount; + void* params[WTP_KMOD_EVENT_MAX_ITEMS]; +}; + +/* */ +int wtp_kmod_init(void); +void wtp_kmod_free(void); + +/* */ +int wtp_kmod_isconnected(void); +int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count); + +/* */ +int wtp_kmod_bind(uint16_t family); +int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu); +int wtp_kmod_resetsession(void); + +/* */ +int wtp_kmod_send_keepalive(void); +int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate); + +/* */ +int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags); +int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan); + +#endif /* __WTP_KMOD_HEADER__ */ diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index 91c1dfc..90f8df1 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -1,789 +1,789 @@ -#include "wtp.h" -#include "capwap_hash.h" -#include "capwap_list.h" -#include "wtp_radio.h" -#include "wtp_dfa.h" -#include "wtp_kmod.h" - -/* */ -#define WTP_UPDATE_FREQUENCY_DSSS 1 -#define WTP_UPDATE_FREQUENCY_OFDM 2 -#define WTP_UPDATE_RATES 3 -#define WTP_UPDATE_CONFIGURATION 4 - -struct wtp_update_configuration_item { - int type; - struct wtp_radio* radio; -}; - -/* */ -static int wtp_radio_configure_phy(struct wtp_radio* radio) { - /* Default rate set is all supported rate */ - if (radio->radioid != radio->rateset.radioid) { - if (radio->radioid != radio->supportedrates.radioid) { - return -1; /* Supported rate not set */ - } - - /* */ - radio->rateset.radioid = radio->radioid; - radio->rateset.ratesetcount = radio->supportedrates.supportedratescount; - memcpy(radio->rateset.rateset, radio->supportedrates.supportedrates, CAPWAP_RATESET_MAXLENGTH); - - /* Update rates */ - if (wifi_device_updaterates(radio->devicehandle, radio->rateset.rateset, radio->rateset.ratesetcount)) { - return -1; - } - } - - /* Check channel radio */ - if (radio->radioid != radio->radioinformation.radioid) { - return -1; - } else if (radio->radioid != radio->radioconfig.radioid) { - return -1; - } else if ((!radio->directsequencecontrol.radioid && !radio->ofdmcontrol.radioid) || ((radio->directsequencecontrol.radioid == radio->radioid) && (radio->ofdmcontrol.radioid == radio->radioid))) { - return -1; /* Only one from DSSS and OFDM can select */ - } else if ((radio->radioid == radio->directsequencecontrol.radioid) && !(radio->radioinformation.radiotype & (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G))) { - return -1; - } else if ((radio->radioid == radio->ofdmcontrol.radioid) && !(radio->radioinformation.radiotype & CAPWAP_RADIO_TYPE_80211A)) { - return -1; - } - - return 0; -} - -/* */ -static unsigned long wtp_radio_acl_item_gethash(const void* key, unsigned long hashsize) { - uint8_t* macaddress = (uint8_t*)key; - - return (((unsigned long)macaddress[3] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]) >> 2); -} - -/* */ -static const void* wtp_radio_acl_item_getkey(const void* data) { - return NULL; // TODO -} - -/* */ -static int wtp_radio_acl_item_cmp(const void* key1, const void* key2) { - return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); -} - - -/* */ -void wtp_radio_init(void) { - g_wtp.radios = capwap_array_create(sizeof(struct wtp_radio), 0, 1); - - g_wtp.defaultaclstations = WTP_RADIO_ACL_STATION_ALLOW; - g_wtp.aclstations = capwap_hash_create(WTP_RADIO_ACL_HASH_SIZE); - g_wtp.aclstations->item_gethash = wtp_radio_acl_item_gethash; - g_wtp.aclstations->item_getkey = wtp_radio_acl_item_getkey; - g_wtp.aclstations->item_cmp = wtp_radio_acl_item_cmp; -} - -/* */ -void wtp_radio_close(void) { - int i; - struct capwap_list_item* itemwlan; - - ASSERT(g_wtp.radios != NULL); - - for (i = 0; i < g_wtp.radios->count; i++) { - struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); - - if (radio->antenna.selections) { - capwap_array_free(radio->antenna.selections); - } - - if (radio->wlan) { - for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { - struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; - - /* Destroy BSS interface */ - if (wlan->wlanhandle) { - wifi_wlan_destroy(wlan->wlanhandle); - } - } - - capwap_list_free(radio->wlan); - } - - if (radio->wlanpool) { - for (itemwlan = radio->wlanpool->first; itemwlan != NULL; itemwlan = itemwlan->next) { - struct wtp_radio_wlanpool* wlanpool = (struct wtp_radio_wlanpool*)itemwlan->item; - - /* Destroy BSS interface */ - if (wlanpool->wlanhandle) { - wifi_wlan_destroy(wlanpool->wlanhandle); - } - } - - capwap_list_free(radio->wlanpool); - } - } - - capwap_array_resize(g_wtp.radios, 0); -} - -/* */ -void wtp_radio_free(void) { - ASSERT(g_wtp.radios != NULL); - - if (g_wtp.radios->count > 0) { - wtp_radio_close(); - } - - capwap_array_free(g_wtp.radios); - capwap_hash_free(g_wtp.aclstations); -} - -/* */ -int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { - int i; - int result = 0; - unsigned short binding; - struct capwap_array* messageelements; - struct capwap_array* updateitems; - struct wtp_update_configuration_item* item; - - ASSERT(packet != NULL); - - /* */ - updateitems = capwap_array_create(sizeof(struct wtp_update_configuration_item), 0, 1); - - /* */ - binding = GET_WBID_HEADER(packet->rxmngpacket->header); - if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { - struct wtp_radio* radio; - struct capwap_list_item* search; - - /* Set radio configuration and invalidate the old values */ - search = packet->messages->first; - while (search) { - struct capwap_message_element_itemlist* messageelement = (struct capwap_message_element_itemlist*)search->item; - - /* Parsing only IEEE 802.11 message element */ - if (IS_80211_MESSAGE_ELEMENTS(messageelement->type)) { - switch (messageelement->type) { - case CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_directsequencecontrol_element* directsequencecontrol; - - for (i = 0; i < messageelements->count; i++) { - directsequencecontrol = *(struct capwap_80211_directsequencecontrol_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(directsequencecontrol->radioid); - if (radio) { - memset(&radio->directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); - memset(&radio->ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_OFDMCONTROL: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_ofdmcontrol_element* ofdmcontrol; - - for (i = 0; i < messageelements->count; i++) { - ofdmcontrol = *(struct capwap_80211_ofdmcontrol_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(ofdmcontrol->radioid); - if (radio) { - memset(&radio->directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); - memset(&radio->ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_wtpradioinformation_element* radioinformation; - - for (i = 0; i < messageelements->count; i++) { - radioinformation = *(struct capwap_80211_wtpradioinformation_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(radioinformation->radioid); - if (radio && (radio->radioid == radioinformation->radioid)) { - memcpy(&radio->radioinformation, radioinformation, sizeof(struct capwap_80211_wtpradioinformation_element)); - } - } - } - - break; - } - } - } - - /* Next */ - search = search->next; - } - - /* Update new values */ - search = packet->messages->first; - while (search) { - struct capwap_message_element_itemlist* messageelement = (struct capwap_message_element_itemlist*)search->item; - - /* Parsing only IEEE 802.11 message element */ - if (IS_80211_MESSAGE_ELEMENTS(messageelement->type)) { - switch (messageelement->type) { - case CAPWAP_ELEMENT_80211_ANTENNA: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_antenna_element* antenna; - - for (i = 0; i < messageelements->count; i++) { - antenna = *(struct capwap_80211_antenna_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(antenna->radioid); - if (radio && (radio->radioid == antenna->radioid)) { - capwap_element_80211_antenna_copy(&radio->antenna, antenna); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_MACOPERATION: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_macoperation_element* macoperation; - - for (i = 0; i < messageelements->count; i++) { - macoperation = *(struct capwap_80211_macoperation_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(macoperation->radioid); - if (radio && (radio->radioid == macoperation->radioid)) { - memcpy(&radio->macoperation, macoperation, sizeof(struct capwap_80211_macoperation_element)); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_multidomaincapability_element* multidomaincapability; - - for (i = 0; i < messageelements->count; i++) { - multidomaincapability = *(struct capwap_80211_multidomaincapability_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(multidomaincapability->radioid); - if (radio && (radio->radioid == multidomaincapability->radioid)) { - memcpy(&radio->multidomaincapability, multidomaincapability, sizeof(struct capwap_80211_multidomaincapability_element)); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_directsequencecontrol_element* directsequencecontrol; - - for (i = 0; i < messageelements->count; i++) { - directsequencecontrol = *(struct capwap_80211_directsequencecontrol_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(directsequencecontrol->radioid); - if (radio && (radio->radioid == directsequencecontrol->radioid)) { - if (radio->radioinformation.radiotype & (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G)) { - memcpy(&radio->directsequencecontrol, directsequencecontrol, sizeof(struct capwap_80211_directsequencecontrol_element)); - - /* Pending change radio channel */ - item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); - item->type = WTP_UPDATE_FREQUENCY_DSSS; - item->radio = radio; - } - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_OFDMCONTROL: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_ofdmcontrol_element* ofdmcontrol; - - for (i = 0; i < messageelements->count; i++) { - ofdmcontrol = *(struct capwap_80211_ofdmcontrol_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(ofdmcontrol->radioid); - if (radio && (radio->radioid == ofdmcontrol->radioid)) { - if (radio->radioinformation.radiotype & CAPWAP_RADIO_TYPE_80211A) { - memcpy(&radio->ofdmcontrol, ofdmcontrol, sizeof(struct capwap_80211_ofdmcontrol_element)); - - /* Pending change radio channel */ - item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); - item->type = WTP_UPDATE_FREQUENCY_OFDM; - item->radio = radio; - } - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_RATESET: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_rateset_element* rateset; - - for (i = 0; i < messageelements->count; i++) { - rateset = *(struct capwap_80211_rateset_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(rateset->radioid); - if (radio && (radio->radioid == rateset->radioid)) { - memcpy(&radio->rateset, rateset, sizeof(struct capwap_80211_rateset_element)); - - /* Pending change radio rates */ - item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); - item->type = WTP_UPDATE_RATES; - item->radio = radio; - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_SUPPORTEDRATES: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_supportedrates_element* supportedrates; - - for (i = 0; i < messageelements->count; i++) { - supportedrates = *(struct capwap_80211_supportedrates_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(supportedrates->radioid); - if (radio && (radio->radioid == supportedrates->radioid)) { - memcpy(&radio->supportedrates, supportedrates, sizeof(struct capwap_80211_supportedrates_element)); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_TXPOWER: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_txpower_element* txpower; - - for (i = 0; i < messageelements->count; i++) { - txpower = *(struct capwap_80211_txpower_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(txpower->radioid); - if (radio && (radio->radioid == txpower->radioid)) { - memcpy(&radio->txpower, txpower, sizeof(struct capwap_80211_txpower_element)); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_WTP_QOS: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_wtpqos_element* qos; - - for (i = 0; i < messageelements->count; i++) { - qos = *(struct capwap_80211_wtpqos_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(qos->radioid); - if (radio && (radio->radioid == qos->radioid)) { - memcpy(&radio->qos, qos, sizeof(struct capwap_80211_wtpqos_element)); - } - } - } - - break; - } - - case CAPWAP_ELEMENT_80211_WTP_RADIO_CONF: { - messageelements = (struct capwap_array*)messageelement->data; - if (messageelements && (messageelements->count > 0)) { - struct capwap_80211_wtpradioconf_element* radioconfig; - - for (i = 0; i < messageelements->count; i++) { - radioconfig = *(struct capwap_80211_wtpradioconf_element**)capwap_array_get_item_pointer(messageelements, i); - radio = wtp_radio_get_phy(radioconfig->radioid); - if (radio && (radio->radioid == radioconfig->radioid)) { - memcpy(&radio->radioconfig, radioconfig, sizeof(struct capwap_80211_wtpradioconf_element)); - - /* Pending change radio configuration */ - item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); - item->type = WTP_UPDATE_CONFIGURATION; - item->radio = radio; - } - } - } - - break; - } - } - } - - /* Next */ - search = search->next; - } - } - - /* Update radio frequency */ - for (i = 0; (i < updateitems->count) && !result; i++) { - struct wtp_update_configuration_item* item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, i); - - switch (item->type) { - case WTP_UPDATE_FREQUENCY_DSSS: { - result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_2GHZ, item->radio->radioinformation.radiotype, item->radio->directsequencecontrol.currentchannel); - break; - } - - case WTP_UPDATE_FREQUENCY_OFDM: { - result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_5GHZ, item->radio->radioinformation.radiotype, item->radio->ofdmcontrol.currentchannel); - break; - } - } - } - - /* Update radio configuration */ - for (i = 0; (i < updateitems->count) && !result; i++) { - struct wtp_update_configuration_item* item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, i); - - switch (item->type) { - case WTP_UPDATE_RATES: { - result = wifi_device_updaterates(item->radio->devicehandle, item->radio->rateset.rateset, item->radio->rateset.ratesetcount); - break; - } - - case WTP_UPDATE_CONFIGURATION: { - struct device_setconfiguration_params params; - - memset(¶ms, 0, sizeof(struct device_setconfiguration_params)); - params.shortpreamble = ((item->radio->radioconfig.shortpreamble == CAPWAP_WTP_RADIO_CONF_SHORTPREAMBLE_ENABLE) ? 1 : 0); - params.maxbssid = item->radio->radioconfig.maxbssid; - params.dtimperiod = item->radio->radioconfig.dtimperiod; - memcpy(params.bssid, item->radio->radioconfig.bssid, ETH_ALEN); - params.beaconperiod = item->radio->radioconfig.beaconperiod; - memcpy(params.country, item->radio->radioconfig.country, WIFI_COUNTRY_LENGTH); - result = wifi_device_setconfiguration(item->radio->devicehandle, ¶ms); - break; - } - } - } - - /* */ - capwap_array_free(updateitems); - return result; -} - -/* */ -struct wtp_radio* wtp_radio_create_phy(void) { - struct wtp_radio* radio; - - /* Create disabled radio */ - radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, g_wtp.radios->count); - radio->radioid = (uint8_t)g_wtp.radios->count; - radio->status = WTP_RADIO_DISABLED; - - /* Init configuration radio */ - radio->wlan = capwap_list_create(); - radio->wlanpool = capwap_list_create(); - radio->antenna.selections = capwap_array_create(sizeof(uint8_t), 0, 1); - return radio; -} - -/* */ -struct wtp_radio* wtp_radio_get_phy(uint8_t radioid) { - int i; - - /* Check */ - if (!IS_VALID_RADIOID(radioid)) { - return NULL; - } - - /* Retrieve radio */ - for (i = 0; i < g_wtp.radios->count; i++) { - struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); - if (radioid == radio->radioid) { - return radio; - } - } - - return NULL; -} - -/* */ -struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlanid) { - struct capwap_list_item* itemwlan; - - ASSERT(radio != NULL); - - /* Check */ - if (!IS_VALID_WLANID(wlanid)) { - return NULL; - } - - /* Retrieve BSS */ - for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { - struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; - if (wlanid == wlan->wlanid) { - return wlan; - } - } - - return NULL; -} - -/* */ -static struct wtp_radio_wlan* __wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) { - struct capwap_list_item* itemwlan; - - ASSERT(radio != NULL); - - /* Retrieve BSS */ - for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { - struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; - if (!memcmp(bssid, wlan->wlanhandle->address, MACADDRESS_EUI48_LENGTH)) { - return wlan; - } - } - - return NULL; -} - -/* */ -struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) { - int i; - - ASSERT(bssid != NULL); - - if (radio) { - return __wtp_radio_search_wlan(radio, bssid); - } - - /* Search from any radio */ - for (i = 0; i < g_wtp.radios->count; i++) { - struct wtp_radio_wlan* wlansearch = __wtp_radio_search_wlan((struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i), bssid); - if (wlansearch) { - return wlansearch; - } - } - - return NULL; -} - -/* */ -void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, const uint8_t* frame, int length) { - struct wtp_radio* radio; - struct wtp_radio_wlan* wlan; - - ASSERT(frame != NULL); - ASSERT(length > 0); - - /* Get radio */ - radio = wtp_radio_get_phy(radioid); - if (!radio) { - return; - } - - if ((binding == CAPWAP_WIRELESS_BINDING_IEEE80211) && (length >= sizeof(struct ieee80211_header))) { - struct ieee80211_header* header = (struct ieee80211_header*)frame; - const uint8_t* bssid = ieee80211_get_bssid_addr(header); - - if (bssid) { - wlan = wtp_radio_search_wlan(radio, bssid); - if (wlan) { - wifi_wlan_receive_ac_frame(wlan->wlanhandle, header, length); - } - } - } -} - -/* */ -uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid) { - struct wtp_radio* radio; - struct wtp_radio_wlan* wlan; - struct wtp_radio_wlanpool* wlanpool; - struct capwap_list_item* itemwlan; - struct capwap_list_item* itemwlanpool; - struct wlan_startap_params params; - struct capwap_80211_addwlan_element* addwlan; - - ASSERT(packet != NULL); - - /* Get message elements */ - addwlan = (struct capwap_80211_addwlan_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_ADD_WLAN); - if (!addwlan) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Get physical radio */ - radio = wtp_radio_get_phy(addwlan->radioid); - if (!radio) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Check if virtual interface is already exist */ - wlan = wtp_radio_get_wlan(radio, addwlan->wlanid); - if (wlan) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Verify exist interface into pool */ - if (!radio->wlanpool->first) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Prepare physical interface for create wlan */ - if (!radio->wlan->count) { - if (wtp_radio_configure_phy(radio)) { - return CAPWAP_RESULTCODE_FAILURE; - } - } - - /* Get interface from pool */ - itemwlanpool = capwap_itemlist_remove_head(radio->wlanpool); - wlanpool = (struct wtp_radio_wlanpool*)itemwlanpool->item; - - /* Create interface used */ - itemwlan = capwap_itemlist_create(sizeof(struct wtp_radio_wlan)); - wlan = (struct wtp_radio_wlan*)itemwlan->item; - wlan->wlanid = addwlan->wlanid; - wlan->wlanhandle = wlanpool->wlanhandle; - wlan->radio = wlanpool->radio; - - /* Wlan configuration */ - memset(¶ms, 0, sizeof(struct wlan_startap_params)); - params.radioid = addwlan->radioid; - params.wlanid = addwlan->wlanid; - params.ssid = (const char*)addwlan->ssid; - params.ssid_hidden = addwlan->suppressssid; - params.capability = addwlan->capability; - params.qos = addwlan->qos; - params.authmode = addwlan->authmode; - params.macmode = addwlan->macmode; - params.tunnelmode = addwlan->tunnelmode; - /* TODO (struct capwap_array*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE) */ - - /* Start AP */ - if (wifi_wlan_startap(wlanpool->wlanhandle, ¶ms)) { - /* Set interface to pool */ - capwap_itemlist_free(itemwlan); - capwap_itemlist_insert_before(radio->wlanpool, NULL, itemwlanpool); - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Move interface from pool to used */ - capwap_itemlist_free(itemwlanpool); - capwap_itemlist_insert_after(radio->wlan, NULL, itemwlan); - - /* Update Event File Descriptor */ - wtp_dfa_update_fdspool(&g_wtp.fds); - - /* Retrieve macaddress of new device */ - bssid->radioid = addwlan->radioid; - bssid->wlanid = addwlan->wlanid; - wifi_wlan_getbssid(wlan->wlanhandle, bssid->bssid); - - return CAPWAP_RESULTCODE_SUCCESS; -} - -/* */ -uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet) { - /* TODO */ - return CAPWAP_RESULTCODE_SUCCESS; -} - -/* */ -uint32_t wtp_radio_delete_wlan(struct capwap_parsed_packet* packet) { - /* TODO */ - return CAPWAP_RESULTCODE_SUCCESS; -} - -/* */ -uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet) { - struct capwap_addstation_element* addstation; - struct capwap_80211_station_element* station80211; - struct wtp_radio* radio; - struct wtp_radio_wlan* wlan; - struct station_add_params stationparams; - - /* Get message elements */ - addstation = (struct capwap_addstation_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_ADDSTATION); - station80211 = (struct capwap_80211_station_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_STATION); - if (!station80211 || (addstation->radioid != station80211->radioid)) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Get physical radio */ - radio = wtp_radio_get_phy(addstation->radioid); - if (!radio) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Get virtual interface */ - wlan = wtp_radio_get_wlan(radio, station80211->wlanid); - if (!wlan) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* Authorize station */ - memset(&stationparams, 0, sizeof(struct station_add_params)); - stationparams.address = station80211->address; - - if (wifi_station_authorize(wlan->wlanhandle, &stationparams)) { - return CAPWAP_RESULTCODE_FAILURE; - } - - return CAPWAP_RESULTCODE_SUCCESS; -} - -/* */ -uint32_t wtp_radio_delete_station(struct capwap_parsed_packet* packet) { - struct wtp_radio* radio; - struct capwap_deletestation_element* deletestation; - - /* Get message elements */ - deletestation = (struct capwap_deletestation_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_DELETESTATION); - - /* Get physical radio */ - radio = wtp_radio_get_phy(deletestation->radioid); - if (!radio) { - return CAPWAP_RESULTCODE_FAILURE; - } - - /* */ - wifi_station_deauthorize(radio->devicehandle, deletestation->address); - - return CAPWAP_RESULTCODE_SUCCESS; -} - -/* */ -int wtp_radio_acl_station(const uint8_t* macaddress) { - ASSERT(macaddress != NULL); - - /* Check if exist ACL for station */ - if (capwap_hash_search(g_wtp.aclstations, macaddress)) { - return ((g_wtp.defaultaclstations == WTP_RADIO_ACL_STATION_ALLOW) ? WTP_RADIO_ACL_STATION_DENY : WTP_RADIO_ACL_STATION_ALLOW); - } - - /* Default ACL station */ - return g_wtp.defaultaclstations; -} - -/* */ -void wtp_radio_acl_addstation(const uint8_t* macaddress) { - ASSERT(macaddress != NULL); - - // TODO capwap_hash_add(g_wtp.aclstations, macaddress, NULL); -} - -void wtp_radio_acl_deletestation(const uint8_t* macaddress) { - ASSERT(macaddress != NULL); - - // TODO capwap_hash_delete(g_wtp.aclstations, macaddress); -} +#include "wtp.h" +#include "capwap_hash.h" +#include "capwap_list.h" +#include "wtp_radio.h" +#include "wtp_dfa.h" +#include "wtp_kmod.h" + +/* */ +#define WTP_UPDATE_FREQUENCY_DSSS 1 +#define WTP_UPDATE_FREQUENCY_OFDM 2 +#define WTP_UPDATE_RATES 3 +#define WTP_UPDATE_CONFIGURATION 4 + +struct wtp_update_configuration_item { + int type; + struct wtp_radio* radio; +}; + +/* */ +static int wtp_radio_configure_phy(struct wtp_radio* radio) { + /* Default rate set is all supported rate */ + if (radio->radioid != radio->rateset.radioid) { + if (radio->radioid != radio->supportedrates.radioid) { + return -1; /* Supported rate not set */ + } + + /* */ + radio->rateset.radioid = radio->radioid; + radio->rateset.ratesetcount = radio->supportedrates.supportedratescount; + memcpy(radio->rateset.rateset, radio->supportedrates.supportedrates, CAPWAP_RATESET_MAXLENGTH); + + /* Update rates */ + if (wifi_device_updaterates(radio->devicehandle, radio->rateset.rateset, radio->rateset.ratesetcount)) { + return -1; + } + } + + /* Check channel radio */ + if (radio->radioid != radio->radioinformation.radioid) { + return -1; + } else if (radio->radioid != radio->radioconfig.radioid) { + return -1; + } else if ((!radio->directsequencecontrol.radioid && !radio->ofdmcontrol.radioid) || ((radio->directsequencecontrol.radioid == radio->radioid) && (radio->ofdmcontrol.radioid == radio->radioid))) { + return -1; /* Only one from DSSS and OFDM can select */ + } else if ((radio->radioid == radio->directsequencecontrol.radioid) && !(radio->radioinformation.radiotype & (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G))) { + return -1; + } else if ((radio->radioid == radio->ofdmcontrol.radioid) && !(radio->radioinformation.radiotype & CAPWAP_RADIO_TYPE_80211A)) { + return -1; + } + + return 0; +} + +/* */ +static unsigned long wtp_radio_acl_item_gethash(const void* key, unsigned long hashsize) { + uint8_t* macaddress = (uint8_t*)key; + + return (((unsigned long)macaddress[3] ^ (unsigned long)macaddress[4] ^ (unsigned long)macaddress[5]) >> 2); +} + +/* */ +static const void* wtp_radio_acl_item_getkey(const void* data) { + return NULL; // TODO +} + +/* */ +static int wtp_radio_acl_item_cmp(const void* key1, const void* key2) { + return memcmp(key1, key2, MACADDRESS_EUI48_LENGTH); +} + + +/* */ +void wtp_radio_init(void) { + g_wtp.radios = capwap_array_create(sizeof(struct wtp_radio), 0, 1); + + g_wtp.defaultaclstations = WTP_RADIO_ACL_STATION_ALLOW; + g_wtp.aclstations = capwap_hash_create(WTP_RADIO_ACL_HASH_SIZE); + g_wtp.aclstations->item_gethash = wtp_radio_acl_item_gethash; + g_wtp.aclstations->item_getkey = wtp_radio_acl_item_getkey; + g_wtp.aclstations->item_cmp = wtp_radio_acl_item_cmp; +} + +/* */ +void wtp_radio_close(void) { + int i; + struct capwap_list_item* itemwlan; + + ASSERT(g_wtp.radios != NULL); + + for (i = 0; i < g_wtp.radios->count; i++) { + struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); + + if (radio->antenna.selections) { + capwap_array_free(radio->antenna.selections); + } + + if (radio->wlan) { + for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; + + /* Destroy BSS interface */ + if (wlan->wlanhandle) { + wifi_wlan_destroy(wlan->wlanhandle); + } + } + + capwap_list_free(radio->wlan); + } + + if (radio->wlanpool) { + for (itemwlan = radio->wlanpool->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wtp_radio_wlanpool* wlanpool = (struct wtp_radio_wlanpool*)itemwlan->item; + + /* Destroy BSS interface */ + if (wlanpool->wlanhandle) { + wifi_wlan_destroy(wlanpool->wlanhandle); + } + } + + capwap_list_free(radio->wlanpool); + } + } + + capwap_array_resize(g_wtp.radios, 0); +} + +/* */ +void wtp_radio_free(void) { + ASSERT(g_wtp.radios != NULL); + + if (g_wtp.radios->count > 0) { + wtp_radio_close(); + } + + capwap_array_free(g_wtp.radios); + capwap_hash_free(g_wtp.aclstations); +} + +/* */ +int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { + int i; + int result = 0; + unsigned short binding; + struct capwap_array* messageelements; + struct capwap_array* updateitems; + struct wtp_update_configuration_item* item; + + ASSERT(packet != NULL); + + /* */ + updateitems = capwap_array_create(sizeof(struct wtp_update_configuration_item), 0, 1); + + /* */ + binding = GET_WBID_HEADER(packet->rxmngpacket->header); + if (binding == CAPWAP_WIRELESS_BINDING_IEEE80211) { + struct wtp_radio* radio; + struct capwap_list_item* search; + + /* Set radio configuration and invalidate the old values */ + search = packet->messages->first; + while (search) { + struct capwap_message_element_itemlist* messageelement = (struct capwap_message_element_itemlist*)search->item; + + /* Parsing only IEEE 802.11 message element */ + if (IS_80211_MESSAGE_ELEMENTS(messageelement->type)) { + switch (messageelement->type) { + case CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_directsequencecontrol_element* directsequencecontrol; + + for (i = 0; i < messageelements->count; i++) { + directsequencecontrol = *(struct capwap_80211_directsequencecontrol_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(directsequencecontrol->radioid); + if (radio) { + memset(&radio->directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); + memset(&radio->ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_OFDMCONTROL: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_ofdmcontrol_element* ofdmcontrol; + + for (i = 0; i < messageelements->count; i++) { + ofdmcontrol = *(struct capwap_80211_ofdmcontrol_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(ofdmcontrol->radioid); + if (radio) { + memset(&radio->directsequencecontrol, 0, sizeof(struct capwap_80211_directsequencecontrol_element)); + memset(&radio->ofdmcontrol, 0, sizeof(struct capwap_80211_ofdmcontrol_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_WTPRADIOINFORMATION: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_wtpradioinformation_element* radioinformation; + + for (i = 0; i < messageelements->count; i++) { + radioinformation = *(struct capwap_80211_wtpradioinformation_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(radioinformation->radioid); + if (radio && (radio->radioid == radioinformation->radioid)) { + memcpy(&radio->radioinformation, radioinformation, sizeof(struct capwap_80211_wtpradioinformation_element)); + } + } + } + + break; + } + } + } + + /* Next */ + search = search->next; + } + + /* Update new values */ + search = packet->messages->first; + while (search) { + struct capwap_message_element_itemlist* messageelement = (struct capwap_message_element_itemlist*)search->item; + + /* Parsing only IEEE 802.11 message element */ + if (IS_80211_MESSAGE_ELEMENTS(messageelement->type)) { + switch (messageelement->type) { + case CAPWAP_ELEMENT_80211_ANTENNA: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_antenna_element* antenna; + + for (i = 0; i < messageelements->count; i++) { + antenna = *(struct capwap_80211_antenna_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(antenna->radioid); + if (radio && (radio->radioid == antenna->radioid)) { + capwap_element_80211_antenna_copy(&radio->antenna, antenna); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_MACOPERATION: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_macoperation_element* macoperation; + + for (i = 0; i < messageelements->count; i++) { + macoperation = *(struct capwap_80211_macoperation_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(macoperation->radioid); + if (radio && (radio->radioid == macoperation->radioid)) { + memcpy(&radio->macoperation, macoperation, sizeof(struct capwap_80211_macoperation_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_MULTIDOMAINCAPABILITY: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_multidomaincapability_element* multidomaincapability; + + for (i = 0; i < messageelements->count; i++) { + multidomaincapability = *(struct capwap_80211_multidomaincapability_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(multidomaincapability->radioid); + if (radio && (radio->radioid == multidomaincapability->radioid)) { + memcpy(&radio->multidomaincapability, multidomaincapability, sizeof(struct capwap_80211_multidomaincapability_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_DIRECTSEQUENCECONTROL: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_directsequencecontrol_element* directsequencecontrol; + + for (i = 0; i < messageelements->count; i++) { + directsequencecontrol = *(struct capwap_80211_directsequencecontrol_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(directsequencecontrol->radioid); + if (radio && (radio->radioid == directsequencecontrol->radioid)) { + if (radio->radioinformation.radiotype & (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G)) { + memcpy(&radio->directsequencecontrol, directsequencecontrol, sizeof(struct capwap_80211_directsequencecontrol_element)); + + /* Pending change radio channel */ + item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); + item->type = WTP_UPDATE_FREQUENCY_DSSS; + item->radio = radio; + } + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_OFDMCONTROL: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_ofdmcontrol_element* ofdmcontrol; + + for (i = 0; i < messageelements->count; i++) { + ofdmcontrol = *(struct capwap_80211_ofdmcontrol_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(ofdmcontrol->radioid); + if (radio && (radio->radioid == ofdmcontrol->radioid)) { + if (radio->radioinformation.radiotype & CAPWAP_RADIO_TYPE_80211A) { + memcpy(&radio->ofdmcontrol, ofdmcontrol, sizeof(struct capwap_80211_ofdmcontrol_element)); + + /* Pending change radio channel */ + item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); + item->type = WTP_UPDATE_FREQUENCY_OFDM; + item->radio = radio; + } + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_RATESET: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_rateset_element* rateset; + + for (i = 0; i < messageelements->count; i++) { + rateset = *(struct capwap_80211_rateset_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(rateset->radioid); + if (radio && (radio->radioid == rateset->radioid)) { + memcpy(&radio->rateset, rateset, sizeof(struct capwap_80211_rateset_element)); + + /* Pending change radio rates */ + item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); + item->type = WTP_UPDATE_RATES; + item->radio = radio; + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_SUPPORTEDRATES: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_supportedrates_element* supportedrates; + + for (i = 0; i < messageelements->count; i++) { + supportedrates = *(struct capwap_80211_supportedrates_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(supportedrates->radioid); + if (radio && (radio->radioid == supportedrates->radioid)) { + memcpy(&radio->supportedrates, supportedrates, sizeof(struct capwap_80211_supportedrates_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_TXPOWER: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_txpower_element* txpower; + + for (i = 0; i < messageelements->count; i++) { + txpower = *(struct capwap_80211_txpower_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(txpower->radioid); + if (radio && (radio->radioid == txpower->radioid)) { + memcpy(&radio->txpower, txpower, sizeof(struct capwap_80211_txpower_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_WTP_QOS: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_wtpqos_element* qos; + + for (i = 0; i < messageelements->count; i++) { + qos = *(struct capwap_80211_wtpqos_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(qos->radioid); + if (radio && (radio->radioid == qos->radioid)) { + memcpy(&radio->qos, qos, sizeof(struct capwap_80211_wtpqos_element)); + } + } + } + + break; + } + + case CAPWAP_ELEMENT_80211_WTP_RADIO_CONF: { + messageelements = (struct capwap_array*)messageelement->data; + if (messageelements && (messageelements->count > 0)) { + struct capwap_80211_wtpradioconf_element* radioconfig; + + for (i = 0; i < messageelements->count; i++) { + radioconfig = *(struct capwap_80211_wtpradioconf_element**)capwap_array_get_item_pointer(messageelements, i); + radio = wtp_radio_get_phy(radioconfig->radioid); + if (radio && (radio->radioid == radioconfig->radioid)) { + memcpy(&radio->radioconfig, radioconfig, sizeof(struct capwap_80211_wtpradioconf_element)); + + /* Pending change radio configuration */ + item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, updateitems->count); + item->type = WTP_UPDATE_CONFIGURATION; + item->radio = radio; + } + } + } + + break; + } + } + } + + /* Next */ + search = search->next; + } + } + + /* Update radio frequency */ + for (i = 0; (i < updateitems->count) && !result; i++) { + struct wtp_update_configuration_item* item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, i); + + switch (item->type) { + case WTP_UPDATE_FREQUENCY_DSSS: { + result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_2GHZ, item->radio->radioinformation.radiotype, item->radio->directsequencecontrol.currentchannel); + break; + } + + case WTP_UPDATE_FREQUENCY_OFDM: { + result = wifi_device_setfrequency(item->radio->devicehandle, WIFI_BAND_5GHZ, item->radio->radioinformation.radiotype, item->radio->ofdmcontrol.currentchannel); + break; + } + } + } + + /* Update radio configuration */ + for (i = 0; (i < updateitems->count) && !result; i++) { + struct wtp_update_configuration_item* item = (struct wtp_update_configuration_item*)capwap_array_get_item_pointer(updateitems, i); + + switch (item->type) { + case WTP_UPDATE_RATES: { + result = wifi_device_updaterates(item->radio->devicehandle, item->radio->rateset.rateset, item->radio->rateset.ratesetcount); + break; + } + + case WTP_UPDATE_CONFIGURATION: { + struct device_setconfiguration_params params; + + memset(¶ms, 0, sizeof(struct device_setconfiguration_params)); + params.shortpreamble = ((item->radio->radioconfig.shortpreamble == CAPWAP_WTP_RADIO_CONF_SHORTPREAMBLE_ENABLE) ? 1 : 0); + params.maxbssid = item->radio->radioconfig.maxbssid; + params.dtimperiod = item->radio->radioconfig.dtimperiod; + memcpy(params.bssid, item->radio->radioconfig.bssid, ETH_ALEN); + params.beaconperiod = item->radio->radioconfig.beaconperiod; + memcpy(params.country, item->radio->radioconfig.country, WIFI_COUNTRY_LENGTH); + result = wifi_device_setconfiguration(item->radio->devicehandle, ¶ms); + break; + } + } + } + + /* */ + capwap_array_free(updateitems); + return result; +} + +/* */ +struct wtp_radio* wtp_radio_create_phy(void) { + struct wtp_radio* radio; + + /* Create disabled radio */ + radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, g_wtp.radios->count); + radio->radioid = (uint8_t)g_wtp.radios->count; + radio->status = WTP_RADIO_DISABLED; + + /* Init configuration radio */ + radio->wlan = capwap_list_create(); + radio->wlanpool = capwap_list_create(); + radio->antenna.selections = capwap_array_create(sizeof(uint8_t), 0, 1); + return radio; +} + +/* */ +struct wtp_radio* wtp_radio_get_phy(uint8_t radioid) { + int i; + + /* Check */ + if (!IS_VALID_RADIOID(radioid)) { + return NULL; + } + + /* Retrieve radio */ + for (i = 0; i < g_wtp.radios->count; i++) { + struct wtp_radio* radio = (struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i); + if (radioid == radio->radioid) { + return radio; + } + } + + return NULL; +} + +/* */ +struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlanid) { + struct capwap_list_item* itemwlan; + + ASSERT(radio != NULL); + + /* Check */ + if (!IS_VALID_WLANID(wlanid)) { + return NULL; + } + + /* Retrieve BSS */ + for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; + if (wlanid == wlan->wlanid) { + return wlan; + } + } + + return NULL; +} + +/* */ +static struct wtp_radio_wlan* __wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) { + struct capwap_list_item* itemwlan; + + ASSERT(radio != NULL); + + /* Retrieve BSS */ + for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) { + struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)itemwlan->item; + if (!memcmp(bssid, wlan->wlanhandle->address, MACADDRESS_EUI48_LENGTH)) { + return wlan; + } + } + + return NULL; +} + +/* */ +struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) { + int i; + + ASSERT(bssid != NULL); + + if (radio) { + return __wtp_radio_search_wlan(radio, bssid); + } + + /* Search from any radio */ + for (i = 0; i < g_wtp.radios->count; i++) { + struct wtp_radio_wlan* wlansearch = __wtp_radio_search_wlan((struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i), bssid); + if (wlansearch) { + return wlansearch; + } + } + + return NULL; +} + +/* */ +void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, const uint8_t* frame, int length) { + struct wtp_radio* radio; + struct wtp_radio_wlan* wlan; + + ASSERT(frame != NULL); + ASSERT(length > 0); + + /* Get radio */ + radio = wtp_radio_get_phy(radioid); + if (!radio) { + return; + } + + if ((binding == CAPWAP_WIRELESS_BINDING_IEEE80211) && (length >= sizeof(struct ieee80211_header))) { + struct ieee80211_header* header = (struct ieee80211_header*)frame; + const uint8_t* bssid = ieee80211_get_bssid_addr(header); + + if (bssid) { + wlan = wtp_radio_search_wlan(radio, bssid); + if (wlan) { + wifi_wlan_receive_ac_frame(wlan->wlanhandle, header, length); + } + } + } +} + +/* */ +uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid) { + struct wtp_radio* radio; + struct wtp_radio_wlan* wlan; + struct wtp_radio_wlanpool* wlanpool; + struct capwap_list_item* itemwlan; + struct capwap_list_item* itemwlanpool; + struct wlan_startap_params params; + struct capwap_80211_addwlan_element* addwlan; + + ASSERT(packet != NULL); + + /* Get message elements */ + addwlan = (struct capwap_80211_addwlan_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_ADD_WLAN); + if (!addwlan) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Get physical radio */ + radio = wtp_radio_get_phy(addwlan->radioid); + if (!radio) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Check if virtual interface is already exist */ + wlan = wtp_radio_get_wlan(radio, addwlan->wlanid); + if (wlan) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Verify exist interface into pool */ + if (!radio->wlanpool->first) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Prepare physical interface for create wlan */ + if (!radio->wlan->count) { + if (wtp_radio_configure_phy(radio)) { + return CAPWAP_RESULTCODE_FAILURE; + } + } + + /* Get interface from pool */ + itemwlanpool = capwap_itemlist_remove_head(radio->wlanpool); + wlanpool = (struct wtp_radio_wlanpool*)itemwlanpool->item; + + /* Create interface used */ + itemwlan = capwap_itemlist_create(sizeof(struct wtp_radio_wlan)); + wlan = (struct wtp_radio_wlan*)itemwlan->item; + wlan->wlanid = addwlan->wlanid; + wlan->wlanhandle = wlanpool->wlanhandle; + wlan->radio = wlanpool->radio; + + /* Wlan configuration */ + memset(¶ms, 0, sizeof(struct wlan_startap_params)); + params.radioid = addwlan->radioid; + params.wlanid = addwlan->wlanid; + params.ssid = (const char*)addwlan->ssid; + params.ssid_hidden = addwlan->suppressssid; + params.capability = addwlan->capability; + params.qos = addwlan->qos; + params.authmode = addwlan->authmode; + params.macmode = addwlan->macmode; + params.tunnelmode = addwlan->tunnelmode; + /* TODO (struct capwap_array*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE) */ + + /* Start AP */ + if (wifi_wlan_startap(wlanpool->wlanhandle, ¶ms)) { + /* Set interface to pool */ + capwap_itemlist_free(itemwlan); + capwap_itemlist_insert_before(radio->wlanpool, NULL, itemwlanpool); + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Move interface from pool to used */ + capwap_itemlist_free(itemwlanpool); + capwap_itemlist_insert_after(radio->wlan, NULL, itemwlan); + + /* Update Event File Descriptor */ + wtp_dfa_update_fdspool(&g_wtp.fds); + + /* Retrieve macaddress of new device */ + bssid->radioid = addwlan->radioid; + bssid->wlanid = addwlan->wlanid; + wifi_wlan_getbssid(wlan->wlanhandle, bssid->bssid); + + return CAPWAP_RESULTCODE_SUCCESS; +} + +/* */ +uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet) { + /* TODO */ + return CAPWAP_RESULTCODE_SUCCESS; +} + +/* */ +uint32_t wtp_radio_delete_wlan(struct capwap_parsed_packet* packet) { + /* TODO */ + return CAPWAP_RESULTCODE_SUCCESS; +} + +/* */ +uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet) { + struct capwap_addstation_element* addstation; + struct capwap_80211_station_element* station80211; + struct wtp_radio* radio; + struct wtp_radio_wlan* wlan; + struct station_add_params stationparams; + + /* Get message elements */ + addstation = (struct capwap_addstation_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_ADDSTATION); + station80211 = (struct capwap_80211_station_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_STATION); + if (!station80211 || (addstation->radioid != station80211->radioid)) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Get physical radio */ + radio = wtp_radio_get_phy(addstation->radioid); + if (!radio) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Get virtual interface */ + wlan = wtp_radio_get_wlan(radio, station80211->wlanid); + if (!wlan) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* Authorize station */ + memset(&stationparams, 0, sizeof(struct station_add_params)); + stationparams.address = station80211->address; + + if (wifi_station_authorize(wlan->wlanhandle, &stationparams)) { + return CAPWAP_RESULTCODE_FAILURE; + } + + return CAPWAP_RESULTCODE_SUCCESS; +} + +/* */ +uint32_t wtp_radio_delete_station(struct capwap_parsed_packet* packet) { + struct wtp_radio* radio; + struct capwap_deletestation_element* deletestation; + + /* Get message elements */ + deletestation = (struct capwap_deletestation_element*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_DELETESTATION); + + /* Get physical radio */ + radio = wtp_radio_get_phy(deletestation->radioid); + if (!radio) { + return CAPWAP_RESULTCODE_FAILURE; + } + + /* */ + wifi_station_deauthorize(radio->devicehandle, deletestation->address); + + return CAPWAP_RESULTCODE_SUCCESS; +} + +/* */ +int wtp_radio_acl_station(const uint8_t* macaddress) { + ASSERT(macaddress != NULL); + + /* Check if exist ACL for station */ + if (capwap_hash_search(g_wtp.aclstations, macaddress)) { + return ((g_wtp.defaultaclstations == WTP_RADIO_ACL_STATION_ALLOW) ? WTP_RADIO_ACL_STATION_DENY : WTP_RADIO_ACL_STATION_ALLOW); + } + + /* Default ACL station */ + return g_wtp.defaultaclstations; +} + +/* */ +void wtp_radio_acl_addstation(const uint8_t* macaddress) { + ASSERT(macaddress != NULL); + + // TODO capwap_hash_add(g_wtp.aclstations, macaddress, NULL); +} + +void wtp_radio_acl_deletestation(const uint8_t* macaddress) { + ASSERT(macaddress != NULL); + + // TODO capwap_hash_delete(g_wtp.aclstations, macaddress); +} diff --git a/src/wtp/wtp_radio.h b/src/wtp/wtp_radio.h index 87799fa..8a14a3f 100644 --- a/src/wtp/wtp_radio.h +++ b/src/wtp/wtp_radio.h @@ -1,90 +1,90 @@ -#ifndef __WTP_RADIO_HEADER__ -#define __WTP_RADIO_HEADER__ - -#include "ieee80211.h" - -/* */ -#define WTP_RADIO_ENABLED 0 -#define WTP_RADIO_DISABLED 1 -#define WTP_RADIO_HWFAILURE 2 -#define WTP_RADIO_SWFAILURE 3 - -/* */ -#define WTP_RADIO_ACL_HASH_SIZE 64 - -#define WTP_RADIO_ACL_STATION_ALLOW 0 -#define WTP_RADIO_ACL_STATION_DENY 1 - -/* */ -#define WTP_PREFIX_NAME_MAX_LENGTH (IFNAMSIZ - 6) -#define WTP_PREFIX_DEFAULT_NAME "ap" - -struct wtp_radio_wlan { - uint8_t wlanid; - struct wifi_wlan* wlanhandle; - struct wtp_radio* radio; -}; - -/* */ -struct wtp_radio_wlanpool { - struct wifi_wlan* wlanhandle; - struct wtp_radio* radio; -}; - -/* */ -struct wtp_radio { - uint8_t radioid; - char device[IFNAMSIZ]; - struct wifi_device* devicehandle; - - char wlanprefix[IFNAMSIZ]; - struct capwap_list* wlan; - struct capwap_list* wlanpool; - - int status; - struct capwap_80211_antenna_element antenna; - struct capwap_80211_directsequencecontrol_element directsequencecontrol; - struct capwap_80211_macoperation_element macoperation; - struct capwap_80211_multidomaincapability_element multidomaincapability; - struct capwap_80211_ofdmcontrol_element ofdmcontrol; - struct capwap_80211_rateset_element rateset; - struct capwap_80211_supportedrates_element supportedrates; - struct capwap_80211_txpower_element txpower; - struct capwap_80211_txpowerlevel_element txpowerlevel; - struct capwap_80211_wtpradioconf_element radioconfig; - struct capwap_80211_wtpradioinformation_element radioinformation; - struct capwap_80211_wtpqos_element qos; -}; - -/* */ -void wtp_radio_init(void); -void wtp_radio_close(void); -void wtp_radio_free(void); - -/* */ -struct wtp_radio* wtp_radio_create_phy(void); -struct wtp_radio* wtp_radio_get_phy(uint8_t radioid); -struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlanid); -struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid); - -/* */ -void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, const uint8_t* frame, int length); - -/* */ -int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet); - -/* */ -uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid); -uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet); -uint32_t wtp_radio_delete_wlan(struct capwap_parsed_packet* packet); - -/* */ -uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet); -uint32_t wtp_radio_delete_station(struct capwap_parsed_packet* packet); - -/* Station ACL */ -int wtp_radio_acl_station(const uint8_t* macaddress); -void wtp_radio_acl_addstation(const uint8_t* macaddress); -void wtp_radio_acl_deletestation(const uint8_t* macaddress); - -#endif /* __WTP_RADIO_HEADER__ */ +#ifndef __WTP_RADIO_HEADER__ +#define __WTP_RADIO_HEADER__ + +#include "ieee80211.h" + +/* */ +#define WTP_RADIO_ENABLED 0 +#define WTP_RADIO_DISABLED 1 +#define WTP_RADIO_HWFAILURE 2 +#define WTP_RADIO_SWFAILURE 3 + +/* */ +#define WTP_RADIO_ACL_HASH_SIZE 64 + +#define WTP_RADIO_ACL_STATION_ALLOW 0 +#define WTP_RADIO_ACL_STATION_DENY 1 + +/* */ +#define WTP_PREFIX_NAME_MAX_LENGTH (IFNAMSIZ - 6) +#define WTP_PREFIX_DEFAULT_NAME "ap" + +struct wtp_radio_wlan { + uint8_t wlanid; + struct wifi_wlan* wlanhandle; + struct wtp_radio* radio; +}; + +/* */ +struct wtp_radio_wlanpool { + struct wifi_wlan* wlanhandle; + struct wtp_radio* radio; +}; + +/* */ +struct wtp_radio { + uint8_t radioid; + char device[IFNAMSIZ]; + struct wifi_device* devicehandle; + + char wlanprefix[IFNAMSIZ]; + struct capwap_list* wlan; + struct capwap_list* wlanpool; + + int status; + struct capwap_80211_antenna_element antenna; + struct capwap_80211_directsequencecontrol_element directsequencecontrol; + struct capwap_80211_macoperation_element macoperation; + struct capwap_80211_multidomaincapability_element multidomaincapability; + struct capwap_80211_ofdmcontrol_element ofdmcontrol; + struct capwap_80211_rateset_element rateset; + struct capwap_80211_supportedrates_element supportedrates; + struct capwap_80211_txpower_element txpower; + struct capwap_80211_txpowerlevel_element txpowerlevel; + struct capwap_80211_wtpradioconf_element radioconfig; + struct capwap_80211_wtpradioinformation_element radioinformation; + struct capwap_80211_wtpqos_element qos; +}; + +/* */ +void wtp_radio_init(void); +void wtp_radio_close(void); +void wtp_radio_free(void); + +/* */ +struct wtp_radio* wtp_radio_create_phy(void); +struct wtp_radio* wtp_radio_get_phy(uint8_t radioid); +struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlanid); +struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid); + +/* */ +void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, const uint8_t* frame, int length); + +/* */ +int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet); + +/* */ +uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid); +uint32_t wtp_radio_update_wlan(struct capwap_parsed_packet* packet); +uint32_t wtp_radio_delete_wlan(struct capwap_parsed_packet* packet); + +/* */ +uint32_t wtp_radio_add_station(struct capwap_parsed_packet* packet); +uint32_t wtp_radio_delete_station(struct capwap_parsed_packet* packet); + +/* Station ACL */ +int wtp_radio_acl_station(const uint8_t* macaddress); +void wtp_radio_acl_addstation(const uint8_t* macaddress); +void wtp_radio_acl_deletestation(const uint8_t* macaddress); + +#endif /* __WTP_RADIO_HEADER__ */ diff --git a/webservice/smartcapwap.wsdl b/webservice/smartcapwap.wsdl index 6eafbab..0f41754 100644 --- a/webservice/smartcapwap.wsdl +++ b/webservice/smartcapwap.wsdl @@ -1,326 +1,326 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +