diff options
Diffstat (limited to 'contrib/wpa/src/ap/ieee802_11.c')
-rw-r--r-- | contrib/wpa/src/ap/ieee802_11.c | 821 |
1 files changed, 571 insertions, 250 deletions
diff --git a/contrib/wpa/src/ap/ieee802_11.c b/contrib/wpa/src/ap/ieee802_11.c index 3375aa2..51c8d28 100644 --- a/contrib/wpa/src/ap/ieee802_11.c +++ b/contrib/wpa/src/ap/ieee802_11.c @@ -1,15 +1,9 @@ /* * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "utils/includes.h" @@ -25,6 +19,7 @@ #include "common/wpa_ctrl.h" #include "radius/radius.h" #include "radius/radius_client.h" +#include "p2p/p2p.h" #include "wps/wps.h" #include "hostapd.h" #include "beacon.h" @@ -37,6 +32,9 @@ #include "accounting.h" #include "ap_config.h" #include "ap_mlme.h" +#include "p2p_hostapd.h" +#include "ap_drv_ops.h" +#include "wnm_ap.h" #include "ieee802_11.h" @@ -50,6 +48,10 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) *pos++ = WLAN_EID_SUPP_RATES; num = hapd->iface->num_rates; + if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) + num++; + if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) + num++; if (num > 8) { /* rest of the rates are encoded in Extended supported * rates element */ @@ -67,6 +69,16 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) pos++; } + if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) { + count++; + *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; + } + + if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) { + count++; + *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; + } + return pos; } @@ -80,6 +92,10 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) return eid; num = hapd->iface->num_rates; + if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) + num++; + if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) + num++; if (num <= 8) return eid; num -= 8; @@ -98,6 +114,18 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) pos++; } + if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) { + count++; + if (count > 8) + *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; + } + + if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) { + count++; + if (count > 8) + *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; + } + return pos; } @@ -148,34 +176,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, } -#ifdef CONFIG_IEEE80211W -static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, - struct sta_info *sta, u8 *eid) -{ - u8 *pos = eid; - u32 timeout, tu; - struct os_time now, passed; - - *pos++ = WLAN_EID_TIMEOUT_INTERVAL; - *pos++ = 5; - *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; - os_get_time(&now); - os_time_sub(&now, &sta->sa_query_start, &passed); - tu = (passed.sec * 1000000 + passed.usec) / 1024; - if (hapd->conf->assoc_sa_query_max_timeout > tu) - timeout = hapd->conf->assoc_sa_query_max_timeout - tu; - else - timeout = 0; - if (timeout < hapd->conf->assoc_sa_query_max_timeout) - timeout++; /* add some extra time for local timers */ - WPA_PUT_LE32(pos, timeout); - pos += 4; - - return pos; -} -#endif /* CONFIG_IEEE80211W */ - - void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) { int i; @@ -204,15 +204,15 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, if (!sta->challenge) { /* Generate a pseudo-random challenge */ u8 key[8]; - time_t now; + struct os_time now; int r; sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN); if (sta->challenge == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; - now = time(NULL); - r = random(); - os_memcpy(key, &now, 4); + os_get_time(&now); + r = os_random(); + os_memcpy(key, &now.sec, 4); os_memcpy(key + 4, &r, 4); rc4_skip(key, sizeof(key), 0, sta->challenge, WLAN_AUTH_CHALLENGE_LEN); @@ -282,7 +282,7 @@ static void send_auth_reply(struct hostapd_data *hapd, " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)", MAC2STR(dst), auth_alg, auth_transaction, resp, (unsigned long) ies_len); - if (hapd->drv.send_mgmt_frame(hapd, reply, rlen) < 0) + if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0) perror("send_auth_reply: send"); os_free(buf); @@ -315,6 +315,142 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SAE + +static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(2); + if (buf == NULL) + return NULL; + + wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */ + /* TODO: Anti-Clogging Token (if requested) */ + /* TODO: Scalar */ + /* TODO: Element */ + + return buf; +} + + +static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(2); + if (buf == NULL) + return NULL; + + wpabuf_put_le16(buf, sta->sae_send_confirm); + sta->sae_send_confirm++; + /* TODO: Confirm */ + + return buf; +} + + +static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, size_t len) +{ + wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len); + + /* Check Finite Cyclic Group */ + if (len < 2) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + if (WPA_GET_LE16(data) != 19) { + wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u", + WPA_GET_LE16(data)); + return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + } + + return WLAN_STATUS_SUCCESS; +} + + +static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, size_t len) +{ + u16 rc; + + wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len); + + if (len < 2) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + rc = WPA_GET_LE16(data); + wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc); + + return WLAN_STATUS_SUCCESS; +} + + +static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, + const struct ieee80211_mgmt *mgmt, size_t len, + u8 auth_transaction) +{ + u16 resp = WLAN_STATUS_SUCCESS; + struct wpabuf *data; + + if (auth_transaction == 1) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "start SAE authentication (RX commit)"); + resp = handle_sae_commit(hapd, sta, mgmt->u.auth.variable, + ((u8 *) mgmt) + len - + mgmt->u.auth.variable); + if (resp == WLAN_STATUS_SUCCESS) + sta->sae_state = SAE_COMMIT; + } else if (auth_transaction == 2) { + if (sta->sae_state != SAE_COMMIT) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "SAE confirm before commit"); + resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; + } + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "SAE authentication (RX confirm)"); + resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable, + ((u8 *) mgmt) + len - + mgmt->u.auth.variable); + if (resp == WLAN_STATUS_SUCCESS) { + sta->flags |= WLAN_STA_AUTH; + wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); + sta->auth_alg = WLAN_AUTH_SAE; + mlme_authenticate_indication(hapd, sta); + } + } else { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "unexpected SAE authentication transaction %u", + auth_transaction); + resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; + } + + sta->auth_alg = WLAN_AUTH_SAE; + + if (resp == WLAN_STATUS_SUCCESS) { + if (auth_transaction == 1) + data = auth_build_sae_commit(hapd, sta); + else + data = auth_build_sae_confirm(hapd, sta); + if (data == NULL) + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + } else + data = NULL; + + send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, + auth_transaction, resp, + data ? wpabuf_head(data) : (u8 *) "", + data ? wpabuf_len(data) : 0); + wpabuf_free(data); +} +#endif /* CONFIG_SAE */ + + static void handle_auth(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -326,8 +462,11 @@ static void handle_auth(struct hostapd_data *hapd, const u8 *challenge = NULL; u32 session_timeout, acct_interim_interval; int vlan_id = 0; + struct hostapd_sta_wpa_psk_short *psk = NULL; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; + char *identity = NULL; + char *radius_cui = NULL; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { printf("handle_auth - too short payload (len=%lu)\n", @@ -360,11 +499,13 @@ static void handle_auth(struct hostapd_data *hapd, if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && auth_alg == WLAN_AUTH_OPEN) || #ifdef CONFIG_IEEE80211R - (hapd->conf->wpa && - (hapd->conf->wpa_key_mgmt & - (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) && + (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && auth_alg == WLAN_AUTH_FT) || #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SAE + (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && + auth_alg == WLAN_AUTH_SAE) || +#endif /* CONFIG_SAE */ ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && auth_alg == WLAN_AUTH_SHARED_KEY))) { printf("Unsupported authentication algorithm (%d)\n", @@ -373,7 +514,7 @@ static void handle_auth(struct hostapd_data *hapd, goto fail; } - if (!(auth_transaction == 1 || + if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE || (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { printf("Unknown authentication transaction number (%d)\n", auth_transaction); @@ -390,7 +531,9 @@ static void handle_auth(struct hostapd_data *hapd, res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, &session_timeout, - &acct_interim_interval, &vlan_id); + &acct_interim_interval, &vlan_id, + &psk, &identity, &radius_cui); + if (res == HOSTAPD_ACL_REJECT) { printf("Station " MACSTR " not allowed to authenticate.\n", MAC2STR(mgmt->sa)); @@ -428,6 +571,19 @@ static void handle_auth(struct hostapd_data *hapd, HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); } + hostapd_free_psk_list(sta->psk); + if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { + sta->psk = psk; + psk = NULL; + } else { + sta->psk = NULL; + } + + sta->identity = identity; + identity = NULL; + sta->radius_cui = radius_cui; + radius_cui = NULL; + sta->flags &= ~WLAN_STA_PREAUTH; ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); @@ -486,9 +642,18 @@ static void handle_auth(struct hostapd_data *hapd, /* handle_auth_ft_finish() callback will complete auth. */ return; #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SAE + case WLAN_AUTH_SAE: + handle_auth_sae(hapd, sta, mgmt, len, auth_transaction); + return; +#endif /* CONFIG_SAE */ } fail: + os_free(identity); + os_free(radius_cui); + hostapd_free_psk_list(psk); + send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, auth_transaction + 1, resp, resp_ies, resp_ies_len); } @@ -552,15 +717,22 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, const u8 *wmm_ie, size_t wmm_ie_len) { sta->flags &= ~WLAN_STA_WMM; + sta->qosinfo = 0; if (wmm_ie && hapd->conf->wmm_enabled) { - if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) + struct wmm_information_element *wmm; + + if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, "invalid WMM element in association " "request"); - else - sta->flags |= WLAN_STA_WMM; + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + sta->flags |= WLAN_STA_WMM; + wmm = (struct wmm_information_element *) wmm_ie; + sta->qosinfo = wmm->qos_info; } return WLAN_STATUS_SUCCESS; } @@ -576,35 +748,20 @@ static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_UNSPECIFIED_FAILURE; } - if (elems->supp_rates_len > sizeof(sta->supported_rates)) { + if (elems->supp_rates_len + elems->ext_supp_rates_len > + sizeof(sta->supported_rates)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, - "Invalid supported rates element length %d", - elems->supp_rates_len); + "Invalid supported rates element length %d+%d", + elems->supp_rates_len, + elems->ext_supp_rates_len); return WLAN_STATUS_UNSPECIFIED_FAILURE; } - os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); - os_memcpy(sta->supported_rates, elems->supp_rates, - elems->supp_rates_len); - sta->supported_rates_len = elems->supp_rates_len; - - if (elems->ext_supp_rates) { - if (elems->supp_rates_len + elems->ext_supp_rates_len > - sizeof(sta->supported_rates)) { - hostapd_logger(hapd, sta->addr, - HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Invalid supported rates element length" - " %d+%d", elems->supp_rates_len, - elems->ext_supp_rates_len); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - os_memcpy(sta->supported_rates + elems->supp_rates_len, - elems->ext_supp_rates, elems->ext_supp_rates_len); - sta->supported_rates_len += elems->ext_supp_rates_len; - } + sta->supported_rates_len = merge_byte_arrays( + sta->supported_rates, sizeof(sta->supported_rates), + elems->supp_rates, elems->supp_rates_len, + elems->ext_supp_rates, elems->ext_supp_rates_len); return WLAN_STATUS_SUCCESS; } @@ -635,12 +792,33 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, if (resp != WLAN_STATUS_SUCCESS) return resp; #ifdef CONFIG_IEEE80211N - resp = copy_sta_ht_capab(sta, elems.ht_capabilities, + resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities, elems.ht_capabilities_len); if (resp != WLAN_STATUS_SUCCESS) return resp; + if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && + !(sta->flags & WLAN_STA_HT)) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Station does not support " + "mandatory HT PHY - reject association"); + return WLAN_STATUS_ASSOC_DENIED_NO_HT; + } #endif /* CONFIG_IEEE80211N */ +#ifdef CONFIG_IEEE80211AC + resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities, + elems.vht_capabilities_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && + !(sta->flags & WLAN_STA_VHT)) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Station does not support " + "mandatory VHT PHY - reject association"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } +#endif /* CONFIG_IEEE80211AC */ + if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) { wpa_ie = elems.rsn_ie; wpa_ie_len = elems.rsn_ie_len; @@ -654,7 +832,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #ifdef CONFIG_WPS - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); if (hapd->conf->wps_state && elems.wps_ie) { wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " "Request - assume WPS is used"); @@ -662,8 +840,17 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, wpabuf_free(sta->wps_ie); sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_IE_VENDOR_TYPE); + if (sta->wps_ie && wps_is_20(sta->wps_ie)) { + wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } wpa_ie = NULL; wpa_ie_len = 0; + if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) { + wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in " + "(Re)Association Request - reject"); + return WLAN_STATUS_INVALID_IE; + } } else if (hapd->conf->wps_state && wpa_ie == NULL) { wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in " "(Re)Association Request - possible WPS use"); @@ -754,8 +941,18 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SAE + if (wpa_auth_uses_sae(sta->wpa_sm) && + sta->auth_alg != WLAN_AUTH_SAE) { + wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use " + "SAE AKM after non-SAE auth_alg %u", + MAC2STR(sta->addr), sta->auth_alg); + return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; + } +#endif /* CONFIG_SAE */ + #ifdef CONFIG_IEEE80211N - if ((sta->flags & WLAN_STA_HT) && + if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) && wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, @@ -768,6 +965,29 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } else wpa_auth_sta_no_wpa(sta->wpa_sm); +#ifdef CONFIG_P2P + if (elems.p2p) { + wpabuf_free(sta->p2p_ie); + sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, + P2P_IE_VENDOR_TYPE); + + } else { + wpabuf_free(sta->p2p_ie); + sta->p2p_ie = NULL; + } + + p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len); +#endif /* CONFIG_P2P */ + +#ifdef CONFIG_HS20 + wpabuf_free(sta->hs20_ie); + if (elems.hs20 && elems.hs20_len > 4) { + sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, + elems.hs20_len - 4); + } else + sta->hs20_ie = NULL; +#endif /* CONFIG_HS20 */ + return WLAN_STATUS_SUCCESS; } @@ -788,7 +1008,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr, send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); reply.u.deauth.reason_code = host_to_le16(reason_code); - if (hapd->drv.send_mgmt_frame(hapd, &reply, send_len) < 0) + if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0) wpa_printf(MSG_INFO, "Failed to send deauth: %s", strerror(errno)); } @@ -845,11 +1065,20 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, p = hostapd_eid_ht_operation(hapd, p); #endif /* CONFIG_IEEE80211N */ +#ifdef CONFIG_IEEE80211AC + p = hostapd_eid_vht_capabilities(hapd, p); + p = hostapd_eid_vht_operation(hapd, p); +#endif /* CONFIG_IEEE80211AC */ + + p = hostapd_eid_ext_capab(hapd, p); + p = hostapd_eid_bss_max_idle_period(hapd, p); + if (sta->flags & WLAN_STA_WMM) p = hostapd_eid_wmm(hapd, p); #ifdef CONFIG_WPS - if (sta->flags & WLAN_STA_WPS) { + if ((sta->flags & WLAN_STA_WPS) || + ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) { struct wpabuf *wps = wps_build_assoc_resp_ie(); if (wps) { os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); @@ -859,9 +1088,39 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_WPS */ +#ifdef CONFIG_P2P + if (sta->p2p_ie) { + struct wpabuf *p2p_resp_ie; + enum p2p_status_code status; + switch (status_code) { + case WLAN_STATUS_SUCCESS: + status = P2P_SC_SUCCESS; + break; + case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA: + status = P2P_SC_FAIL_LIMIT_REACHED; + break; + default: + status = P2P_SC_FAIL_INVALID_PARAMS; + break; + } + p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status); + if (p2p_resp_ie) { + os_memcpy(p, wpabuf_head(p2p_resp_ie), + wpabuf_len(p2p_resp_ie)); + p += wpabuf_len(p2p_resp_ie); + wpabuf_free(p2p_resp_ie); + } + } +#endif /* CONFIG_P2P */ + +#ifdef CONFIG_P2P_MANAGER + if (hapd->conf->p2p & P2P_MANAGE) + p = hostapd_eid_p2p_manage(hapd, p); +#endif /* CONFIG_P2P_MANAGER */ + send_len += p - reply->u.assoc_resp.variable; - if (hapd->drv.send_mgmt_frame(hapd, reply, send_len) < 0) + if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", strerror(errno)); } @@ -1005,6 +1264,7 @@ static void handle_assoc(struct hostapd_data *hapd, "association OK (aid %d)", sta->aid); /* Station will be marked associated, after it acknowledges AssocResp */ + sta->flags |= WLAN_STA_ASSOC_REQ_OK; #ifdef CONFIG_IEEE80211W if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) { @@ -1061,9 +1321,8 @@ static void handle_disassoc(struct hostapd_data *hapd, return; } - sta->flags &= ~WLAN_STA_ASSOC; - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); + ap_sta_set_authorized(hapd, sta, 0); + sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated"); @@ -1073,7 +1332,7 @@ static void handle_disassoc(struct hostapd_data *hapd, * authenticated. */ accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); - hapd->drv.sta_remove(hapd, sta->addr); + hostapd_drv_sta_remove(hapd, sta->addr); if (sta->timeout_next == STA_NULLFUNC || sta->timeout_next == STA_DISASSOC) { @@ -1094,26 +1353,26 @@ static void handle_deauth(struct hostapd_data *hapd, struct sta_info *sta; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { - printf("handle_deauth - too short payload (len=%lu)\n", - (unsigned long) len); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short " + "payload (len=%lu)", (unsigned long) len); return; } - wpa_printf(MSG_DEBUG, "deauthentication: STA=" MACSTR - " reason_code=%d", - MAC2STR(mgmt->sa), - le_to_host16(mgmt->u.deauth.reason_code)); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR + " reason_code=%d", + MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { - printf("Station " MACSTR " trying to deauthenticate, but it " - "is not authenticated.\n", MAC2STR(mgmt->sa)); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " + "to deauthenticate, but it is not authenticated", + MAC2STR(mgmt->sa)); return; } - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); + ap_sta_set_authorized(hapd, sta, 0); + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_ASSOC_REQ_OK); wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "deauthenticated"); @@ -1148,81 +1407,11 @@ static void handle_beacon(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211W -/* MLME-SAQuery.request */ -void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, - const u8 *addr, const u8 *trans_id) -{ - struct ieee80211_mgmt mgmt; - u8 *end; - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " - MACSTR, MAC2STR(addr)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - trans_id, WLAN_SA_QUERY_TR_ID_LEN); - - os_memset(&mgmt, 0, sizeof(mgmt)); - mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(mgmt.da, addr, ETH_ALEN); - os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); - mgmt.u.action.category = WLAN_ACTION_SA_QUERY; - mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; - os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; - if (hapd->drv.send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt) < 0) - perror("ieee802_11_send_sa_query_req: send"); -} - - -static void hostapd_sa_query_request(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt) -{ - struct sta_info *sta; - struct ieee80211_mgmt resp; - u8 *end; - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " - MACSTR, MAC2STR(mgmt->sa)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " - "from unassociated STA " MACSTR, MAC2STR(mgmt->sa)); - return; - } - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " - MACSTR, MAC2STR(mgmt->sa)); - - os_memset(&resp, 0, sizeof(resp)); - resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - os_memcpy(resp.da, mgmt->sa, ETH_ALEN); - os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); - os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); - resp.u.action.category = WLAN_ACTION_SA_QUERY; - resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; - os_memcpy(resp.u.action.u.sa_query_req.trans_id, - mgmt->u.action.u.sa_query_req.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; - if (hapd->drv.send_mgmt_frame(hapd, &resp, end - (u8 *) &resp) < 0) - perror("hostapd_sa_query_request: send"); -} - - static void hostapd_sa_query_action(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { - struct sta_info *sta; const u8 *end; - int i; end = mgmt->u.action.u.sa_query_resp.trans_id + WLAN_SA_QUERY_TR_ID_LEN; @@ -1232,50 +1421,9 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd, return; } - if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) { - hostapd_sa_query_request(hapd, mgmt); - return; - } - - if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " - "Action %d", mgmt->u.action.u.sa_query_resp.action); - return; - } - - wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " - MACSTR, MAC2STR(mgmt->sa)); - wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - - /* MLME-SAQuery.confirm */ - - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL || sta->sa_query_trans_id == NULL) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " - "pending SA Query request found"); - return; - } - - for (i = 0; i < sta->sa_query_count; i++) { - if (os_memcmp(sta->sa_query_trans_id + - i * WLAN_SA_QUERY_TR_ID_LEN, - mgmt->u.action.u.sa_query_resp.trans_id, - WLAN_SA_QUERY_TR_ID_LEN) == 0) - break; - } - - if (i >= sta->sa_query_count) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " - "transaction identifier found"); - return; - } - - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "Reply to pending SA Query received"); - ap_sta_stop_sa_query(hapd, sta); + ieee802_11_sa_query_action(hapd, mgmt->sa, + mgmt->u.action.u.sa_query_resp.action, + mgmt->u.action.u.sa_query_resp.trans_id); } @@ -1287,10 +1435,32 @@ static int robust_action_frame(u8 category) #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_WNM +static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta, + const struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct rx_action action; + if (len < IEEE80211_HDRLEN + 2) + return; + os_memset(&action, 0, sizeof(action)); + action.da = mgmt->da; + action.sa = mgmt->sa; + action.bssid = mgmt->bssid; + action.category = mgmt->u.action.category; + action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action; + action.len = len - IEEE80211_HDRLEN - 1; + action.freq = hapd->iface->freq; + ieee802_11_rx_wnm_action_ap(hapd, &action); +} +#endif /* CONFIG_WNM */ + + static void handle_action(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; + sta = ap_get_sta(hapd, mgmt->sa); if (len < IEEE80211_HDRLEN + 1) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1300,7 +1470,14 @@ static void handle_action(struct hostapd_data *hapd, return; } - sta = ap_get_sta(hapd, mgmt->sa); + if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && + (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action " + "frame (category=%u) from unassociated STA " MACSTR, + MAC2STR(mgmt->sa), mgmt->u.action.category); + return; + } + #ifdef CONFIG_IEEE80211W if (sta && (sta->flags & WLAN_STA_MFP) && !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) && @@ -1316,20 +1493,10 @@ static void handle_action(struct hostapd_data *hapd, switch (mgmt->u.action.category) { #ifdef CONFIG_IEEE80211R case WLAN_ACTION_FT: - { - if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action " - "frame from unassociated STA " MACSTR, - MAC2STR(mgmt->sa)); - return; - } - if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, len - IEEE80211_HDRLEN)) break; - return; - } #endif /* CONFIG_IEEE80211R */ case WLAN_ACTION_WMM: hostapd_wmm_action(hapd, mgmt, len); @@ -1339,6 +1506,11 @@ static void handle_action(struct hostapd_data *hapd, hostapd_sa_query_action(hapd, mgmt, len); return; #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_WNM + case WLAN_ACTION_WNM: + hostapd_wnm_action(hapd, sta, mgmt, len); + return; +#endif /* CONFIG_WNM */ case WLAN_ACTION_PUBLIC: if (hapd->public_action_cb) { hapd->public_action_cb(hapd->public_action_cb_ctx, @@ -1347,6 +1519,14 @@ static void handle_action(struct hostapd_data *hapd, return; } break; + case WLAN_ACTION_VENDOR_SPECIFIC: + if (hapd->vendor_action_cb) { + if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, + (u8 *) mgmt, len, + hapd->iface->freq) == 0) + return; + } + break; } hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -1374,7 +1554,10 @@ static void handle_action(struct hostapd_data *hapd, os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); resp->u.action.category |= 0x80; - hapd->drv.send_mgmt_frame(hapd, resp, len); + if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) { + wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send " + "Action frame"); + } os_free(resp); } } @@ -1400,6 +1583,9 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, int broadcast; u16 fc, stype; + if (len < 24) + return; + mgmt = (struct ieee80211_mgmt *) buf; fc = le_to_host16(mgmt->frame_control); stype = WLAN_FC_GET_STYPE(fc); @@ -1414,6 +1600,11 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff; if (!broadcast && +#ifdef CONFIG_P2P + /* Invitation responses can be sent with the peer MAC as BSSID */ + !((hapd->conf->p2p & P2P_GROUP_OWNER) && + stype == WLAN_FC_STYPE_ACTION) && +#endif /* CONFIG_P2P */ os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { printf("MGMT: BSSID=" MACSTR " not our address\n", MAC2STR(mgmt->bssid)); @@ -1422,7 +1613,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, if (stype == WLAN_FC_STYPE_PROBE_REQ) { - handle_probe_req(hapd, mgmt, len); + handle_probe_req(hapd, mgmt, len, fi->ssi_signal); return; } @@ -1452,7 +1643,7 @@ void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, handle_disassoc(hapd, mgmt, len); break; case WLAN_FC_STYPE_DEAUTH: - wpa_printf(MSG_DEBUG, "mgmt::deauth"); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); handle_deauth(hapd, mgmt, len); break; case WLAN_FC_STYPE_ACTION: @@ -1518,13 +1709,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd, int new_assoc = 1; struct ieee80211_ht_capabilities ht_cap; - if (!ok) { - hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, - "did not acknowledge association response"); - return; - } - if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : sizeof(mgmt->u.assoc_resp))) { printf("handle_assoc_cb(reassoc=%d) - too short payload " @@ -1532,11 +1716,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd, return; } - if (reassoc) - status = le_to_host16(mgmt->u.reassoc_resp.status_code); - else - status = le_to_host16(mgmt->u.assoc_resp.status_code); - sta = ap_get_sta(hapd, mgmt->da); if (!sta) { printf("handle_assoc_cb: STA " MACSTR " not found\n", @@ -1544,6 +1723,19 @@ static void handle_assoc_cb(struct hostapd_data *hapd, return; } + if (!ok) { + hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "did not acknowledge association response"); + sta->flags &= ~WLAN_STA_ASSOC_REQ_OK; + return; + } + + if (reassoc) + status = le_to_host16(mgmt->u.reassoc_resp.status_code); + else + status = le_to_host16(mgmt->u.assoc_resp.status_code); + if (status != WLAN_STATUS_SUCCESS) goto fail; @@ -1565,9 +1757,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * Open, static WEP, or FT protocol; no separate authorization * step. */ - sta->flags |= WLAN_STA_AUTHORIZED; - wpa_msg(hapd->msg_ctx, MSG_INFO, - AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); + ap_sta_set_authorized(hapd, sta, 1); } if (reassoc) @@ -1584,22 +1774,31 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * cleared and configuration gets updated in case of reassociation back * to the same AP. */ - hapd->drv.sta_remove(hapd, sta->addr); + hostapd_drv_sta_remove(hapd, sta->addr); #ifdef CONFIG_IEEE80211N if (sta->flags & WLAN_STA_HT) hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); #endif /* CONFIG_IEEE80211N */ - if (hapd->drv.sta_add(hapd, sta->addr, sta->aid, sta->capability, - sta->supported_rates, sta->supported_rates_len, - sta->listen_interval, - sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) { + if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, + sta->supported_rates, sta->supported_rates_len, + sta->listen_interval, + sta->flags & WLAN_STA_HT ? &ht_cap : NULL, + sta->flags, sta->qosinfo)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "Could not add STA to kernel driver"); + + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_DISASSOC_AP_BUSY); + + goto fail; } + if (sta->flags & WLAN_STA_WDS) + hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1); + if (sta->eapol_sm == NULL) { /* * This STA does not use RADIUS server for EAP authentication, @@ -1614,7 +1813,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, goto fail; } - hapd->drv.set_sta_flags(hapd, sta); + hostapd_set_sta_flags(hapd, sta); if (sta->auth_alg == WLAN_AUTH_FT) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); @@ -1633,6 +1832,54 @@ static void handle_assoc_cb(struct hostapd_data *hapd, } +static void handle_deauth_cb(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, int ok) +{ + struct sta_info *sta; + if (mgmt->da[0] & 0x01) + return; + sta = ap_get_sta(hapd, mgmt->da); + if (!sta) { + wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR + " not found", MAC2STR(mgmt->da)); + return; + } + if (ok) + wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth", + MAC2STR(sta->addr)); + else + wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " + "deauth", MAC2STR(sta->addr)); + + ap_sta_deauth_cb(hapd, sta); +} + + +static void handle_disassoc_cb(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, int ok) +{ + struct sta_info *sta; + if (mgmt->da[0] & 0x01) + return; + sta = ap_get_sta(hapd, mgmt->da); + if (!sta) { + wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR + " not found", MAC2STR(mgmt->da)); + return; + } + if (ok) + wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc", + MAC2STR(sta->addr)); + else + wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " + "disassoc", MAC2STR(sta->addr)); + + ap_sta_disassoc_cb(hapd, sta); +} + + /** * ieee802_11_mgmt_cb - Process management frame TX status callback * @hapd: hostapd BSS data structure (the BSS from which the management frame @@ -1662,10 +1909,15 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, handle_assoc_cb(hapd, mgmt, len, 1, ok); break; case WLAN_FC_STYPE_PROBE_RESP: - wpa_printf(MSG_DEBUG, "mgmt::proberesp cb"); + wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb"); break; case WLAN_FC_STYPE_DEAUTH: - /* ignore */ + wpa_printf(MSG_DEBUG, "mgmt::deauth cb"); + handle_deauth_cb(hapd, mgmt, len, ok); + break; + case WLAN_FC_STYPE_DISASSOC: + wpa_printf(MSG_DEBUG, "mgmt::disassoc cb"); + handle_disassoc_cb(hapd, mgmt, len, ok); break; case WLAN_FC_STYPE_ACTION: wpa_printf(MSG_DEBUG, "mgmt::action cb"); @@ -1708,7 +1960,7 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, break; } } - if (sta == NULL) + if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) return; if (sta->flags & WLAN_STA_PENDING_POLL) { wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " @@ -1722,6 +1974,59 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, } +void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, dst); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, dst); + if (sta) + break; + } + } + if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { + wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA " + MACSTR " that is not currently associated", + MAC2STR(dst)); + return; + } + + ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); +} + + +void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, addr); + if (sta) + break; + } + } + if (sta == NULL) + return; + if (!(sta->flags & WLAN_STA_PENDING_POLL)) + return; + + wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending " + "activity poll", MAC2STR(sta->addr)); + sta->flags &= ~WLAN_STA_PENDING_POLL; +} + + void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, int wds) { @@ -1729,24 +2034,40 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, sta = ap_get_sta(hapd, src); if (sta && (sta->flags & WLAN_STA_ASSOC)) { + if (!hapd->conf->wds_sta) + return; + if (wds && !(sta->flags & WLAN_STA_WDS)) { wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " "STA " MACSTR " (aid %u)", MAC2STR(sta->addr), sta->aid); sta->flags |= WLAN_STA_WDS; - hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 1); + hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1); } return; } wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " MACSTR, MAC2STR(src)); + if (src[0] & 0x01) { + /* Broadcast bit set in SA?! Ignore the frame silently. */ + return; + } + + if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) { + wpa_printf(MSG_DEBUG, "Association Response to the STA has " + "already been sent, but no TX status yet known - " + "ignore Class 3 frame issue with " MACSTR, + MAC2STR(src)); + return; + } + if (sta && (sta->flags & WLAN_STA_AUTH)) - hapd->drv.sta_disassoc( + hostapd_drv_sta_disassoc( hapd, src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); else - hapd->drv.sta_deauth( + hostapd_drv_sta_deauth( hapd, src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); } |