From bc2a6183cea431a103d51dffdbe13a1ec80ef40d Mon Sep 17 00:00:00 2001 From: vemax78 Date: Mon, 13 Jan 2014 19:00:51 +0100 Subject: [PATCH] Add code to simple management IEEE802.11 Authentication packets --- src/binding/ieee80211/ieee80211.c | 46 ++- src/binding/ieee80211/ieee80211.h | 135 +++++++- src/binding/ieee80211/wifi_nl80211.c | 489 +++++++++++++++++++++++---- src/binding/ieee80211/wifi_nl80211.h | 9 + 4 files changed, 583 insertions(+), 96 deletions(-) diff --git a/src/binding/ieee80211/ieee80211.c b/src/binding/ieee80211/ieee80211.c index 679a617..89003b1 100644 --- a/src/binding/ieee80211/ieee80211.c +++ b/src/binding/ieee80211/ieee80211.c @@ -114,15 +114,17 @@ int ieee80211_create_beacon(char* buffer, int length, struct ieee80211_beacon_pa ASSERT(length == IEEE80211_MTU); /* */ - memset(buffer, 0x00, length); 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); @@ -196,18 +198,20 @@ int ieee80211_create_probe_response(char* buffer, int length, const struct ieee8 ASSERT(length == IEEE80211_MTU); /* */ - memset(buffer, 0x00, length); header = (struct ieee80211_header_mgmt*)buffer; /* Management header frame */ - header->framecontrol = IEEE80211_FRAME_CONTROL(IEEE80211_FRAMECONTROL_TYPE_MGMT, IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESP); + 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, 0x00, ETH_ALEN); + memset(header->da, 0, 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); @@ -264,4 +268,36 @@ int ieee80211_create_probe_response(char* buffer, int length, const struct ieee8 responselength += result; return responselength; -} \ No newline at end of file +} + +/* */ +int ieee80211_create_authentication_response(char* buffer, int length, const struct ieee80211_header_mgmt* authenticationheader, struct ieee80211_authentication_params* params) { + char* pos; + 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_AUTHENTICATION); + header->durationid = __cpu_to_le16(0); + memcpy(header->da, authenticationheader->sa, 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); + pos = buffer + responselength; + + /* TODO: add custon IE */ + + return responselength; +} diff --git a/src/binding/ieee80211/ieee80211.h b/src/binding/ieee80211/ieee80211.h index c393f45..a191bf2 100644 --- a/src/binding/ieee80211/ieee80211.h +++ b/src/binding/ieee80211/ieee80211.h @@ -53,20 +53,20 @@ #define IEEE80211_FRAMECONTROL_TYPE_DATA 2 /* Frame control Management subtype */ -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOC_REQ 0 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOC_RESP 1 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOC_REQ 2 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOC_RESP 3 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQ 4 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_RESP 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_DISASSOC 10 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTH 11 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTH 12 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION 13 -#define IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ACTION_NOACK 14 +#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 @@ -101,6 +101,96 @@ #define IEEE80211_FRAME_CONTROL_GET_TYPE(framecontrol) (((framecontrol) & 0x000c) >> 2) #define IEEE80211_FRAME_CONTROL_GET_SUBTYPE(framecontrol) (((framecontrol) & 0x00f0) >> 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 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 + /* 802.11 Packet - IEEE802.11 is a little-endian protocol */ struct ieee80211_header { __le16 framecontrol; @@ -140,9 +230,9 @@ struct ieee80211_header_mgmt { } STRUCT_PACKED proberesponse; struct { - __le16 auth_alg; - __le16 auth_transaction; - __le16 status_code; + __le16 algorithm; + __le16 transactionseqnumber; + __le16 statuscode; uint8_t ie[0]; } STRUCT_PACKED authetication; }; @@ -347,4 +437,15 @@ struct ieee80211_probe_response_params { int ieee80211_create_probe_response(char* buffer, int length, const struct ieee80211_header_mgmt* proberequestheader, struct ieee80211_probe_response_params* params); +/* Management Authentication */ +struct ieee80211_authentication_params { + /* Header information */ + uint8_t bssid[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); + #endif /* __CAPWAP_IEEE802_11_HEADER__ */ diff --git a/src/binding/ieee80211/wifi_nl80211.c b/src/binding/ieee80211/wifi_nl80211.c index 53a27b6..ef3a637 100644 --- a/src/binding/ieee80211/wifi_nl80211.c +++ b/src/binding/ieee80211/wifi_nl80211.c @@ -12,6 +12,12 @@ #include "wifi_drivers.h" #include "wifi_nl80211.h" +/* */ +struct family_data { + int id; + const char* group; +}; + /* Compatibility functions */ #if !defined(HAVE_LIBNL20) && !defined(HAVE_LIBNL30) static uint32_t port_bitmap[32] = { 0 }; @@ -141,6 +147,64 @@ static int nl80211_send_and_recv_msg(struct nl80211_global_handle* globalhandle, 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; + } + + /* */ + nlmsg_free(msg); + return result; +} + /* */ static int nl80211_wlan_send_frame(wifi_wlan_handle handle, struct wlan_send_frame_params* params) { int result; @@ -251,7 +315,78 @@ static void nl80211_do_mgmt_probe_request_event(struct nl80211_wlan_handle* wlan } /* */ -static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, uint16_t framecontrol_subtype, int mgmtlength, uint32_t frequency) { +static void nl80211_do_mgmt_authentication_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { + int ielength; + struct ieee80211_ie_items ieitems; + int responselength; + uint16_t algorithm; + uint16_t transactionseqnumber; + uint16_t responsestatuscode; + char buffer[IEEE80211_MTU]; + struct ieee80211_authentication_params ieee80211_params; + struct wlan_send_frame_params wlan_params; + + /* Information Elements packet length */ + ielength = mgmtlength - (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication)); + if (ielength < 0) { + return; + } + + /* Parsing Information Elements */ + if (wifi_retrieve_information_elements_position(&ieitems, &mgmt->authetication.ie[0], ielength)) { + return; + } + + /* Ignore authentication packet from same AP */ + if (!memcmp(mgmt->sa, wlanhandle->address, ETH_ALEN)) { + return; + } + + /* ACL Station */ + /* TODO */ + + /* Create station reference */ + /* TODO */ + + /* */ + 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 */ + } + + /* Create authentication packet */ + memset(&ieee80211_params, 0, sizeof(struct ieee80211_authentication_params)); + memcpy(ieee80211_params.bssid, wlanhandle->address, 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); + 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; + + 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 Authentication 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 */ @@ -259,38 +394,38 @@ static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, return; } - /* Check if sent packet to correct virtual ap */ + /* Check if sent packet to correct AP */ broadcast = wifi_is_broadcast_addr(mgmt->bssid); if (!broadcast && memcmp(mgmt->bssid, wlanhandle->address, ETH_ALEN)) { return; } /* */ - if (framecontrol_subtype == IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQ) { + if (framecontrol_subtype == IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQUEST) { nl80211_do_mgmt_probe_request_event(wlanhandle, mgmt, mgmtlength); } else if (!memcmp(mgmt->da, wlanhandle->address, ETH_ALEN)) { switch (framecontrol_subtype) { - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTH: { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { + nl80211_do_mgmt_authentication_event(wlanhandle, mgmt, mgmtlength); + break; + } + + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOCIATION_REQUEST: { /* TODO */ break; } - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_ASSOC_REQ: { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOCIATION_REQUEST: { /* TODO */ break; } - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOC_REQ: { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOCIATION: { /* TODO */ break; } - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOC: { - /* TODO */ - break; - } - - case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTH: { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTHENTICATION: { /* TODO */ break; } @@ -304,23 +439,14 @@ static void nl80211_do_mgmt_frame_event(struct nl80211_wlan_handle* wlanhandle, } /* */ -static void nl80211_do_frame_event(struct nl80211_wlan_handle* wlanhandle, struct nlattr* frame, uint32_t frequency) { - const uint8_t* framedata; +static void nl80211_do_frame_event(struct nl80211_wlan_handle* wlanhandle, const uint8_t* framedata, int framelength, uint32_t frequency) { const struct ieee80211_header* header; - int framelength; uint16_t framecontrol; uint16_t framecontrol_type; uint16_t framecontrol_subtype; - /* */ - if (!frame) { - return; - } - - /* Get frame data */ - framedata = nla_data(frame); - framelength = nla_len(frame); - if (framelength < sizeof(struct ieee80211_header)) { + /* Check frame */ + if (!framedata || (framelength < sizeof(struct ieee80211_header))) { return; } @@ -332,10 +458,118 @@ static void nl80211_do_frame_event(struct nl80211_wlan_handle* wlanhandle, struc /* Parsing frame */ if (framecontrol_type == IEEE80211_FRAMECONTROL_TYPE_MGMT) { - nl80211_do_mgmt_frame_event(wlanhandle, (const struct ieee80211_header_mgmt*)framedata, framecontrol_subtype, framelength, frequency); + nl80211_do_mgmt_frame_event(wlanhandle, (const struct ieee80211_header_mgmt*)framedata, framelength, framecontrol_subtype, frequency); } } +/* */ +static void nl80211_do_mgmt_frame_tx_status_authentication_event(struct nl80211_wlan_handle* wlanhandle, const struct ieee80211_header_mgmt* mgmt, int mgmtlength, uint64_t cookie, int ack) { + uint16_t algorithm; + uint16_t transactionseqnumber; + uint16_t statuscode; + + /* Accept only acknowledge authentication response with same cookie */ + if (!ack || (wlanhandle->last_cookie != cookie)) { + return; + } + + /* Check packet */ + if (mgmtlength < (sizeof(struct ieee80211_header) + sizeof(mgmt->authetication))) { + return; + } + + /* */ + statuscode = __le16_to_cpu(mgmt->authetication.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)) { + capwap_logging_debug("Authenticate station"); + } else if ((algorithm == IEEE80211_AUTHENTICATION_ALGORITHM_SHARED_KEY) && (transactionseqnumber == 4)) { + /* TODO */ + } + } +} + +/* */ +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 */ + if (memcmp(mgmt->bssid, wlanhandle->address, ETH_ALEN)) { + return; + } + + /* */ + switch (framecontrol_subtype) { + case IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTHENTICATION: { + nl80211_do_mgmt_frame_tx_status_authentication_event(wlanhandle, mgmt, mgmtlength, cookie, ack); + break; + } + } + + /* Remove cookie */ + wlanhandle->last_cookie = 0; +} + +/* */ +static void nl80211_do_frame_tx_status_event(struct nl80211_wlan_handle* wlanhandle, const uint8_t* framedata, int framelength, uint64_t cookie, int ack) { + const struct ieee80211_header* header; + uint16_t framecontrol; + uint16_t framecontrol_type; + uint16_t framecontrol_subtype; + + /* Check frame */ + if (!framedata || (framelength < sizeof(struct ieee80211_header))) { + return; + } + + /* Get type frame */ + header = (const struct ieee80211_header*)framedata; + 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) { + nl80211_do_mgmt_frame_tx_status_event(wlanhandle, (const struct ieee80211_header_mgmt*)framedata, framelength, framecontrol_subtype, cookie, ack); + } +} + +/* */ +static int nl80211_execute_bss_event(struct nl80211_wlan_handle* wlanhandle, struct genlmsghdr* gnlh, struct nlattr** tb_msg) { + switch (gnlh->cmd) { + case NL80211_CMD_FRAME: { + if (tb_msg[NL80211_ATTR_FRAME]) { + uint32_t frequency = 0; + + if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { + frequency = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); + } + + nl80211_do_frame_event(wlanhandle, nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), frequency); + } + + break; + } + + case NL80211_CMD_FRAME_TX_STATUS: { + if (tb_msg[NL80211_ATTR_FRAME] && tb_msg[NL80211_ATTR_COOKIE]) { + nl80211_do_frame_tx_status_event(wlanhandle, nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), nla_get_u64(tb_msg[NL80211_ATTR_COOKIE]), (tb_msg[NL80211_ATTR_ACK] ? 1 : 0)); + } + + break; + } + + default: { + capwap_logging_debug("nl80211_execute_bss_event: %d", (int)gnlh->cmd); + break; + } + } + + return NL_SKIP; +} + /* */ static int nl80211_process_bss_event(struct nl_msg* msg, void* arg) { struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; @@ -344,20 +578,7 @@ static int nl80211_process_bss_event(struct nl_msg* msg, void* arg) { nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - switch (gnlh->cmd) { - case NL80211_CMD_FRAME: { - uint32_t frequency = 0; - - if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { - frequency = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); - } - - nl80211_do_frame_event(wlanhandle, tb_msg[NL80211_ATTR_FRAME], frequency); - break; - } - } - - return NL_SKIP; + return nl80211_execute_bss_event(wlanhandle, gnlh, tb_msg); } /* */ @@ -374,10 +595,40 @@ static void nl80211_event_receive(int fd, void* param1, void* param2) { } /* */ -static int nl80211_global_valid_handler(struct nl_msg* msg, void* arg) { - /* TODO */ - capwap_logging_debug("nl80211_global_valid_handler"); - /* TODO */ +static int nl80211_global_valid_handler(struct nl_msg* msg, void* data) { + uint32_t ifindex; + struct nl80211_device_handle* devicehandle; + struct nl80211_wlan_handle* wlanhandle; + struct capwap_list_item* devicesearch; + struct capwap_list_item* wlansearch; + struct nlattr* tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)data; + + 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 device */ + devicesearch = globalhandle->devicelist->first; + while (devicesearch) { + devicehandle = (struct nl80211_device_handle*)devicesearch->item; + + /* Search wlan */ + wlansearch = devicehandle->wlanlist->first; + while (wlansearch) { + wlanhandle = (struct nl80211_wlan_handle*)wlansearch->item; + if (wlanhandle->virtindex == ifindex) { + return nl80211_execute_bss_event(wlanhandle, gnlh, tb_msg); + } + + wlansearch = wlansearch->next; + } + + devicesearch = devicesearch->next; + } + } return NL_SKIP; } @@ -934,6 +1185,9 @@ static wifi_device_handle nl80211_device_init(wifi_global_handle handle, struct /* Remove all virtual adapter from wifi device */ nl80211_destroy_all_virtdevice(globalhandle, devicehandle->phyindex); + /* AP list */ + devicehandle->wlanlist = capwap_list_create(); + /* Save device handle into global handle */ item = capwap_itemlist_create_with_item(devicehandle, sizeof(struct nl80211_device_handle)); item->autodelete = 0; @@ -978,6 +1232,43 @@ static int nl80211_device_setfrequency(wifi_device_handle handle, struct wifi_fr return result; } +/* */ +static void nl80211_wlan_delete(wifi_wlan_handle handle) { + struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; + + if (wlanhandle) { + if (wlanhandle->devicehandle) { + struct capwap_list_item* search; + + /* Remove wlan handle from device handle */ + search = wlanhandle->devicehandle->wlanlist->first; + while (search) { + if ((struct nl80211_wlan_handle*)search->item == wlanhandle) { + /* Remove item from list */ + capwap_itemlist_free(capwap_itemlist_remove(wlanhandle->devicehandle->wlanlist, search)); + break; + } + + search = search->next; + } + } + + if (wlanhandle->virtindex) { + nl80211_destroy_virtdevice(wlanhandle->devicehandle->globalhandle, wlanhandle->virtindex); + } + + if (wlanhandle->nl) { + nl_socket_free(wlanhandle->nl); + } + + if (wlanhandle->nl_cb) { + nl_cb_put(wlanhandle->nl_cb); + } + + capwap_free(wlanhandle); + } +} + /* */ static void nl80211_device_deinit(wifi_device_handle handle) { int i; @@ -986,13 +1277,15 @@ static void nl80211_device_deinit(wifi_device_handle handle) { if (devicehandle) { struct capwap_list_item* search; + /* Destroy AP */ + while (devicehandle->wlanlist->first) { + nl80211_wlan_delete((wifi_wlan_handle)devicehandle->wlanlist->first->item); + } + /* Remove device handle from global handle */ search = devicehandle->globalhandle->devicelist->first; while (search) { if ((struct nl80211_device_handle*)search->item == devicehandle) { - /* Remove all virtual adapter from wifi device */ - nl80211_destroy_all_virtdevice(devicehandle->globalhandle, devicehandle->phyindex); - /* Remove item from list */ capwap_itemlist_free(capwap_itemlist_remove(devicehandle->globalhandle->devicelist, search)); break; @@ -1026,37 +1319,22 @@ static void nl80211_device_deinit(wifi_device_handle handle) { capwap_free(devicehandle->capability); } + if (devicehandle->wlanlist) { + ASSERT(devicehandle->wlanlist->count == 0); + capwap_list_free(devicehandle->wlanlist); + } + /* */ capwap_free(devicehandle); } } -/* */ -static void nl80211_wlan_delete(wifi_wlan_handle handle) { - struct nl80211_wlan_handle* wlanhandle = (struct nl80211_wlan_handle*)handle; - - ASSERT(handle != NULL); - - if (wlanhandle->virtindex) { - nl80211_destroy_virtdevice(wlanhandle->devicehandle->globalhandle, wlanhandle->virtindex); - } - - if (wlanhandle->nl) { - nl_socket_free(wlanhandle->nl); - } - - if (wlanhandle->nl_cb) { - nl_cb_put(wlanhandle->nl_cb); - } - - capwap_free(wlanhandle); -} - /* */ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wlan_init_params* params) { 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; @@ -1104,6 +1382,11 @@ static wifi_wlan_handle nl80211_wlan_create(wifi_device_handle handle, struct wl wlanhandle->virtindex = ifindex; strcpy(wlanhandle->virtname, params->ifname); + /* Save AP handle into device handle */ + item = capwap_itemlist_create_with_item(wlanhandle, sizeof(struct nl80211_wlan_handle)); + item->autodelete = 0; + capwap_itemlist_insert_after(devicehandle->wlanlist, NULL, item); + /* Mac address */ if (wifi_iface_hwaddr(devicehandle->globalhandle->sock_util, wlanhandle->virtname, wlanhandle->address)) { nl80211_wlan_delete((wifi_wlan_handle)wlanhandle); @@ -1156,12 +1439,12 @@ 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_ASSOC_REQ, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_REASSOC_REQ, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_PROBE_REQ, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DISASSOC, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_AUTH, - IEEE80211_FRAMECONTROL_MGMT_SUBTYPE_DEAUTH, + 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 }; @@ -1213,6 +1496,7 @@ static int nl80211_wlan_startap(wifi_wlan_handle handle, struct wlan_startap_par wlanhandle->capability = params->capability; memcpy(wlanhandle->supportedrates, params->supportedrates, params->supportedratescount); wlanhandle->supportedratescount = params->supportedratescount; + wlanhandle->authenticationtype = params->authenticationtype; /* */ msg = nlmsg_alloc(); @@ -1288,6 +1572,10 @@ static void nl80211_global_deinit(wifi_global_handle handle) { 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); } @@ -1307,6 +1595,7 @@ static void nl80211_global_deinit(wifi_global_handle handle) { /* */ static wifi_global_handle nl80211_global_init(void) { + int result; struct nl80211_global_handle* globalhandle; /* */ @@ -1328,6 +1617,43 @@ static wifi_global_handle nl80211_global_init(void) { 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) { + result = 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) { @@ -1355,7 +1681,22 @@ static wifi_global_handle nl80211_global_init(void) { /* */ static int nl80211_global_getfdevent(wifi_global_handle handle, struct pollfd* fds, struct wifi_event* events) { - return 0; + struct nl80211_global_handle* globalhandle = (struct nl80211_global_handle*)handle; + + ASSERT(handle != NULL); + + if (fds) { + fds[0].fd = globalhandle->nl_event_fd; + fds[0].events = POLLIN | POLLERR | POLLHUP; + } + + if (events) { + events[0].event_handler = nl80211_event_receive; + events[0].param1 = (void*)globalhandle->nl_event; + events[0].param2 = (void*)globalhandle->nl_cb; + } + + return 1; } /* Driver function */ diff --git a/src/binding/ieee80211/wifi_nl80211.h b/src/binding/ieee80211/wifi_nl80211.h index 958d323..e7fa847 100644 --- a/src/binding/ieee80211/wifi_nl80211.h +++ b/src/binding/ieee80211/wifi_nl80211.h @@ -15,6 +15,9 @@ struct nl80211_global_handle { struct nl_cb* nl_cb; int nl80211_id; + struct nl_sock* nl_event; + int nl_event_fd; + int sock_util; struct capwap_list* devicelist; @@ -27,6 +30,8 @@ struct nl80211_device_handle { uint32_t phyindex; char phyname[IFNAMSIZ]; + struct capwap_list* wlanlist; + uint32_t currentfrequency; struct wifi_capability* capability; /* Cached capability */ @@ -45,6 +50,8 @@ struct nl80211_wlan_handle { uint8_t address[ETH_ALEN]; + uint64_t last_cookie; + /* WLAN information */ char ssid[WIFI_SSID_MAX_LENGTH + 1]; @@ -53,6 +60,8 @@ struct nl80211_wlan_handle { int supportedratescount; uint8_t supportedrates[IEEE80211_SUPPORTEDRATE_MAX_COUNT]; + + uint8_t authenticationtype; }; /* Physical device info */