From 547e39892475a8116224916b6dda1870039c1f2a Mon Sep 17 00:00:00 2001 From: vemax78 Date: Tue, 14 Jan 2014 19:15:58 +0100 Subject: [PATCH] Add code to simple management IEEE802.11 Association Request/Response packets. Need more code for complete the management of station association. --- src/binding/ieee80211/ieee80211.c | 57 +++++++++++++++-- src/binding/ieee80211/ieee80211.h | 47 ++++++++++---- src/binding/ieee80211/wifi_nl80211.c | 95 +++++++++++++++++++++++++--- src/binding/ieee80211/wifi_nl80211.h | 2 +- 4 files changed, 176 insertions(+), 25 deletions(-) diff --git a/src/binding/ieee80211/ieee80211.c b/src/binding/ieee80211/ieee80211.c index 89003b1..0ed5fe1 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) { +static int ieee80211_ie_set_erp(char* buffer, uint32_t mode, uint32_t erpmode) { struct ieee80211_ie_erp* ieerp = (struct ieee80211_ie_erp*)buffer; ASSERT(buffer != NULL); @@ -99,7 +99,7 @@ static int ieee80211_ie_set_erp(char* buffer, uint32_t mode) { ieerp->id = IEEE80211_IE_ERP; ieerp->len = IEEE80211_IE_ERP_LENGTH; - ieerp->params = 0; /* TODO */ + ieerp->params = erpmode; return sizeof(struct ieee80211_ie_erp); } @@ -167,7 +167,7 @@ int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_pa /* TODO */ /* Information Element: ERP */ - result = ieee80211_ie_set_erp(pos, params->erpmode); + result = ieee80211_ie_set_erp(pos, params->mode, params->erpmode); if (result < 0) { return -1; } @@ -250,7 +250,7 @@ int ieee80211_create_probe_response(char* buffer, int length, const struct ieee8 /* TODO */ /* Information Element: ERP */ - result = ieee80211_ie_set_erp(pos, params->erpmode); + result = ieee80211_ie_set_erp(pos, params->mode, params->erpmode); if (result < 0) { return -1; } @@ -301,3 +301,52 @@ int ieee80211_create_authentication_response(char* buffer, int length, const str return responselength; } + +/* */ +int ieee80211_create_associationresponse_response(char* buffer, int length, const struct ieee80211_header_mgmt* associationrequestheader, struct ieee80211_associationresponse_params* params) { + char* pos; + int result; + int responselength; + 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_ASSOCIATION_RESPONSE); + header->durationid = __cpu_to_le16(0); + memcpy(header->da, associationrequestheader->sa, 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; + responselength += result; + + return responselength; +} \ No newline at end of file diff --git a/src/binding/ieee80211/ieee80211.h b/src/binding/ieee80211/ieee80211.h index a191bf2..aaf6e33 100644 --- a/src/binding/ieee80211/ieee80211.h +++ b/src/binding/ieee80211/ieee80211.h @@ -191,6 +191,9 @@ #define IEEE80211_AUTHENTICATION_ALGORITHM_FAST_BSS 2 #define IEEE80211_AUTHENTICATION_ALGORITHM_SAE 3 +/* */ +#define IEEE80211_AID_FIELD 0xC000 + /* 802.11 Packet - IEEE802.11 is a little-endian protocol */ struct ieee80211_header { __le16 framecontrol; @@ -235,6 +238,19 @@ struct ieee80211_header_mgmt { __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_PACKED; @@ -386,29 +402,25 @@ struct ieee80211_ie_items { /* Management Beacon */ struct ieee80211_beacon_params { - /* Beacon packet */ char* headbeacon; int headbeaconlength; char* tailbeacon; int tailbeaconlength; - /* Header information */ uint8_t bssid[ETH_ALEN]; + uint16_t beaconperiod; uint16_t capability; - /* SSID */ const char* ssid; int ssid_hidden; - /* Supported Rates */ int supportedratescount; uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - /* DSSS */ uint8_t channel; - /* ERP */ + uint32_t mode; uint32_t erpmode; }; @@ -416,22 +428,19 @@ int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_pa /* Management Probe Response */ struct ieee80211_probe_response_params { - /* Header information */ uint8_t bssid[ETH_ALEN]; + uint16_t beaconperiod; uint16_t capability; - /* SSID */ const char* ssid; - /* Supported Rates */ int supportedratescount; uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; - /* DSSS */ uint8_t channel; - /* ERP */ + uint32_t mode; uint32_t erpmode; }; @@ -439,8 +448,8 @@ int ieee80211_create_probe_response(char* buffer, int length, const struct ieee8 /* Management Authentication */ struct ieee80211_authentication_params { - /* Header information */ uint8_t bssid[ETH_ALEN]; + uint16_t algorithm; uint16_t transactionseqnumber; uint16_t statuscode; @@ -448,4 +457,18 @@ struct ieee80211_authentication_params { int ieee80211_create_authentication_response(char* buffer, int length, const struct ieee80211_header_mgmt* authenticationheader, struct ieee80211_authentication_params* params); +/* Management Association Response */ +struct ieee80211_associationresponse_params { + uint8_t bssid[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(char* buffer, int length, const struct ieee80211_header_mgmt* associationrequestheader, struct ieee80211_associationresponse_params* params); + #endif /* __CAPWAP_IEEE802_11_HEADER__ */ diff --git a/src/binding/ieee80211/wifi_nl80211.c b/src/binding/ieee80211/wifi_nl80211.c index ef3a637..bd99df7 100644 --- a/src/binding/ieee80211/wifi_nl80211.c +++ b/src/binding/ieee80211/wifi_nl80211.c @@ -294,8 +294,9 @@ static void nl80211_do_mgmt_probe_request_event(struct nl80211_wlan_handle* wlan ieee80211_params.ssid = wlanhandle->ssid; memcpy(ieee80211_params.supportedrates, wlanhandle->supportedrates, wlanhandle->supportedratescount); ieee80211_params.supportedratescount = wlanhandle->supportedratescount; + ieee80211_params.mode = wlanhandle->devicehandle->currentfrequency.mode; ieee80211_params.erpmode = 0; /* TODO */ - ieee80211_params.channel = wifi_frequency_to_channel(wlanhandle->devicehandle->currentfrequency); + ieee80211_params.channel = wlanhandle->devicehandle->currentfrequency.channel; responselength = ieee80211_create_probe_response(buffer, IEEE80211_MTU, mgmt, &ieee80211_params); if (responselength < 0) { @@ -306,7 +307,7 @@ static void nl80211_do_mgmt_probe_request_event(struct nl80211_wlan_handle* wlan memset(&wlan_params, 0, sizeof(struct wlan_send_frame_params)); wlan_params.packet = buffer; wlan_params.length = responselength; - wlan_params.frequency = wlanhandle->devicehandle->currentfrequency; + wlan_params.frequency = wlanhandle->devicehandle->currentfrequency.frequency; wlan_params.no_wait_ack = ((ssidcheck == WIFI_WILDCARD_SSID) && wifi_is_broadcast_addr(mgmt->da) ? 1 : 0); if (nl80211_wlan_send_frame((wifi_wlan_handle)wlanhandle, &wlan_params)) { @@ -376,7 +377,7 @@ static void nl80211_do_mgmt_authentication_event(struct nl80211_wlan_handle* wla memset(&wlan_params, 0, sizeof(struct wlan_send_frame_params)); wlan_params.packet = buffer; wlan_params.length = responselength; - wlan_params.frequency = wlanhandle->devicehandle->currentfrequency; + wlan_params.frequency = wlanhandle->devicehandle->currentfrequency.frequency; if (!nl80211_wlan_send_frame((wifi_wlan_handle)wlanhandle, &wlan_params)) { wlanhandle->last_cookie = wlan_params.cookie; @@ -385,12 +386,62 @@ static void nl80211_do_mgmt_authentication_event(struct nl80211_wlan_handle* wla } } +/* */ +static void nl80211_do_mgmt_association_request_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + int responselength; + char buffer[IEEE80211_MTU]; + struct ieee80211_ie_items ieitems; + struct ieee80211_associationresponse_params ieee80211_params; + struct wlan_send_frame_params wlan_params; + + /* Information Elements packet length */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->associationrequest)); + if (ielength < 0) { + return; + } + + /* Parsing Information Elements */ + if (wifi_retrieve_information_elements_position(&ieitems, &mgmt->associationrequest.ie[0], ielength)) { + return; + } + + /* Get station reference */ + /* TODO */ + + /* 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; + + responselength = ieee80211_create_associationresponse_response(buffer, IEEE80211_MTU, mgmt, &ieee80211_params); + if (responselength < 0) { + return; + } + + /* Send authentication response */ + 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 Association Response"); + } +} + /* */ static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint16_t framecontrol_subtype, uint32_t frequency) { int broadcast; /* Check frequency */ - if (frequency && (wlanhandle->devicehandle->currentfrequency != frequency)) { + if (frequency && (wlanhandle->devicehandle->currentfrequency.frequency != frequency)) { return; } @@ -411,7 +462,7 @@ static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, } case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { - /* TODO */ + nl80211_do_mgmt_association_request_event(wlanhandle, mgmt, mgmtlength); break; } @@ -493,6 +544,26 @@ 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; + + /* Accept only acknowledge association response with same cookie */ + if (!ack || (wlanhandle->last_cookie != cookie)) { + return; + } + + /* Check packet */ + if (mgmtlength < (sizeof(struct ieee80211_header) + sizeof(mgmt->associationresponse))) { + return; + } + + /* */ + statuscode = __le16_to_cpu(mgmt->associationresponse.statuscode); + if (statuscode == IEEE80211_STATUS_SUCCESS) { + capwap_logging_debug("Associate station"); + } +} /* */ 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 */ @@ -506,6 +577,11 @@ static void nl80211_do_mgmt_frame_tx_status_event(struct nl80211_wlan_handle* wl nl80211_do_mgmt_frame_tx_status_authentication_event(wlanhandle, mgmt, mgmtlength, cookie, ack); break; } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_RESPONSE: { + nl80211_do_mgmt_frame_tx_status_association_response_event(wlanhandle, mgmt, mgmtlength, cookie, ack); + break; + } } /* Remove cookie */ @@ -562,7 +638,7 @@ static int nl80211_execute_bss_event(struct nl80211_wlan_handle* wlanhandle, str } default: { - capwap_logging_debug("nl80211_execute_bss_event: %d", (int)gnlh->cmd); + capwap_logging_debug("*** nl80211_execute_bss_event: %d", (int)gnlh->cmd); break; } } @@ -628,6 +704,8 @@ static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { devicesearch = devicesearch->next; } + } else { + capwap_logging_debug("*** Receive nl80211_global_valid_handler without interface index"); } return NL_SKIP; @@ -1222,7 +1300,7 @@ static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_fr /* Set wifi frequency */ result = nl80211_send_and_recv_msg(devicehandle->globalhandle, msg, NULL, NULL); if (!result) { - devicehandle->currentfrequency = freq->frequency; + memcpy(&devicehandle->currentfrequency, freq, sizeof(struct wifi_frequency)); } else { capwap_logging_error("Unable retrieve physical device capability, error code: %d", result); } @@ -1482,8 +1560,9 @@ static int nl80211_wlan_startap(wifi_wlan_handle handle, struct wlan_startap_par 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 = wifi_frequency_to_channel(wlanhandle->devicehandle->currentfrequency); + ieee80211_params.channel = wlanhandle->devicehandle->currentfrequency.channel; result = ieee80211_create_beacon(buffer, IEEE80211_MTU, &ieee80211_params); if (result < 0) { diff --git a/src/binding/ieee80211/wifi_nl80211.h b/src/binding/ieee80211/wifi_nl80211.h index e7fa847..b283550 100644 --- a/src/binding/ieee80211/wifi_nl80211.h +++ b/src/binding/ieee80211/wifi_nl80211.h @@ -32,7 +32,7 @@ struct nl80211_device_handle { struct capwap_list* wlanlist; - uint32_t currentfrequency; + struct wifi_frequency currentfrequency; struct wifi_capability* capability; /* Cached capability */ };