From 0790fb511a1d976f7c2bd6db385360645f800b81 Mon Sep 17 00:00:00 2001 From: vemax78 Date: Tue, 21 Jan 2014 19:54:59 +0100 Subject: [PATCH] Improved the management of authentication and association of the stations --- src/binding/ieee80211/ieee80211.c | 71 +++- src/binding/ieee80211/ieee80211.h | 84 +++- src/binding/ieee80211/wifi_drivers.c | 186 ++++++--- src/binding/ieee80211/wifi_drivers.h | 54 ++- src/binding/ieee80211/wifi_nl80211.c | 604 ++++++++++++++++++++++----- src/binding/ieee80211/wifi_nl80211.h | 68 ++- src/common/capwap_protocol.h | 11 - src/wtp/wtp_dfa.c | 4 + src/wtp/wtp_radio.c | 145 +++++-- src/wtp/wtp_radio.h | 16 +- 10 files changed, 975 insertions(+), 268 deletions(-) diff --git a/src/binding/ieee80211/ieee80211.c b/src/binding/ieee80211/ieee80211.c index 0ed5fe1..b77881f 100644 --- a/src/binding/ieee80211/ieee80211.c +++ b/src/binding/ieee80211/ieee80211.c @@ -88,7 +88,7 @@ static int ieee80211_ie_set_dsss(char* buffer, uint8_t channel) { } /* */ -static int ieee80211_ie_set_erp(char* buffer, uint32_t mode, uint32_t erpmode) { +static int ieee80211_ie_set_erp(char* buffer, uint32_t mode, uint8_t erpinfo) { struct ieee80211_ie_erp* ieerp = (struct ieee80211_ie_erp*)buffer; ASSERT(buffer != NULL); @@ -99,11 +99,34 @@ static int ieee80211_ie_set_erp(char* buffer, uint32_t mode, uint32_t erpmode) { ieerp->id = IEEE80211_IE_ERP; ieerp->len = IEEE80211_IE_ERP_LENGTH; - ieerp->params = erpmode; + ieerp->params = erpinfo; return sizeof(struct ieee80211_ie_erp); } +/* */ +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(char* buffer, int length, struct ieee80211_beacon_params* params) { int result; @@ -167,7 +190,7 @@ int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_pa /* TODO */ /* Information Element: ERP */ - result = ieee80211_ie_set_erp(pos, params->mode, params->erpmode); + result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo); if (result < 0) { return -1; } @@ -188,7 +211,7 @@ int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_pa } /* */ -int ieee80211_create_probe_response(char* buffer, int length, const struct ieee80211_header_mgmt* proberequestheader, struct ieee80211_probe_response_params* params) { +int ieee80211_create_probe_response(char* buffer, int length, struct ieee80211_probe_response_params* params) { int result; char* pos; int responselength; @@ -203,11 +226,7 @@ int ieee80211_create_probe_response(char* buffer, int length, const struct ieee8 /* Management header frame */ header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESPONSE); header->durationid = __cpu_to_le16(0); - if (proberequestheader) { - memcpy(header->da, proberequestheader->sa, ETH_ALEN); - } else { - memset(header->da, 0, ETH_ALEN); - } + 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); @@ -250,7 +269,7 @@ int ieee80211_create_probe_response(char* buffer, int length, const struct ieee8 /* TODO */ /* Information Element: ERP */ - result = ieee80211_ie_set_erp(pos, params->mode, params->erpmode); + result = ieee80211_ie_set_erp(pos, params->mode, params->erpinfo); if (result < 0) { return -1; } @@ -271,7 +290,7 @@ int ieee80211_create_probe_response(char* buffer, int length, const struct ieee8 } /* */ -int ieee80211_create_authentication_response(char* buffer, int length, const struct ieee80211_header_mgmt* authenticationheader, struct ieee80211_authentication_params* params) { +int ieee80211_create_authentication_response(char* buffer, int length, struct ieee80211_authentication_params* params) { char* pos; int responselength; struct ieee80211_header_mgmt* header; @@ -285,7 +304,7 @@ int ieee80211_create_authentication_response(char* buffer, int length, const str /* 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, authenticationheader->sa, ETH_ALEN); + 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); @@ -303,7 +322,7 @@ int ieee80211_create_authentication_response(char* buffer, int length, const str } /* */ -int ieee80211_create_associationresponse_response(char* buffer, int length, const struct ieee80211_header_mgmt* associationrequestheader, struct ieee80211_associationresponse_params* params) { +int ieee80211_create_associationresponse_response(char* buffer, int length, struct ieee80211_associationresponse_params* params) { char* pos; int result; int responselength; @@ -318,7 +337,7 @@ int ieee80211_create_associationresponse_response(char* buffer, int length, cons /* 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, associationrequestheader->sa, ETH_ALEN); + 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); @@ -349,4 +368,26 @@ int ieee80211_create_associationresponse_response(char* buffer, int length, cons responselength += result; return responselength; -} \ No newline at end of file +} + +/* */ +int ieee80211_create_deauthentication(char* buffer, int length, struct ieee80211_deauthentication_params* params) { + struct ieee80211_header_mgmt* header; + + ASSERT(buffer != NULL); + ASSERT(length == IEEE80211_MTU); + + /* */ + 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/binding/ieee80211/ieee80211.h b/src/binding/ieee80211/ieee80211.h index aaf6e33..ba37c33 100644 --- a/src/binding/ieee80211/ieee80211.h +++ b/src/binding/ieee80211/ieee80211.h @@ -10,7 +10,8 @@ #endif /* Global values */ -#define IEEE80211_MTU 2304 +#define IEEE80211_MTU 2304 +#define IEEE80211_SUPPORTEDRATE_MAX_COUNT 16 /* Radio type with value same of IEEE802.11 Radio Information Message Element */ #define IEEE80211_RADIO_TYPE_80211B 0x00000001 @@ -185,6 +186,34 @@ #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 @@ -193,6 +222,29 @@ /* */ #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 { @@ -251,6 +303,11 @@ struct ieee80211_header_mgmt { __le16 aid; uint8_t ie[0]; } STRUCT_PACKED associationresponse; + + struct { + __le16 reasoncode; + uint8_t ie[0]; + } STRUCT_PACKED deauthetication; }; } STRUCT_PACKED; @@ -398,7 +455,7 @@ struct ieee80211_ie_items { }; /* IEEE 802.11 functions */ -#define IEEE80211_SUPPORTEDRATE_MAX_COUNT 16 +uint8_t ieee80211_get_erpinfo(uint32_t mode, int olbc, unsigned long stationnonerpcount, unsigned long stationnoshortpreamblecount, int shortpreamble); /* Management Beacon */ struct ieee80211_beacon_params { @@ -421,7 +478,7 @@ struct ieee80211_beacon_params { uint8_t channel; uint32_t mode; - uint32_t erpmode; + uint8_t erpinfo; }; int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_params* params); @@ -429,6 +486,7 @@ int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_pa /* Management Probe Response */ struct ieee80211_probe_response_params { uint8_t bssid[ETH_ALEN]; + uint8_t station[ETH_ALEN]; uint16_t beaconperiod; uint16_t capability; @@ -441,25 +499,27 @@ struct ieee80211_probe_response_params { uint8_t channel; uint32_t mode; - uint32_t erpmode; + uint8_t erpinfo; }; -int ieee80211_create_probe_response(char* buffer, int length, const struct ieee80211_header_mgmt* proberequestheader, struct ieee80211_probe_response_params* params); +int ieee80211_create_probe_response(char* 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(char* buffer, int length, const struct ieee80211_header_mgmt* authenticationheader, struct ieee80211_authentication_params* params); +int ieee80211_create_authentication_response(char* 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; @@ -469,6 +529,16 @@ struct ieee80211_associationresponse_params { uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; }; -int ieee80211_create_associationresponse_response(char* buffer, int length, const struct ieee80211_header_mgmt* associationrequestheader, struct ieee80211_associationresponse_params* params); +int ieee80211_create_associationresponse_response(char* 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(char* buffer, int length, struct ieee80211_deauthentication_params* params); #endif /* __CAPWAP_IEEE802_11_HEADER__ */ diff --git a/src/binding/ieee80211/wifi_drivers.c b/src/binding/ieee80211/wifi_drivers.c index db3982c..ff1ffba 100644 --- a/src/binding/ieee80211/wifi_drivers.c +++ b/src/binding/ieee80211/wifi_drivers.c @@ -170,6 +170,25 @@ int wifi_device_connect(int radioid, const char* ifname, const char* driver) { return result; } +/* */ +static struct wifi_device* wifi_device_getdevice(int radioid) { + struct wifi_device* device; + + ASSERT(radioid > 0); + + if (g_wifidevice->count < radioid) { + return NULL; + } + + /* Get radio connection */ + device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); + if (!device->handle) { + return NULL; + } + + return device; +} + /* */ static struct wifi_wlan* wifi_wlan_getdevice(int radioid, int wlanid) { struct wifi_device* device; @@ -183,7 +202,7 @@ static struct wifi_wlan* wifi_wlan_getdevice(int radioid, int wlanid) { /* Get radio connection */ device = (struct wifi_device*)capwap_array_get_item_pointer(g_wifidevice, radioid); - if (device->wlan->count < wlanid) { + if (!device->handle || (device->wlan->count < wlanid)) { return NULL; } @@ -202,10 +221,7 @@ int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid struct wifi_device* device; struct wifi_wlan* wlan; wifi_wlan_handle wlanhandle; - struct wlan_init_params params = { - .ifname = ifname, - .type = WLAN_INTERFACE_AP - }; + struct wlan_init_params params; ASSERT(radioid > 0); ASSERT(wlanid > 0); @@ -239,6 +255,8 @@ int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid } /* Create interface */ + params.ifname = ifname; + params.type = WLAN_INTERFACE_AP; wlanhandle = device->instance->ops->wlan_create(device->handle, ¶ms); if (!wlanhandle) { capwap_logging_warning("Unable to create virtual interface: %s", ifname); @@ -254,7 +272,7 @@ int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid } /* */ -static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* radio) { +static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* radio, struct device_setrates_params* device_params) { int i, j, w; int radiotype; uint32_t mode = 0; @@ -262,9 +280,10 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad ASSERT(device != NULL); ASSERT(radio != NULL); + ASSERT(radio->rateset.ratesetcount > 0); - /* Free old supported rates */ - device->supportedratescount = 0; + /* */ + memset(device_params, 0, sizeof(struct device_setrates_params)); /* Retrieve capability */ capability = wifi_device_getcapability(radio->radioid); @@ -299,10 +318,10 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad /* Add implicit 802.11b rate with only 802.11g rate */ if ((device->currentfreq.band == WIFI_BAND_2GHZ) && !(mode & CAPWAP_RADIO_TYPE_80211B) && (device->currentfreq.mode & CAPWAP_RADIO_TYPE_80211B)) { - device->supportedrates[device->supportedratescount++] = IEEE80211_RATE_1M; - device->supportedrates[device->supportedratescount++] = IEEE80211_RATE_2M; - device->supportedrates[device->supportedratescount++] = IEEE80211_RATE_5_5M; - device->supportedrates[device->supportedratescount++] = IEEE80211_RATE_11M; + 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 */ @@ -316,7 +335,7 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad /* Validate rate */ for (w = 0; w < radio->rateset.ratesetcount; w++) { if (radio->rateset.rateset[w] == rate->bitrate) { - device->supportedrates[device->supportedratescount++] = rate->bitrate; + device_params->supportedrates[device_params->supportedratescount++] = rate->bitrate; break; } } @@ -327,49 +346,34 @@ static void wifi_wlan_getrates(struct wifi_device* device, struct wtp_radio* rad } /* Apply basic rate */ - for (i = 0; i < device->supportedratescount; i++) { + for (i = 0; i < device_params->supportedratescount; i++) { if (radiotype == CAPWAP_RADIO_TYPE_80211A) { - if (IS_IEEE80211_BASICRATE_A(device->supportedrates[i])) { - device->supportedrates[i] |= IEEE80211_BASICRATE; + 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->supportedrates[i])) { - device->supportedrates[i] |= IEEE80211_BASICRATE; + 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->supportedrates[i])) { - device->supportedrates[i] |= IEEE80211_BASICRATE; + 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->currentfreq.mode & CAPWAP_RADIO_TYPE_80211N)) { - device->supportedrates[device->supportedratescount++] = IEEE80211_RATE_80211N; + device_params->supportedrates[device_params->supportedratescount++] = IEEE80211_RATE_80211N; } } /* */ -int wifi_wlan_setupap(int radioid, int wlanid) { +int wifi_wlan_startap(int radioid, int wlanid, struct wifi_wlan_startap_params* params) { struct wifi_wlan* wlan; - - ASSERT(radioid > 0); - ASSERT(wlanid > 0); - - /* */ - wlan = wifi_wlan_getdevice(radioid, wlanid); - if (!wlan || !wlan->device->instance->ops->wlan_setupap) { - return -1; - } - - return wlan->device->instance->ops->wlan_setupap(wlan->handle); -} - -/* */ -int wifi_wlan_startap(int radioid, int wlanid) { - struct wifi_wlan* wlan; - struct wtp_radio* radio; - struct wtp_radio_wlan* radiowlan; struct wlan_startap_params wlan_params; ASSERT(radioid > 0); @@ -377,30 +381,16 @@ int wifi_wlan_startap(int radioid, int wlanid) { /* */ wlan = wifi_wlan_getdevice(radioid, wlanid); - radio = wtp_radio_get_phy(radioid); - if (!wlan || !radio || !wlan->device->instance->ops->wlan_startap) { + if (!wlan || !wlan->device->instance->ops->wlan_startap) { return -1; } - /* */ - radiowlan = wtp_radio_get_wlan(radio, wlanid); - if (!radiowlan) { - return -1; - } - - /* Retrieve supported rates */ - wifi_wlan_getrates(wlan->device, radiowlan->radio); - /* Start AP */ memset(&wlan_params, 0, sizeof(struct wlan_startap_params)); - wlan_params.ssid = radiowlan->ssid; - wlan_params.ssid_hidden = radiowlan->ssid_hidden; - wlan_params.beaconperiod = radio->radioconfig.beaconperiod; - wlan_params.capability = radiowlan->capability; - wlan_params.dtimperiod = radio->radioconfig.dtimperiod; - memcpy(wlan_params.supportedrates, wlan->device->supportedrates, wlan->device->supportedratescount); - wlan_params.supportedratescount = wlan->device->supportedratescount; - wlan_params.authenticationtype = radiowlan->authmode; + wlan_params.ssid = params->ssid; + wlan_params.ssid_hidden = params->ssid_hidden; + wlan_params.capability = params->capability; + wlan_params.authenticationtype = params->authmode; return wlan->device->instance->ops->wlan_startap(wlan->handle, &wlan_params); } @@ -467,6 +457,20 @@ const struct wifi_capability* wifi_device_getcapability(int radioid) { return device->instance->ops->device_getcapability(device->handle); } +/* */ +int wifi_device_setconfiguration(int radioid, struct device_setconfiguration_params* params) { + struct wifi_device* device; + + /* Get radio device */ + device = wifi_device_getdevice(radioid); + if (!device || !device->handle || !device->instance->ops->device_setconfiguration) { + return -1; + } + + /* Set rates */ + return device->instance->ops->device_setconfiguration(device->handle, params); +} + /* */ int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t channel) { int i, j; @@ -529,6 +533,24 @@ int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t return result; } +/* */ +int wifi_device_updaterates(int radioid) { + struct wtp_radio* radio; + struct wifi_device* device; + struct device_setrates_params params; + + /* Get radio device */ + device = wifi_device_getdevice(radioid); + radio = wtp_radio_get_phy(radioid); + if (!device || !radio || !device->handle || !device->instance->ops->device_setrates) { + return -1; + } + + /* Set rates */ + wifi_wlan_getrates(device, radio, ¶ms); + return device->instance->ops->device_setrates(device->handle, ¶ms); +} + /* */ uint32_t wifi_iface_index(const char* ifname) { if (!ifname || !*ifname) { @@ -626,7 +648,10 @@ int wifi_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struc int ssidlength; ASSERT(ssid != NULL); - ASSERT(iessid != NULL); + + if (!iessid) { + return WIFI_WRONG_SSID; + } /* Check SSID */ ssidlength = strlen((char*)ssid); @@ -777,3 +802,44 @@ int wifi_retrieve_information_elements_position(struct ieee80211_ie_items* items return (!length ? 0 : -1); } + +/* */ +int wifi_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 < WIFI_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 wifi_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)); +} diff --git a/src/binding/ieee80211/wifi_drivers.h b/src/binding/ieee80211/wifi_drivers.h index 85c1f54..0cb1c29 100644 --- a/src/binding/ieee80211/wifi_drivers.h +++ b/src/binding/ieee80211/wifi_drivers.h @@ -62,6 +62,9 @@ #define WLAN_INTERFACE_AP 1 +/* IEEE802.11 Aid management */ +#define WIFI_AID_BITFIELD_SIZE 63 + /* */ typedef void* wifi_global_handle; typedef void* wifi_device_handle; @@ -72,6 +75,25 @@ struct device_init_params { const char* ifname; }; +/* */ +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[ETH_ALEN]; + uint16_t beaconperiod; + uint8_t country[WIFI_COUNTRY_LENGTH]; +}; + /* */ struct wlan_init_params { const char* ifname; @@ -83,12 +105,7 @@ struct wlan_startap_params { const char* ssid; uint8_t ssid_hidden; - uint16_t beaconperiod; uint16_t capability; - uint8_t dtimperiod; - - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; uint8_t authenticationtype; }; @@ -207,13 +224,14 @@ struct wifi_driver_ops { wifi_device_handle (*device_init)(wifi_global_handle handle, struct device_init_params* params); int (*device_getfdevent)(wifi_device_handle handle, struct pollfd* fds, struct wifi_event* events); const struct wifi_capability* (*device_getcapability)(wifi_device_handle handle); + int (*device_setconfiguration)(wifi_device_handle handle, struct device_setconfiguration_params* params); int (*device_setfrequency)(wifi_device_handle handle, struct wifi_frequency* freq); + int (*device_setrates)(wifi_device_handle handle, struct device_setrates_params* params); void (*device_deinit)(wifi_device_handle handle); /* WLAN functions */ wifi_wlan_handle (*wlan_create)(wifi_device_handle handle, struct wlan_init_params* params); int (*wlan_getfdevent)(wifi_wlan_handle handle, struct pollfd* fds, struct wifi_event* events); - int (*wlan_setupap)(wifi_wlan_handle handle); int (*wlan_startap)(wifi_wlan_handle handle, struct wlan_startap_params* params); int (*wlan_stopap)(wifi_wlan_handle handle); int (*wlan_getmacaddress)(wifi_wlan_handle handle, uint8_t* address); @@ -235,10 +253,6 @@ struct wifi_device { /* Current frequency */ struct wifi_frequency currentfreq; - - /* Supported Rates */ - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; }; /* */ @@ -247,6 +261,17 @@ struct wifi_wlan { struct wifi_device* device; }; +/* */ +struct wifi_wlan_startap_params { + uint16_t capability; + uint8_t qos; + uint8_t authmode; + uint8_t macmode; + uint8_t tunnelmode; + uint8_t ssid_hidden; + char ssid[IEEE80211_IE_SSID_MAX_LENGTH + 1]; +}; + /* Initialize wifi driver engine */ int wifi_driver_init(void); void wifi_driver_free(void); @@ -257,12 +282,13 @@ int wifi_event_getfd(struct pollfd* fds, struct wifi_event* events, int count); /* */ int wifi_device_connect(int radioid, const char* ifname, const char* driver); const struct wifi_capability* wifi_device_getcapability(int radioid); +int wifi_device_setconfiguration(int radioid, struct device_setconfiguration_params* params); int wifi_device_setfrequency(int radioid, uint32_t band, uint32_t mode, uint8_t channel); +int wifi_device_updaterates(int radioid); /* */ int wifi_wlan_create(int radioid, int wlanid, const char* ifname, uint8_t* bssid); -int wifi_wlan_setupap(int radioid, int wlanid); -int wifi_wlan_startap(int radioid, int wlanid); +int wifi_wlan_startap(int radioid, int wlanid, struct wifi_wlan_startap_params* params); int wifi_wlan_stopap(int radioid, int wlanid); int wifi_wlan_getbssid(int radioid, int wlanid, uint8_t* bssid); void wifi_wlan_destroy(int radioid, int wlanid); @@ -281,6 +307,10 @@ int wifi_is_broadcast_addr(const uint8_t* addr); #define WIFI_WRONG_SSID -1 int wifi_is_valid_ssid(const char* ssid, struct ieee80211_ie_ssid* iessid, struct ieee80211_ie_ssid_list* isssidlist); +/* */ +int wifi_aid_create(uint32_t* aidbitfield, uint16_t* aid); +void wifi_aid_free(uint32_t* aidbitfield, uint16_t aid); + /* */ int wifi_retrieve_information_elements_position(struct ieee80211_ie_items* items, const uint8_t* data, int length); diff --git a/src/binding/ieee80211/wifi_nl80211.c b/src/binding/ieee80211/wifi_nl80211.c index 701a761..211edf7 100644 --- a/src/binding/ieee80211/wifi_nl80211.c +++ b/src/binding/ieee80211/wifi_nl80211.c @@ -2,6 +2,7 @@ #include "capwap_array.h" #include "capwap_list.h" #include "capwap_element.h" +#include "wtp_radio.h" #include #include #include @@ -254,6 +255,267 @@ static int nl80211_wlan_send_frame(wifi_wlan_handle handle, struct wlan_send_fra return result; } +/* */ +static uint16_t nl80211_wlan_check_capability(struct nl80211_wlan_handle* wlanhandle, uint16_t capability) { + uint16_t result = capability; + + /* Force ESS capability */ + result |= IEEE80211_CAPABILITY_ESS; + + /* Check short preamble capability */ + if (wlanhandle->devicehandle->shortpreamble && !wlanhandle->devicehandle->stationsnoshortpreamblecount) { + result |= IEEE80211_CAPABILITY_SHORTPREAMBLE; + } else { + result &= ~IEEE80211_CAPABILITY_SHORTPREAMBLE; + } + + /* Check privacy capability */ + /* TODO */ + + /* Check short slot time capability */ + if ((wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) && !wlanhandle->devicehandle->stationsnoshortslottimecount) { + result |= IEEE80211_CAPABILITY_SHORTSLOTTIME; + } else { + result &= ~IEEE80211_CAPABILITY_SHORTSLOTTIME; + } + + return capability; +} + +/* */ +static int nl80211_wlan_setbss(struct nl80211_wlan_handle* wlanhandle, int cts, int preamble, int slot, int htopmode, int apisolate) { + int result; + struct nl_msg* msg; + + /* */ + 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, wlanhandle->virtindex); + + if (cts >= 0) { + nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts); + } + + if (preamble >= 0) { + nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble); + } + + if (slot >= 0) { + nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot); + } + + if (htopmode >= 0) { + nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, htopmode); + } + + if (apisolate >= 0) { + nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, apisolate); + } + + if (wlanhandle->devicehandle->basicratescount > 0) { + nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, wlanhandle->devicehandle->basicratescount, wlanhandle->devicehandle->basicrates); + } + + /* */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + nlmsg_free(msg); + + return result; +} + +/* */ +static int nl80211_wlan_setbeacon(struct nl80211_wlan_handle* wlanhandle) { + int result; + struct nl_msg* msg; + char buffer[IEEE80211_MTU]; + struct ieee80211_beacon_params ieee80211_params; + + /* Create beacon packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_beacon_params)); + memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); + ieee80211_params.beaconperiod = wlanhandle->devicehandle->beaconperiod; + ieee80211_params.capability = nl80211_wlan_check_capability(wlanhandle, wlanhandle->capability); + ieee80211_params.ssid = wlanhandle->ssid; + ieee80211_params.ssid_hidden = wlanhandle->ssid_hidden; + memcpy(ieee80211_params.supportedrates, wlanhandle->devicehandle->supportedrates, wlanhandle->devicehandle->supportedratescount); + ieee80211_params.supportedratescount = wlanhandle->devicehandle->supportedratescount; + ieee80211_params.mode = wlanhandle->devicehandle->currentfrequency.mode; + ieee80211_params.erpinfo = ieee80211_get_erpinfo(wlanhandle->devicehandle->currentfrequency.mode, wlanhandle->devicehandle->olbc, wlanhandle->devicehandle->stationsnonerpcount, wlanhandle->devicehandle->stationsnoshortpreamblecount, wlanhandle->devicehandle->shortpreamble); + ieee80211_params.channel = wlanhandle->devicehandle->currentfrequency.channel; + + result = ieee80211_create_beacon(buffer, IEEE80211_MTU, &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, ((wlanhandle->flags & NL80211_WLAN_SET_BEACON) ? NL80211_CMD_SET_BEACON : NL80211_CMD_START_AP), 0); + nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->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, wlanhandle->devicehandle->beaconperiod); + nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, wlanhandle->devicehandle->dtimperiod); + nla_put(msg, NL80211_ATTR_SSID, strlen(wlanhandle->ssid), wlanhandle->ssid); + nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID, (wlanhandle->ssid_hidden ? NL80211_HIDDEN_SSID_ZERO_LEN : NL80211_HIDDEN_SSID_NOT_IN_USE)); + nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, wlanhandle->authenticationtype); + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); + + /* Start AP */ + result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); + nlmsg_free(msg); + + /* Configure AP */ + if (!result) { + int cts = ((ieee80211_params.erpinfo & IEEE80211_ERP_INFO_USE_PROTECTION) ? 1 : 0); + int preamble = ((!wlanhandle->devicehandle->stationsnoshortpreamblecount && wlanhandle->devicehandle->shortpreamble) ? 1 : 0); + int slot = ((wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G) ? (wlanhandle->devicehandle->stationsnoshortslottimecount ? 0 : 1) : -1); + int htopmode = -1; /* TODO: 802.11n */ + int apisolate = -1; /* TODO: AP Isolation */ + + result = nl80211_wlan_setbss(wlanhandle, cts, preamble, slot, htopmode, apisolate); + if (!result) { + wlanhandle->flags |= NL80211_WLAN_SET_BEACON; + } + } + + return result; +} + +/* */ +static void nl80211_device_updatebeacons(struct nl80211_device_handle* devicehandle) { + struct capwap_list_item* wlansearch; + + ASSERT(devicehandle != NULL); + + /* Update all wlan beacon */ + wlansearch = devicehandle->wlanlist->first; + while (wlansearch) { + nl80211_wlan_setbeacon((struct nl80211_wlan_handle*)wlansearch->item); + wlansearch = wlansearch->next; + } +} + +/* */ +static void nl80211_station_delete(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { + int updatebeacons = 0; + struct nl80211_station* station; + + ASSERT(macaddress != NULL); + + station = (struct nl80211_station*)capwap_hash_search(wlanhandle->stations, macaddress); + if (station) { + if (station->aid) { + wifi_aid_free(wlanhandle->aidbitfield, station->aid); + } + + if (station->flags & NL80211_STATION_FLAGS_NON_ERP) { + wlanhandle->devicehandle->stationsnonerpcount--; + if (!wlanhandle->devicehandle->stationsnonerpcount) { + updatebeacons = 1; + } + } + + if (station->flags & NL80211_STATION_FLAGS_NO_SHORT_SLOT_TIME) { + wlanhandle->devicehandle->stationsnoshortslottimecount--; + if (!wlanhandle->devicehandle->stationsnoshortslottimecount && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + if (station->flags & NL80211_STATION_FLAGS_NO_SHORT_PREAMBLE) { + wlanhandle->devicehandle->stationsnoshortpreamblecount--; + if (!wlanhandle->devicehandle->stationsnoshortpreamblecount && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + /* Free station into hash callback */ + wlanhandle->stationscount--; + capwap_hash_delete(wlanhandle->stations, macaddress); + + /* Update beacons */ + if (updatebeacons) { + nl80211_device_updatebeacons(wlanhandle->devicehandle); + } + } +} + +/* */ +static struct nl80211_station* nl80211_station_create(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { + struct nl80211_station* station; + + ASSERT(macaddress != NULL); + + /* If exist free old station */ + nl80211_station_delete(wlanhandle, macaddress); + + /* Checks if it has reached the maximum number of stations */ + /* TODO */ + + /* Disconnect from another WLAN */ + /* TODO */ + + /* Create new station */ + station = (struct nl80211_station*)capwap_alloc(sizeof(struct nl80211_station)); + memset(station, 0, sizeof(struct nl80211_station)); + + /* TODO */ + + /* */ + wlanhandle->stationscount++; + capwap_hash_add(wlanhandle->stations, macaddress, station); + return station; +} + +/* */ +static struct nl80211_station* nl80211_station_get(struct nl80211_wlan_handle* wlanhandle, const uint8_t* macaddress) { + ASSERT(macaddress != NULL); + + return (struct nl80211_station*)capwap_hash_search(wlanhandle->stations, macaddress); +} + +/* */ +static void nl80211_wlan_send_deauthentication(struct nl80211_wlan_handle* wlanhandle, const uint8_t* stationaddress, uint16_t reasoncode) { + int responselength; + char buffer[IEEE80211_MTU]; + struct ieee80211_deauthentication_params ieee80211_params; + struct wlan_send_frame_params wlan_params; + + /* Create deauthentication packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_deauthentication_params)); + memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); + memcpy(ieee80211_params.station, stationaddress, ETH_ALEN); + ieee80211_params.reasoncode = reasoncode; + + responselength = ieee80211_create_deauthentication(buffer, IEEE80211_MTU, &ieee80211_params); + if (responselength < 0) { + return; + } + + /* Send deauthentication */ + memset(&wlan_params, 0, sizeof(struct wlan_send_frame_params)); + wlan_params.packet = buffer; + wlan_params.length = responselength; + wlan_params.frequency = wlanhandle->devicehandle->currentfrequency.frequency; + + if (!nl80211_wlan_send_frame((wifi_wlan_handle)wlanhandle, &wlan_params)) { + wlanhandle->last_cookie = wlan_params.cookie; + } else { + capwap_logging_warning("Unable to send IEEE802.11 Deuthentication"); + } +} + /* */ static void nl80211_do_mgmt_probe_request_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { int ielength; @@ -289,16 +551,17 @@ static void nl80211_do_mgmt_probe_request_event(struct nl80211_wlan_handle* wlan /* Create probe response */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_probe_response_params)); memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); - ieee80211_params.beaconperiod = wlanhandle->beaconperiod; - ieee80211_params.capability = wlanhandle->capability; + memcpy(ieee80211_params.station, mgmt->sa, ETH_ALEN); + ieee80211_params.beaconperiod = wlanhandle->devicehandle->beaconperiod; + ieee80211_params.capability = nl80211_wlan_check_capability(wlanhandle, wlanhandle->capability); ieee80211_params.ssid = wlanhandle->ssid; - memcpy(ieee80211_params.supportedrates, wlanhandle->supportedrates, wlanhandle->supportedratescount); - ieee80211_params.supportedratescount = wlanhandle->supportedratescount; + memcpy(ieee80211_params.supportedrates, wlanhandle->devicehandle->supportedrates, wlanhandle->devicehandle->supportedratescount); + ieee80211_params.supportedratescount = wlanhandle->devicehandle->supportedratescount; ieee80211_params.mode = wlanhandle->devicehandle->currentfrequency.mode; - ieee80211_params.erpmode = 0; /* TODO */ + ieee80211_params.erpinfo = ieee80211_get_erpinfo(wlanhandle->devicehandle->currentfrequency.mode, wlanhandle->devicehandle->olbc, wlanhandle->devicehandle->stationsnonerpcount, wlanhandle->devicehandle->stationsnoshortpreamblecount, wlanhandle->devicehandle->shortpreamble); ieee80211_params.channel = wlanhandle->devicehandle->currentfrequency.channel; - responselength = ieee80211_create_probe_response(buffer, IEEE80211_MTU, mgmt, &ieee80211_params); + responselength = ieee80211_create_probe_response(buffer, IEEE80211_MTU, &ieee80211_params); if (responselength < 0) { return; } @@ -327,6 +590,7 @@ static void nl80211_do_mgmt_authentication_event(struct nl80211_wlan_handle* wla char buffer[IEEE80211_MTU]; struct ieee80211_authentication_params ieee80211_params; struct wlan_send_frame_params wlan_params; + struct nl80211_station* station; /* Ignore authentication packet from same AP */ if (!memcmp(mgmt->sa, wlanhandle->address, ETH_ALEN)) { @@ -351,28 +615,36 @@ static void nl80211_do_mgmt_authentication_event(struct nl80211_wlan_handle* wla } /* Create station reference */ - /* TODO */ + station = nl80211_station_create(wlanhandle, mgmt->sa); + if (station) { + algorithm = __le16_to_cpu(mgmt->authetication.algorithm); + transactionseqnumber = __le16_to_cpu(mgmt->authetication.transactionseqnumber); - /* */ - algorithm = __le16_to_cpu(mgmt->authetication.algorithm); - transactionseqnumber = __le16_to_cpu(mgmt->authetication.transactionseqnumber); - - /* Check authentication algorithm */ - responsestatuscode = IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM; - if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlanhandle->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_OPEN)) { - responsestatuscode = ((transactionseqnumber == 1) ? IEEE80211_STATUS_SUCCESS : IEEE80211_STATUS_UNKNOWN_AUTHENTICATION_TRANSACTION); - } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlanhandle->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_WEP)) { - /* TODO */ + /* Check authentication algorithm */ + responsestatuscode = IEEE80211_STATUS_NOT_SUPPORTED_AUTHENTICATION_ALGORITHM; + if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (wlanhandle->authenticationtype == 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) && (wlanhandle->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_WEP)) { + /* TODO */ + } + } else { + responsestatuscode = IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; } /* Create authentication packet */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); + memcpy(ieee80211_params.station, mgmt->sa, ETH_ALEN); ieee80211_params.algorithm = algorithm; ieee80211_params.transactionseqnumber = transactionseqnumber + 1; ieee80211_params.statuscode = responsestatuscode; - responselength = ieee80211_create_authentication_response(buffer, IEEE80211_MTU, mgmt, &ieee80211_params); + responselength = ieee80211_create_authentication_response(buffer, IEEE80211_MTU, &ieee80211_params); if (responselength < 0) { return; } @@ -390,6 +662,83 @@ static void nl80211_do_mgmt_authentication_event(struct nl80211_wlan_handle* wla } } +/* */ +static int nl80211_set_station_information(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, struct ieee80211_ie_items* ieitems, struct nl80211_station* station) { + int updatebeacons = 0; + + /* Verify SSID */ + if (wifi_is_valid_ssid(wlanhandle->ssid, ieitems->ssid, NULL) != WIFI_VALID_SSID) { + return IEEE80211_STATUS_UNSPECIFIED_FAILURE; + } + + /* */ + station->capability = __le16_to_cpu(mgmt->associationrequest.capability); + station->listeninterval = __le16_to_cpu(mgmt->associationrequest.listeninterval); + if (wifi_aid_create(wlanhandle->aidbitfield, &station->aid)) { + return IEEE80211_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + } + + /* Get supported rates */ + if (!ieitems->supported_rates) { + return IEEE80211_STATUS_UNSPECIFIED_FAILURE; + } else if ((ieitems->supported_rates->len + (ieitems->extended_supported_rates ? ieitems->extended_supported_rates->len : 0)) > sizeof(station->supportedrates)) { + return IEEE80211_STATUS_UNSPECIFIED_FAILURE; + } + + 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); + } + + /* Check NON ERP */ + if (wlanhandle->devicehandle->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 |= NL80211_STATION_FLAGS_NON_ERP; + wlanhandle->devicehandle->stationsnonerpcount++; + if (wlanhandle->devicehandle->stationsnonerpcount == 1) { + updatebeacons = 1; + } + } + } + + /* Check short slot capability */ + if (!(station->capability & IEEE80211_CAPABILITY_SHORTSLOTTIME)) { + station->flags |= NL80211_STATION_FLAGS_NO_SHORT_SLOT_TIME; + wlanhandle->devicehandle->stationsnoshortslottimecount++; + if ((wlanhandle->devicehandle->stationsnoshortslottimecount == 1) && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + /* Check short preamble capability */ + if (!(station->capability & IEEE80211_CAPABILITY_SHORTPREAMBLE)) { + station->flags |= NL80211_STATION_FLAGS_NO_SHORT_PREAMBLE; + wlanhandle->devicehandle->stationsnoshortpreamblecount++; + if ((wlanhandle->devicehandle->stationsnoshortpreamblecount == 1) && (wlanhandle->devicehandle->currentfrequency.mode & IEEE80211_RADIO_TYPE_80211G)) { + updatebeacons = 1; + } + } + + /* Update beacon */ + if (updatebeacons) { + nl80211_device_updatebeacons(wlanhandle->devicehandle); + } + + return IEEE80211_STATUS_SUCCESS; +} + /* */ static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { int ielength; @@ -398,6 +747,16 @@ static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle struct ieee80211_ie_items ieitems; struct ieee80211_associationresponse_params ieee80211_params; struct wlan_send_frame_params wlan_params; + struct nl80211_station* station; + uint16_t resultstatuscode = IEEE80211_STATUS_SUCCESS; + + /* Get station reference */ + station = nl80211_station_get(wlanhandle, mgmt->sa); + if (!station || !(station->flags & NL80211_STATION_FLAGS_AUTHENTICATED)) { + /* Invalid station, send deauthentication message */ + nl80211_wlan_send_deauthentication(wlanhandle, mgmt->sa, IEEE80211_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); + return; + } /* Information Elements packet length */ ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest)); @@ -410,19 +769,20 @@ static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle return; } - /* Get station reference */ - /* TODO */ + /* */ + resultstatuscode = nl80211_set_station_information(wlanhandle, mgmt, &ieitems, station); /* Create association response packet */ memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); - ieee80211_params.capability = wlanhandle->capability; - ieee80211_params.statuscode = IEEE80211_STATUS_SUCCESS; - ieee80211_params.aid = IEEE80211_AID_FIELD | 1; - memcpy(ieee80211_params.supportedrates, wlanhandle->supportedrates, wlanhandle->supportedratescount); - ieee80211_params.supportedratescount = wlanhandle->supportedratescount; + memcpy(ieee80211_params.station, mgmt->sa, ETH_ALEN); + ieee80211_params.capability = nl80211_wlan_check_capability(wlanhandle, wlanhandle->capability); + ieee80211_params.statuscode = resultstatuscode; + ieee80211_params.aid = IEEE80211_AID_FIELD | station->aid; + memcpy(ieee80211_params.supportedrates, wlanhandle->devicehandle->supportedrates, wlanhandle->devicehandle->supportedratescount); + ieee80211_params.supportedratescount = wlanhandle->devicehandle->supportedratescount; - responselength = ieee80211_create_associationresponse_response(buffer, IEEE80211_MTU, mgmt, &ieee80211_params); + responselength = ieee80211_create_associationresponse_response(buffer, IEEE80211_MTU, &ieee80211_params); if (responselength < 0) { return; } @@ -522,6 +882,7 @@ static void nl80211_do_mgmt_frame_tx_status_authentication_event(struct nl80211_ uint16_t algorithm; uint16_t transactionseqnumber; uint16_t statuscode; + struct nl80211_station* station; /* Accept only acknowledge authentication response with same cookie */ if (!ack || (wlanhandle->last_cookie != cookie)) { @@ -533,6 +894,12 @@ static void nl80211_do_mgmt_frame_tx_status_authentication_event(struct nl80211_ return; } + /* Get station information */ + station = nl80211_station_get(wlanhandle, mgmt->da); + if (!station) { + return; + } + /* */ statuscode = __le16_to_cpu(mgmt->authetication.statuscode); if (statuscode == IEEE80211_STATUS_SUCCESS) { @@ -541,7 +908,7 @@ static void nl80211_do_mgmt_frame_tx_status_authentication_event(struct nl80211_ /* Check if authenticate */ if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_OPEN) && (transactionseqnumber == 2)) { - capwap_logging_debug("Authenticate station"); + station->flags |= NL80211_STATION_FLAGS_AUTHENTICATED; } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { /* TODO */ } @@ -551,6 +918,7 @@ static void nl80211_do_mgmt_frame_tx_status_authentication_event(struct nl80211_ /* */ static void nl80211_do_mgmt_frame_tx_status_association_response_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint64_t cookie, int ack) { uint16_t statuscode; + struct nl80211_station* station; /* Accept only acknowledge association response with same cookie */ if (!ack || (wlanhandle->last_cookie != cookie)) { @@ -562,12 +930,19 @@ static void nl80211_do_mgmt_frame_tx_status_association_response_event(struct nl return; } + /* Get station information */ + station = nl80211_station_get(wlanhandle, mgmt->da); + if (!station) { + return; + } + /* */ statuscode = __le16_to_cpu(mgmt->associationresponse.statuscode); if (statuscode == IEEE80211_STATUS_SUCCESS) { - capwap_logging_debug("Associate station"); + station->flags |= NL80211_STATION_FLAGS_ASSOCIATE; } } + /* */ static void nl80211_do_mgmt_frame_tx_status_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype, uint64_t cookie, int ack) { /* Ignore packet if not sent to AP */ @@ -586,6 +961,11 @@ static void nl80211_do_mgmt_frame_tx_status_event(struct nl80211_wlan_handle* wl nl80211_do_mgmt_frame_tx_status_association_response_event(wlanhandle, mgmt, mgmtlength, cookie, ack); break; } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { + /* TODO */ + break; + } } /* Remove cookie */ @@ -674,6 +1054,24 @@ static void nl80211_event_receive(int fd, void* param1, void* param2) { } } +/* */ +static unsigned long nl80211_hash_station_gethash(const void* key, unsigned long keysize, unsigned long hashsize) { + uint8_t* macaddress = (uint8_t*)key; + + ASSERT(keysize == ETH_ALEN); + + return ((macaddress[3] ^ macaddress[4] ^ macaddress[5]) >> 2); +} + +/* */ +static void nl80211_hash_station_free(const void* key, unsigned long keysize, void* data) { + struct nl80211_station* station = (struct nl80211_station*)data; + + ASSERT(data != NULL); + + capwap_free(station); +} + /* */ static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { uint32_t ifindex; @@ -1283,6 +1681,22 @@ static int nl80211_device_getfdevent(wifi_device_handle handle, struct pollfd* f return 0; } +/* */ +static int nl80211_device_setconfiguration(wifi_device_handle handle, struct device_setconfiguration_params* params) { + struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; + + ASSERT(handle != NULL); + + /* */ + devicehandle->beaconperiod = params->beaconperiod; + devicehandle->dtimperiod = params->dtimperiod; + devicehandle->shortpreamble = (params->shortpreamble ? 1 : 0); + + /* Update beacons */ + nl80211_device_updatebeacons(devicehandle); + return 0; +} + /* */ static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_frequency* freq) { int result; @@ -1314,6 +1728,31 @@ static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_fr return result; } +/* */ +static int nl80211_device_setrates(wifi_device_handle handle, struct device_setrates_params* params) { + struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; + + ASSERT(handle != NULL); + ASSERT(params != NULL); + + /* */ + if (!params->supportedratescount || (params->supportedratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { + return -1; + } else if (!params->basicratescount || (params->basicratescount > IEEE80211_SUPPORTEDRATE_MAX_COUNT)) { + return -1; + } + + /* Set new rates */ + memcpy(devicehandle->supportedrates, params->supportedrates, params->supportedratescount); + devicehandle->supportedratescount = params->supportedratescount; + memcpy(devicehandle->basicrates, params->basicrates, params->basicratescount); + devicehandle->basicratescount = params->basicratescount; + + /* Update beacons */ + nl80211_device_updatebeacons(devicehandle); + return 0; +} + /* */ static void nl80211_wlan_delete(wifi_wlan_handle handle) { struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; @@ -1347,6 +1786,10 @@ static void nl80211_wlan_delete(wifi_wlan_handle handle) { nl_cb_put(wlanhandle->nl_cb); } + if (wlanhandle->stations) { + capwap_hash_free(wlanhandle->stations); + } + capwap_free(wlanhandle); } } @@ -1413,12 +1856,22 @@ static void nl80211_device_deinit(wifi_device_handle handle) { /* */ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wlan_init_params* params) { + int i; int result; uint32_t ifindex; struct nl_msg* msg; struct capwap_list_item* item; struct nl80211_wlan_handle* wlanhandle = NULL; struct nl80211_device_handle* devicehandle = (struct nl80211_device_handle*)handle; + static const int stypes[] = { + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION, + IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION + }; ASSERT(handle != NULL); ASSERT(params != NULL); @@ -1493,6 +1946,17 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl return NULL; } + /* Register frames */ + for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) { + if (nl80211_registerframe(wlanhandle, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (stypes[i] << 4), NULL, 0)) { + nl80211_wlan_delete((wifi_wlan_handle)wlanhandle); + return NULL; + } + } + + /* Stations */ + wlanhandle->stations = capwap_hash_create(WIFI_NL80211_STATIONS_HASH_SIZE, WIFI_NL80211_STATIONS_KEY_SIZE, nl80211_hash_station_gethash, NULL, nl80211_hash_station_free); + return wlanhandle; } @@ -1516,38 +1980,8 @@ static int nl80211_wlan_getfdevent(wifi_wlan_handle handle, struct pollfd* fds, return 1; } -/* */ -static int nl80211_wlan_setupap(wifi_wlan_handle handle) { - int i; - struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; - static const int stypes[] = { - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION - }; - - ASSERT(handle != NULL); - - /* Register frames */ - for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) { - if (nl80211_registerframe(wlanhandle, (IEEE80211_FRAMECONTROL_TYPE_MGMT << 2) | (stypes[i] << 4), NULL, 0)) { - return -1; - } - } - - return 0; -} - /* */ static int nl80211_wlan_startap(wifi_wlan_handle handle, struct wlan_startap_params* params) { - int result; - struct nl_msg* msg; - char buffer[IEEE80211_MTU]; - struct ieee80211_beacon_params ieee80211_params; struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; /* Enable interface */ @@ -1555,55 +1989,14 @@ static int nl80211_wlan_startap(wifi_wlan_handle handle, struct wlan_startap_par return -1; } - /* Create beacon packet */ - memset(&ieee80211_params, 0, sizeof(struct ieee80211_beacon_params)); - memcpy(ieee80211_params.bssid, wlanhandle->address, ETH_ALEN); - ieee80211_params.beaconperiod = params->beaconperiod; - ieee80211_params.capability = params->capability; - ieee80211_params.ssid = params->ssid; - ieee80211_params.ssid_hidden = params->ssid_hidden; - memcpy(ieee80211_params.supportedrates, params->supportedrates, params->supportedratescount); - ieee80211_params.supportedratescount = params->supportedratescount; - ieee80211_params.mode = wlanhandle->devicehandle->currentfrequency.mode; - ieee80211_params.erpmode = 0; /* TODO */ - ieee80211_params.channel = wlanhandle->devicehandle->currentfrequency.channel; - - result = ieee80211_create_beacon(buffer, IEEE80211_MTU, &ieee80211_params); - if (result < 0) { - return -1; - } - - /* */ + /* Save configuration */ strcpy(wlanhandle->ssid, params->ssid); - wlanhandle->beaconperiod = params->beaconperiod; + wlanhandle->ssid_hidden = params->ssid_hidden; wlanhandle->capability = params->capability; - memcpy(wlanhandle->supportedrates, params->supportedrates, params->supportedratescount); - wlanhandle->supportedratescount = params->supportedratescount; - wlanhandle->authenticationtype = params->authenticationtype; + wlanhandle->authenticationtype = ((params->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM); - /* */ - msg = nlmsg_alloc(); - if (!msg) { - return -1; - } - - /* */ - genlmsg_put(msg, 0, 0, wlanhandle->devicehandle->globalhandle->nl80211_id, 0, 0, NL80211_CMD_START_AP, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, wlanhandle->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, params->beaconperiod); - nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtimperiod); - nla_put(msg, NL80211_ATTR_SSID, strlen(params->ssid), params->ssid); - nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID, (params->ssid_hidden ? NL80211_HIDDEN_SSID_ZERO_LEN : NL80211_HIDDEN_SSID_NOT_IN_USE)); - nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, ((params->authenticationtype == CAPWAP_ADD_WLAN_AUTHTYPE_WEP) ? NL80211_AUTHTYPE_SHARED_KEY : NL80211_AUTHTYPE_OPEN_SYSTEM)); - nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT); - - /* Start AP */ - result = nl80211_send_and_recv_msg(wlanhandle->devicehandle->globalhandle, msg, NULL, NULL); - nlmsg_free(msg); - - return result; + /* Set beacon */ + return nl80211_wlan_setbeacon(wlanhandle); } /* */ @@ -1792,11 +2185,12 @@ const struct wifi_driver_ops wifi_driver_nl80211_ops = { .device_init = nl80211_device_init, .device_getfdevent = nl80211_device_getfdevent, .device_getcapability = nl80211_device_getcachedcapability, + .device_setconfiguration = nl80211_device_setconfiguration, .device_setfrequency = nl80211_device_setfrequency, + .device_setrates = nl80211_device_setrates, .device_deinit = nl80211_device_deinit, .wlan_create = nl80211_wlan_create, .wlan_getfdevent = nl80211_wlan_getfdevent, - .wlan_setupap = nl80211_wlan_setupap, .wlan_startap = nl80211_wlan_startap, .wlan_stopap = nl80211_wlan_stopap, .wlan_getmacaddress = nl80211_wlan_getmacaddress, diff --git a/src/binding/ieee80211/wifi_nl80211.h b/src/binding/ieee80211/wifi_nl80211.h index b283550..426136c 100644 --- a/src/binding/ieee80211/wifi_nl80211.h +++ b/src/binding/ieee80211/wifi_nl80211.h @@ -1,11 +1,17 @@ #ifndef __WIFI_NL80211_HEADER__ #define __WIFI_NL80211_HEADER__ +#include "capwap_hash.h" + /* Compatibility functions */ #if !defined(HAVE_LIBNL20) && !defined(HAVE_LIBNL30) #define nl_sock nl_handle #endif +/* */ +#define WIFI_NL80211_STATIONS_HASH_SIZE 64 +#define WIFI_NL80211_STATIONS_KEY_SIZE ETH_ALEN + /* */ typedef int (*nl_valid_cb)(struct nl_msg* msg, void* data); @@ -32,12 +38,33 @@ struct nl80211_device_handle { struct capwap_list* wlanlist; + /* */ + uint16_t beaconperiod; + uint8_t dtimperiod; + int shortpreamble; + + /* */ struct wifi_frequency currentfrequency; - struct wifi_capability* capability; /* Cached capability */ + /* 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 NL80211_WLAN_SET_BEACON 0x00000001 + struct nl80211_wlan_handle { struct nl80211_device_handle* devicehandle; @@ -45,6 +72,8 @@ struct nl80211_wlan_handle { int nl_fd; struct nl_cb* nl_cb; + unsigned long flags; + uint32_t virtindex; char virtname[IFNAMSIZ]; @@ -54,14 +83,17 @@ struct nl80211_wlan_handle { /* WLAN information */ char ssid[WIFI_SSID_MAX_LENGTH + 1]; - - uint16_t beaconperiod; + uint8_t ssid_hidden; uint16_t capability; - int supportedratescount; - uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - + /* Authentication */ uint8_t authenticationtype; + + /* Station information */ + unsigned long stationscount; + struct capwap_hash* stations; + + uint32_t aidbitfield[WIFI_AID_BITFIELD_SIZE]; }; /* Physical device info */ @@ -77,4 +109,28 @@ struct nl80211_virtdevice_item { char virtname[IFNAMSIZ]; }; +/* Station */ +#define NL80211_STATION_FLAGS_AUTHENTICATED 0x00000001 +#define NL80211_STATION_FLAGS_ASSOCIATE 0x00000002 +#define NL80211_STATION_FLAGS_NON_ERP 0x00000004 +#define NL80211_STATION_FLAGS_NO_SHORT_SLOT_TIME 0x00000008 +#define NL80211_STATION_FLAGS_NO_SHORT_PREAMBLE 0x00000010 + +/* */ +struct nl80211_station { + unsigned long flags; + + /* */ + uint16_t capability; + uint16_t listeninterval; + uint16_t aid; + + /* */ + int supportedratescount; + uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + /* Authentication */ + uint16_t authalgorithm; +}; + #endif /* __WIFI_NL80211_HEADER__ */ diff --git a/src/common/capwap_protocol.h b/src/common/capwap_protocol.h index 587912d..6e1e9e5 100644 --- a/src/common/capwap_protocol.h +++ b/src/common/capwap_protocol.h @@ -122,15 +122,4 @@ int capwap_check_message_type(struct capwap_packet_rxmng* rxmngpacket); void capwap_get_packet_digest(struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, unsigned char packetdigest[16]); int capwap_recv_retrasmitted_request(struct capwap_dtls* dtls, struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, unsigned char packetdigest[16], struct capwap_list* txfragmentpacket); -/* TODO utile ? -#define CAPWAP_VALID_PACKET 0x00000000 -#define CAPWAP_MISSING_MANDATORY_MSG_ELEMENT 0x00000001 -#define CAPWAP_UNRECOGNIZED_MSG_ELEMENT 0x00000002 - -struct unrecognized_info { - unsigned short element; - unsigned char reason; -}; -*/ - #endif /* __CAPWAP_PROTOCOL_HEADER__ */ diff --git a/src/wtp/wtp_dfa.c b/src/wtp/wtp_dfa.c index 69088c4..d132216 100644 --- a/src/wtp/wtp_dfa.c +++ b/src/wtp/wtp_dfa.c @@ -3,6 +3,7 @@ #include "capwap_array.h" #include "capwap_dfa.h" #include "capwap_dtls.h" +#include "wtp_radio.h" #include @@ -221,6 +222,9 @@ int wtp_dfa_running(void) { g_wtp.fdstotalcount = g_wtp.fdsnetworkcount; ASSERT(g_wtp.fdstotalcount > 0); + /* Update Event File Descriptor */ + wtp_radio_update_fdevent(); + /* Handler signal */ g_wtp.running = 1; signal(SIGPIPE, SIG_IGN); diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index d9619e6..0ccd68e 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -2,6 +2,17 @@ #include "capwap_hash.h" #include "wtp_radio.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 */ @@ -14,6 +25,11 @@ static int wtp_radio_configure_phy(struct wtp_radio* radio) { 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->radioid)) { + return -1; + } } /* Check channel radio */ @@ -107,12 +123,18 @@ void wtp_radio_free(void) { /* */ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { int i; + int result = 0; unsigned short binding; struct wtp_radio* radio; 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) { @@ -253,14 +275,13 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { 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))) { - return -1; - } + if (radio->radioinformation.radiotype & (CAPWAP_RADIO_TYPE_80211B | CAPWAP_RADIO_TYPE_80211G)) { + memcpy(&radio->directsequencecontrol, directsequencecontrol, sizeof(struct capwap_80211_directsequencecontrol_element)); - /* Configure radio channel */ - memcpy(&radio->directsequencecontrol, directsequencecontrol, sizeof(struct capwap_80211_directsequencecontrol_element)); - if (wifi_device_setfrequency(radio->radioid, WIFI_BAND_2GHZ, radio->radioinformation.radiotype, radio->directsequencecontrol.currentchannel)) { - return -1; + /* 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; } } } @@ -278,14 +299,13 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { 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)) { - return -1; - } + if (radio->radioinformation.radiotype & CAPWAP_RADIO_TYPE_80211A) { + memcpy(&radio->ofdmcontrol, ofdmcontrol, sizeof(struct capwap_80211_ofdmcontrol_element)); - /* Configure radio channel */ - memcpy(&radio->ofdmcontrol, ofdmcontrol, sizeof(struct capwap_80211_ofdmcontrol_element)); - if (wifi_device_setfrequency(radio->radioid, WIFI_BAND_5GHZ, radio->radioinformation.radiotype, radio->ofdmcontrol.currentchannel)) { - return -1; + /* 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; } } } @@ -304,6 +324,11 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { 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; } } } @@ -372,6 +397,11 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { 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; } } } @@ -386,7 +416,52 @@ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet) { } } - return 0; + /* 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->radioid, WIFI_BAND_2GHZ, item->radio->radioinformation.radiotype, item->radio->directsequencecontrol.currentchannel); + break; + } + + case WTP_UPDATE_FREQUENCY_OFDM: { + result = wifi_device_setfrequency(item->radio->radioid, 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(radio->radioid); + 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->radioid, ¶ms); + break; + } + } + } + + /* */ + capwap_array_free(updateitems); + return result; } /* */ @@ -437,7 +512,7 @@ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlani } /* */ -static void wtp_radio_update_fdevent(void) { +void wtp_radio_update_fdevent(void) { int count; /* Retrieve number of File Descriptor Event */ @@ -477,8 +552,10 @@ static void wtp_radio_update_fdevent(void) { /* */ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid) { + char wlanname[IFNAMSIZ]; struct wtp_radio* radio; struct wtp_radio_wlan* wlan; + struct wifi_wlan_startap_params params; struct capwap_80211_addwlan_element* addwlan; /* Get message elements */ @@ -510,42 +587,34 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa wlan = (struct wtp_radio_wlan*)capwap_array_get_item_pointer(radio->wlan, radio->wlan->count); wlan->radio = radio; wlan->wlanid = addwlan->wlanid; - sprintf(wlan->wlanname, "%s%02d.%02d", g_wtp.wlanprefix, (int)addwlan->radioid, (int)addwlan->wlanid); - if (wifi_iface_index(wlan->wlanname)) { + sprintf(wlanname, "%s%02d.%02d", g_wtp.wlanprefix, (int)addwlan->radioid, (int)addwlan->wlanid); + if (wifi_iface_index(wlanname)) { memset(wlan, 0, sizeof(struct wtp_radio_wlan)); return CAPWAP_RESULTCODE_FAILURE; } /* Create virtual interface */ - if (!wifi_wlan_create(addwlan->radioid, addwlan->wlanid, wlan->wlanname, NULL)) { + if (!wifi_wlan_create(addwlan->radioid, addwlan->wlanid, wlanname, NULL)) { wlan->state = WTP_RADIO_WLAN_STATE_CREATED; } else { wtp_radio_destroy_wlan(wlan); return CAPWAP_RESULTCODE_FAILURE; } - /* Save wlan configuration */ - wlan->capability = addwlan->capability; - wlan->qos = addwlan->qos; - wlan->authmode = addwlan->authmode; - wlan->macmode = addwlan->macmode; - wlan->tunnelmode = addwlan->tunnelmode; - wlan->ssid_hidden = addwlan->suppressssid; - strcpy(wlan->ssid, (const char*)addwlan->ssid); - wifi_wlan_getbssid(addwlan->radioid, addwlan->wlanid, wlan->bssid); + /* Wlan configuration */ + memset(¶ms, 0, sizeof(struct wifi_wlan_startap_params)); + params.capability = addwlan->capability; + params.qos = addwlan->qos; + params.authmode = addwlan->authmode; + params.macmode = addwlan->macmode; + params.tunnelmode = addwlan->tunnelmode; + params.ssid_hidden = addwlan->suppressssid; + strcpy(params.ssid, (const char*)addwlan->ssid); /* TODO (struct capwap_array*)capwap_get_message_element_data(packet, CAPWAP_ELEMENT_80211_IE) */ - /* Configure virtual interface */ - if (!wifi_wlan_setupap(addwlan->radioid, addwlan->wlanid)) { - wlan->state = WTP_RADIO_WLAN_STATE_READY; - } else { - wtp_radio_destroy_wlan(wlan); - return CAPWAP_RESULTCODE_FAILURE; - } - /* Start AP */ - if (!wifi_wlan_startap(addwlan->radioid, addwlan->wlanid)) { + if (!wifi_wlan_startap(addwlan->radioid, addwlan->wlanid, ¶ms)) { wlan->state = WTP_RADIO_WLAN_STATE_AP; } else { wtp_radio_destroy_wlan(wlan); @@ -558,7 +627,7 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa /* Retrieve macaddress of new device */ bssid->radioid = addwlan->radioid; bssid->wlanid = addwlan->wlanid; - memcpy(bssid->bssid, wlan->bssid, ETH_ALEN); + wifi_wlan_getbssid(addwlan->radioid, addwlan->wlanid, bssid->bssid); return CAPWAP_RESULTCODE_SUCCESS; } diff --git a/src/wtp/wtp_radio.h b/src/wtp/wtp_radio.h index a280e51..03bc8f6 100644 --- a/src/wtp/wtp_radio.h +++ b/src/wtp/wtp_radio.h @@ -22,25 +22,12 @@ #define WTP_RADIO_WLAN_STATE_IDLE 0 #define WTP_RADIO_WLAN_STATE_CREATED 1 -#define WTP_RADIO_WLAN_STATE_READY 2 -#define WTP_RADIO_WLAN_STATE_AP 3 +#define WTP_RADIO_WLAN_STATE_AP 2 struct wtp_radio_wlan { struct wtp_radio* radio; int state; - uint8_t wlanid; - char wlanname[IFNAMSIZ]; - uint8_t bssid[ETH_ALEN]; - - /* */ - uint16_t capability; - uint8_t qos; - uint8_t authmode; - uint8_t macmode; - uint8_t tunnelmode; - uint8_t ssid_hidden; - char ssid[IEEE80211_IE_SSID_MAX_LENGTH + 1]; }; /* */ @@ -77,6 +64,7 @@ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlani /* */ int wtp_radio_setconfiguration(struct capwap_parsed_packet* packet); +void wtp_radio_update_fdevent(void); /* */ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwap_80211_assignbssid_element* bssid);