1214501Srpaulo/* 2214501Srpaulo * hostapd / IEEE 802.11 Management 3346981Scy * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#ifndef CONFIG_NATIVE_WINDOWS 12214501Srpaulo 13214501Srpaulo#include "utils/common.h" 14214501Srpaulo#include "utils/eloop.h" 15214501Srpaulo#include "crypto/crypto.h" 16281806Srpaulo#include "crypto/sha256.h" 17346981Scy#include "crypto/sha384.h" 18346981Scy#include "crypto/sha512.h" 19281806Srpaulo#include "crypto/random.h" 20214501Srpaulo#include "common/ieee802_11_defs.h" 21214501Srpaulo#include "common/ieee802_11_common.h" 22214501Srpaulo#include "common/wpa_ctrl.h" 23281806Srpaulo#include "common/sae.h" 24346981Scy#include "common/dpp.h" 25346981Scy#include "common/ocv.h" 26351611Scy#include "common/wpa_common.h" 27214501Srpaulo#include "radius/radius.h" 28214501Srpaulo#include "radius/radius_client.h" 29252726Srpaulo#include "p2p/p2p.h" 30214501Srpaulo#include "wps/wps.h" 31289549Srpaulo#include "fst/fst.h" 32214501Srpaulo#include "hostapd.h" 33214501Srpaulo#include "beacon.h" 34214501Srpaulo#include "ieee802_11_auth.h" 35214501Srpaulo#include "sta_info.h" 36214501Srpaulo#include "ieee802_1x.h" 37214501Srpaulo#include "wpa_auth.h" 38281806Srpaulo#include "pmksa_cache_auth.h" 39214501Srpaulo#include "wmm.h" 40214501Srpaulo#include "ap_list.h" 41214501Srpaulo#include "accounting.h" 42214501Srpaulo#include "ap_config.h" 43214501Srpaulo#include "ap_mlme.h" 44252726Srpaulo#include "p2p_hostapd.h" 45252726Srpaulo#include "ap_drv_ops.h" 46252726Srpaulo#include "wnm_ap.h" 47289549Srpaulo#include "hw_features.h" 48214501Srpaulo#include "ieee802_11.h" 49281806Srpaulo#include "dfs.h" 50337817Scy#include "mbo_ap.h" 51337817Scy#include "rrm.h" 52337817Scy#include "taxonomy.h" 53346981Scy#include "fils_hlp.h" 54346981Scy#include "dpp_hostapd.h" 55346981Scy#include "gas_query_ap.h" 56214501Srpaulo 57214501Srpaulo 58346981Scy#ifdef CONFIG_FILS 59346981Scystatic struct wpabuf * 60346981Scyprepare_auth_resp_fils(struct hostapd_data *hapd, 61346981Scy struct sta_info *sta, u16 *resp, 62346981Scy struct rsn_pmksa_cache_entry *pmksa, 63346981Scy struct wpabuf *erp_resp, 64346981Scy const u8 *msk, size_t msk_len, 65346981Scy int *is_pub); 66346981Scy#endif /* CONFIG_FILS */ 67346981Scystatic void handle_auth(struct hostapd_data *hapd, 68346981Scy const struct ieee80211_mgmt *mgmt, size_t len, 69346981Scy int rssi, int from_queue); 70346981Scy 71346981Scy 72346981Scyu8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid) 73346981Scy{ 74346981Scy u8 multi_ap_val = 0; 75346981Scy 76346981Scy if (!hapd->conf->multi_ap) 77346981Scy return eid; 78346981Scy if (hapd->conf->multi_ap & BACKHAUL_BSS) 79346981Scy multi_ap_val |= MULTI_AP_BACKHAUL_BSS; 80346981Scy if (hapd->conf->multi_ap & FRONTHAUL_BSS) 81346981Scy multi_ap_val |= MULTI_AP_FRONTHAUL_BSS; 82346981Scy 83346981Scy return eid + add_multi_ap_ie(eid, 9, multi_ap_val); 84346981Scy} 85346981Scy 86346981Scy 87214501Srpaulou8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) 88214501Srpaulo{ 89214501Srpaulo u8 *pos = eid; 90214501Srpaulo int i, num, count; 91214501Srpaulo 92214501Srpaulo if (hapd->iface->current_rates == NULL) 93214501Srpaulo return eid; 94214501Srpaulo 95214501Srpaulo *pos++ = WLAN_EID_SUPP_RATES; 96214501Srpaulo num = hapd->iface->num_rates; 97252726Srpaulo if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) 98252726Srpaulo num++; 99252726Srpaulo if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) 100252726Srpaulo num++; 101214501Srpaulo if (num > 8) { 102214501Srpaulo /* rest of the rates are encoded in Extended supported 103214501Srpaulo * rates element */ 104214501Srpaulo num = 8; 105214501Srpaulo } 106214501Srpaulo 107214501Srpaulo *pos++ = num; 108214501Srpaulo for (i = 0, count = 0; i < hapd->iface->num_rates && count < num; 109214501Srpaulo i++) { 110214501Srpaulo count++; 111214501Srpaulo *pos = hapd->iface->current_rates[i].rate / 5; 112214501Srpaulo if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) 113214501Srpaulo *pos |= 0x80; 114214501Srpaulo pos++; 115214501Srpaulo } 116214501Srpaulo 117252726Srpaulo if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) { 118252726Srpaulo count++; 119252726Srpaulo *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; 120252726Srpaulo } 121252726Srpaulo 122252726Srpaulo if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) { 123252726Srpaulo count++; 124252726Srpaulo *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; 125252726Srpaulo } 126252726Srpaulo 127214501Srpaulo return pos; 128214501Srpaulo} 129214501Srpaulo 130214501Srpaulo 131214501Srpaulou8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) 132214501Srpaulo{ 133214501Srpaulo u8 *pos = eid; 134214501Srpaulo int i, num, count; 135214501Srpaulo 136214501Srpaulo if (hapd->iface->current_rates == NULL) 137214501Srpaulo return eid; 138214501Srpaulo 139214501Srpaulo num = hapd->iface->num_rates; 140252726Srpaulo if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) 141252726Srpaulo num++; 142252726Srpaulo if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) 143252726Srpaulo num++; 144214501Srpaulo if (num <= 8) 145214501Srpaulo return eid; 146214501Srpaulo num -= 8; 147214501Srpaulo 148214501Srpaulo *pos++ = WLAN_EID_EXT_SUPP_RATES; 149214501Srpaulo *pos++ = num; 150214501Srpaulo for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8; 151214501Srpaulo i++) { 152214501Srpaulo count++; 153214501Srpaulo if (count <= 8) 154214501Srpaulo continue; /* already in SuppRates IE */ 155214501Srpaulo *pos = hapd->iface->current_rates[i].rate / 5; 156214501Srpaulo if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) 157214501Srpaulo *pos |= 0x80; 158214501Srpaulo pos++; 159214501Srpaulo } 160214501Srpaulo 161252726Srpaulo if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) { 162252726Srpaulo count++; 163252726Srpaulo if (count > 8) 164252726Srpaulo *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; 165252726Srpaulo } 166252726Srpaulo 167252726Srpaulo if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) { 168252726Srpaulo count++; 169252726Srpaulo if (count > 8) 170252726Srpaulo *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; 171252726Srpaulo } 172252726Srpaulo 173214501Srpaulo return pos; 174214501Srpaulo} 175214501Srpaulo 176214501Srpaulo 177289549Srpaulou16 hostapd_own_capab_info(struct hostapd_data *hapd) 178214501Srpaulo{ 179214501Srpaulo int capab = WLAN_CAPABILITY_ESS; 180214501Srpaulo int privacy; 181281806Srpaulo int dfs; 182337817Scy int i; 183214501Srpaulo 184281806Srpaulo /* Check if any of configured channels require DFS */ 185281806Srpaulo dfs = hostapd_is_dfs_required(hapd->iface); 186281806Srpaulo if (dfs < 0) { 187281806Srpaulo wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d", 188281806Srpaulo dfs); 189281806Srpaulo dfs = 0; 190281806Srpaulo } 191281806Srpaulo 192214501Srpaulo if (hapd->iface->num_sta_no_short_preamble == 0 && 193214501Srpaulo hapd->iconf->preamble == SHORT_PREAMBLE) 194214501Srpaulo capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; 195214501Srpaulo 196214501Srpaulo privacy = hapd->conf->ssid.wep.keys_set; 197214501Srpaulo 198214501Srpaulo if (hapd->conf->ieee802_1x && 199214501Srpaulo (hapd->conf->default_wep_key_len || 200214501Srpaulo hapd->conf->individual_wep_key_len)) 201214501Srpaulo privacy = 1; 202214501Srpaulo 203214501Srpaulo if (hapd->conf->wpa) 204214501Srpaulo privacy = 1; 205214501Srpaulo 206281806Srpaulo#ifdef CONFIG_HS20 207281806Srpaulo if (hapd->conf->osen) 208281806Srpaulo privacy = 1; 209281806Srpaulo#endif /* CONFIG_HS20 */ 210281806Srpaulo 211214501Srpaulo if (privacy) 212214501Srpaulo capab |= WLAN_CAPABILITY_PRIVACY; 213214501Srpaulo 214214501Srpaulo if (hapd->iface->current_mode && 215214501Srpaulo hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && 216214501Srpaulo hapd->iface->num_sta_no_short_slot_time == 0) 217214501Srpaulo capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; 218214501Srpaulo 219281806Srpaulo /* 220281806Srpaulo * Currently, Spectrum Management capability bit is set when directly 221281806Srpaulo * requested in configuration by spectrum_mgmt_required or when AP is 222281806Srpaulo * running on DFS channel. 223281806Srpaulo * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit 224281806Srpaulo */ 225281806Srpaulo if (hapd->iface->current_mode && 226281806Srpaulo hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && 227281806Srpaulo (hapd->iconf->spectrum_mgmt_required || dfs)) 228281806Srpaulo capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; 229214501Srpaulo 230337817Scy for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) { 231337817Scy if (hapd->conf->radio_measurements[i]) { 232337817Scy capab |= IEEE80211_CAP_RRM; 233337817Scy break; 234337817Scy } 235337817Scy } 236214501Srpaulo 237281806Srpaulo return capab; 238214501Srpaulo} 239214501Srpaulo 240214501Srpaulo 241289549Srpaulo#ifndef CONFIG_NO_RC4 242214501Srpaulostatic u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, 243214501Srpaulo u16 auth_transaction, const u8 *challenge, 244214501Srpaulo int iswep) 245214501Srpaulo{ 246214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 247214501Srpaulo HOSTAPD_LEVEL_DEBUG, 248214501Srpaulo "authentication (shared key, transaction %d)", 249214501Srpaulo auth_transaction); 250214501Srpaulo 251214501Srpaulo if (auth_transaction == 1) { 252214501Srpaulo if (!sta->challenge) { 253214501Srpaulo /* Generate a pseudo-random challenge */ 254214501Srpaulo u8 key[8]; 255337817Scy 256214501Srpaulo sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN); 257214501Srpaulo if (sta->challenge == NULL) 258214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 259214501Srpaulo 260337817Scy if (os_get_random(key, sizeof(key)) < 0) { 261337817Scy os_free(sta->challenge); 262337817Scy sta->challenge = NULL; 263337817Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 264337817Scy } 265337817Scy 266214501Srpaulo rc4_skip(key, sizeof(key), 0, 267214501Srpaulo sta->challenge, WLAN_AUTH_CHALLENGE_LEN); 268214501Srpaulo } 269214501Srpaulo return 0; 270214501Srpaulo } 271214501Srpaulo 272214501Srpaulo if (auth_transaction != 3) 273214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 274214501Srpaulo 275214501Srpaulo /* Transaction 3 */ 276214501Srpaulo if (!iswep || !sta->challenge || !challenge || 277281806Srpaulo os_memcmp_const(sta->challenge, challenge, 278281806Srpaulo WLAN_AUTH_CHALLENGE_LEN)) { 279214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 280214501Srpaulo HOSTAPD_LEVEL_INFO, 281214501Srpaulo "shared key authentication - invalid " 282214501Srpaulo "challenge-response"); 283214501Srpaulo return WLAN_STATUS_CHALLENGE_FAIL; 284214501Srpaulo } 285214501Srpaulo 286214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 287214501Srpaulo HOSTAPD_LEVEL_DEBUG, 288214501Srpaulo "authentication OK (shared key)"); 289214501Srpaulo sta->flags |= WLAN_STA_AUTH; 290214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 291214501Srpaulo os_free(sta->challenge); 292214501Srpaulo sta->challenge = NULL; 293214501Srpaulo 294214501Srpaulo return 0; 295214501Srpaulo} 296289549Srpaulo#endif /* CONFIG_NO_RC4 */ 297214501Srpaulo 298214501Srpaulo 299337817Scystatic int send_auth_reply(struct hostapd_data *hapd, 300337817Scy const u8 *dst, const u8 *bssid, 301337817Scy u16 auth_alg, u16 auth_transaction, u16 resp, 302346981Scy const u8 *ies, size_t ies_len, const char *dbg) 303214501Srpaulo{ 304214501Srpaulo struct ieee80211_mgmt *reply; 305214501Srpaulo u8 *buf; 306214501Srpaulo size_t rlen; 307337817Scy int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE; 308214501Srpaulo 309214501Srpaulo rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len; 310214501Srpaulo buf = os_zalloc(rlen); 311214501Srpaulo if (buf == NULL) 312337817Scy return -1; 313214501Srpaulo 314214501Srpaulo reply = (struct ieee80211_mgmt *) buf; 315214501Srpaulo reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 316214501Srpaulo WLAN_FC_STYPE_AUTH); 317214501Srpaulo os_memcpy(reply->da, dst, ETH_ALEN); 318214501Srpaulo os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); 319214501Srpaulo os_memcpy(reply->bssid, bssid, ETH_ALEN); 320214501Srpaulo 321214501Srpaulo reply->u.auth.auth_alg = host_to_le16(auth_alg); 322214501Srpaulo reply->u.auth.auth_transaction = host_to_le16(auth_transaction); 323214501Srpaulo reply->u.auth.status_code = host_to_le16(resp); 324214501Srpaulo 325214501Srpaulo if (ies && ies_len) 326214501Srpaulo os_memcpy(reply->u.auth.variable, ies, ies_len); 327214501Srpaulo 328214501Srpaulo wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR 329346981Scy " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)", 330214501Srpaulo MAC2STR(dst), auth_alg, auth_transaction, 331346981Scy resp, (unsigned long) ies_len, dbg); 332252726Srpaulo if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0) 333337817Scy wpa_printf(MSG_INFO, "send_auth_reply: send failed"); 334337817Scy else 335337817Scy reply_res = WLAN_STATUS_SUCCESS; 336214501Srpaulo 337214501Srpaulo os_free(buf); 338337817Scy 339337817Scy return reply_res; 340214501Srpaulo} 341214501Srpaulo 342214501Srpaulo 343346981Scy#ifdef CONFIG_IEEE80211R_AP 344214501Srpaulostatic void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, 345214501Srpaulo u16 auth_transaction, u16 status, 346214501Srpaulo const u8 *ies, size_t ies_len) 347214501Srpaulo{ 348214501Srpaulo struct hostapd_data *hapd = ctx; 349214501Srpaulo struct sta_info *sta; 350337817Scy int reply_res; 351214501Srpaulo 352337817Scy reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, 353346981Scy auth_transaction, status, ies, ies_len, 354346981Scy "auth-ft-finish"); 355214501Srpaulo 356214501Srpaulo sta = ap_get_sta(hapd, dst); 357214501Srpaulo if (sta == NULL) 358214501Srpaulo return; 359214501Srpaulo 360337817Scy if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS || 361337817Scy status != WLAN_STATUS_SUCCESS)) { 362337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 363337817Scy sta->added_unassoc = 0; 364337817Scy return; 365337817Scy } 366337817Scy 367337817Scy if (status != WLAN_STATUS_SUCCESS) 368337817Scy return; 369337817Scy 370214501Srpaulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 371214501Srpaulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 372214501Srpaulo sta->flags |= WLAN_STA_AUTH; 373214501Srpaulo mlme_authenticate_indication(hapd, sta); 374214501Srpaulo} 375346981Scy#endif /* CONFIG_IEEE80211R_AP */ 376214501Srpaulo 377214501Srpaulo 378252726Srpaulo#ifdef CONFIG_SAE 379252726Srpaulo 380346981Scystatic void sae_set_state(struct sta_info *sta, enum sae_state state, 381346981Scy const char *reason) 382346981Scy{ 383346981Scy wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)", 384346981Scy sae_state_txt(sta->sae->state), sae_state_txt(state), 385346981Scy MAC2STR(sta->addr), reason); 386346981Scy sta->sae->state = state; 387346981Scy} 388281806Srpaulo 389281806Srpaulo 390252726Srpaulostatic struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, 391281806Srpaulo struct sta_info *sta, int update) 392252726Srpaulo{ 393252726Srpaulo struct wpabuf *buf; 394346981Scy const char *password = NULL; 395346981Scy struct sae_password_entry *pw; 396346981Scy const char *rx_id = NULL; 397252726Srpaulo 398346981Scy if (sta->sae->tmp) 399346981Scy rx_id = sta->sae->tmp->pw_id; 400346981Scy 401346981Scy for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) { 402346981Scy if (!is_broadcast_ether_addr(pw->peer_addr) && 403346981Scy os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0) 404346981Scy continue; 405346981Scy if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier)) 406346981Scy continue; 407346981Scy if (rx_id && pw->identifier && 408346981Scy os_strcmp(rx_id, pw->identifier) != 0) 409346981Scy continue; 410346981Scy password = pw->password; 411346981Scy break; 412346981Scy } 413346981Scy if (!password) 414346981Scy password = hapd->conf->ssid.wpa_passphrase; 415346981Scy if (!password) { 416281806Srpaulo wpa_printf(MSG_DEBUG, "SAE: No password available"); 417281806Srpaulo return NULL; 418281806Srpaulo } 419281806Srpaulo 420281806Srpaulo if (update && 421281806Srpaulo sae_prepare_commit(hapd->own_addr, sta->addr, 422346981Scy (u8 *) password, os_strlen(password), rx_id, 423281806Srpaulo sta->sae) < 0) { 424281806Srpaulo wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); 425281806Srpaulo return NULL; 426281806Srpaulo } 427281806Srpaulo 428346981Scy if (pw && pw->vlan_id) { 429346981Scy if (!sta->sae->tmp) { 430346981Scy wpa_printf(MSG_INFO, 431346981Scy "SAE: No temporary data allocated - cannot store VLAN ID"); 432346981Scy return NULL; 433346981Scy } 434346981Scy sta->sae->tmp->vlan_id = pw->vlan_id; 435346981Scy } 436346981Scy 437346981Scy buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN + 438346981Scy (rx_id ? 3 + os_strlen(rx_id) : 0)); 439252726Srpaulo if (buf == NULL) 440252726Srpaulo return NULL; 441281806Srpaulo sae_write_commit(sta->sae, buf, sta->sae->tmp ? 442346981Scy sta->sae->tmp->anti_clogging_token : NULL, rx_id); 443252726Srpaulo 444252726Srpaulo return buf; 445252726Srpaulo} 446252726Srpaulo 447252726Srpaulo 448252726Srpaulostatic struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, 449252726Srpaulo struct sta_info *sta) 450252726Srpaulo{ 451252726Srpaulo struct wpabuf *buf; 452252726Srpaulo 453281806Srpaulo buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN); 454252726Srpaulo if (buf == NULL) 455252726Srpaulo return NULL; 456252726Srpaulo 457281806Srpaulo sae_write_confirm(sta->sae, buf); 458252726Srpaulo 459252726Srpaulo return buf; 460252726Srpaulo} 461252726Srpaulo 462252726Srpaulo 463281806Srpaulostatic int auth_sae_send_commit(struct hostapd_data *hapd, 464281806Srpaulo struct sta_info *sta, 465281806Srpaulo const u8 *bssid, int update) 466252726Srpaulo{ 467281806Srpaulo struct wpabuf *data; 468337817Scy int reply_res; 469252726Srpaulo 470281806Srpaulo data = auth_build_sae_commit(hapd, sta, update); 471346981Scy if (!data && sta->sae->tmp && sta->sae->tmp->pw_id) 472346981Scy return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER; 473281806Srpaulo if (data == NULL) 474252726Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 475252726Srpaulo 476337817Scy reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1, 477337817Scy WLAN_STATUS_SUCCESS, wpabuf_head(data), 478346981Scy wpabuf_len(data), "sae-send-commit"); 479281806Srpaulo 480281806Srpaulo wpabuf_free(data); 481281806Srpaulo 482337817Scy return reply_res; 483252726Srpaulo} 484252726Srpaulo 485252726Srpaulo 486281806Srpaulostatic int auth_sae_send_confirm(struct hostapd_data *hapd, 487281806Srpaulo struct sta_info *sta, 488281806Srpaulo const u8 *bssid) 489252726Srpaulo{ 490281806Srpaulo struct wpabuf *data; 491337817Scy int reply_res; 492252726Srpaulo 493281806Srpaulo data = auth_build_sae_confirm(hapd, sta); 494281806Srpaulo if (data == NULL) 495281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 496252726Srpaulo 497337817Scy reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2, 498337817Scy WLAN_STATUS_SUCCESS, wpabuf_head(data), 499346981Scy wpabuf_len(data), "sae-send-confirm"); 500281806Srpaulo 501281806Srpaulo wpabuf_free(data); 502281806Srpaulo 503337817Scy return reply_res; 504281806Srpaulo} 505281806Srpaulo 506281806Srpaulo 507281806Srpaulostatic int use_sae_anti_clogging(struct hostapd_data *hapd) 508281806Srpaulo{ 509281806Srpaulo struct sta_info *sta; 510281806Srpaulo unsigned int open = 0; 511281806Srpaulo 512281806Srpaulo if (hapd->conf->sae_anti_clogging_threshold == 0) 513281806Srpaulo return 1; 514281806Srpaulo 515281806Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 516281806Srpaulo if (!sta->sae) 517281806Srpaulo continue; 518281806Srpaulo if (sta->sae->state != SAE_COMMITTED && 519281806Srpaulo sta->sae->state != SAE_CONFIRMED) 520281806Srpaulo continue; 521281806Srpaulo open++; 522281806Srpaulo if (open >= hapd->conf->sae_anti_clogging_threshold) 523281806Srpaulo return 1; 524281806Srpaulo } 525281806Srpaulo 526346981Scy /* In addition to already existing open SAE sessions, check whether 527346981Scy * there are enough pending commit messages in the processing queue to 528346981Scy * potentially result in too many open sessions. */ 529346981Scy if (open + dl_list_len(&hapd->sae_commit_queue) >= 530346981Scy hapd->conf->sae_anti_clogging_threshold) 531346981Scy return 1; 532346981Scy 533281806Srpaulo return 0; 534281806Srpaulo} 535281806Srpaulo 536281806Srpaulo 537346981Scystatic u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr) 538346981Scy{ 539346981Scy u8 hash[SHA256_MAC_LEN]; 540346981Scy 541346981Scy hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), 542346981Scy addr, ETH_ALEN, hash); 543346981Scy return hash[0]; 544346981Scy} 545346981Scy 546346981Scy 547281806Srpaulostatic int check_sae_token(struct hostapd_data *hapd, const u8 *addr, 548281806Srpaulo const u8 *token, size_t token_len) 549281806Srpaulo{ 550281806Srpaulo u8 mac[SHA256_MAC_LEN]; 551346981Scy const u8 *addrs[2]; 552346981Scy size_t len[2]; 553346981Scy u16 token_idx; 554346981Scy u8 idx; 555281806Srpaulo 556281806Srpaulo if (token_len != SHA256_MAC_LEN) 557281806Srpaulo return -1; 558346981Scy idx = sae_token_hash(hapd, addr); 559346981Scy token_idx = hapd->sae_pending_token_idx[idx]; 560346981Scy if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) { 561346981Scy wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from " 562346981Scy MACSTR " - token_idx 0x%04x, expected 0x%04x", 563346981Scy MAC2STR(addr), WPA_GET_BE16(token), token_idx); 564281806Srpaulo return -1; 565346981Scy } 566281806Srpaulo 567346981Scy addrs[0] = addr; 568346981Scy len[0] = ETH_ALEN; 569346981Scy addrs[1] = token; 570346981Scy len[1] = 2; 571346981Scy if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key), 572346981Scy 2, addrs, len, mac) < 0 || 573346981Scy os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0) 574346981Scy return -1; 575346981Scy 576346981Scy hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */ 577346981Scy 578281806Srpaulo return 0; 579281806Srpaulo} 580281806Srpaulo 581281806Srpaulo 582281806Srpaulostatic struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, 583281806Srpaulo int group, const u8 *addr) 584281806Srpaulo{ 585281806Srpaulo struct wpabuf *buf; 586281806Srpaulo u8 *token; 587281806Srpaulo struct os_reltime now; 588346981Scy u8 idx[2]; 589346981Scy const u8 *addrs[2]; 590346981Scy size_t len[2]; 591346981Scy u8 p_idx; 592346981Scy u16 token_idx; 593281806Srpaulo 594281806Srpaulo os_get_reltime(&now); 595281806Srpaulo if (!os_reltime_initialized(&hapd->last_sae_token_key_update) || 596346981Scy os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) || 597346981Scy hapd->sae_token_idx == 0xffff) { 598281806Srpaulo if (random_get_bytes(hapd->sae_token_key, 599281806Srpaulo sizeof(hapd->sae_token_key)) < 0) 600281806Srpaulo return NULL; 601281806Srpaulo wpa_hexdump(MSG_DEBUG, "SAE: Updated token key", 602281806Srpaulo hapd->sae_token_key, sizeof(hapd->sae_token_key)); 603281806Srpaulo hapd->last_sae_token_key_update = now; 604346981Scy hapd->sae_token_idx = 0; 605346981Scy os_memset(hapd->sae_pending_token_idx, 0, 606346981Scy sizeof(hapd->sae_pending_token_idx)); 607281806Srpaulo } 608281806Srpaulo 609281806Srpaulo buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN); 610281806Srpaulo if (buf == NULL) 611281806Srpaulo return NULL; 612281806Srpaulo 613281806Srpaulo wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ 614281806Srpaulo 615346981Scy p_idx = sae_token_hash(hapd, addr); 616346981Scy token_idx = hapd->sae_pending_token_idx[p_idx]; 617346981Scy if (!token_idx) { 618346981Scy hapd->sae_token_idx++; 619346981Scy token_idx = hapd->sae_token_idx; 620346981Scy hapd->sae_pending_token_idx[p_idx] = token_idx; 621346981Scy } 622346981Scy WPA_PUT_BE16(idx, token_idx); 623281806Srpaulo token = wpabuf_put(buf, SHA256_MAC_LEN); 624346981Scy addrs[0] = addr; 625346981Scy len[0] = ETH_ALEN; 626346981Scy addrs[1] = idx; 627346981Scy len[1] = sizeof(idx); 628346981Scy if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key), 629346981Scy 2, addrs, len, token) < 0) { 630346981Scy wpabuf_free(buf); 631346981Scy return NULL; 632346981Scy } 633346981Scy WPA_PUT_BE16(token, token_idx); 634281806Srpaulo 635281806Srpaulo return buf; 636281806Srpaulo} 637281806Srpaulo 638281806Srpaulo 639346981Scystatic int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta) 640281806Srpaulo{ 641346981Scy if (sta->sae->sync > hapd->conf->sae_sync) { 642346981Scy sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync"); 643281806Srpaulo sta->sae->sync = 0; 644281806Srpaulo return -1; 645281806Srpaulo } 646281806Srpaulo return 0; 647281806Srpaulo} 648281806Srpaulo 649281806Srpaulo 650281806Srpaulostatic void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data) 651281806Srpaulo{ 652281806Srpaulo struct hostapd_data *hapd = eloop_ctx; 653281806Srpaulo struct sta_info *sta = eloop_data; 654281806Srpaulo int ret; 655281806Srpaulo 656346981Scy if (sae_check_big_sync(hapd, sta)) 657281806Srpaulo return; 658281806Srpaulo sta->sae->sync++; 659337817Scy wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR 660346981Scy " (sync=%d state=%s)", 661346981Scy MAC2STR(sta->addr), sta->sae->sync, 662346981Scy sae_state_txt(sta->sae->state)); 663281806Srpaulo 664281806Srpaulo switch (sta->sae->state) { 665281806Srpaulo case SAE_COMMITTED: 666281806Srpaulo ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0); 667289549Srpaulo eloop_register_timeout(0, 668289549Srpaulo hapd->dot11RSNASAERetransPeriod * 1000, 669281806Srpaulo auth_sae_retransmit_timer, hapd, sta); 670281806Srpaulo break; 671281806Srpaulo case SAE_CONFIRMED: 672281806Srpaulo ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr); 673289549Srpaulo eloop_register_timeout(0, 674289549Srpaulo hapd->dot11RSNASAERetransPeriod * 1000, 675281806Srpaulo auth_sae_retransmit_timer, hapd, sta); 676281806Srpaulo break; 677281806Srpaulo default: 678281806Srpaulo ret = -1; 679281806Srpaulo break; 680281806Srpaulo } 681281806Srpaulo 682281806Srpaulo if (ret != WLAN_STATUS_SUCCESS) 683281806Srpaulo wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret); 684281806Srpaulo} 685281806Srpaulo 686281806Srpaulo 687281806Srpaulovoid sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta) 688281806Srpaulo{ 689281806Srpaulo eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta); 690281806Srpaulo} 691281806Srpaulo 692281806Srpaulo 693281806Srpaulostatic void sae_set_retransmit_timer(struct hostapd_data *hapd, 694281806Srpaulo struct sta_info *sta) 695281806Srpaulo{ 696281806Srpaulo if (!(hapd->conf->mesh & MESH_ENABLED)) 697281806Srpaulo return; 698281806Srpaulo 699281806Srpaulo eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta); 700289549Srpaulo eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000, 701281806Srpaulo auth_sae_retransmit_timer, hapd, sta); 702281806Srpaulo} 703281806Srpaulo 704281806Srpaulo 705346981Scystatic void sae_sme_send_external_auth_status(struct hostapd_data *hapd, 706346981Scy struct sta_info *sta, u16 status) 707346981Scy{ 708346981Scy struct external_auth params; 709346981Scy 710346981Scy os_memset(¶ms, 0, sizeof(params)); 711346981Scy params.status = status; 712346981Scy params.bssid = sta->addr; 713351611Scy if (status == WLAN_STATUS_SUCCESS && sta->sae && 714351611Scy !hapd->conf->disable_pmksa_caching) 715346981Scy params.pmkid = sta->sae->pmkid; 716346981Scy 717346981Scy hostapd_drv_send_external_auth_status(hapd, ¶ms); 718346981Scy} 719346981Scy 720346981Scy 721337817Scyvoid sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta) 722337817Scy{ 723346981Scy#ifndef CONFIG_NO_VLAN 724346981Scy struct vlan_description vlan_desc; 725346981Scy 726346981Scy if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) { 727346981Scy wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR 728346981Scy " to VLAN ID %d", 729346981Scy MAC2STR(sta->addr), sta->sae->tmp->vlan_id); 730346981Scy 731346981Scy os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 732346981Scy vlan_desc.notempty = 1; 733346981Scy vlan_desc.untagged = sta->sae->tmp->vlan_id; 734346981Scy if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 735346981Scy wpa_printf(MSG_INFO, 736346981Scy "Invalid VLAN ID %d in sae_password", 737346981Scy sta->sae->tmp->vlan_id); 738346981Scy return; 739346981Scy } 740346981Scy 741346981Scy if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 || 742346981Scy ap_sta_bind_vlan(hapd, sta) < 0) { 743346981Scy wpa_printf(MSG_INFO, 744346981Scy "Failed to assign VLAN ID %d from sae_password to " 745346981Scy MACSTR, sta->sae->tmp->vlan_id, 746346981Scy MAC2STR(sta->addr)); 747346981Scy return; 748346981Scy } 749346981Scy } 750346981Scy#endif /* CONFIG_NO_VLAN */ 751346981Scy 752337817Scy sta->flags |= WLAN_STA_AUTH; 753337817Scy sta->auth_alg = WLAN_AUTH_SAE; 754337817Scy mlme_authenticate_indication(hapd, sta); 755337817Scy wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 756346981Scy sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm"); 757337817Scy wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr, 758337817Scy sta->sae->pmk, sta->sae->pmkid); 759346981Scy sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS); 760337817Scy} 761337817Scy 762337817Scy 763281806Srpaulostatic int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, 764346981Scy const u8 *bssid, u8 auth_transaction, int allow_reuse, 765346981Scy int *sta_removed) 766281806Srpaulo{ 767281806Srpaulo int ret; 768281806Srpaulo 769346981Scy *sta_removed = 0; 770346981Scy 771281806Srpaulo if (auth_transaction != 1 && auth_transaction != 2) 772252726Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 773252726Srpaulo 774346981Scy wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u", 775346981Scy MAC2STR(sta->addr), sae_state_txt(sta->sae->state), 776346981Scy auth_transaction); 777281806Srpaulo switch (sta->sae->state) { 778281806Srpaulo case SAE_NOTHING: 779281806Srpaulo if (auth_transaction == 1) { 780346981Scy ret = auth_sae_send_commit(hapd, sta, bssid, 781346981Scy !allow_reuse); 782281806Srpaulo if (ret) 783281806Srpaulo return ret; 784346981Scy sae_set_state(sta, SAE_COMMITTED, "Sent Commit"); 785281806Srpaulo 786281806Srpaulo if (sae_process_commit(sta->sae) < 0) 787281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 788281806Srpaulo 789281806Srpaulo /* 790281806Srpaulo * In mesh case, both Commit and Confirm can be sent 791281806Srpaulo * immediately. In infrastructure BSS, only a single 792281806Srpaulo * Authentication frame (Commit) is expected from the AP 793281806Srpaulo * here and the second one (Confirm) will be sent once 794281806Srpaulo * the STA has sent its second Authentication frame 795281806Srpaulo * (Confirm). 796281806Srpaulo */ 797281806Srpaulo if (hapd->conf->mesh & MESH_ENABLED) { 798281806Srpaulo /* 799281806Srpaulo * Send both Commit and Confirm immediately 800281806Srpaulo * based on SAE finite state machine 801281806Srpaulo * Nothing -> Confirm transition. 802281806Srpaulo */ 803281806Srpaulo ret = auth_sae_send_confirm(hapd, sta, bssid); 804281806Srpaulo if (ret) 805281806Srpaulo return ret; 806346981Scy sae_set_state(sta, SAE_CONFIRMED, 807346981Scy "Sent Confirm (mesh)"); 808281806Srpaulo } else { 809281806Srpaulo /* 810281806Srpaulo * For infrastructure BSS, send only the Commit 811281806Srpaulo * message now to get alternating sequence of 812281806Srpaulo * Authentication frames between the AP and STA. 813281806Srpaulo * Confirm will be sent in 814337817Scy * Committed -> Confirmed/Accepted transition 815281806Srpaulo * when receiving Confirm from STA. 816281806Srpaulo */ 817281806Srpaulo } 818281806Srpaulo sta->sae->sync = 0; 819281806Srpaulo sae_set_retransmit_timer(hapd, sta); 820281806Srpaulo } else { 821281806Srpaulo hostapd_logger(hapd, sta->addr, 822281806Srpaulo HOSTAPD_MODULE_IEEE80211, 823281806Srpaulo HOSTAPD_LEVEL_DEBUG, 824281806Srpaulo "SAE confirm before commit"); 825281806Srpaulo } 826281806Srpaulo break; 827281806Srpaulo case SAE_COMMITTED: 828281806Srpaulo sae_clear_retransmit_timer(hapd, sta); 829281806Srpaulo if (auth_transaction == 1) { 830281806Srpaulo if (sae_process_commit(sta->sae) < 0) 831281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 832281806Srpaulo 833281806Srpaulo ret = auth_sae_send_confirm(hapd, sta, bssid); 834281806Srpaulo if (ret) 835281806Srpaulo return ret; 836346981Scy sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm"); 837281806Srpaulo sta->sae->sync = 0; 838281806Srpaulo sae_set_retransmit_timer(hapd, sta); 839281806Srpaulo } else if (hapd->conf->mesh & MESH_ENABLED) { 840281806Srpaulo /* 841281806Srpaulo * In mesh case, follow SAE finite state machine and 842281806Srpaulo * send Commit now, if sync count allows. 843281806Srpaulo */ 844346981Scy if (sae_check_big_sync(hapd, sta)) 845281806Srpaulo return WLAN_STATUS_SUCCESS; 846281806Srpaulo sta->sae->sync++; 847281806Srpaulo 848289549Srpaulo ret = auth_sae_send_commit(hapd, sta, bssid, 0); 849281806Srpaulo if (ret) 850281806Srpaulo return ret; 851281806Srpaulo 852281806Srpaulo sae_set_retransmit_timer(hapd, sta); 853281806Srpaulo } else { 854281806Srpaulo /* 855281806Srpaulo * For instructure BSS, send the postponed Confirm from 856281806Srpaulo * Nothing -> Confirmed transition that was reduced to 857281806Srpaulo * Nothing -> Committed above. 858281806Srpaulo */ 859281806Srpaulo ret = auth_sae_send_confirm(hapd, sta, bssid); 860281806Srpaulo if (ret) 861281806Srpaulo return ret; 862281806Srpaulo 863346981Scy sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm"); 864281806Srpaulo 865281806Srpaulo /* 866281806Srpaulo * Since this was triggered on Confirm RX, run another 867281806Srpaulo * step to get to Accepted without waiting for 868281806Srpaulo * additional events. 869281806Srpaulo */ 870346981Scy return sae_sm_step(hapd, sta, bssid, auth_transaction, 871346981Scy 0, sta_removed); 872281806Srpaulo } 873281806Srpaulo break; 874281806Srpaulo case SAE_CONFIRMED: 875281806Srpaulo sae_clear_retransmit_timer(hapd, sta); 876281806Srpaulo if (auth_transaction == 1) { 877346981Scy if (sae_check_big_sync(hapd, sta)) 878281806Srpaulo return WLAN_STATUS_SUCCESS; 879281806Srpaulo sta->sae->sync++; 880281806Srpaulo 881281806Srpaulo ret = auth_sae_send_commit(hapd, sta, bssid, 1); 882281806Srpaulo if (ret) 883281806Srpaulo return ret; 884281806Srpaulo 885281806Srpaulo if (sae_process_commit(sta->sae) < 0) 886281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 887281806Srpaulo 888281806Srpaulo ret = auth_sae_send_confirm(hapd, sta, bssid); 889281806Srpaulo if (ret) 890281806Srpaulo return ret; 891281806Srpaulo 892281806Srpaulo sae_set_retransmit_timer(hapd, sta); 893281806Srpaulo } else { 894346981Scy sta->sae->send_confirm = 0xffff; 895337817Scy sae_accept_sta(hapd, sta); 896281806Srpaulo } 897281806Srpaulo break; 898281806Srpaulo case SAE_ACCEPTED: 899346981Scy if (auth_transaction == 1 && 900346981Scy (hapd->conf->mesh & MESH_ENABLED)) { 901281806Srpaulo wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR 902281806Srpaulo ") doing reauthentication", 903281806Srpaulo MAC2STR(sta->addr)); 904346981Scy wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 905281806Srpaulo ap_free_sta(hapd, sta); 906346981Scy *sta_removed = 1; 907346981Scy } else if (auth_transaction == 1) { 908346981Scy wpa_printf(MSG_DEBUG, "SAE: Start reauthentication"); 909346981Scy ret = auth_sae_send_commit(hapd, sta, bssid, 1); 910346981Scy if (ret) 911346981Scy return ret; 912346981Scy sae_set_state(sta, SAE_COMMITTED, "Sent Commit"); 913346981Scy 914346981Scy if (sae_process_commit(sta->sae) < 0) 915346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 916346981Scy sta->sae->sync = 0; 917346981Scy sae_set_retransmit_timer(hapd, sta); 918281806Srpaulo } else { 919346981Scy if (sae_check_big_sync(hapd, sta)) 920281806Srpaulo return WLAN_STATUS_SUCCESS; 921281806Srpaulo sta->sae->sync++; 922281806Srpaulo 923281806Srpaulo ret = auth_sae_send_confirm(hapd, sta, bssid); 924281806Srpaulo sae_clear_temp_data(sta->sae); 925281806Srpaulo if (ret) 926281806Srpaulo return ret; 927281806Srpaulo } 928281806Srpaulo break; 929281806Srpaulo default: 930281806Srpaulo wpa_printf(MSG_ERROR, "SAE: invalid state %d", 931281806Srpaulo sta->sae->state); 932281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 933281806Srpaulo } 934252726Srpaulo return WLAN_STATUS_SUCCESS; 935252726Srpaulo} 936252726Srpaulo 937252726Srpaulo 938337817Scystatic void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta) 939337817Scy{ 940337817Scy struct sae_data *sae = sta->sae; 941337817Scy int i, *groups = hapd->conf->sae_groups; 942346981Scy int default_groups[] = { 19, 0 }; 943337817Scy 944337817Scy if (sae->state != SAE_COMMITTED) 945337817Scy return; 946337817Scy 947337817Scy wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group); 948337817Scy 949346981Scy if (!groups) 950346981Scy groups = default_groups; 951346981Scy for (i = 0; groups[i] > 0; i++) { 952337817Scy if (sae->group == groups[i]) 953337817Scy break; 954337817Scy } 955337817Scy 956346981Scy if (groups[i] <= 0) { 957337817Scy wpa_printf(MSG_DEBUG, 958337817Scy "SAE: Previously selected group not found from the current configuration"); 959337817Scy return; 960337817Scy } 961337817Scy 962337817Scy for (;;) { 963337817Scy i++; 964337817Scy if (groups[i] <= 0) { 965337817Scy wpa_printf(MSG_DEBUG, 966337817Scy "SAE: No alternative group enabled"); 967337817Scy return; 968337817Scy } 969337817Scy 970337817Scy if (sae_set_group(sae, groups[i]) < 0) 971337817Scy continue; 972337817Scy 973337817Scy break; 974337817Scy } 975337817Scy wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]); 976337817Scy} 977337817Scy 978337817Scy 979252726Srpaulostatic void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, 980252726Srpaulo const struct ieee80211_mgmt *mgmt, size_t len, 981281806Srpaulo u16 auth_transaction, u16 status_code) 982252726Srpaulo{ 983337817Scy int resp = WLAN_STATUS_SUCCESS; 984281806Srpaulo struct wpabuf *data = NULL; 985346981Scy int *groups = hapd->conf->sae_groups; 986346981Scy int default_groups[] = { 19, 0 }; 987346981Scy const u8 *pos, *end; 988346981Scy int sta_removed = 0; 989252726Srpaulo 990346981Scy if (!groups) 991346981Scy groups = default_groups; 992346981Scy 993346981Scy#ifdef CONFIG_TESTING_OPTIONS 994346981Scy if (hapd->conf->sae_reflection_attack && auth_transaction == 1) { 995346981Scy wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack"); 996346981Scy pos = mgmt->u.auth.variable; 997346981Scy end = ((const u8 *) mgmt) + len; 998346981Scy send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, 999346981Scy auth_transaction, resp, pos, end - pos, 1000346981Scy "auth-sae-reflection-attack"); 1001346981Scy goto remove_sta; 1002346981Scy } 1003346981Scy 1004346981Scy if (hapd->conf->sae_commit_override && auth_transaction == 1) { 1005346981Scy wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override"); 1006346981Scy send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, 1007346981Scy auth_transaction, resp, 1008346981Scy wpabuf_head(hapd->conf->sae_commit_override), 1009346981Scy wpabuf_len(hapd->conf->sae_commit_override), 1010346981Scy "sae-commit-override"); 1011346981Scy goto remove_sta; 1012346981Scy } 1013346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 1014281806Srpaulo if (!sta->sae) { 1015337817Scy if (auth_transaction != 1 || 1016337817Scy status_code != WLAN_STATUS_SUCCESS) { 1017337817Scy resp = -1; 1018337817Scy goto remove_sta; 1019337817Scy } 1020281806Srpaulo sta->sae = os_zalloc(sizeof(*sta->sae)); 1021337817Scy if (!sta->sae) { 1022337817Scy resp = -1; 1023337817Scy goto remove_sta; 1024337817Scy } 1025346981Scy sae_set_state(sta, SAE_NOTHING, "Init"); 1026281806Srpaulo sta->sae->sync = 0; 1027281806Srpaulo } 1028281806Srpaulo 1029337817Scy if (sta->mesh_sae_pmksa_caching) { 1030337817Scy wpa_printf(MSG_DEBUG, 1031337817Scy "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication"); 1032337817Scy wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 1033337817Scy sta->mesh_sae_pmksa_caching = 0; 1034337817Scy } 1035337817Scy 1036252726Srpaulo if (auth_transaction == 1) { 1037346981Scy const u8 *token = NULL; 1038281806Srpaulo size_t token_len = 0; 1039346981Scy int allow_reuse = 0; 1040346981Scy 1041252726Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1042252726Srpaulo HOSTAPD_LEVEL_DEBUG, 1043351611Scy "start SAE authentication (RX commit, status=%u (%s))", 1044351611Scy status_code, status2str(status_code)); 1045281806Srpaulo 1046281806Srpaulo if ((hapd->conf->mesh & MESH_ENABLED) && 1047281806Srpaulo status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ && 1048281806Srpaulo sta->sae->tmp) { 1049281806Srpaulo pos = mgmt->u.auth.variable; 1050281806Srpaulo end = ((const u8 *) mgmt) + len; 1051281806Srpaulo if (pos + sizeof(le16) > end) { 1052281806Srpaulo wpa_printf(MSG_ERROR, 1053281806Srpaulo "SAE: Too short anti-clogging token request"); 1054281806Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1055281806Srpaulo goto reply; 1056281806Srpaulo } 1057346981Scy resp = sae_group_allowed(sta->sae, groups, 1058281806Srpaulo WPA_GET_LE16(pos)); 1059281806Srpaulo if (resp != WLAN_STATUS_SUCCESS) { 1060281806Srpaulo wpa_printf(MSG_ERROR, 1061281806Srpaulo "SAE: Invalid group in anti-clogging token request"); 1062281806Srpaulo goto reply; 1063281806Srpaulo } 1064281806Srpaulo pos += sizeof(le16); 1065281806Srpaulo 1066281806Srpaulo wpabuf_free(sta->sae->tmp->anti_clogging_token); 1067281806Srpaulo sta->sae->tmp->anti_clogging_token = 1068281806Srpaulo wpabuf_alloc_copy(pos, end - pos); 1069281806Srpaulo if (sta->sae->tmp->anti_clogging_token == NULL) { 1070281806Srpaulo wpa_printf(MSG_ERROR, 1071281806Srpaulo "SAE: Failed to alloc for anti-clogging token"); 1072337817Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1073337817Scy goto remove_sta; 1074281806Srpaulo } 1075281806Srpaulo 1076281806Srpaulo /* 1077281806Srpaulo * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code 1078281806Srpaulo * is 76, a new Commit Message shall be constructed 1079281806Srpaulo * with the Anti-Clogging Token from the received 1080281806Srpaulo * Authentication frame, and the commit-scalar and 1081281806Srpaulo * COMMIT-ELEMENT previously sent. 1082281806Srpaulo */ 1083337817Scy resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0); 1084337817Scy if (resp != WLAN_STATUS_SUCCESS) { 1085281806Srpaulo wpa_printf(MSG_ERROR, 1086281806Srpaulo "SAE: Failed to send commit message"); 1087337817Scy goto remove_sta; 1088281806Srpaulo } 1089346981Scy sae_set_state(sta, SAE_COMMITTED, 1090346981Scy "Sent Commit (anti-clogging token case in mesh)"); 1091281806Srpaulo sta->sae->sync = 0; 1092281806Srpaulo sae_set_retransmit_timer(hapd, sta); 1093281806Srpaulo return; 1094281806Srpaulo } 1095281806Srpaulo 1096337817Scy if ((hapd->conf->mesh & MESH_ENABLED) && 1097337817Scy status_code == 1098337817Scy WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && 1099337817Scy sta->sae->tmp) { 1100337817Scy wpa_printf(MSG_DEBUG, 1101337817Scy "SAE: Peer did not accept our SAE group"); 1102337817Scy sae_pick_next_group(hapd, sta); 1103337817Scy goto remove_sta; 1104337817Scy } 1105337817Scy 1106281806Srpaulo if (status_code != WLAN_STATUS_SUCCESS) 1107337817Scy goto remove_sta; 1108281806Srpaulo 1109346981Scy if (!(hapd->conf->mesh & MESH_ENABLED) && 1110346981Scy sta->sae->state == SAE_COMMITTED) { 1111346981Scy /* This is needed in the infrastructure BSS case to 1112346981Scy * address a sequence where a STA entry may remain in 1113346981Scy * hostapd across two attempts to do SAE authentication 1114346981Scy * by the same STA. The second attempt may end up trying 1115346981Scy * to use a different group and that would not be 1116346981Scy * allowed if we remain in Committed state with the 1117346981Scy * previously set parameters. */ 1118346981Scy pos = mgmt->u.auth.variable; 1119346981Scy end = ((const u8 *) mgmt) + len; 1120346981Scy if (end - pos >= (int) sizeof(le16) && 1121346981Scy sae_group_allowed(sta->sae, groups, 1122346981Scy WPA_GET_LE16(pos)) == 1123346981Scy WLAN_STATUS_SUCCESS) { 1124346981Scy /* Do not waste resources deriving the same PWE 1125346981Scy * again since the same group is reused. */ 1126346981Scy sae_set_state(sta, SAE_NOTHING, 1127346981Scy "Allow previous PWE to be reused"); 1128346981Scy allow_reuse = 1; 1129346981Scy } else { 1130346981Scy sae_set_state(sta, SAE_NOTHING, 1131346981Scy "Clear existing state to allow restart"); 1132346981Scy sae_clear_data(sta->sae); 1133346981Scy } 1134346981Scy } 1135346981Scy 1136281806Srpaulo resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable, 1137281806Srpaulo ((const u8 *) mgmt) + len - 1138281806Srpaulo mgmt->u.auth.variable, &token, 1139346981Scy &token_len, groups); 1140289549Srpaulo if (resp == SAE_SILENTLY_DISCARD) { 1141289549Srpaulo wpa_printf(MSG_DEBUG, 1142289549Srpaulo "SAE: Drop commit message from " MACSTR " due to reflection attack", 1143289549Srpaulo MAC2STR(sta->addr)); 1144337817Scy goto remove_sta; 1145289549Srpaulo } 1146346981Scy 1147346981Scy if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) { 1148346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 1149346981Scy WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER 1150346981Scy MACSTR, MAC2STR(sta->addr)); 1151346981Scy sae_clear_retransmit_timer(hapd, sta); 1152346981Scy sae_set_state(sta, SAE_NOTHING, 1153346981Scy "Unknown Password Identifier"); 1154346981Scy goto remove_sta; 1155346981Scy } 1156346981Scy 1157281806Srpaulo if (token && check_sae_token(hapd, sta->addr, token, token_len) 1158281806Srpaulo < 0) { 1159281806Srpaulo wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " 1160281806Srpaulo "incorrect token from " MACSTR, 1161281806Srpaulo MAC2STR(sta->addr)); 1162337817Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1163337817Scy goto remove_sta; 1164281806Srpaulo } 1165281806Srpaulo 1166281806Srpaulo if (resp != WLAN_STATUS_SUCCESS) 1167281806Srpaulo goto reply; 1168281806Srpaulo 1169346981Scy if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) { 1170281806Srpaulo wpa_printf(MSG_DEBUG, 1171281806Srpaulo "SAE: Request anti-clogging token from " 1172281806Srpaulo MACSTR, MAC2STR(sta->addr)); 1173281806Srpaulo data = auth_build_token_req(hapd, sta->sae->group, 1174281806Srpaulo sta->addr); 1175281806Srpaulo resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ; 1176281806Srpaulo if (hapd->conf->mesh & MESH_ENABLED) 1177346981Scy sae_set_state(sta, SAE_NOTHING, 1178346981Scy "Request anti-clogging token case in mesh"); 1179281806Srpaulo goto reply; 1180281806Srpaulo } 1181281806Srpaulo 1182346981Scy resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 1183346981Scy allow_reuse, &sta_removed); 1184252726Srpaulo } else if (auth_transaction == 2) { 1185252726Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1186252726Srpaulo HOSTAPD_LEVEL_DEBUG, 1187351611Scy "SAE authentication (RX confirm, status=%u (%s))", 1188351611Scy status_code, status2str(status_code)); 1189281806Srpaulo if (status_code != WLAN_STATUS_SUCCESS) 1190337817Scy goto remove_sta; 1191281806Srpaulo if (sta->sae->state >= SAE_CONFIRMED || 1192281806Srpaulo !(hapd->conf->mesh & MESH_ENABLED)) { 1193346981Scy const u8 *var; 1194346981Scy size_t var_len; 1195346981Scy u16 peer_send_confirm; 1196346981Scy 1197346981Scy var = mgmt->u.auth.variable; 1198346981Scy var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable; 1199346981Scy if (var_len < 2) { 1200281806Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1201281806Srpaulo goto reply; 1202281806Srpaulo } 1203346981Scy 1204346981Scy peer_send_confirm = WPA_GET_LE16(var); 1205346981Scy 1206346981Scy if (sta->sae->state == SAE_ACCEPTED && 1207346981Scy (peer_send_confirm <= sta->sae->rc || 1208346981Scy peer_send_confirm == 0xffff)) { 1209346981Scy wpa_printf(MSG_DEBUG, 1210346981Scy "SAE: Silently ignore unexpected Confirm from peer " 1211346981Scy MACSTR 1212346981Scy " (peer-send-confirm=%u Rc=%u)", 1213346981Scy MAC2STR(sta->addr), 1214346981Scy peer_send_confirm, sta->sae->rc); 1215346981Scy return; 1216346981Scy } 1217346981Scy 1218346981Scy if (sae_check_confirm(sta->sae, var, var_len) < 0) { 1219346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1220346981Scy goto reply; 1221346981Scy } 1222346981Scy sta->sae->rc = peer_send_confirm; 1223252726Srpaulo } 1224346981Scy resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0, 1225346981Scy &sta_removed); 1226252726Srpaulo } else { 1227252726Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1228252726Srpaulo HOSTAPD_LEVEL_DEBUG, 1229351611Scy "unexpected SAE authentication transaction %u (status=%u (%s))", 1230351611Scy auth_transaction, status_code, 1231351611Scy status2str(status_code)); 1232281806Srpaulo if (status_code != WLAN_STATUS_SUCCESS) 1233337817Scy goto remove_sta; 1234252726Srpaulo resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; 1235252726Srpaulo } 1236252726Srpaulo 1237281806Srpauloreply: 1238346981Scy if (!sta_removed && resp != WLAN_STATUS_SUCCESS) { 1239346981Scy pos = mgmt->u.auth.variable; 1240346981Scy end = ((const u8 *) mgmt) + len; 1241346981Scy 1242346981Scy /* Copy the Finite Cyclic Group field from the request if we 1243346981Scy * rejected it as unsupported group. */ 1244346981Scy if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && 1245346981Scy !data && end - pos >= 2) 1246346981Scy data = wpabuf_alloc_copy(pos, 2); 1247346981Scy 1248346981Scy sae_sme_send_external_auth_status(hapd, sta, resp); 1249281806Srpaulo send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, 1250281806Srpaulo auth_transaction, resp, 1251281806Srpaulo data ? wpabuf_head(data) : (u8 *) "", 1252346981Scy data ? wpabuf_len(data) : 0, "auth-sae"); 1253281806Srpaulo } 1254337817Scy 1255337817Scyremove_sta: 1256346981Scy if (!sta_removed && sta->added_unassoc && 1257346981Scy (resp != WLAN_STATUS_SUCCESS || 1258346981Scy status_code != WLAN_STATUS_SUCCESS)) { 1259337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 1260337817Scy sta->added_unassoc = 0; 1261337817Scy } 1262281806Srpaulo wpabuf_free(data); 1263281806Srpaulo} 1264252726Srpaulo 1265252726Srpaulo 1266281806Srpaulo/** 1267281806Srpaulo * auth_sae_init_committed - Send COMMIT and start SAE in committed state 1268281806Srpaulo * @hapd: BSS data for the device initiating the authentication 1269281806Srpaulo * @sta: the peer to which commit authentication frame is sent 1270281806Srpaulo * 1271281806Srpaulo * This function implements Init event handling (IEEE Std 802.11-2012, 1272281806Srpaulo * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the 1273281806Srpaulo * sta->sae structure should be initialized appropriately via a call to 1274281806Srpaulo * sae_prepare_commit(). 1275281806Srpaulo */ 1276281806Srpauloint auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta) 1277281806Srpaulo{ 1278281806Srpaulo int ret; 1279281806Srpaulo 1280281806Srpaulo if (!sta->sae || !sta->sae->tmp) 1281281806Srpaulo return -1; 1282281806Srpaulo 1283281806Srpaulo if (sta->sae->state != SAE_NOTHING) 1284281806Srpaulo return -1; 1285281806Srpaulo 1286281806Srpaulo ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0); 1287281806Srpaulo if (ret) 1288281806Srpaulo return -1; 1289281806Srpaulo 1290346981Scy sae_set_state(sta, SAE_COMMITTED, "Init and sent commit"); 1291281806Srpaulo sta->sae->sync = 0; 1292281806Srpaulo sae_set_retransmit_timer(hapd, sta); 1293281806Srpaulo 1294281806Srpaulo return 0; 1295252726Srpaulo} 1296281806Srpaulo 1297346981Scy 1298346981Scyvoid auth_sae_process_commit(void *eloop_ctx, void *user_ctx) 1299346981Scy{ 1300346981Scy struct hostapd_data *hapd = eloop_ctx; 1301346981Scy struct hostapd_sae_commit_queue *q; 1302346981Scy unsigned int queue_len; 1303346981Scy 1304346981Scy q = dl_list_first(&hapd->sae_commit_queue, 1305346981Scy struct hostapd_sae_commit_queue, list); 1306346981Scy if (!q) 1307346981Scy return; 1308346981Scy wpa_printf(MSG_DEBUG, 1309346981Scy "SAE: Process next available message from queue"); 1310346981Scy dl_list_del(&q->list); 1311346981Scy handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len, 1312346981Scy q->rssi, 1); 1313346981Scy os_free(q); 1314346981Scy 1315346981Scy if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL)) 1316346981Scy return; 1317346981Scy queue_len = dl_list_len(&hapd->sae_commit_queue); 1318346981Scy eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit, 1319346981Scy hapd, NULL); 1320346981Scy} 1321346981Scy 1322346981Scy 1323346981Scystatic void auth_sae_queue(struct hostapd_data *hapd, 1324346981Scy const struct ieee80211_mgmt *mgmt, size_t len, 1325346981Scy int rssi) 1326346981Scy{ 1327346981Scy struct hostapd_sae_commit_queue *q, *q2; 1328346981Scy unsigned int queue_len; 1329346981Scy const struct ieee80211_mgmt *mgmt2; 1330346981Scy 1331346981Scy queue_len = dl_list_len(&hapd->sae_commit_queue); 1332346981Scy if (queue_len >= 15) { 1333346981Scy wpa_printf(MSG_DEBUG, 1334346981Scy "SAE: No more room in message queue - drop the new frame from " 1335346981Scy MACSTR, MAC2STR(mgmt->sa)); 1336346981Scy return; 1337346981Scy } 1338346981Scy 1339346981Scy wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from " 1340346981Scy MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa), 1341346981Scy queue_len); 1342346981Scy q = os_zalloc(sizeof(*q) + len); 1343346981Scy if (!q) 1344346981Scy return; 1345346981Scy q->rssi = rssi; 1346346981Scy q->len = len; 1347346981Scy os_memcpy(q->msg, mgmt, len); 1348346981Scy 1349346981Scy /* Check whether there is already a queued Authentication frame from the 1350346981Scy * same station with the same transaction number and if so, replace that 1351346981Scy * queue entry with the new one. This avoids issues with a peer that 1352346981Scy * sends multiple times (e.g., due to frequent SAE retries). There is no 1353346981Scy * point in us trying to process the old attempts after a new one has 1354346981Scy * obsoleted them. */ 1355346981Scy dl_list_for_each(q2, &hapd->sae_commit_queue, 1356346981Scy struct hostapd_sae_commit_queue, list) { 1357346981Scy mgmt2 = (const struct ieee80211_mgmt *) q2->msg; 1358346981Scy if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 && 1359346981Scy mgmt->u.auth.auth_transaction == 1360346981Scy mgmt2->u.auth.auth_transaction) { 1361346981Scy wpa_printf(MSG_DEBUG, 1362346981Scy "SAE: Replace queued message from same STA with same transaction number"); 1363346981Scy dl_list_add(&q2->list, &q->list); 1364346981Scy dl_list_del(&q2->list); 1365346981Scy os_free(q2); 1366346981Scy goto queued; 1367346981Scy } 1368346981Scy } 1369346981Scy 1370346981Scy /* No pending identical entry, so add to the end of the queue */ 1371346981Scy dl_list_add_tail(&hapd->sae_commit_queue, &q->list); 1372346981Scy 1373346981Scyqueued: 1374346981Scy if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL)) 1375346981Scy return; 1376346981Scy eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit, 1377346981Scy hapd, NULL); 1378346981Scy} 1379346981Scy 1380346981Scy 1381346981Scystatic int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr) 1382346981Scy{ 1383346981Scy struct hostapd_sae_commit_queue *q; 1384346981Scy const struct ieee80211_mgmt *mgmt; 1385346981Scy 1386346981Scy dl_list_for_each(q, &hapd->sae_commit_queue, 1387346981Scy struct hostapd_sae_commit_queue, list) { 1388346981Scy mgmt = (const struct ieee80211_mgmt *) q->msg; 1389346981Scy if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0) 1390346981Scy return 1; 1391346981Scy } 1392346981Scy 1393346981Scy return 0; 1394346981Scy} 1395346981Scy 1396252726Srpaulo#endif /* CONFIG_SAE */ 1397252726Srpaulo 1398252726Srpaulo 1399346981Scystatic u16 wpa_res_to_status_code(int res) 1400346981Scy{ 1401346981Scy if (res == WPA_INVALID_GROUP) 1402346981Scy return WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 1403346981Scy if (res == WPA_INVALID_PAIRWISE) 1404346981Scy return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 1405346981Scy if (res == WPA_INVALID_AKMP) 1406346981Scy return WLAN_STATUS_AKMP_NOT_VALID; 1407346981Scy if (res == WPA_ALLOC_FAIL) 1408346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 1409346981Scy#ifdef CONFIG_IEEE80211W 1410346981Scy if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) 1411346981Scy return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; 1412346981Scy if (res == WPA_INVALID_MGMT_GROUP_CIPHER) 1413346981Scy return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 1414346981Scy#endif /* CONFIG_IEEE80211W */ 1415346981Scy if (res == WPA_INVALID_MDIE) 1416346981Scy return WLAN_STATUS_INVALID_MDIE; 1417346981Scy if (res == WPA_INVALID_PMKID) 1418346981Scy return WLAN_STATUS_INVALID_PMKID; 1419346981Scy if (res != WPA_IE_OK) 1420346981Scy return WLAN_STATUS_INVALID_IE; 1421346981Scy return WLAN_STATUS_SUCCESS; 1422346981Scy} 1423346981Scy 1424346981Scy 1425346981Scy#ifdef CONFIG_FILS 1426346981Scy 1427346981Scystatic void handle_auth_fils_finish(struct hostapd_data *hapd, 1428346981Scy struct sta_info *sta, u16 resp, 1429346981Scy struct wpabuf *data, int pub); 1430346981Scy 1431346981Scyvoid handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, 1432346981Scy const u8 *pos, size_t len, u16 auth_alg, 1433346981Scy u16 auth_transaction, u16 status_code, 1434346981Scy void (*cb)(struct hostapd_data *hapd, 1435346981Scy struct sta_info *sta, u16 resp, 1436346981Scy struct wpabuf *data, int pub)) 1437346981Scy{ 1438346981Scy u16 resp = WLAN_STATUS_SUCCESS; 1439346981Scy const u8 *end; 1440346981Scy struct ieee802_11_elems elems; 1441346981Scy int res; 1442346981Scy struct wpa_ie_data rsn; 1443346981Scy struct rsn_pmksa_cache_entry *pmksa = NULL; 1444346981Scy 1445346981Scy if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS) 1446346981Scy return; 1447346981Scy 1448346981Scy end = pos + len; 1449346981Scy 1450346981Scy wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields", 1451346981Scy pos, end - pos); 1452346981Scy 1453346981Scy /* TODO: FILS PK */ 1454346981Scy#ifdef CONFIG_FILS_SK_PFS 1455346981Scy if (auth_alg == WLAN_AUTH_FILS_SK_PFS) { 1456346981Scy u16 group; 1457346981Scy struct wpabuf *pub; 1458346981Scy size_t elem_len; 1459346981Scy 1460346981Scy /* Using FILS PFS */ 1461346981Scy 1462346981Scy /* Finite Cyclic Group */ 1463346981Scy if (end - pos < 2) { 1464346981Scy wpa_printf(MSG_DEBUG, 1465346981Scy "FILS: No room for Finite Cyclic Group"); 1466346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1467346981Scy goto fail; 1468346981Scy } 1469346981Scy group = WPA_GET_LE16(pos); 1470346981Scy pos += 2; 1471346981Scy if (group != hapd->conf->fils_dh_group) { 1472346981Scy wpa_printf(MSG_DEBUG, 1473346981Scy "FILS: Unsupported Finite Cyclic Group: %u (expected %u)", 1474346981Scy group, hapd->conf->fils_dh_group); 1475346981Scy resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 1476346981Scy goto fail; 1477346981Scy } 1478346981Scy 1479346981Scy crypto_ecdh_deinit(sta->fils_ecdh); 1480346981Scy sta->fils_ecdh = crypto_ecdh_init(group); 1481346981Scy if (!sta->fils_ecdh) { 1482346981Scy wpa_printf(MSG_INFO, 1483346981Scy "FILS: Could not initialize ECDH with group %d", 1484346981Scy group); 1485346981Scy resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 1486346981Scy goto fail; 1487346981Scy } 1488346981Scy 1489346981Scy pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1); 1490346981Scy if (!pub) { 1491346981Scy wpa_printf(MSG_DEBUG, 1492346981Scy "FILS: Failed to derive ECDH public key"); 1493346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1494346981Scy goto fail; 1495346981Scy } 1496346981Scy elem_len = wpabuf_len(pub); 1497346981Scy wpabuf_free(pub); 1498346981Scy 1499346981Scy /* Element */ 1500346981Scy if ((size_t) (end - pos) < elem_len) { 1501346981Scy wpa_printf(MSG_DEBUG, "FILS: No room for Element"); 1502346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1503346981Scy goto fail; 1504346981Scy } 1505346981Scy 1506346981Scy wpabuf_free(sta->fils_g_sta); 1507346981Scy sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len); 1508346981Scy wpabuf_clear_free(sta->fils_dh_ss); 1509346981Scy sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1, 1510346981Scy pos, elem_len); 1511346981Scy if (!sta->fils_dh_ss) { 1512346981Scy wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed"); 1513346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1514346981Scy goto fail; 1515346981Scy } 1516346981Scy wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss); 1517346981Scy pos += elem_len; 1518346981Scy } else { 1519346981Scy crypto_ecdh_deinit(sta->fils_ecdh); 1520346981Scy sta->fils_ecdh = NULL; 1521346981Scy wpabuf_clear_free(sta->fils_dh_ss); 1522346981Scy sta->fils_dh_ss = NULL; 1523346981Scy } 1524346981Scy#endif /* CONFIG_FILS_SK_PFS */ 1525346981Scy 1526346981Scy wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos); 1527346981Scy if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) { 1528346981Scy wpa_printf(MSG_DEBUG, "FILS: Could not parse elements"); 1529346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1530346981Scy goto fail; 1531346981Scy } 1532346981Scy 1533346981Scy /* RSNE */ 1534346981Scy wpa_hexdump(MSG_DEBUG, "FILS: RSN element", 1535346981Scy elems.rsn_ie, elems.rsn_ie_len); 1536346981Scy if (!elems.rsn_ie || 1537346981Scy wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2, 1538346981Scy &rsn) < 0) { 1539346981Scy wpa_printf(MSG_DEBUG, "FILS: No valid RSN element"); 1540346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1541346981Scy goto fail; 1542346981Scy } 1543346981Scy 1544346981Scy if (!sta->wpa_sm) 1545346981Scy sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, 1546346981Scy NULL); 1547346981Scy if (!sta->wpa_sm) { 1548346981Scy wpa_printf(MSG_DEBUG, 1549346981Scy "FILS: Failed to initialize RSN state machine"); 1550346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1551346981Scy goto fail; 1552346981Scy } 1553346981Scy 1554346981Scy res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 1555346981Scy hapd->iface->freq, 1556346981Scy elems.rsn_ie - 2, elems.rsn_ie_len + 2, 1557346981Scy elems.mdie, elems.mdie_len, NULL, 0); 1558346981Scy resp = wpa_res_to_status_code(res); 1559346981Scy if (resp != WLAN_STATUS_SUCCESS) 1560346981Scy goto fail; 1561346981Scy 1562346981Scy if (!elems.fils_nonce) { 1563346981Scy wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field"); 1564346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1565346981Scy goto fail; 1566346981Scy } 1567346981Scy wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce, 1568346981Scy FILS_NONCE_LEN); 1569346981Scy os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN); 1570346981Scy 1571346981Scy /* PMKID List */ 1572346981Scy if (rsn.pmkid && rsn.num_pmkid > 0) { 1573346981Scy u8 num; 1574346981Scy const u8 *pmkid; 1575346981Scy 1576346981Scy wpa_hexdump(MSG_DEBUG, "FILS: PMKID List", 1577346981Scy rsn.pmkid, rsn.num_pmkid * PMKID_LEN); 1578346981Scy 1579346981Scy pmkid = rsn.pmkid; 1580346981Scy num = rsn.num_pmkid; 1581346981Scy while (num) { 1582346981Scy wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN); 1583346981Scy pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, 1584346981Scy pmkid); 1585346981Scy if (pmksa) 1586346981Scy break; 1587346981Scy pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth, 1588346981Scy sta->addr, 1589346981Scy pmkid); 1590346981Scy if (pmksa) 1591346981Scy break; 1592346981Scy pmkid += PMKID_LEN; 1593346981Scy num--; 1594346981Scy } 1595346981Scy } 1596346981Scy if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) { 1597346981Scy wpa_printf(MSG_DEBUG, 1598346981Scy "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore", 1599346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp); 1600346981Scy pmksa = NULL; 1601346981Scy } 1602346981Scy if (pmksa) 1603346981Scy wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry"); 1604346981Scy 1605346981Scy /* FILS Session */ 1606346981Scy if (!elems.fils_session) { 1607346981Scy wpa_printf(MSG_DEBUG, "FILS: No FILS Session element"); 1608346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1609346981Scy goto fail; 1610346981Scy } 1611346981Scy wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session, 1612346981Scy FILS_SESSION_LEN); 1613346981Scy os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN); 1614346981Scy 1615346981Scy /* FILS Wrapped Data */ 1616346981Scy if (elems.fils_wrapped_data) { 1617346981Scy wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data", 1618346981Scy elems.fils_wrapped_data, 1619346981Scy elems.fils_wrapped_data_len); 1620346981Scy if (!pmksa) { 1621346981Scy#ifndef CONFIG_NO_RADIUS 1622346981Scy if (!sta->eapol_sm) { 1623346981Scy sta->eapol_sm = 1624346981Scy ieee802_1x_alloc_eapol_sm(hapd, sta); 1625346981Scy } 1626346981Scy wpa_printf(MSG_DEBUG, 1627346981Scy "FILS: Forward EAP-Initiate/Re-auth to authentication server"); 1628346981Scy ieee802_1x_encapsulate_radius( 1629346981Scy hapd, sta, elems.fils_wrapped_data, 1630346981Scy elems.fils_wrapped_data_len); 1631346981Scy sta->fils_pending_cb = cb; 1632346981Scy wpa_printf(MSG_DEBUG, 1633346981Scy "FILS: Will send Authentication frame once the response from authentication server is available"); 1634346981Scy sta->flags |= WLAN_STA_PENDING_FILS_ERP; 1635346981Scy /* Calculate pending PMKID here so that we do not need 1636346981Scy * to maintain a copy of the EAP-Initiate/Reauth 1637346981Scy * message. */ 1638346981Scy if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm), 1639346981Scy elems.fils_wrapped_data, 1640346981Scy elems.fils_wrapped_data_len, 1641346981Scy sta->fils_erp_pmkid) == 0) 1642346981Scy sta->fils_erp_pmkid_set = 1; 1643346981Scy return; 1644346981Scy#else /* CONFIG_NO_RADIUS */ 1645346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1646346981Scy goto fail; 1647346981Scy#endif /* CONFIG_NO_RADIUS */ 1648346981Scy } 1649346981Scy } 1650346981Scy 1651346981Scyfail: 1652346981Scy if (cb) { 1653346981Scy struct wpabuf *data; 1654346981Scy int pub = 0; 1655346981Scy 1656346981Scy data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL, 1657346981Scy NULL, 0, &pub); 1658346981Scy if (!data) { 1659346981Scy wpa_printf(MSG_DEBUG, 1660346981Scy "%s: prepare_auth_resp_fils() returned failure", 1661346981Scy __func__); 1662346981Scy } 1663346981Scy 1664346981Scy cb(hapd, sta, resp, data, pub); 1665346981Scy } 1666346981Scy} 1667346981Scy 1668346981Scy 1669346981Scystatic struct wpabuf * 1670346981Scyprepare_auth_resp_fils(struct hostapd_data *hapd, 1671346981Scy struct sta_info *sta, u16 *resp, 1672346981Scy struct rsn_pmksa_cache_entry *pmksa, 1673346981Scy struct wpabuf *erp_resp, 1674346981Scy const u8 *msk, size_t msk_len, 1675346981Scy int *is_pub) 1676346981Scy{ 1677346981Scy u8 fils_nonce[FILS_NONCE_LEN]; 1678346981Scy size_t ielen; 1679346981Scy struct wpabuf *data = NULL; 1680346981Scy const u8 *ie; 1681346981Scy u8 *ie_buf = NULL; 1682346981Scy const u8 *pmk = NULL; 1683346981Scy size_t pmk_len = 0; 1684346981Scy u8 pmk_buf[PMK_LEN_MAX]; 1685346981Scy struct wpabuf *pub = NULL; 1686346981Scy 1687346981Scy if (*resp != WLAN_STATUS_SUCCESS) 1688346981Scy goto fail; 1689346981Scy 1690346981Scy ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); 1691346981Scy if (!ie) { 1692346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1693346981Scy goto fail; 1694346981Scy } 1695346981Scy 1696346981Scy if (pmksa) { 1697346981Scy /* Add PMKID of the selected PMKSA into RSNE */ 1698346981Scy ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN); 1699346981Scy if (!ie_buf) { 1700346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1701346981Scy goto fail; 1702346981Scy } 1703346981Scy 1704346981Scy os_memcpy(ie_buf, ie, ielen); 1705346981Scy if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) { 1706346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1707346981Scy goto fail; 1708346981Scy } 1709346981Scy ie = ie_buf; 1710346981Scy } 1711346981Scy 1712346981Scy if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) { 1713346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1714346981Scy goto fail; 1715346981Scy } 1716346981Scy wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce", 1717346981Scy fils_nonce, FILS_NONCE_LEN); 1718346981Scy 1719346981Scy#ifdef CONFIG_FILS_SK_PFS 1720346981Scy if (sta->fils_dh_ss && sta->fils_ecdh) { 1721346981Scy pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1); 1722346981Scy if (!pub) { 1723346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1724346981Scy goto fail; 1725346981Scy } 1726346981Scy } 1727346981Scy#endif /* CONFIG_FILS_SK_PFS */ 1728346981Scy 1729346981Scy data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0)); 1730346981Scy if (!data) { 1731346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1732346981Scy goto fail; 1733346981Scy } 1734346981Scy 1735346981Scy /* TODO: FILS PK */ 1736346981Scy#ifdef CONFIG_FILS_SK_PFS 1737346981Scy if (pub) { 1738346981Scy /* Finite Cyclic Group */ 1739346981Scy wpabuf_put_le16(data, hapd->conf->fils_dh_group); 1740346981Scy 1741346981Scy /* Element */ 1742346981Scy wpabuf_put_buf(data, pub); 1743346981Scy } 1744346981Scy#endif /* CONFIG_FILS_SK_PFS */ 1745346981Scy 1746346981Scy /* RSNE */ 1747346981Scy wpabuf_put_data(data, ie, ielen); 1748346981Scy 1749346981Scy /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */ 1750346981Scy 1751346981Scy#ifdef CONFIG_IEEE80211R_AP 1752346981Scy if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) { 1753346981Scy /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */ 1754346981Scy int res; 1755346981Scy int use_sha384 = wpa_key_mgmt_sha384( 1756346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm)); 1757346981Scy 1758346981Scy res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384, 1759346981Scy wpabuf_put(data, 0), 1760346981Scy wpabuf_tailroom(data)); 1761346981Scy if (res < 0) { 1762346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1763346981Scy goto fail; 1764346981Scy } 1765346981Scy wpabuf_put(data, res); 1766346981Scy } 1767346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1768346981Scy 1769346981Scy /* FILS Nonce */ 1770346981Scy wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ 1771346981Scy wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */ 1772346981Scy /* Element ID Extension */ 1773346981Scy wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE); 1774346981Scy wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN); 1775346981Scy 1776346981Scy /* FILS Session */ 1777346981Scy wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ 1778346981Scy wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */ 1779346981Scy /* Element ID Extension */ 1780346981Scy wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION); 1781346981Scy wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN); 1782346981Scy 1783346981Scy /* FILS Wrapped Data */ 1784346981Scy if (!pmksa && erp_resp) { 1785346981Scy wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ 1786346981Scy wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */ 1787346981Scy /* Element ID Extension */ 1788346981Scy wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA); 1789346981Scy wpabuf_put_buf(data, erp_resp); 1790346981Scy 1791346981Scy if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm), 1792346981Scy msk, msk_len, sta->fils_snonce, fils_nonce, 1793346981Scy sta->fils_dh_ss ? 1794346981Scy wpabuf_head(sta->fils_dh_ss) : NULL, 1795346981Scy sta->fils_dh_ss ? 1796346981Scy wpabuf_len(sta->fils_dh_ss) : 0, 1797346981Scy pmk_buf, &pmk_len)) { 1798346981Scy wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK"); 1799346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1800346981Scy wpabuf_free(data); 1801346981Scy data = NULL; 1802346981Scy goto fail; 1803346981Scy } 1804346981Scy pmk = pmk_buf; 1805346981Scy 1806346981Scy /* Don't use DHss in PTK derivation if PMKSA caching is not 1807346981Scy * used. */ 1808346981Scy wpabuf_clear_free(sta->fils_dh_ss); 1809346981Scy sta->fils_dh_ss = NULL; 1810346981Scy 1811346981Scy if (sta->fils_erp_pmkid_set) { 1812346981Scy /* TODO: get PMKLifetime from WPA parameters */ 1813346981Scy unsigned int dot11RSNAConfigPMKLifetime = 43200; 1814346981Scy int session_timeout; 1815346981Scy 1816346981Scy session_timeout = dot11RSNAConfigPMKLifetime; 1817346981Scy if (sta->session_timeout_set) { 1818346981Scy struct os_reltime now, diff; 1819346981Scy 1820346981Scy os_get_reltime(&now); 1821346981Scy os_reltime_sub(&sta->session_timeout, &now, 1822346981Scy &diff); 1823346981Scy session_timeout = diff.sec; 1824346981Scy } 1825346981Scy 1826346981Scy sta->fils_erp_pmkid_set = 0; 1827346981Scy wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len, 1828346981Scy sta->fils_erp_pmkid); 1829346981Scy if (!hapd->conf->disable_pmksa_caching && 1830346981Scy wpa_auth_pmksa_add2( 1831346981Scy hapd->wpa_auth, sta->addr, 1832346981Scy pmk, pmk_len, 1833346981Scy sta->fils_erp_pmkid, 1834346981Scy session_timeout, 1835346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) { 1836346981Scy wpa_printf(MSG_ERROR, 1837346981Scy "FILS: Failed to add PMKSA cache entry based on ERP"); 1838346981Scy } 1839346981Scy } 1840346981Scy } else if (pmksa) { 1841346981Scy pmk = pmksa->pmk; 1842346981Scy pmk_len = pmksa->pmk_len; 1843346981Scy } 1844346981Scy 1845346981Scy if (!pmk) { 1846346981Scy wpa_printf(MSG_DEBUG, "FILS: No PMK available"); 1847346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1848346981Scy wpabuf_free(data); 1849346981Scy data = NULL; 1850346981Scy goto fail; 1851346981Scy } 1852346981Scy 1853346981Scy if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len, 1854346981Scy sta->fils_snonce, fils_nonce, 1855346981Scy sta->fils_dh_ss ? 1856346981Scy wpabuf_head(sta->fils_dh_ss) : NULL, 1857346981Scy sta->fils_dh_ss ? 1858346981Scy wpabuf_len(sta->fils_dh_ss) : 0, 1859346981Scy sta->fils_g_sta, pub) < 0) { 1860346981Scy *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1861346981Scy wpabuf_free(data); 1862346981Scy data = NULL; 1863346981Scy goto fail; 1864346981Scy } 1865346981Scy 1866346981Scyfail: 1867346981Scy if (is_pub) 1868346981Scy *is_pub = pub != NULL; 1869346981Scy os_free(ie_buf); 1870346981Scy wpabuf_free(pub); 1871346981Scy wpabuf_clear_free(sta->fils_dh_ss); 1872346981Scy sta->fils_dh_ss = NULL; 1873346981Scy#ifdef CONFIG_FILS_SK_PFS 1874346981Scy crypto_ecdh_deinit(sta->fils_ecdh); 1875346981Scy sta->fils_ecdh = NULL; 1876346981Scy#endif /* CONFIG_FILS_SK_PFS */ 1877346981Scy return data; 1878346981Scy} 1879346981Scy 1880346981Scy 1881346981Scystatic void handle_auth_fils_finish(struct hostapd_data *hapd, 1882346981Scy struct sta_info *sta, u16 resp, 1883346981Scy struct wpabuf *data, int pub) 1884346981Scy{ 1885346981Scy u16 auth_alg; 1886346981Scy 1887346981Scy auth_alg = (pub || 1888346981Scy resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ? 1889346981Scy WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK; 1890346981Scy send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp, 1891346981Scy data ? wpabuf_head(data) : (u8 *) "", 1892346981Scy data ? wpabuf_len(data) : 0, "auth-fils-finish"); 1893346981Scy wpabuf_free(data); 1894346981Scy 1895346981Scy if (resp == WLAN_STATUS_SUCCESS) { 1896346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1897346981Scy HOSTAPD_LEVEL_DEBUG, 1898346981Scy "authentication OK (FILS)"); 1899346981Scy sta->flags |= WLAN_STA_AUTH; 1900346981Scy wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 1901346981Scy sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK; 1902346981Scy mlme_authenticate_indication(hapd, sta); 1903346981Scy } 1904346981Scy} 1905346981Scy 1906346981Scy 1907346981Scyvoid ieee802_11_finish_fils_auth(struct hostapd_data *hapd, 1908346981Scy struct sta_info *sta, int success, 1909346981Scy struct wpabuf *erp_resp, 1910346981Scy const u8 *msk, size_t msk_len) 1911346981Scy{ 1912346981Scy struct wpabuf *data; 1913346981Scy int pub = 0; 1914346981Scy u16 resp; 1915346981Scy 1916346981Scy sta->flags &= ~WLAN_STA_PENDING_FILS_ERP; 1917346981Scy 1918346981Scy if (!sta->fils_pending_cb) 1919346981Scy return; 1920346981Scy resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE; 1921346981Scy data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp, 1922346981Scy msk, msk_len, &pub); 1923346981Scy if (!data) { 1924346981Scy wpa_printf(MSG_DEBUG, 1925346981Scy "%s: prepare_auth_resp_fils() returned failure", 1926346981Scy __func__); 1927346981Scy } 1928346981Scy sta->fils_pending_cb(hapd, sta, resp, data, pub); 1929346981Scy} 1930346981Scy 1931346981Scy#endif /* CONFIG_FILS */ 1932346981Scy 1933346981Scy 1934346981Scyint 1935346981Scyieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, 1936346981Scy const u8 *msg, size_t len, u32 *session_timeout, 1937346981Scy u32 *acct_interim_interval, 1938346981Scy struct vlan_description *vlan_id, 1939346981Scy struct hostapd_sta_wpa_psk_short **psk, 1940346981Scy char **identity, char **radius_cui, int is_probe_req) 1941346981Scy{ 1942346981Scy int res; 1943346981Scy 1944346981Scy os_memset(vlan_id, 0, sizeof(*vlan_id)); 1945346981Scy res = hostapd_allowed_address(hapd, addr, msg, len, 1946346981Scy session_timeout, acct_interim_interval, 1947346981Scy vlan_id, psk, identity, radius_cui, 1948346981Scy is_probe_req); 1949346981Scy 1950346981Scy if (res == HOSTAPD_ACL_REJECT) { 1951346981Scy if (!is_probe_req) 1952346981Scy wpa_printf(MSG_DEBUG, 1953346981Scy "Station " MACSTR 1954346981Scy " not allowed to authenticate", 1955346981Scy MAC2STR(addr)); 1956346981Scy return HOSTAPD_ACL_REJECT; 1957346981Scy } 1958346981Scy 1959346981Scy if (res == HOSTAPD_ACL_PENDING) { 1960346981Scy wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR 1961346981Scy " waiting for an external authentication", 1962346981Scy MAC2STR(addr)); 1963346981Scy /* Authentication code will re-send the authentication frame 1964346981Scy * after it has received (and cached) information from the 1965346981Scy * external source. */ 1966346981Scy return HOSTAPD_ACL_PENDING; 1967346981Scy } 1968346981Scy 1969346981Scy return res; 1970346981Scy} 1971346981Scy 1972346981Scy 1973346981Scystatic int 1974346981Scyieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, 1975346981Scy int res, u32 session_timeout, 1976346981Scy u32 acct_interim_interval, 1977346981Scy struct vlan_description *vlan_id, 1978346981Scy struct hostapd_sta_wpa_psk_short **psk, 1979346981Scy char **identity, char **radius_cui) 1980346981Scy{ 1981346981Scy if (vlan_id->notempty && 1982346981Scy !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) { 1983346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 1984346981Scy HOSTAPD_LEVEL_INFO, 1985346981Scy "Invalid VLAN %d%s received from RADIUS server", 1986346981Scy vlan_id->untagged, 1987346981Scy vlan_id->tagged[0] ? "+" : ""); 1988346981Scy return -1; 1989346981Scy } 1990346981Scy if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0) 1991346981Scy return -1; 1992346981Scy if (sta->vlan_id) 1993346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 1994346981Scy HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); 1995346981Scy 1996346981Scy hostapd_free_psk_list(sta->psk); 1997346981Scy if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { 1998346981Scy sta->psk = *psk; 1999346981Scy *psk = NULL; 2000346981Scy } else { 2001346981Scy sta->psk = NULL; 2002346981Scy } 2003346981Scy 2004346981Scy os_free(sta->identity); 2005346981Scy sta->identity = *identity; 2006346981Scy *identity = NULL; 2007346981Scy 2008346981Scy os_free(sta->radius_cui); 2009346981Scy sta->radius_cui = *radius_cui; 2010346981Scy *radius_cui = NULL; 2011346981Scy 2012346981Scy if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval) 2013346981Scy sta->acct_interim_interval = acct_interim_interval; 2014346981Scy if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) { 2015346981Scy sta->session_timeout_set = 1; 2016346981Scy os_get_reltime(&sta->session_timeout); 2017346981Scy sta->session_timeout.sec += session_timeout; 2018346981Scy ap_sta_session_timeout(hapd, sta, session_timeout); 2019346981Scy } else { 2020346981Scy sta->session_timeout_set = 0; 2021346981Scy ap_sta_no_session_timeout(hapd, sta); 2022346981Scy } 2023346981Scy 2024346981Scy return 0; 2025346981Scy} 2026346981Scy 2027346981Scy 2028214501Srpaulostatic void handle_auth(struct hostapd_data *hapd, 2029346981Scy const struct ieee80211_mgmt *mgmt, size_t len, 2030346981Scy int rssi, int from_queue) 2031214501Srpaulo{ 2032214501Srpaulo u16 auth_alg, auth_transaction, status_code; 2033214501Srpaulo u16 resp = WLAN_STATUS_SUCCESS; 2034214501Srpaulo struct sta_info *sta = NULL; 2035337817Scy int res, reply_res; 2036214501Srpaulo u16 fc; 2037214501Srpaulo const u8 *challenge = NULL; 2038214501Srpaulo u32 session_timeout, acct_interim_interval; 2039337817Scy struct vlan_description vlan_id; 2040252726Srpaulo struct hostapd_sta_wpa_psk_short *psk = NULL; 2041214501Srpaulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 2042214501Srpaulo size_t resp_ies_len = 0; 2043252726Srpaulo char *identity = NULL; 2044252726Srpaulo char *radius_cui = NULL; 2045281806Srpaulo u16 seq_ctrl; 2046214501Srpaulo 2047214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { 2048281806Srpaulo wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", 2049281806Srpaulo (unsigned long) len); 2050214501Srpaulo return; 2051214501Srpaulo } 2052214501Srpaulo 2053281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 2054281806Srpaulo if (hapd->iconf->ignore_auth_probability > 0.0 && 2055281806Srpaulo drand48() < hapd->iconf->ignore_auth_probability) { 2056281806Srpaulo wpa_printf(MSG_INFO, 2057281806Srpaulo "TESTING: ignoring auth frame from " MACSTR, 2058281806Srpaulo MAC2STR(mgmt->sa)); 2059281806Srpaulo return; 2060281806Srpaulo } 2061281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 2062281806Srpaulo 2063214501Srpaulo auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 2064214501Srpaulo auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 2065214501Srpaulo status_code = le_to_host16(mgmt->u.auth.status_code); 2066214501Srpaulo fc = le_to_host16(mgmt->frame_control); 2067281806Srpaulo seq_ctrl = le_to_host16(mgmt->seq_ctrl); 2068214501Srpaulo 2069214501Srpaulo if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) + 2070214501Srpaulo 2 + WLAN_AUTH_CHALLENGE_LEN && 2071214501Srpaulo mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE && 2072214501Srpaulo mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN) 2073214501Srpaulo challenge = &mgmt->u.auth.variable[2]; 2074214501Srpaulo 2075214501Srpaulo wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d " 2076281806Srpaulo "auth_transaction=%d status_code=%d wep=%d%s " 2077346981Scy "seq_ctrl=0x%x%s%s", 2078214501Srpaulo MAC2STR(mgmt->sa), auth_alg, auth_transaction, 2079214501Srpaulo status_code, !!(fc & WLAN_FC_ISWEP), 2080281806Srpaulo challenge ? " challenge" : "", 2081346981Scy seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "", 2082346981Scy from_queue ? " (from queue)" : ""); 2083214501Srpaulo 2084289549Srpaulo#ifdef CONFIG_NO_RC4 2085289549Srpaulo if (auth_alg == WLAN_AUTH_SHARED_KEY) { 2086289549Srpaulo wpa_printf(MSG_INFO, 2087289549Srpaulo "Unsupported authentication algorithm (%d)", 2088289549Srpaulo auth_alg); 2089289549Srpaulo resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 2090289549Srpaulo goto fail; 2091289549Srpaulo } 2092289549Srpaulo#endif /* CONFIG_NO_RC4 */ 2093289549Srpaulo 2094214501Srpaulo if (hapd->tkip_countermeasures) { 2095346981Scy wpa_printf(MSG_DEBUG, 2096346981Scy "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication"); 2097346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2098214501Srpaulo goto fail; 2099214501Srpaulo } 2100214501Srpaulo 2101214501Srpaulo if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && 2102214501Srpaulo auth_alg == WLAN_AUTH_OPEN) || 2103346981Scy#ifdef CONFIG_IEEE80211R_AP 2104252726Srpaulo (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && 2105214501Srpaulo auth_alg == WLAN_AUTH_FT) || 2106346981Scy#endif /* CONFIG_IEEE80211R_AP */ 2107252726Srpaulo#ifdef CONFIG_SAE 2108252726Srpaulo (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && 2109252726Srpaulo auth_alg == WLAN_AUTH_SAE) || 2110252726Srpaulo#endif /* CONFIG_SAE */ 2111346981Scy#ifdef CONFIG_FILS 2112346981Scy (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) && 2113346981Scy auth_alg == WLAN_AUTH_FILS_SK) || 2114346981Scy (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) && 2115346981Scy hapd->conf->fils_dh_group && 2116346981Scy auth_alg == WLAN_AUTH_FILS_SK_PFS) || 2117346981Scy#endif /* CONFIG_FILS */ 2118214501Srpaulo ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && 2119214501Srpaulo auth_alg == WLAN_AUTH_SHARED_KEY))) { 2120281806Srpaulo wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)", 2121281806Srpaulo auth_alg); 2122214501Srpaulo resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 2123214501Srpaulo goto fail; 2124214501Srpaulo } 2125214501Srpaulo 2126252726Srpaulo if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE || 2127214501Srpaulo (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { 2128281806Srpaulo wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)", 2129281806Srpaulo auth_transaction); 2130214501Srpaulo resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; 2131214501Srpaulo goto fail; 2132214501Srpaulo } 2133214501Srpaulo 2134214501Srpaulo if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { 2135281806Srpaulo wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate", 2136281806Srpaulo MAC2STR(mgmt->sa)); 2137214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2138214501Srpaulo goto fail; 2139214501Srpaulo } 2140214501Srpaulo 2141289549Srpaulo if (hapd->conf->no_auth_if_seen_on) { 2142289549Srpaulo struct hostapd_data *other; 2143289549Srpaulo 2144289549Srpaulo other = sta_track_seen_on(hapd->iface, mgmt->sa, 2145289549Srpaulo hapd->conf->no_auth_if_seen_on); 2146289549Srpaulo if (other) { 2147289549Srpaulo u8 *pos; 2148289549Srpaulo u32 info; 2149289549Srpaulo u8 op_class, channel, phytype; 2150289549Srpaulo 2151289549Srpaulo wpa_printf(MSG_DEBUG, "%s: Reject authentication from " 2152289549Srpaulo MACSTR " since STA has been seen on %s", 2153289549Srpaulo hapd->conf->iface, MAC2STR(mgmt->sa), 2154289549Srpaulo hapd->conf->no_auth_if_seen_on); 2155289549Srpaulo 2156289549Srpaulo resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION; 2157289549Srpaulo pos = &resp_ies[0]; 2158289549Srpaulo *pos++ = WLAN_EID_NEIGHBOR_REPORT; 2159289549Srpaulo *pos++ = 13; 2160289549Srpaulo os_memcpy(pos, other->own_addr, ETH_ALEN); 2161289549Srpaulo pos += ETH_ALEN; 2162289549Srpaulo info = 0; /* TODO: BSSID Information */ 2163289549Srpaulo WPA_PUT_LE32(pos, info); 2164289549Srpaulo pos += 4; 2165289549Srpaulo if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD) 2166289549Srpaulo phytype = 8; /* dmg */ 2167289549Srpaulo else if (other->iconf->ieee80211ac) 2168289549Srpaulo phytype = 9; /* vht */ 2169289549Srpaulo else if (other->iconf->ieee80211n) 2170289549Srpaulo phytype = 7; /* ht */ 2171289549Srpaulo else if (other->iconf->hw_mode == 2172289549Srpaulo HOSTAPD_MODE_IEEE80211A) 2173289549Srpaulo phytype = 4; /* ofdm */ 2174289549Srpaulo else if (other->iconf->hw_mode == 2175289549Srpaulo HOSTAPD_MODE_IEEE80211G) 2176289549Srpaulo phytype = 6; /* erp */ 2177289549Srpaulo else 2178289549Srpaulo phytype = 5; /* hrdsss */ 2179289549Srpaulo if (ieee80211_freq_to_channel_ext( 2180289549Srpaulo hostapd_hw_get_freq(other, 2181289549Srpaulo other->iconf->channel), 2182289549Srpaulo other->iconf->secondary_channel, 2183289549Srpaulo other->iconf->ieee80211ac, 2184289549Srpaulo &op_class, &channel) == NUM_HOSTAPD_MODES) { 2185289549Srpaulo op_class = 0; 2186289549Srpaulo channel = other->iconf->channel; 2187289549Srpaulo } 2188289549Srpaulo *pos++ = op_class; 2189289549Srpaulo *pos++ = channel; 2190289549Srpaulo *pos++ = phytype; 2191289549Srpaulo resp_ies_len = pos - &resp_ies[0]; 2192289549Srpaulo goto fail; 2193289549Srpaulo } 2194289549Srpaulo } 2195289549Srpaulo 2196346981Scy res = ieee802_11_allowed_address( 2197346981Scy hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout, 2198346981Scy &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui, 2199346981Scy 0); 2200214501Srpaulo if (res == HOSTAPD_ACL_REJECT) { 2201346981Scy wpa_msg(hapd->msg_ctx, MSG_DEBUG, 2202346981Scy "Ignore Authentication frame from " MACSTR 2203346981Scy " due to ACL reject", MAC2STR(mgmt->sa)); 2204214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2205214501Srpaulo goto fail; 2206214501Srpaulo } 2207346981Scy if (res == HOSTAPD_ACL_PENDING) 2208214501Srpaulo return; 2209346981Scy 2210346981Scy#ifdef CONFIG_SAE 2211346981Scy if (auth_alg == WLAN_AUTH_SAE && !from_queue && 2212346981Scy (auth_transaction == 1 || 2213346981Scy (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) { 2214346981Scy /* Handle SAE Authentication commit message through a queue to 2215346981Scy * provide more control for postponing the needed heavy 2216346981Scy * processing under a possible DoS attack scenario. In addition, 2217346981Scy * queue SAE Authentication confirm message if there happens to 2218346981Scy * be a queued commit message from the same peer. This is needed 2219346981Scy * to avoid reordering Authentication frames within the same 2220346981Scy * SAE exchange. */ 2221346981Scy auth_sae_queue(hapd, mgmt, len, rssi); 2222346981Scy return; 2223214501Srpaulo } 2224346981Scy#endif /* CONFIG_SAE */ 2225214501Srpaulo 2226281806Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 2227281806Srpaulo if (sta) { 2228346981Scy sta->flags &= ~WLAN_STA_PENDING_FILS_ERP; 2229346981Scy sta->ft_over_ds = 0; 2230281806Srpaulo if ((fc & WLAN_FC_RETRY) && 2231281806Srpaulo sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ && 2232281806Srpaulo sta->last_seq_ctrl == seq_ctrl && 2233281806Srpaulo sta->last_subtype == WLAN_FC_STYPE_AUTH) { 2234281806Srpaulo hostapd_logger(hapd, sta->addr, 2235281806Srpaulo HOSTAPD_MODULE_IEEE80211, 2236281806Srpaulo HOSTAPD_LEVEL_DEBUG, 2237281806Srpaulo "Drop repeated authentication frame seq_ctrl=0x%x", 2238281806Srpaulo seq_ctrl); 2239281806Srpaulo return; 2240281806Srpaulo } 2241337817Scy#ifdef CONFIG_MESH 2242337817Scy if ((hapd->conf->mesh & MESH_ENABLED) && 2243337817Scy sta->plink_state == PLINK_BLOCKED) { 2244337817Scy wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR 2245337817Scy " is blocked - drop Authentication frame", 2246337817Scy MAC2STR(mgmt->sa)); 2247337817Scy return; 2248337817Scy } 2249337817Scy#endif /* CONFIG_MESH */ 2250281806Srpaulo } else { 2251281806Srpaulo#ifdef CONFIG_MESH 2252281806Srpaulo if (hapd->conf->mesh & MESH_ENABLED) { 2253281806Srpaulo /* if the mesh peer is not available, we don't do auth. 2254281806Srpaulo */ 2255281806Srpaulo wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR 2256337817Scy " not yet known - drop Authentication frame", 2257281806Srpaulo MAC2STR(mgmt->sa)); 2258281806Srpaulo /* 2259281806Srpaulo * Save a copy of the frame so that it can be processed 2260281806Srpaulo * if a new peer entry is added shortly after this. 2261281806Srpaulo */ 2262281806Srpaulo wpabuf_free(hapd->mesh_pending_auth); 2263281806Srpaulo hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len); 2264281806Srpaulo os_get_reltime(&hapd->mesh_pending_auth_time); 2265281806Srpaulo return; 2266281806Srpaulo } 2267281806Srpaulo#endif /* CONFIG_MESH */ 2268281806Srpaulo 2269281806Srpaulo sta = ap_sta_add(hapd, mgmt->sa); 2270281806Srpaulo if (!sta) { 2271346981Scy wpa_printf(MSG_DEBUG, "ap_sta_add() failed"); 2272281806Srpaulo resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 2273281806Srpaulo goto fail; 2274281806Srpaulo } 2275214501Srpaulo } 2276281806Srpaulo sta->last_seq_ctrl = seq_ctrl; 2277281806Srpaulo sta->last_subtype = WLAN_FC_STYPE_AUTH; 2278346981Scy#ifdef CONFIG_MBO 2279346981Scy sta->auth_rssi = rssi; 2280346981Scy#endif /* CONFIG_MBO */ 2281214501Srpaulo 2282346981Scy res = ieee802_11_set_radius_info( 2283346981Scy hapd, sta, res, session_timeout, acct_interim_interval, 2284346981Scy &vlan_id, &psk, &identity, &radius_cui); 2285346981Scy if (res) { 2286346981Scy wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed"); 2287337817Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2288337817Scy goto fail; 2289337817Scy } 2290214501Srpaulo 2291214501Srpaulo sta->flags &= ~WLAN_STA_PREAUTH; 2292214501Srpaulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 2293214501Srpaulo 2294337817Scy /* 2295337817Scy * If the driver supports full AP client state, add a station to the 2296337817Scy * driver before sending authentication reply to make sure the driver 2297337817Scy * has resources, and not to go through the entire authentication and 2298337817Scy * association handshake, and fail it at the end. 2299337817Scy * 2300337817Scy * If this is not the first transaction, in a multi-step authentication 2301337817Scy * algorithm, the station already exists in the driver 2302337817Scy * (sta->added_unassoc = 1) so skip it. 2303337817Scy * 2304337817Scy * In mesh mode, the station was already added to the driver when the 2305337817Scy * NEW_PEER_CANDIDATE event is received. 2306346981Scy * 2307346981Scy * If PMF was negotiated for the existing association, skip this to 2308346981Scy * avoid dropping the STA entry and the associated keys. This is needed 2309346981Scy * to allow the original connection work until the attempt can complete 2310346981Scy * (re)association, so that unprotected Authentication frame cannot be 2311346981Scy * used to bypass PMF protection. 2312337817Scy */ 2313337817Scy if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) && 2314346981Scy (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) && 2315337817Scy !(hapd->conf->mesh & MESH_ENABLED) && 2316337817Scy !(sta->added_unassoc)) { 2317337817Scy /* 2318337817Scy * If a station that is already associated to the AP, is trying 2319337817Scy * to authenticate again, remove the STA entry, in order to make 2320337817Scy * sure the STA PS state gets cleared and configuration gets 2321337817Scy * updated. To handle this, station's added_unassoc flag is 2322337817Scy * cleared once the station has completed association. 2323337817Scy */ 2324346981Scy ap_sta_set_authorized(hapd, sta, 0); 2325337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 2326337817Scy sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | 2327337817Scy WLAN_STA_AUTHORIZED); 2328337817Scy 2329351611Scy if (hostapd_sta_add(hapd, sta->addr, 0, 0, 2330351611Scy sta->supported_rates, 2331351611Scy sta->supported_rates_len, 2332351611Scy 0, NULL, NULL, NULL, 0, 2333351611Scy sta->flags, 0, 0, 0, 0)) { 2334337817Scy hostapd_logger(hapd, sta->addr, 2335337817Scy HOSTAPD_MODULE_IEEE80211, 2336337817Scy HOSTAPD_LEVEL_NOTICE, 2337337817Scy "Could not add STA to kernel driver"); 2338337817Scy resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 2339337817Scy goto fail; 2340337817Scy } 2341337817Scy 2342337817Scy sta->added_unassoc = 1; 2343337817Scy } 2344337817Scy 2345214501Srpaulo switch (auth_alg) { 2346214501Srpaulo case WLAN_AUTH_OPEN: 2347214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2348214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2349214501Srpaulo "authentication OK (open system)"); 2350214501Srpaulo sta->flags |= WLAN_STA_AUTH; 2351214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 2352214501Srpaulo sta->auth_alg = WLAN_AUTH_OPEN; 2353214501Srpaulo mlme_authenticate_indication(hapd, sta); 2354214501Srpaulo break; 2355289549Srpaulo#ifndef CONFIG_NO_RC4 2356214501Srpaulo case WLAN_AUTH_SHARED_KEY: 2357214501Srpaulo resp = auth_shared_key(hapd, sta, auth_transaction, challenge, 2358214501Srpaulo fc & WLAN_FC_ISWEP); 2359346981Scy if (resp != 0) 2360346981Scy wpa_printf(MSG_DEBUG, 2361346981Scy "auth_shared_key() failed: status=%d", resp); 2362214501Srpaulo sta->auth_alg = WLAN_AUTH_SHARED_KEY; 2363214501Srpaulo mlme_authenticate_indication(hapd, sta); 2364214501Srpaulo if (sta->challenge && auth_transaction == 1) { 2365214501Srpaulo resp_ies[0] = WLAN_EID_CHALLENGE; 2366214501Srpaulo resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN; 2367214501Srpaulo os_memcpy(resp_ies + 2, sta->challenge, 2368214501Srpaulo WLAN_AUTH_CHALLENGE_LEN); 2369214501Srpaulo resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN; 2370214501Srpaulo } 2371214501Srpaulo break; 2372289549Srpaulo#endif /* CONFIG_NO_RC4 */ 2373346981Scy#ifdef CONFIG_IEEE80211R_AP 2374214501Srpaulo case WLAN_AUTH_FT: 2375214501Srpaulo sta->auth_alg = WLAN_AUTH_FT; 2376214501Srpaulo if (sta->wpa_sm == NULL) 2377214501Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 2378281806Srpaulo sta->addr, NULL); 2379214501Srpaulo if (sta->wpa_sm == NULL) { 2380214501Srpaulo wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " 2381214501Srpaulo "state machine"); 2382214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2383214501Srpaulo goto fail; 2384214501Srpaulo } 2385214501Srpaulo wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid, 2386214501Srpaulo auth_transaction, mgmt->u.auth.variable, 2387214501Srpaulo len - IEEE80211_HDRLEN - 2388214501Srpaulo sizeof(mgmt->u.auth), 2389214501Srpaulo handle_auth_ft_finish, hapd); 2390214501Srpaulo /* handle_auth_ft_finish() callback will complete auth. */ 2391214501Srpaulo return; 2392346981Scy#endif /* CONFIG_IEEE80211R_AP */ 2393252726Srpaulo#ifdef CONFIG_SAE 2394252726Srpaulo case WLAN_AUTH_SAE: 2395281806Srpaulo#ifdef CONFIG_MESH 2396281806Srpaulo if (status_code == WLAN_STATUS_SUCCESS && 2397281806Srpaulo hapd->conf->mesh & MESH_ENABLED) { 2398281806Srpaulo if (sta->wpa_sm == NULL) 2399281806Srpaulo sta->wpa_sm = 2400281806Srpaulo wpa_auth_sta_init(hapd->wpa_auth, 2401281806Srpaulo sta->addr, NULL); 2402281806Srpaulo if (sta->wpa_sm == NULL) { 2403281806Srpaulo wpa_printf(MSG_DEBUG, 2404281806Srpaulo "SAE: Failed to initialize WPA state machine"); 2405281806Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2406281806Srpaulo goto fail; 2407281806Srpaulo } 2408281806Srpaulo } 2409281806Srpaulo#endif /* CONFIG_MESH */ 2410281806Srpaulo handle_auth_sae(hapd, sta, mgmt, len, auth_transaction, 2411281806Srpaulo status_code); 2412252726Srpaulo return; 2413252726Srpaulo#endif /* CONFIG_SAE */ 2414346981Scy#ifdef CONFIG_FILS 2415346981Scy case WLAN_AUTH_FILS_SK: 2416346981Scy case WLAN_AUTH_FILS_SK_PFS: 2417346981Scy handle_auth_fils(hapd, sta, mgmt->u.auth.variable, 2418346981Scy len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth), 2419346981Scy auth_alg, auth_transaction, status_code, 2420346981Scy handle_auth_fils_finish); 2421346981Scy return; 2422346981Scy#endif /* CONFIG_FILS */ 2423214501Srpaulo } 2424214501Srpaulo 2425214501Srpaulo fail: 2426252726Srpaulo os_free(identity); 2427252726Srpaulo os_free(radius_cui); 2428252726Srpaulo hostapd_free_psk_list(psk); 2429252726Srpaulo 2430337817Scy reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, 2431337817Scy auth_transaction + 1, resp, resp_ies, 2432346981Scy resp_ies_len, "handle-auth"); 2433337817Scy 2434337817Scy if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS || 2435337817Scy reply_res != WLAN_STATUS_SUCCESS)) { 2436337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 2437337817Scy sta->added_unassoc = 0; 2438337817Scy } 2439214501Srpaulo} 2440214501Srpaulo 2441214501Srpaulo 2442337817Scyint hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) 2443214501Srpaulo{ 2444214501Srpaulo int i, j = 32, aid; 2445214501Srpaulo 2446214501Srpaulo /* get a unique AID */ 2447214501Srpaulo if (sta->aid > 0) { 2448214501Srpaulo wpa_printf(MSG_DEBUG, " old AID %d", sta->aid); 2449214501Srpaulo return 0; 2450214501Srpaulo } 2451214501Srpaulo 2452337817Scy if (TEST_FAIL()) 2453337817Scy return -1; 2454337817Scy 2455214501Srpaulo for (i = 0; i < AID_WORDS; i++) { 2456214501Srpaulo if (hapd->sta_aid[i] == (u32) -1) 2457214501Srpaulo continue; 2458214501Srpaulo for (j = 0; j < 32; j++) { 2459214501Srpaulo if (!(hapd->sta_aid[i] & BIT(j))) 2460214501Srpaulo break; 2461214501Srpaulo } 2462214501Srpaulo if (j < 32) 2463214501Srpaulo break; 2464214501Srpaulo } 2465214501Srpaulo if (j == 32) 2466214501Srpaulo return -1; 2467214501Srpaulo aid = i * 32 + j + 1; 2468214501Srpaulo if (aid > 2007) 2469214501Srpaulo return -1; 2470214501Srpaulo 2471214501Srpaulo sta->aid = aid; 2472214501Srpaulo hapd->sta_aid[i] |= BIT(j); 2473214501Srpaulo wpa_printf(MSG_DEBUG, " new AID %d", sta->aid); 2474214501Srpaulo return 0; 2475214501Srpaulo} 2476214501Srpaulo 2477214501Srpaulo 2478214501Srpaulostatic u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta, 2479214501Srpaulo const u8 *ssid_ie, size_t ssid_ie_len) 2480214501Srpaulo{ 2481214501Srpaulo if (ssid_ie == NULL) 2482214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 2483214501Srpaulo 2484214501Srpaulo if (ssid_ie_len != hapd->conf->ssid.ssid_len || 2485214501Srpaulo os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) { 2486214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2487214501Srpaulo HOSTAPD_LEVEL_INFO, 2488214501Srpaulo "Station tried to associate with unknown SSID " 2489281806Srpaulo "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len)); 2490214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 2491214501Srpaulo } 2492214501Srpaulo 2493214501Srpaulo return WLAN_STATUS_SUCCESS; 2494214501Srpaulo} 2495214501Srpaulo 2496214501Srpaulo 2497214501Srpaulostatic u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, 2498214501Srpaulo const u8 *wmm_ie, size_t wmm_ie_len) 2499214501Srpaulo{ 2500214501Srpaulo sta->flags &= ~WLAN_STA_WMM; 2501252726Srpaulo sta->qosinfo = 0; 2502214501Srpaulo if (wmm_ie && hapd->conf->wmm_enabled) { 2503252726Srpaulo struct wmm_information_element *wmm; 2504252726Srpaulo 2505252726Srpaulo if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) { 2506214501Srpaulo hostapd_logger(hapd, sta->addr, 2507214501Srpaulo HOSTAPD_MODULE_WPA, 2508214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2509214501Srpaulo "invalid WMM element in association " 2510214501Srpaulo "request"); 2511252726Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 2512252726Srpaulo } 2513252726Srpaulo 2514252726Srpaulo sta->flags |= WLAN_STA_WMM; 2515252726Srpaulo wmm = (struct wmm_information_element *) wmm_ie; 2516252726Srpaulo sta->qosinfo = wmm->qos_info; 2517214501Srpaulo } 2518214501Srpaulo return WLAN_STATUS_SUCCESS; 2519214501Srpaulo} 2520214501Srpaulo 2521346981Scystatic u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta, 2522346981Scy const u8 *multi_ap_ie, size_t multi_ap_len) 2523346981Scy{ 2524346981Scy u8 multi_ap_value = 0; 2525214501Srpaulo 2526346981Scy sta->flags &= ~WLAN_STA_MULTI_AP; 2527346981Scy 2528346981Scy if (!hapd->conf->multi_ap) 2529346981Scy return WLAN_STATUS_SUCCESS; 2530346981Scy 2531346981Scy if (multi_ap_ie) { 2532346981Scy const u8 *multi_ap_subelem; 2533346981Scy 2534346981Scy multi_ap_subelem = get_ie(multi_ap_ie + 4, 2535346981Scy multi_ap_len - 4, 2536346981Scy MULTI_AP_SUB_ELEM_TYPE); 2537346981Scy if (multi_ap_subelem && multi_ap_subelem[1] == 1) { 2538346981Scy multi_ap_value = multi_ap_subelem[2]; 2539346981Scy } else { 2540346981Scy hostapd_logger(hapd, sta->addr, 2541346981Scy HOSTAPD_MODULE_IEEE80211, 2542346981Scy HOSTAPD_LEVEL_INFO, 2543346981Scy "Multi-AP IE has missing or invalid Multi-AP subelement"); 2544346981Scy return WLAN_STATUS_INVALID_IE; 2545346981Scy } 2546346981Scy } 2547346981Scy 2548346981Scy if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA) 2549346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2550346981Scy HOSTAPD_LEVEL_INFO, 2551346981Scy "Multi-AP IE with unexpected value 0x%02x", 2552346981Scy multi_ap_value); 2553346981Scy 2554346981Scy if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) { 2555346981Scy if (hapd->conf->multi_ap & FRONTHAUL_BSS) 2556346981Scy return WLAN_STATUS_SUCCESS; 2557346981Scy 2558346981Scy hostapd_logger(hapd, sta->addr, 2559346981Scy HOSTAPD_MODULE_IEEE80211, 2560346981Scy HOSTAPD_LEVEL_INFO, 2561346981Scy "Non-Multi-AP STA tries to associate with backhaul-only BSS"); 2562346981Scy return WLAN_STATUS_ASSOC_DENIED_UNSPEC; 2563346981Scy } 2564346981Scy 2565346981Scy if (!(hapd->conf->multi_ap & BACKHAUL_BSS)) 2566346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2567346981Scy HOSTAPD_LEVEL_DEBUG, 2568346981Scy "Backhaul STA tries to associate with fronthaul-only BSS"); 2569346981Scy 2570346981Scy sta->flags |= WLAN_STA_MULTI_AP; 2571346981Scy return WLAN_STATUS_SUCCESS; 2572346981Scy} 2573346981Scy 2574346981Scy 2575214501Srpaulostatic u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, 2576214501Srpaulo struct ieee802_11_elems *elems) 2577214501Srpaulo{ 2578346981Scy /* Supported rates not used in IEEE 802.11ad/DMG */ 2579346981Scy if (hapd->iface->current_mode && 2580346981Scy hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) 2581346981Scy return WLAN_STATUS_SUCCESS; 2582346981Scy 2583214501Srpaulo if (!elems->supp_rates) { 2584214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2585214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2586214501Srpaulo "No supported rates element in AssocReq"); 2587214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 2588214501Srpaulo } 2589214501Srpaulo 2590252726Srpaulo if (elems->supp_rates_len + elems->ext_supp_rates_len > 2591252726Srpaulo sizeof(sta->supported_rates)) { 2592214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2593214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2594252726Srpaulo "Invalid supported rates element length %d+%d", 2595252726Srpaulo elems->supp_rates_len, 2596252726Srpaulo elems->ext_supp_rates_len); 2597214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 2598214501Srpaulo } 2599214501Srpaulo 2600252726Srpaulo sta->supported_rates_len = merge_byte_arrays( 2601252726Srpaulo sta->supported_rates, sizeof(sta->supported_rates), 2602252726Srpaulo elems->supp_rates, elems->supp_rates_len, 2603252726Srpaulo elems->ext_supp_rates, elems->ext_supp_rates_len); 2604214501Srpaulo 2605214501Srpaulo return WLAN_STATUS_SUCCESS; 2606214501Srpaulo} 2607214501Srpaulo 2608214501Srpaulo 2609281806Srpaulostatic u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, 2610281806Srpaulo const u8 *ext_capab_ie, size_t ext_capab_ie_len) 2611281806Srpaulo{ 2612281806Srpaulo#ifdef CONFIG_INTERWORKING 2613281806Srpaulo /* check for QoS Map support */ 2614281806Srpaulo if (ext_capab_ie_len >= 5) { 2615281806Srpaulo if (ext_capab_ie[4] & 0x01) 2616281806Srpaulo sta->qos_map_enabled = 1; 2617281806Srpaulo } 2618281806Srpaulo#endif /* CONFIG_INTERWORKING */ 2619281806Srpaulo 2620346981Scy if (ext_capab_ie_len > 0) { 2621337817Scy sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); 2622346981Scy os_free(sta->ext_capability); 2623346981Scy sta->ext_capability = os_malloc(1 + ext_capab_ie_len); 2624346981Scy if (sta->ext_capability) { 2625346981Scy sta->ext_capability[0] = ext_capab_ie_len; 2626346981Scy os_memcpy(sta->ext_capability + 1, ext_capab_ie, 2627346981Scy ext_capab_ie_len); 2628346981Scy } 2629346981Scy } 2630337817Scy 2631281806Srpaulo return WLAN_STATUS_SUCCESS; 2632281806Srpaulo} 2633281806Srpaulo 2634281806Srpaulo 2635346981Scy#ifdef CONFIG_OWE 2636346981Scy 2637346981Scystatic int owe_group_supported(struct hostapd_data *hapd, u16 group) 2638346981Scy{ 2639346981Scy int i; 2640346981Scy int *groups = hapd->conf->owe_groups; 2641346981Scy 2642346981Scy if (group != 19 && group != 20 && group != 21) 2643346981Scy return 0; 2644346981Scy 2645346981Scy if (!groups) 2646346981Scy return 1; 2647346981Scy 2648346981Scy for (i = 0; groups[i] > 0; i++) { 2649346981Scy if (groups[i] == group) 2650346981Scy return 1; 2651346981Scy } 2652346981Scy 2653346981Scy return 0; 2654346981Scy} 2655346981Scy 2656346981Scy 2657346981Scystatic u16 owe_process_assoc_req(struct hostapd_data *hapd, 2658346981Scy struct sta_info *sta, const u8 *owe_dh, 2659346981Scy u8 owe_dh_len) 2660346981Scy{ 2661346981Scy struct wpabuf *secret, *pub, *hkey; 2662346981Scy int res; 2663346981Scy u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN]; 2664346981Scy const char *info = "OWE Key Generation"; 2665346981Scy const u8 *addr[2]; 2666346981Scy size_t len[2]; 2667346981Scy u16 group; 2668346981Scy size_t hash_len, prime_len; 2669346981Scy 2670346981Scy if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) { 2671346981Scy wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching"); 2672346981Scy return WLAN_STATUS_SUCCESS; 2673346981Scy } 2674346981Scy 2675346981Scy group = WPA_GET_LE16(owe_dh); 2676346981Scy if (!owe_group_supported(hapd, group)) { 2677346981Scy wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group); 2678346981Scy return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 2679346981Scy } 2680346981Scy if (group == 19) 2681346981Scy prime_len = 32; 2682346981Scy else if (group == 20) 2683346981Scy prime_len = 48; 2684346981Scy else if (group == 21) 2685346981Scy prime_len = 66; 2686346981Scy else 2687346981Scy return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 2688346981Scy 2689346981Scy crypto_ecdh_deinit(sta->owe_ecdh); 2690346981Scy sta->owe_ecdh = crypto_ecdh_init(group); 2691346981Scy if (!sta->owe_ecdh) 2692346981Scy return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 2693346981Scy sta->owe_group = group; 2694346981Scy 2695346981Scy secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2, 2696346981Scy owe_dh_len - 2); 2697346981Scy secret = wpabuf_zeropad(secret, prime_len); 2698346981Scy if (!secret) { 2699346981Scy wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key"); 2700346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2701346981Scy } 2702346981Scy wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret); 2703346981Scy 2704346981Scy /* prk = HKDF-extract(C | A | group, z) */ 2705346981Scy 2706346981Scy pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 2707346981Scy if (!pub) { 2708346981Scy wpabuf_clear_free(secret); 2709346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2710346981Scy } 2711346981Scy 2712346981Scy /* PMKID = Truncate-128(Hash(C | A)) */ 2713346981Scy addr[0] = owe_dh + 2; 2714346981Scy len[0] = owe_dh_len - 2; 2715346981Scy addr[1] = wpabuf_head(pub); 2716346981Scy len[1] = wpabuf_len(pub); 2717346981Scy if (group == 19) { 2718346981Scy res = sha256_vector(2, addr, len, pmkid); 2719346981Scy hash_len = SHA256_MAC_LEN; 2720346981Scy } else if (group == 20) { 2721346981Scy res = sha384_vector(2, addr, len, pmkid); 2722346981Scy hash_len = SHA384_MAC_LEN; 2723346981Scy } else if (group == 21) { 2724346981Scy res = sha512_vector(2, addr, len, pmkid); 2725346981Scy hash_len = SHA512_MAC_LEN; 2726346981Scy } else { 2727346981Scy wpabuf_free(pub); 2728346981Scy wpabuf_clear_free(secret); 2729346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2730346981Scy } 2731346981Scy pub = wpabuf_zeropad(pub, prime_len); 2732346981Scy if (res < 0 || !pub) { 2733346981Scy wpabuf_free(pub); 2734346981Scy wpabuf_clear_free(secret); 2735346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2736346981Scy } 2737346981Scy 2738346981Scy hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2); 2739346981Scy if (!hkey) { 2740346981Scy wpabuf_free(pub); 2741346981Scy wpabuf_clear_free(secret); 2742346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2743346981Scy } 2744346981Scy 2745346981Scy wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */ 2746346981Scy wpabuf_put_buf(hkey, pub); /* A */ 2747346981Scy wpabuf_free(pub); 2748346981Scy wpabuf_put_le16(hkey, group); /* group */ 2749346981Scy if (group == 19) 2750346981Scy res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey), 2751346981Scy wpabuf_head(secret), wpabuf_len(secret), prk); 2752346981Scy else if (group == 20) 2753346981Scy res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey), 2754346981Scy wpabuf_head(secret), wpabuf_len(secret), prk); 2755346981Scy else if (group == 21) 2756346981Scy res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey), 2757346981Scy wpabuf_head(secret), wpabuf_len(secret), prk); 2758346981Scy wpabuf_clear_free(hkey); 2759346981Scy wpabuf_clear_free(secret); 2760346981Scy if (res < 0) 2761346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2762346981Scy 2763346981Scy wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len); 2764346981Scy 2765346981Scy /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */ 2766346981Scy 2767346981Scy os_free(sta->owe_pmk); 2768346981Scy sta->owe_pmk = os_malloc(hash_len); 2769346981Scy if (!sta->owe_pmk) { 2770346981Scy os_memset(prk, 0, SHA512_MAC_LEN); 2771346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2772346981Scy } 2773346981Scy 2774346981Scy if (group == 19) 2775346981Scy res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info, 2776346981Scy os_strlen(info), sta->owe_pmk, hash_len); 2777346981Scy else if (group == 20) 2778346981Scy res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info, 2779346981Scy os_strlen(info), sta->owe_pmk, hash_len); 2780346981Scy else if (group == 21) 2781346981Scy res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info, 2782346981Scy os_strlen(info), sta->owe_pmk, hash_len); 2783346981Scy os_memset(prk, 0, SHA512_MAC_LEN); 2784346981Scy if (res < 0) { 2785346981Scy os_free(sta->owe_pmk); 2786346981Scy sta->owe_pmk = NULL; 2787346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 2788346981Scy } 2789346981Scy sta->owe_pmk_len = hash_len; 2790346981Scy 2791346981Scy wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len); 2792346981Scy wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN); 2793346981Scy wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk, 2794346981Scy sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE); 2795346981Scy 2796346981Scy return WLAN_STATUS_SUCCESS; 2797346981Scy} 2798346981Scy 2799351611Scy 2800351611Scyu16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, 2801351611Scy const u8 *rsn_ie, size_t rsn_ie_len, 2802351611Scy const u8 *owe_dh, size_t owe_dh_len) 2803351611Scy{ 2804351611Scy struct wpa_ie_data data; 2805351611Scy int res; 2806351611Scy 2807351611Scy if (!rsn_ie || rsn_ie_len < 2) { 2808351611Scy wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR, 2809351611Scy MAC2STR(peer)); 2810351611Scy return WLAN_STATUS_INVALID_IE; 2811351611Scy } 2812351611Scy rsn_ie -= 2; 2813351611Scy rsn_ie_len += 2; 2814351611Scy 2815351611Scy res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data); 2816351611Scy if (res) { 2817351611Scy wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR 2818351611Scy " (res=%d)", MAC2STR(peer), res); 2819351611Scy wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len); 2820351611Scy return wpa_res_to_status_code(res); 2821351611Scy } 2822351611Scy if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) { 2823351611Scy wpa_printf(MSG_DEBUG, 2824351611Scy "OWE: Unexpected key mgmt 0x%x from " MACSTR, 2825351611Scy (unsigned int) data.key_mgmt, MAC2STR(peer)); 2826351611Scy return WLAN_STATUS_AKMP_NOT_VALID; 2827351611Scy } 2828351611Scy if (!owe_dh) { 2829351611Scy wpa_printf(MSG_DEBUG, 2830351611Scy "OWE: No Diffie-Hellman Parameter element from " 2831351611Scy MACSTR, MAC2STR(peer)); 2832351611Scy return WLAN_STATUS_AKMP_NOT_VALID; 2833351611Scy } 2834351611Scy 2835351611Scy return WLAN_STATUS_SUCCESS; 2836351611Scy} 2837351611Scy 2838351611Scy 2839351611Scyu16 owe_process_rsn_ie(struct hostapd_data *hapd, 2840351611Scy struct sta_info *sta, 2841351611Scy const u8 *rsn_ie, size_t rsn_ie_len, 2842351611Scy const u8 *owe_dh, size_t owe_dh_len) 2843351611Scy{ 2844351611Scy u16 status; 2845351611Scy u8 *owe_buf, ie[256 * 2]; 2846351611Scy size_t ie_len = 0; 2847351611Scy int res; 2848351611Scy 2849351611Scy if (!rsn_ie || rsn_ie_len < 2) { 2850351611Scy wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq"); 2851351611Scy status = WLAN_STATUS_INVALID_IE; 2852351611Scy goto end; 2853351611Scy } 2854351611Scy 2855351611Scy if (!sta->wpa_sm) 2856351611Scy sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, 2857351611Scy NULL); 2858351611Scy if (!sta->wpa_sm) { 2859351611Scy wpa_printf(MSG_WARNING, 2860351611Scy "OWE: Failed to initialize WPA state machine"); 2861351611Scy status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2862351611Scy goto end; 2863351611Scy } 2864351611Scy rsn_ie -= 2; 2865351611Scy rsn_ie_len += 2; 2866351611Scy res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 2867351611Scy hapd->iface->freq, rsn_ie, rsn_ie_len, 2868351611Scy NULL, 0, owe_dh, owe_dh_len); 2869351611Scy status = wpa_res_to_status_code(res); 2870351611Scy if (status != WLAN_STATUS_SUCCESS) 2871351611Scy goto end; 2872351611Scy status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len); 2873351611Scy if (status != WLAN_STATUS_SUCCESS) 2874351611Scy goto end; 2875351611Scy owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie), 2876351611Scy NULL, 0); 2877351611Scy if (!owe_buf) { 2878351611Scy status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2879351611Scy goto end; 2880351611Scy } 2881351611Scy 2882351611Scy if (sta->owe_ecdh) { 2883351611Scy struct wpabuf *pub; 2884351611Scy 2885351611Scy pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 2886351611Scy if (!pub) { 2887351611Scy status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2888351611Scy goto end; 2889351611Scy } 2890351611Scy 2891351611Scy /* OWE Diffie-Hellman Parameter element */ 2892351611Scy *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */ 2893351611Scy *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */ 2894351611Scy *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension 2895351611Scy */ 2896351611Scy WPA_PUT_LE16(owe_buf, sta->owe_group); 2897351611Scy owe_buf += 2; 2898351611Scy os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub)); 2899351611Scy owe_buf += wpabuf_len(pub); 2900351611Scy wpabuf_free(pub); 2901351611Scy sta->external_dh_updated = 1; 2902351611Scy } 2903351611Scy ie_len = owe_buf - ie; 2904351611Scy 2905351611Scyend: 2906351611Scy wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer " 2907351611Scy MACSTR, status, (unsigned int) ie_len, 2908351611Scy MAC2STR(sta->addr)); 2909351611Scy hostapd_drv_update_dh_ie(hapd, sta->addr, status, 2910351611Scy status == WLAN_STATUS_SUCCESS ? ie : NULL, 2911351611Scy ie_len); 2912351611Scy 2913351611Scy return status; 2914351611Scy} 2915351611Scy 2916346981Scy#endif /* CONFIG_OWE */ 2917346981Scy 2918346981Scy 2919214501Srpaulostatic u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, 2920214501Srpaulo const u8 *ies, size_t ies_len, int reassoc) 2921214501Srpaulo{ 2922214501Srpaulo struct ieee802_11_elems elems; 2923214501Srpaulo u16 resp; 2924214501Srpaulo const u8 *wpa_ie; 2925214501Srpaulo size_t wpa_ie_len; 2926281806Srpaulo const u8 *p2p_dev_addr = NULL; 2927214501Srpaulo 2928214501Srpaulo if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { 2929214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2930214501Srpaulo HOSTAPD_LEVEL_INFO, "Station sent an invalid " 2931214501Srpaulo "association request"); 2932214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 2933214501Srpaulo } 2934214501Srpaulo 2935214501Srpaulo resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len); 2936214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2937214501Srpaulo return resp; 2938214501Srpaulo resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len); 2939214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2940214501Srpaulo return resp; 2941281806Srpaulo resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len); 2942281806Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2943281806Srpaulo return resp; 2944214501Srpaulo resp = copy_supp_rates(hapd, sta, &elems); 2945214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2946214501Srpaulo return resp; 2947346981Scy 2948346981Scy resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len); 2949346981Scy if (resp != WLAN_STATUS_SUCCESS) 2950346981Scy return resp; 2951346981Scy 2952214501Srpaulo#ifdef CONFIG_IEEE80211N 2953289549Srpaulo resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities); 2954214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2955214501Srpaulo return resp; 2956252726Srpaulo if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && 2957252726Srpaulo !(sta->flags & WLAN_STA_HT)) { 2958252726Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2959252726Srpaulo HOSTAPD_LEVEL_INFO, "Station does not support " 2960252726Srpaulo "mandatory HT PHY - reject association"); 2961252726Srpaulo return WLAN_STATUS_ASSOC_DENIED_NO_HT; 2962252726Srpaulo } 2963214501Srpaulo#endif /* CONFIG_IEEE80211N */ 2964214501Srpaulo 2965252726Srpaulo#ifdef CONFIG_IEEE80211AC 2966289549Srpaulo if (hapd->iconf->ieee80211ac) { 2967289549Srpaulo resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities); 2968289549Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2969289549Srpaulo return resp; 2970281806Srpaulo 2971289549Srpaulo resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif); 2972289549Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2973289549Srpaulo return resp; 2974289549Srpaulo } 2975281806Srpaulo 2976252726Srpaulo if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && 2977252726Srpaulo !(sta->flags & WLAN_STA_VHT)) { 2978252726Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2979252726Srpaulo HOSTAPD_LEVEL_INFO, "Station does not support " 2980252726Srpaulo "mandatory VHT PHY - reject association"); 2981281806Srpaulo return WLAN_STATUS_ASSOC_DENIED_NO_VHT; 2982252726Srpaulo } 2983281806Srpaulo 2984281806Srpaulo if (hapd->conf->vendor_vht && !elems.vht_capabilities) { 2985281806Srpaulo resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht, 2986281806Srpaulo elems.vendor_vht_len); 2987281806Srpaulo if (resp != WLAN_STATUS_SUCCESS) 2988281806Srpaulo return resp; 2989281806Srpaulo } 2990252726Srpaulo#endif /* CONFIG_IEEE80211AC */ 2991351611Scy#ifdef CONFIG_IEEE80211AX 2992351611Scy if (hapd->iconf->ieee80211ax) { 2993351611Scy resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP, 2994351611Scy elems.he_capabilities, 2995351611Scy elems.he_capabilities_len); 2996351611Scy if (resp != WLAN_STATUS_SUCCESS) 2997351611Scy return resp; 2998351611Scy } 2999351611Scy#endif /* CONFIG_IEEE80211AX */ 3000252726Srpaulo 3001281806Srpaulo#ifdef CONFIG_P2P 3002281806Srpaulo if (elems.p2p) { 3003281806Srpaulo wpabuf_free(sta->p2p_ie); 3004281806Srpaulo sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, 3005281806Srpaulo P2P_IE_VENDOR_TYPE); 3006281806Srpaulo if (sta->p2p_ie) 3007281806Srpaulo p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 3008281806Srpaulo } else { 3009281806Srpaulo wpabuf_free(sta->p2p_ie); 3010281806Srpaulo sta->p2p_ie = NULL; 3011281806Srpaulo } 3012281806Srpaulo#endif /* CONFIG_P2P */ 3013281806Srpaulo 3014214501Srpaulo if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) { 3015214501Srpaulo wpa_ie = elems.rsn_ie; 3016214501Srpaulo wpa_ie_len = elems.rsn_ie_len; 3017214501Srpaulo } else if ((hapd->conf->wpa & WPA_PROTO_WPA) && 3018214501Srpaulo elems.wpa_ie) { 3019214501Srpaulo wpa_ie = elems.wpa_ie; 3020214501Srpaulo wpa_ie_len = elems.wpa_ie_len; 3021214501Srpaulo } else { 3022214501Srpaulo wpa_ie = NULL; 3023214501Srpaulo wpa_ie_len = 0; 3024214501Srpaulo } 3025214501Srpaulo 3026214501Srpaulo#ifdef CONFIG_WPS 3027252726Srpaulo sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 3028214501Srpaulo if (hapd->conf->wps_state && elems.wps_ie) { 3029214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " 3030214501Srpaulo "Request - assume WPS is used"); 3031214501Srpaulo sta->flags |= WLAN_STA_WPS; 3032214501Srpaulo wpabuf_free(sta->wps_ie); 3033214501Srpaulo sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, 3034214501Srpaulo WPS_IE_VENDOR_TYPE); 3035252726Srpaulo if (sta->wps_ie && wps_is_20(sta->wps_ie)) { 3036252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); 3037252726Srpaulo sta->flags |= WLAN_STA_WPS2; 3038252726Srpaulo } 3039214501Srpaulo wpa_ie = NULL; 3040214501Srpaulo wpa_ie_len = 0; 3041252726Srpaulo if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) { 3042252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in " 3043252726Srpaulo "(Re)Association Request - reject"); 3044252726Srpaulo return WLAN_STATUS_INVALID_IE; 3045252726Srpaulo } 3046214501Srpaulo } else if (hapd->conf->wps_state && wpa_ie == NULL) { 3047214501Srpaulo wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in " 3048214501Srpaulo "(Re)Association Request - possible WPS use"); 3049214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 3050214501Srpaulo } else 3051214501Srpaulo#endif /* CONFIG_WPS */ 3052214501Srpaulo if (hapd->conf->wpa && wpa_ie == NULL) { 3053214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 3054214501Srpaulo HOSTAPD_LEVEL_INFO, 3055214501Srpaulo "No WPA/RSN IE in association request"); 3056214501Srpaulo return WLAN_STATUS_INVALID_IE; 3057214501Srpaulo } 3058214501Srpaulo 3059214501Srpaulo if (hapd->conf->wpa && wpa_ie) { 3060214501Srpaulo int res; 3061214501Srpaulo wpa_ie -= 2; 3062214501Srpaulo wpa_ie_len += 2; 3063214501Srpaulo if (sta->wpa_sm == NULL) 3064214501Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 3065281806Srpaulo sta->addr, 3066281806Srpaulo p2p_dev_addr); 3067214501Srpaulo if (sta->wpa_sm == NULL) { 3068214501Srpaulo wpa_printf(MSG_WARNING, "Failed to initialize WPA " 3069214501Srpaulo "state machine"); 3070214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 3071214501Srpaulo } 3072346981Scy wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg); 3073214501Srpaulo res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 3074346981Scy hapd->iface->freq, 3075214501Srpaulo wpa_ie, wpa_ie_len, 3076346981Scy elems.mdie, elems.mdie_len, 3077346981Scy elems.owe_dh, elems.owe_dh_len); 3078346981Scy resp = wpa_res_to_status_code(res); 3079214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 3080214501Srpaulo return resp; 3081214501Srpaulo#ifdef CONFIG_IEEE80211W 3082346981Scy if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 3083346981Scy (WLAN_STA_ASSOC | WLAN_STA_MFP) && 3084346981Scy !sta->sa_query_timed_out && 3085214501Srpaulo sta->sa_query_count > 0) 3086214501Srpaulo ap_check_sa_query_timeout(hapd, sta); 3087346981Scy if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 3088346981Scy (WLAN_STA_ASSOC | WLAN_STA_MFP) && 3089346981Scy !sta->sa_query_timed_out && 3090214501Srpaulo (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) { 3091214501Srpaulo /* 3092214501Srpaulo * STA has already been associated with MFP and SA 3093214501Srpaulo * Query timeout has not been reached. Reject the 3094214501Srpaulo * association attempt temporarily and start SA Query, 3095214501Srpaulo * if one is not pending. 3096214501Srpaulo */ 3097214501Srpaulo 3098214501Srpaulo if (sta->sa_query_count == 0) 3099214501Srpaulo ap_sta_start_sa_query(hapd, sta); 3100214501Srpaulo 3101214501Srpaulo return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 3102214501Srpaulo } 3103214501Srpaulo 3104214501Srpaulo if (wpa_auth_uses_mfp(sta->wpa_sm)) 3105214501Srpaulo sta->flags |= WLAN_STA_MFP; 3106214501Srpaulo else 3107214501Srpaulo sta->flags &= ~WLAN_STA_MFP; 3108214501Srpaulo#endif /* CONFIG_IEEE80211W */ 3109214501Srpaulo 3110346981Scy#ifdef CONFIG_IEEE80211R_AP 3111214501Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) { 3112214501Srpaulo if (!reassoc) { 3113214501Srpaulo wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried " 3114214501Srpaulo "to use association (not " 3115214501Srpaulo "re-association) with FT auth_alg", 3116214501Srpaulo MAC2STR(sta->addr)); 3117214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 3118214501Srpaulo } 3119214501Srpaulo 3120214501Srpaulo resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies, 3121214501Srpaulo ies_len); 3122214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 3123214501Srpaulo return resp; 3124214501Srpaulo } 3125346981Scy#endif /* CONFIG_IEEE80211R_AP */ 3126214501Srpaulo 3127252726Srpaulo#ifdef CONFIG_SAE 3128346981Scy if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae && 3129346981Scy sta->sae->state == SAE_ACCEPTED) 3130346981Scy wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid); 3131346981Scy 3132252726Srpaulo if (wpa_auth_uses_sae(sta->wpa_sm) && 3133281806Srpaulo sta->auth_alg == WLAN_AUTH_OPEN) { 3134281806Srpaulo struct rsn_pmksa_cache_entry *sa; 3135281806Srpaulo sa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 3136281806Srpaulo if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) { 3137281806Srpaulo wpa_printf(MSG_DEBUG, 3138281806Srpaulo "SAE: No PMKSA cache entry found for " 3139281806Srpaulo MACSTR, MAC2STR(sta->addr)); 3140281806Srpaulo return WLAN_STATUS_INVALID_PMKID; 3141281806Srpaulo } 3142281806Srpaulo wpa_printf(MSG_DEBUG, "SAE: " MACSTR 3143281806Srpaulo " using PMKSA caching", MAC2STR(sta->addr)); 3144281806Srpaulo } else if (wpa_auth_uses_sae(sta->wpa_sm) && 3145281806Srpaulo sta->auth_alg != WLAN_AUTH_SAE && 3146281806Srpaulo !(sta->auth_alg == WLAN_AUTH_FT && 3147281806Srpaulo wpa_auth_uses_ft_sae(sta->wpa_sm))) { 3148252726Srpaulo wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use " 3149252726Srpaulo "SAE AKM after non-SAE auth_alg %u", 3150252726Srpaulo MAC2STR(sta->addr), sta->auth_alg); 3151252726Srpaulo return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 3152252726Srpaulo } 3153252726Srpaulo#endif /* CONFIG_SAE */ 3154252726Srpaulo 3155346981Scy#ifdef CONFIG_OWE 3156346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 3157346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && 3158346981Scy elems.owe_dh) { 3159346981Scy resp = owe_process_assoc_req(hapd, sta, elems.owe_dh, 3160346981Scy elems.owe_dh_len); 3161346981Scy if (resp != WLAN_STATUS_SUCCESS) 3162346981Scy return resp; 3163346981Scy } 3164346981Scy#endif /* CONFIG_OWE */ 3165346981Scy 3166346981Scy#ifdef CONFIG_DPP2 3167346981Scy dpp_pfs_free(sta->dpp_pfs); 3168346981Scy sta->dpp_pfs = NULL; 3169346981Scy 3170346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && 3171346981Scy hapd->conf->dpp_netaccesskey && sta->wpa_sm && 3172346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && 3173346981Scy elems.owe_dh) { 3174346981Scy sta->dpp_pfs = dpp_pfs_init( 3175346981Scy wpabuf_head(hapd->conf->dpp_netaccesskey), 3176346981Scy wpabuf_len(hapd->conf->dpp_netaccesskey)); 3177346981Scy if (!sta->dpp_pfs) { 3178346981Scy wpa_printf(MSG_DEBUG, 3179346981Scy "DPP: Could not initialize PFS"); 3180346981Scy /* Try to continue without PFS */ 3181346981Scy goto pfs_fail; 3182346981Scy } 3183346981Scy 3184346981Scy if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, 3185346981Scy elems.owe_dh_len) < 0) { 3186346981Scy dpp_pfs_free(sta->dpp_pfs); 3187346981Scy sta->dpp_pfs = NULL; 3188346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 3189346981Scy } 3190346981Scy } 3191346981Scy 3192346981Scy wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? 3193346981Scy sta->dpp_pfs->secret : NULL); 3194346981Scy pfs_fail: 3195346981Scy#endif /* CONFIG_DPP2 */ 3196346981Scy 3197214501Srpaulo#ifdef CONFIG_IEEE80211N 3198252726Srpaulo if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) && 3199214501Srpaulo wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { 3200214501Srpaulo hostapd_logger(hapd, sta->addr, 3201214501Srpaulo HOSTAPD_MODULE_IEEE80211, 3202214501Srpaulo HOSTAPD_LEVEL_INFO, 3203214501Srpaulo "Station tried to use TKIP with HT " 3204214501Srpaulo "association"); 3205214501Srpaulo return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 3206214501Srpaulo } 3207214501Srpaulo#endif /* CONFIG_IEEE80211N */ 3208281806Srpaulo#ifdef CONFIG_HS20 3209281806Srpaulo } else if (hapd->conf->osen) { 3210281806Srpaulo if (elems.osen == NULL) { 3211281806Srpaulo hostapd_logger( 3212281806Srpaulo hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 3213281806Srpaulo HOSTAPD_LEVEL_INFO, 3214281806Srpaulo "No HS 2.0 OSEN element in association request"); 3215281806Srpaulo return WLAN_STATUS_INVALID_IE; 3216281806Srpaulo } 3217281806Srpaulo 3218281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); 3219281806Srpaulo if (sta->wpa_sm == NULL) 3220281806Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 3221281806Srpaulo sta->addr, NULL); 3222281806Srpaulo if (sta->wpa_sm == NULL) { 3223281806Srpaulo wpa_printf(MSG_WARNING, "Failed to initialize WPA " 3224281806Srpaulo "state machine"); 3225281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 3226281806Srpaulo } 3227281806Srpaulo if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, 3228281806Srpaulo elems.osen - 2, elems.osen_len + 2) < 0) 3229281806Srpaulo return WLAN_STATUS_INVALID_IE; 3230281806Srpaulo#endif /* CONFIG_HS20 */ 3231214501Srpaulo } else 3232214501Srpaulo wpa_auth_sta_no_wpa(sta->wpa_sm); 3233214501Srpaulo 3234252726Srpaulo#ifdef CONFIG_P2P 3235252726Srpaulo p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len); 3236252726Srpaulo#endif /* CONFIG_P2P */ 3237252726Srpaulo 3238252726Srpaulo#ifdef CONFIG_HS20 3239252726Srpaulo wpabuf_free(sta->hs20_ie); 3240252726Srpaulo if (elems.hs20 && elems.hs20_len > 4) { 3241346981Scy int release; 3242346981Scy 3243252726Srpaulo sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, 3244252726Srpaulo elems.hs20_len - 4); 3245346981Scy release = ((elems.hs20[4] >> 4) & 0x0f) + 1; 3246346981Scy if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) { 3247346981Scy wpa_printf(MSG_DEBUG, 3248346981Scy "HS 2.0: PMF not negotiated by release %d station " 3249346981Scy MACSTR, release, MAC2STR(sta->addr)); 3250346981Scy return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; 3251346981Scy } 3252346981Scy } else { 3253252726Srpaulo sta->hs20_ie = NULL; 3254346981Scy } 3255346981Scy 3256346981Scy wpabuf_free(sta->roaming_consortium); 3257346981Scy if (elems.roaming_cons_sel) 3258346981Scy sta->roaming_consortium = wpabuf_alloc_copy( 3259346981Scy elems.roaming_cons_sel + 4, 3260346981Scy elems.roaming_cons_sel_len - 4); 3261346981Scy else 3262346981Scy sta->roaming_consortium = NULL; 3263252726Srpaulo#endif /* CONFIG_HS20 */ 3264252726Srpaulo 3265289549Srpaulo#ifdef CONFIG_FST 3266289549Srpaulo wpabuf_free(sta->mb_ies); 3267289549Srpaulo if (hapd->iface->fst) 3268289549Srpaulo sta->mb_ies = mb_ies_by_info(&elems.mb_ies); 3269289549Srpaulo else 3270289549Srpaulo sta->mb_ies = NULL; 3271289549Srpaulo#endif /* CONFIG_FST */ 3272289549Srpaulo 3273337817Scy#ifdef CONFIG_MBO 3274337817Scy mbo_ap_check_sta_assoc(hapd, sta, &elems); 3275337817Scy 3276337817Scy if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && 3277337817Scy elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && 3278337817Scy hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 3279337817Scy wpa_printf(MSG_INFO, 3280337817Scy "MBO: Reject WPA2 association without PMF"); 3281337817Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 3282337817Scy } 3283337817Scy#endif /* CONFIG_MBO */ 3284337817Scy 3285346981Scy#if defined(CONFIG_FILS) && defined(CONFIG_OCV) 3286346981Scy if (wpa_auth_uses_ocv(sta->wpa_sm) && 3287346981Scy (sta->auth_alg == WLAN_AUTH_FILS_SK || 3288346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 3289346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK)) { 3290346981Scy struct wpa_channel_info ci; 3291346981Scy int tx_chanwidth; 3292346981Scy int tx_seg1_idx; 3293346981Scy 3294346981Scy if (hostapd_drv_channel_info(hapd, &ci) != 0) { 3295346981Scy wpa_printf(MSG_WARNING, 3296346981Scy "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame"); 3297346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 3298346981Scy } 3299346981Scy 3300346981Scy if (get_sta_tx_parameters(sta->wpa_sm, 3301346981Scy channel_width_to_int(ci.chanwidth), 3302346981Scy ci.seg1_idx, &tx_chanwidth, 3303346981Scy &tx_seg1_idx) < 0) 3304346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 3305346981Scy 3306346981Scy if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, 3307346981Scy tx_chanwidth, tx_seg1_idx) != 0) { 3308346981Scy wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr); 3309346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 3310346981Scy } 3311346981Scy } 3312346981Scy#endif /* CONFIG_FILS && CONFIG_OCV */ 3313346981Scy 3314337817Scy ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes, 3315337817Scy elems.supp_op_classes_len); 3316337817Scy 3317337817Scy if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) && 3318337817Scy elems.rrm_enabled && 3319337817Scy elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa)) 3320337817Scy os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled, 3321337817Scy sizeof(sta->rrm_enabled_capa)); 3322337817Scy 3323346981Scy if (elems.power_capab) { 3324346981Scy sta->min_tx_power = elems.power_capab[0]; 3325346981Scy sta->max_tx_power = elems.power_capab[1]; 3326346981Scy sta->power_capab = 1; 3327346981Scy } else { 3328346981Scy sta->power_capab = 0; 3329346981Scy } 3330346981Scy 3331214501Srpaulo return WLAN_STATUS_SUCCESS; 3332214501Srpaulo} 3333214501Srpaulo 3334214501Srpaulo 3335214501Srpaulostatic void send_deauth(struct hostapd_data *hapd, const u8 *addr, 3336214501Srpaulo u16 reason_code) 3337214501Srpaulo{ 3338214501Srpaulo int send_len; 3339214501Srpaulo struct ieee80211_mgmt reply; 3340214501Srpaulo 3341214501Srpaulo os_memset(&reply, 0, sizeof(reply)); 3342214501Srpaulo reply.frame_control = 3343214501Srpaulo IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); 3344214501Srpaulo os_memcpy(reply.da, addr, ETH_ALEN); 3345214501Srpaulo os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN); 3346214501Srpaulo os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN); 3347214501Srpaulo 3348214501Srpaulo send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); 3349214501Srpaulo reply.u.deauth.reason_code = host_to_le16(reason_code); 3350214501Srpaulo 3351252726Srpaulo if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0) 3352214501Srpaulo wpa_printf(MSG_INFO, "Failed to send deauth: %s", 3353214501Srpaulo strerror(errno)); 3354214501Srpaulo} 3355214501Srpaulo 3356214501Srpaulo 3357337817Scystatic int add_associated_sta(struct hostapd_data *hapd, 3358346981Scy struct sta_info *sta, int reassoc) 3359214501Srpaulo{ 3360337817Scy struct ieee80211_ht_capabilities ht_cap; 3361337817Scy struct ieee80211_vht_capabilities vht_cap; 3362351611Scy struct ieee80211_he_capabilities he_cap; 3363337817Scy int set = 1; 3364337817Scy 3365337817Scy /* 3366337817Scy * Remove the STA entry to ensure the STA PS state gets cleared and 3367337817Scy * configuration gets updated. This is relevant for cases, such as 3368337817Scy * FT-over-the-DS, where a station re-associates back to the same AP but 3369337817Scy * skips the authentication flow, or if working with a driver that 3370337817Scy * does not support full AP client state. 3371337817Scy * 3372337817Scy * Skip this if the STA has already completed FT reassociation and the 3373337817Scy * TK has been configured since the TX/RX PN must not be reset to 0 for 3374337817Scy * the same key. 3375346981Scy * 3376346981Scy * FT-over-the-DS has a special case where the STA entry (and as such, 3377346981Scy * the TK) has not yet been configured to the driver depending on which 3378346981Scy * driver interface is used. For that case, allow add-STA operation to 3379346981Scy * be used (instead of set-STA). This is needed to allow mac80211-based 3380346981Scy * drivers to accept the STA parameter configuration. Since this is 3381346981Scy * after a new FT-over-DS exchange, a new TK has been derived, so key 3382346981Scy * reinstallation is not a concern for this case. 3383337817Scy */ 3384346981Scy wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR 3385346981Scy " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)", 3386346981Scy MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg, 3387346981Scy sta->ft_over_ds, reassoc, 3388346981Scy !!(sta->flags & WLAN_STA_AUTHORIZED), 3389346981Scy wpa_auth_sta_ft_tk_already_set(sta->wpa_sm), 3390346981Scy wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)); 3391346981Scy 3392337817Scy if (!sta->added_unassoc && 3393337817Scy (!(sta->flags & WLAN_STA_AUTHORIZED) || 3394346981Scy (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) || 3395346981Scy (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) && 3396346981Scy !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) { 3397337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 3398337817Scy wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED); 3399337817Scy set = 0; 3400346981Scy 3401346981Scy /* Do not allow the FT-over-DS exception to be used more than 3402346981Scy * once per authentication exchange to guarantee a new TK is 3403346981Scy * used here */ 3404346981Scy sta->ft_over_ds = 0; 3405337817Scy } 3406337817Scy 3407337817Scy#ifdef CONFIG_IEEE80211N 3408337817Scy if (sta->flags & WLAN_STA_HT) 3409337817Scy hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); 3410337817Scy#endif /* CONFIG_IEEE80211N */ 3411337817Scy#ifdef CONFIG_IEEE80211AC 3412337817Scy if (sta->flags & WLAN_STA_VHT) 3413337817Scy hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap); 3414337817Scy#endif /* CONFIG_IEEE80211AC */ 3415351611Scy#ifdef CONFIG_IEEE80211AX 3416351611Scy if (sta->flags & WLAN_STA_HE) { 3417351611Scy hostapd_get_he_capab(hapd, sta->he_capab, &he_cap, 3418351611Scy sta->he_capab_len); 3419351611Scy } 3420351611Scy#endif /* CONFIG_IEEE80211AX */ 3421337817Scy 3422337817Scy /* 3423337817Scy * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags 3424337817Scy * will be set when the ACK frame for the (Re)Association Response frame 3425337817Scy * is processed (TX status driver event). 3426337817Scy */ 3427337817Scy if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, 3428337817Scy sta->supported_rates, sta->supported_rates_len, 3429337817Scy sta->listen_interval, 3430337817Scy sta->flags & WLAN_STA_HT ? &ht_cap : NULL, 3431337817Scy sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, 3432351611Scy sta->flags & WLAN_STA_HE ? &he_cap : NULL, 3433351611Scy sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0, 3434337817Scy sta->flags | WLAN_STA_ASSOC, sta->qosinfo, 3435337817Scy sta->vht_opmode, sta->p2p_ie ? 1 : 0, 3436337817Scy set)) { 3437337817Scy hostapd_logger(hapd, sta->addr, 3438337817Scy HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, 3439337817Scy "Could not %s STA to kernel driver", 3440337817Scy set ? "set" : "add"); 3441337817Scy 3442337817Scy if (sta->added_unassoc) { 3443337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 3444337817Scy sta->added_unassoc = 0; 3445337817Scy } 3446337817Scy 3447337817Scy return -1; 3448337817Scy } 3449337817Scy 3450337817Scy sta->added_unassoc = 0; 3451337817Scy 3452337817Scy return 0; 3453337817Scy} 3454337817Scy 3455337817Scy 3456337817Scystatic u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, 3457346981Scy const u8 *addr, u16 status_code, int reassoc, 3458346981Scy const u8 *ies, size_t ies_len, int rssi) 3459337817Scy{ 3460214501Srpaulo int send_len; 3461346981Scy u8 *buf; 3462346981Scy size_t buflen; 3463214501Srpaulo struct ieee80211_mgmt *reply; 3464214501Srpaulo u8 *p; 3465346981Scy u16 res = WLAN_STATUS_SUCCESS; 3466214501Srpaulo 3467346981Scy buflen = sizeof(struct ieee80211_mgmt) + 1024; 3468346981Scy#ifdef CONFIG_FILS 3469346981Scy if (sta && sta->fils_hlp_resp) 3470346981Scy buflen += wpabuf_len(sta->fils_hlp_resp); 3471351611Scy if (sta) 3472351611Scy buflen += 150; 3473346981Scy#endif /* CONFIG_FILS */ 3474346981Scy#ifdef CONFIG_OWE 3475346981Scy if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) 3476346981Scy buflen += 150; 3477346981Scy#endif /* CONFIG_OWE */ 3478346981Scy#ifdef CONFIG_DPP2 3479346981Scy if (sta && sta->dpp_pfs) 3480346981Scy buflen += 5 + sta->dpp_pfs->curve->prime_len; 3481346981Scy#endif /* CONFIG_DPP2 */ 3482346981Scy buf = os_zalloc(buflen); 3483346981Scy if (!buf) { 3484346981Scy res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3485346981Scy goto done; 3486346981Scy } 3487214501Srpaulo reply = (struct ieee80211_mgmt *) buf; 3488214501Srpaulo reply->frame_control = 3489214501Srpaulo IEEE80211_FC(WLAN_FC_TYPE_MGMT, 3490214501Srpaulo (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : 3491214501Srpaulo WLAN_FC_STYPE_ASSOC_RESP)); 3492346981Scy os_memcpy(reply->da, addr, ETH_ALEN); 3493214501Srpaulo os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); 3494214501Srpaulo os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN); 3495214501Srpaulo 3496214501Srpaulo send_len = IEEE80211_HDRLEN; 3497214501Srpaulo send_len += sizeof(reply->u.assoc_resp); 3498214501Srpaulo reply->u.assoc_resp.capab_info = 3499289549Srpaulo host_to_le16(hostapd_own_capab_info(hapd)); 3500214501Srpaulo reply->u.assoc_resp.status_code = host_to_le16(status_code); 3501346981Scy 3502346981Scy reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) | 3503346981Scy BIT(14) | BIT(15)); 3504214501Srpaulo /* Supported rates */ 3505214501Srpaulo p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable); 3506214501Srpaulo /* Extended supported rates */ 3507214501Srpaulo p = hostapd_eid_ext_supp_rates(hapd, p); 3508214501Srpaulo 3509346981Scy#ifdef CONFIG_MBO 3510346981Scy if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS && 3511346981Scy rssi != 0) { 3512346981Scy int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi; 3513346981Scy 3514346981Scy p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p, 3515346981Scy delta); 3516346981Scy } 3517346981Scy#endif /* CONFIG_MBO */ 3518346981Scy 3519346981Scy#ifdef CONFIG_IEEE80211R_AP 3520346981Scy if (sta && status_code == WLAN_STATUS_SUCCESS) { 3521214501Srpaulo /* IEEE 802.11r: Mobility Domain Information, Fast BSS 3522214501Srpaulo * Transition Information, RSN, [RIC Response] */ 3523214501Srpaulo p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, 3524346981Scy buf + buflen - p, 3525214501Srpaulo sta->auth_alg, ies, ies_len); 3526346981Scy if (!p) { 3527346981Scy wpa_printf(MSG_DEBUG, 3528346981Scy "FT: Failed to write AssocResp IEs"); 3529346981Scy res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3530346981Scy goto done; 3531346981Scy } 3532214501Srpaulo } 3533346981Scy#endif /* CONFIG_IEEE80211R_AP */ 3534351611Scy#ifdef CONFIG_FILS 3535351611Scy if (sta && status_code == WLAN_STATUS_SUCCESS && 3536351611Scy (sta->auth_alg == WLAN_AUTH_FILS_SK || 3537351611Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 3538351611Scy sta->auth_alg == WLAN_AUTH_FILS_PK)) 3539351611Scy p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p, 3540351611Scy buf + buflen - p, 3541351611Scy ies, ies_len); 3542351611Scy#endif /* CONFIG_FILS */ 3543214501Srpaulo 3544346981Scy#ifdef CONFIG_OWE 3545346981Scy if (sta && status_code == WLAN_STATUS_SUCCESS && 3546346981Scy (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) 3547346981Scy p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p, 3548346981Scy buf + buflen - p, 3549346981Scy ies, ies_len); 3550346981Scy#endif /* CONFIG_OWE */ 3551346981Scy 3552214501Srpaulo#ifdef CONFIG_IEEE80211W 3553346981Scy if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) 3554214501Srpaulo p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 3555214501Srpaulo#endif /* CONFIG_IEEE80211W */ 3556214501Srpaulo 3557214501Srpaulo#ifdef CONFIG_IEEE80211N 3558214501Srpaulo p = hostapd_eid_ht_capabilities(hapd, p); 3559214501Srpaulo p = hostapd_eid_ht_operation(hapd, p); 3560214501Srpaulo#endif /* CONFIG_IEEE80211N */ 3561214501Srpaulo 3562252726Srpaulo#ifdef CONFIG_IEEE80211AC 3563281806Srpaulo if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { 3564337817Scy u32 nsts = 0, sta_nsts; 3565337817Scy 3566346981Scy if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) { 3567337817Scy struct ieee80211_vht_capabilities *capa; 3568337817Scy 3569337817Scy nsts = (hapd->iface->conf->vht_capab >> 3570337817Scy VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7; 3571337817Scy capa = sta->vht_capabilities; 3572337817Scy sta_nsts = (le_to_host32(capa->vht_capabilities_info) >> 3573337817Scy VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7; 3574337817Scy 3575337817Scy if (nsts < sta_nsts) 3576337817Scy nsts = 0; 3577337817Scy else 3578337817Scy nsts = sta_nsts; 3579337817Scy } 3580337817Scy p = hostapd_eid_vht_capabilities(hapd, p, nsts); 3581281806Srpaulo p = hostapd_eid_vht_operation(hapd, p); 3582281806Srpaulo } 3583252726Srpaulo#endif /* CONFIG_IEEE80211AC */ 3584252726Srpaulo 3585351611Scy#ifdef CONFIG_IEEE80211AX 3586351611Scy if (hapd->iconf->ieee80211ax) { 3587351611Scy p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP); 3588351611Scy p = hostapd_eid_he_operation(hapd, p); 3589351611Scy p = hostapd_eid_spatial_reuse(hapd, p); 3590351611Scy p = hostapd_eid_he_mu_edca_parameter_set(hapd, p); 3591351611Scy } 3592351611Scy#endif /* CONFIG_IEEE80211AX */ 3593351611Scy 3594252726Srpaulo p = hostapd_eid_ext_capab(hapd, p); 3595252726Srpaulo p = hostapd_eid_bss_max_idle_period(hapd, p); 3596346981Scy if (sta && sta->qos_map_enabled) 3597281806Srpaulo p = hostapd_eid_qos_map_set(hapd, p); 3598252726Srpaulo 3599289549Srpaulo#ifdef CONFIG_FST 3600289549Srpaulo if (hapd->iface->fst_ies) { 3601289549Srpaulo os_memcpy(p, wpabuf_head(hapd->iface->fst_ies), 3602289549Srpaulo wpabuf_len(hapd->iface->fst_ies)); 3603289549Srpaulo p += wpabuf_len(hapd->iface->fst_ies); 3604289549Srpaulo } 3605289549Srpaulo#endif /* CONFIG_FST */ 3606289549Srpaulo 3607346981Scy#ifdef CONFIG_OWE 3608346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 3609346981Scy sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS && 3610346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) { 3611346981Scy struct wpabuf *pub; 3612346981Scy 3613346981Scy pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 3614346981Scy if (!pub) { 3615346981Scy res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3616346981Scy goto done; 3617346981Scy } 3618346981Scy /* OWE Diffie-Hellman Parameter element */ 3619346981Scy *p++ = WLAN_EID_EXTENSION; /* Element ID */ 3620346981Scy *p++ = 1 + 2 + wpabuf_len(pub); /* Length */ 3621346981Scy *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */ 3622346981Scy WPA_PUT_LE16(p, sta->owe_group); 3623346981Scy p += 2; 3624346981Scy os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub)); 3625346981Scy p += wpabuf_len(pub); 3626346981Scy wpabuf_free(pub); 3627346981Scy } 3628346981Scy#endif /* CONFIG_OWE */ 3629346981Scy 3630346981Scy#ifdef CONFIG_DPP2 3631346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && 3632346981Scy sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS && 3633346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) { 3634346981Scy os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie), 3635346981Scy wpabuf_len(sta->dpp_pfs->ie)); 3636346981Scy p += wpabuf_len(sta->dpp_pfs->ie); 3637346981Scy } 3638346981Scy#endif /* CONFIG_DPP2 */ 3639346981Scy 3640281806Srpaulo#ifdef CONFIG_IEEE80211AC 3641346981Scy if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT)) 3642281806Srpaulo p = hostapd_eid_vendor_vht(hapd, p); 3643281806Srpaulo#endif /* CONFIG_IEEE80211AC */ 3644281806Srpaulo 3645346981Scy if (sta && (sta->flags & WLAN_STA_WMM)) 3646214501Srpaulo p = hostapd_eid_wmm(hapd, p); 3647214501Srpaulo 3648214501Srpaulo#ifdef CONFIG_WPS 3649346981Scy if (sta && 3650346981Scy ((sta->flags & WLAN_STA_WPS) || 3651346981Scy ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) { 3652214501Srpaulo struct wpabuf *wps = wps_build_assoc_resp_ie(); 3653214501Srpaulo if (wps) { 3654214501Srpaulo os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); 3655214501Srpaulo p += wpabuf_len(wps); 3656214501Srpaulo wpabuf_free(wps); 3657214501Srpaulo } 3658214501Srpaulo } 3659214501Srpaulo#endif /* CONFIG_WPS */ 3660214501Srpaulo 3661346981Scy if (sta && (sta->flags & WLAN_STA_MULTI_AP)) 3662346981Scy p = hostapd_eid_multi_ap(hapd, p); 3663346981Scy 3664252726Srpaulo#ifdef CONFIG_P2P 3665346981Scy if (sta && sta->p2p_ie && hapd->p2p_group) { 3666252726Srpaulo struct wpabuf *p2p_resp_ie; 3667252726Srpaulo enum p2p_status_code status; 3668252726Srpaulo switch (status_code) { 3669252726Srpaulo case WLAN_STATUS_SUCCESS: 3670252726Srpaulo status = P2P_SC_SUCCESS; 3671252726Srpaulo break; 3672252726Srpaulo case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA: 3673252726Srpaulo status = P2P_SC_FAIL_LIMIT_REACHED; 3674252726Srpaulo break; 3675252726Srpaulo default: 3676252726Srpaulo status = P2P_SC_FAIL_INVALID_PARAMS; 3677252726Srpaulo break; 3678252726Srpaulo } 3679252726Srpaulo p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status); 3680252726Srpaulo if (p2p_resp_ie) { 3681252726Srpaulo os_memcpy(p, wpabuf_head(p2p_resp_ie), 3682252726Srpaulo wpabuf_len(p2p_resp_ie)); 3683252726Srpaulo p += wpabuf_len(p2p_resp_ie); 3684252726Srpaulo wpabuf_free(p2p_resp_ie); 3685252726Srpaulo } 3686252726Srpaulo } 3687252726Srpaulo#endif /* CONFIG_P2P */ 3688252726Srpaulo 3689252726Srpaulo#ifdef CONFIG_P2P_MANAGER 3690252726Srpaulo if (hapd->conf->p2p & P2P_MANAGE) 3691252726Srpaulo p = hostapd_eid_p2p_manage(hapd, p); 3692252726Srpaulo#endif /* CONFIG_P2P_MANAGER */ 3693252726Srpaulo 3694346981Scy p = hostapd_eid_mbo(hapd, p, buf + buflen - p); 3695337817Scy 3696337817Scy if (hapd->conf->assocresp_elements && 3697346981Scy (size_t) (buf + buflen - p) >= 3698337817Scy wpabuf_len(hapd->conf->assocresp_elements)) { 3699337817Scy os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements), 3700337817Scy wpabuf_len(hapd->conf->assocresp_elements)); 3701337817Scy p += wpabuf_len(hapd->conf->assocresp_elements); 3702337817Scy } 3703337817Scy 3704214501Srpaulo send_len += p - reply->u.assoc_resp.variable; 3705214501Srpaulo 3706346981Scy#ifdef CONFIG_FILS 3707346981Scy if (sta && 3708346981Scy (sta->auth_alg == WLAN_AUTH_FILS_SK || 3709346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 3710346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) && 3711346981Scy status_code == WLAN_STATUS_SUCCESS) { 3712346981Scy struct ieee802_11_elems elems; 3713346981Scy 3714346981Scy if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == 3715346981Scy ParseFailed || !elems.fils_session) { 3716346981Scy res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3717346981Scy goto done; 3718346981Scy } 3719346981Scy 3720346981Scy /* FILS Session */ 3721346981Scy *p++ = WLAN_EID_EXTENSION; /* Element ID */ 3722346981Scy *p++ = 1 + FILS_SESSION_LEN; /* Length */ 3723346981Scy *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */ 3724346981Scy os_memcpy(p, elems.fils_session, FILS_SESSION_LEN); 3725346981Scy send_len += 2 + 1 + FILS_SESSION_LEN; 3726346981Scy 3727346981Scy send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len, 3728346981Scy buflen, sta->fils_hlp_resp); 3729346981Scy if (send_len < 0) { 3730346981Scy res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3731346981Scy goto done; 3732346981Scy } 3733346981Scy } 3734346981Scy#endif /* CONFIG_FILS */ 3735346981Scy 3736337817Scy if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) { 3737214501Srpaulo wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", 3738214501Srpaulo strerror(errno)); 3739346981Scy res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3740337817Scy } 3741337817Scy 3742346981Scydone: 3743346981Scy os_free(buf); 3744346981Scy return res; 3745214501Srpaulo} 3746214501Srpaulo 3747214501Srpaulo 3748346981Scy#ifdef CONFIG_OWE 3749346981Scyu8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, 3750346981Scy const u8 *owe_dh, u8 owe_dh_len, 3751346981Scy u8 *owe_buf, size_t owe_buf_len, u16 *reason) 3752346981Scy{ 3753346981Scy#ifdef CONFIG_TESTING_OPTIONS 3754346981Scy if (hapd->conf->own_ie_override) { 3755346981Scy wpa_printf(MSG_DEBUG, "OWE: Using IE override"); 3756346981Scy *reason = WLAN_STATUS_SUCCESS; 3757346981Scy return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, 3758346981Scy owe_buf_len, NULL, 0); 3759346981Scy } 3760346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 3761346981Scy 3762346981Scy if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) { 3763346981Scy wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching"); 3764346981Scy owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, 3765346981Scy owe_buf_len, NULL, 0); 3766346981Scy *reason = WLAN_STATUS_SUCCESS; 3767346981Scy return owe_buf; 3768346981Scy } 3769346981Scy 3770351611Scy if (sta->owe_pmk && sta->external_dh_updated) { 3771351611Scy wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK"); 3772351611Scy *reason = WLAN_STATUS_SUCCESS; 3773351611Scy return owe_buf; 3774351611Scy } 3775351611Scy 3776346981Scy *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len); 3777346981Scy if (*reason != WLAN_STATUS_SUCCESS) 3778346981Scy return NULL; 3779346981Scy 3780346981Scy owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, 3781346981Scy owe_buf_len, NULL, 0); 3782346981Scy 3783346981Scy if (sta->owe_ecdh && owe_buf) { 3784346981Scy struct wpabuf *pub; 3785346981Scy 3786346981Scy pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 3787346981Scy if (!pub) { 3788346981Scy *reason = WLAN_STATUS_UNSPECIFIED_FAILURE; 3789346981Scy return owe_buf; 3790346981Scy } 3791346981Scy 3792346981Scy /* OWE Diffie-Hellman Parameter element */ 3793346981Scy *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */ 3794346981Scy *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */ 3795346981Scy *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension 3796346981Scy */ 3797346981Scy WPA_PUT_LE16(owe_buf, sta->owe_group); 3798346981Scy owe_buf += 2; 3799346981Scy os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub)); 3800346981Scy owe_buf += wpabuf_len(pub); 3801346981Scy wpabuf_free(pub); 3802346981Scy } 3803346981Scy 3804346981Scy return owe_buf; 3805346981Scy} 3806346981Scy#endif /* CONFIG_OWE */ 3807346981Scy 3808346981Scy 3809346981Scy#ifdef CONFIG_FILS 3810346981Scy 3811346981Scyvoid fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta) 3812346981Scy{ 3813346981Scy u16 reply_res; 3814346981Scy 3815346981Scy wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR, 3816346981Scy MAC2STR(sta->addr)); 3817346981Scy eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 3818346981Scy if (!sta->fils_pending_assoc_req) 3819346981Scy return; 3820346981Scy reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS, 3821346981Scy sta->fils_pending_assoc_is_reassoc, 3822346981Scy sta->fils_pending_assoc_req, 3823346981Scy sta->fils_pending_assoc_req_len, 0); 3824346981Scy os_free(sta->fils_pending_assoc_req); 3825346981Scy sta->fils_pending_assoc_req = NULL; 3826346981Scy sta->fils_pending_assoc_req_len = 0; 3827346981Scy wpabuf_free(sta->fils_hlp_resp); 3828346981Scy sta->fils_hlp_resp = NULL; 3829346981Scy wpabuf_free(sta->hlp_dhcp_discover); 3830346981Scy sta->hlp_dhcp_discover = NULL; 3831346981Scy 3832346981Scy /* 3833346981Scy * Remove the station in case transmission of a success response fails. 3834346981Scy * At this point the station was already added associated to the driver. 3835346981Scy */ 3836346981Scy if (reply_res != WLAN_STATUS_SUCCESS) 3837346981Scy hostapd_drv_sta_remove(hapd, sta->addr); 3838346981Scy} 3839346981Scy 3840346981Scy 3841346981Scyvoid fils_hlp_timeout(void *eloop_ctx, void *eloop_data) 3842346981Scy{ 3843346981Scy struct hostapd_data *hapd = eloop_ctx; 3844346981Scy struct sta_info *sta = eloop_data; 3845346981Scy 3846346981Scy wpa_printf(MSG_DEBUG, 3847346981Scy "FILS: HLP response timeout - continue with association response for " 3848346981Scy MACSTR, MAC2STR(sta->addr)); 3849346981Scy if (sta->fils_drv_assoc_finish) 3850346981Scy hostapd_notify_assoc_fils_finish(hapd, sta); 3851346981Scy else 3852346981Scy fils_hlp_finish_assoc(hapd, sta); 3853346981Scy} 3854346981Scy 3855346981Scy#endif /* CONFIG_FILS */ 3856346981Scy 3857346981Scy 3858214501Srpaulostatic void handle_assoc(struct hostapd_data *hapd, 3859214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len, 3860346981Scy int reassoc, int rssi) 3861214501Srpaulo{ 3862281806Srpaulo u16 capab_info, listen_interval, seq_ctrl, fc; 3863337817Scy u16 resp = WLAN_STATUS_SUCCESS, reply_res; 3864214501Srpaulo const u8 *pos; 3865214501Srpaulo int left, i; 3866214501Srpaulo struct sta_info *sta; 3867346981Scy u8 *tmp = NULL; 3868346981Scy struct hostapd_sta_wpa_psk_short *psk = NULL; 3869346981Scy char *identity = NULL; 3870346981Scy char *radius_cui = NULL; 3871346981Scy#ifdef CONFIG_FILS 3872346981Scy int delay_assoc = 0; 3873346981Scy#endif /* CONFIG_FILS */ 3874214501Srpaulo 3875214501Srpaulo if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : 3876214501Srpaulo sizeof(mgmt->u.assoc_req))) { 3877281806Srpaulo wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)", 3878281806Srpaulo reassoc, (unsigned long) len); 3879214501Srpaulo return; 3880214501Srpaulo } 3881214501Srpaulo 3882281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 3883214501Srpaulo if (reassoc) { 3884281806Srpaulo if (hapd->iconf->ignore_reassoc_probability > 0.0 && 3885281806Srpaulo drand48() < hapd->iconf->ignore_reassoc_probability) { 3886281806Srpaulo wpa_printf(MSG_INFO, 3887281806Srpaulo "TESTING: ignoring reassoc request from " 3888281806Srpaulo MACSTR, MAC2STR(mgmt->sa)); 3889281806Srpaulo return; 3890281806Srpaulo } 3891281806Srpaulo } else { 3892281806Srpaulo if (hapd->iconf->ignore_assoc_probability > 0.0 && 3893281806Srpaulo drand48() < hapd->iconf->ignore_assoc_probability) { 3894281806Srpaulo wpa_printf(MSG_INFO, 3895281806Srpaulo "TESTING: ignoring assoc request from " 3896281806Srpaulo MACSTR, MAC2STR(mgmt->sa)); 3897281806Srpaulo return; 3898281806Srpaulo } 3899281806Srpaulo } 3900281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 3901281806Srpaulo 3902281806Srpaulo fc = le_to_host16(mgmt->frame_control); 3903281806Srpaulo seq_ctrl = le_to_host16(mgmt->seq_ctrl); 3904281806Srpaulo 3905281806Srpaulo if (reassoc) { 3906214501Srpaulo capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info); 3907214501Srpaulo listen_interval = le_to_host16( 3908214501Srpaulo mgmt->u.reassoc_req.listen_interval); 3909214501Srpaulo wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR 3910214501Srpaulo " capab_info=0x%02x listen_interval=%d current_ap=" 3911281806Srpaulo MACSTR " seq_ctrl=0x%x%s", 3912214501Srpaulo MAC2STR(mgmt->sa), capab_info, listen_interval, 3913281806Srpaulo MAC2STR(mgmt->u.reassoc_req.current_ap), 3914281806Srpaulo seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : ""); 3915214501Srpaulo left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); 3916214501Srpaulo pos = mgmt->u.reassoc_req.variable; 3917214501Srpaulo } else { 3918214501Srpaulo capab_info = le_to_host16(mgmt->u.assoc_req.capab_info); 3919214501Srpaulo listen_interval = le_to_host16( 3920214501Srpaulo mgmt->u.assoc_req.listen_interval); 3921214501Srpaulo wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR 3922281806Srpaulo " capab_info=0x%02x listen_interval=%d " 3923281806Srpaulo "seq_ctrl=0x%x%s", 3924281806Srpaulo MAC2STR(mgmt->sa), capab_info, listen_interval, 3925281806Srpaulo seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : ""); 3926214501Srpaulo left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); 3927214501Srpaulo pos = mgmt->u.assoc_req.variable; 3928214501Srpaulo } 3929214501Srpaulo 3930214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 3931346981Scy#ifdef CONFIG_IEEE80211R_AP 3932214501Srpaulo if (sta && sta->auth_alg == WLAN_AUTH_FT && 3933214501Srpaulo (sta->flags & WLAN_STA_AUTH) == 0) { 3934214501Srpaulo wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate " 3935214501Srpaulo "prior to authentication since it is using " 3936214501Srpaulo "over-the-DS FT", MAC2STR(mgmt->sa)); 3937337817Scy 3938337817Scy /* 3939337817Scy * Mark station as authenticated, to avoid adding station 3940337817Scy * entry in the driver as associated and not authenticated 3941337817Scy */ 3942337817Scy sta->flags |= WLAN_STA_AUTH; 3943214501Srpaulo } else 3944346981Scy#endif /* CONFIG_IEEE80211R_AP */ 3945214501Srpaulo if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { 3946346981Scy if (hapd->iface->current_mode && 3947346981Scy hapd->iface->current_mode->mode == 3948346981Scy HOSTAPD_MODE_IEEE80211AD) { 3949346981Scy int acl_res; 3950346981Scy u32 session_timeout, acct_interim_interval; 3951346981Scy struct vlan_description vlan_id; 3952346981Scy 3953346981Scy acl_res = ieee802_11_allowed_address( 3954346981Scy hapd, mgmt->sa, (const u8 *) mgmt, len, 3955346981Scy &session_timeout, &acct_interim_interval, 3956346981Scy &vlan_id, &psk, &identity, &radius_cui, 0); 3957346981Scy if (acl_res == HOSTAPD_ACL_REJECT) { 3958346981Scy wpa_msg(hapd->msg_ctx, MSG_DEBUG, 3959346981Scy "Ignore Association Request frame from " 3960346981Scy MACSTR " due to ACL reject", 3961346981Scy MAC2STR(mgmt->sa)); 3962346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 3963346981Scy goto fail; 3964346981Scy } 3965346981Scy if (acl_res == HOSTAPD_ACL_PENDING) 3966346981Scy return; 3967346981Scy 3968346981Scy /* DMG/IEEE 802.11ad does not use authentication. 3969346981Scy * Allocate sta entry upon association. */ 3970346981Scy sta = ap_sta_add(hapd, mgmt->sa); 3971346981Scy if (!sta) { 3972346981Scy hostapd_logger(hapd, mgmt->sa, 3973346981Scy HOSTAPD_MODULE_IEEE80211, 3974346981Scy HOSTAPD_LEVEL_INFO, 3975346981Scy "Failed to add STA"); 3976346981Scy resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 3977346981Scy goto fail; 3978346981Scy } 3979346981Scy 3980346981Scy acl_res = ieee802_11_set_radius_info( 3981346981Scy hapd, sta, acl_res, session_timeout, 3982346981Scy acct_interim_interval, &vlan_id, &psk, 3983346981Scy &identity, &radius_cui); 3984346981Scy if (acl_res) { 3985346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 3986346981Scy goto fail; 3987346981Scy } 3988346981Scy 3989346981Scy hostapd_logger(hapd, sta->addr, 3990346981Scy HOSTAPD_MODULE_IEEE80211, 3991346981Scy HOSTAPD_LEVEL_DEBUG, 3992346981Scy "Skip authentication for DMG/IEEE 802.11ad"); 3993346981Scy sta->flags |= WLAN_STA_AUTH; 3994346981Scy wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 3995346981Scy sta->auth_alg = WLAN_AUTH_OPEN; 3996346981Scy } else { 3997346981Scy hostapd_logger(hapd, mgmt->sa, 3998346981Scy HOSTAPD_MODULE_IEEE80211, 3999346981Scy HOSTAPD_LEVEL_INFO, 4000346981Scy "Station tried to associate before authentication (aid=%d flags=0x%x)", 4001346981Scy sta ? sta->aid : -1, 4002346981Scy sta ? sta->flags : 0); 4003346981Scy send_deauth(hapd, mgmt->sa, 4004346981Scy WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); 4005346981Scy return; 4006346981Scy } 4007214501Srpaulo } 4008214501Srpaulo 4009281806Srpaulo if ((fc & WLAN_FC_RETRY) && 4010281806Srpaulo sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ && 4011281806Srpaulo sta->last_seq_ctrl == seq_ctrl && 4012346981Scy sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ : 4013346981Scy WLAN_FC_STYPE_ASSOC_REQ)) { 4014281806Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4015281806Srpaulo HOSTAPD_LEVEL_DEBUG, 4016281806Srpaulo "Drop repeated association frame seq_ctrl=0x%x", 4017281806Srpaulo seq_ctrl); 4018281806Srpaulo return; 4019281806Srpaulo } 4020281806Srpaulo sta->last_seq_ctrl = seq_ctrl; 4021281806Srpaulo sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ : 4022281806Srpaulo WLAN_FC_STYPE_ASSOC_REQ; 4023281806Srpaulo 4024214501Srpaulo if (hapd->tkip_countermeasures) { 4025346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 4026214501Srpaulo goto fail; 4027214501Srpaulo } 4028214501Srpaulo 4029214501Srpaulo if (listen_interval > hapd->conf->max_listen_interval) { 4030214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4031214501Srpaulo HOSTAPD_LEVEL_DEBUG, 4032214501Srpaulo "Too large Listen Interval (%d)", 4033214501Srpaulo listen_interval); 4034214501Srpaulo resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE; 4035214501Srpaulo goto fail; 4036214501Srpaulo } 4037214501Srpaulo 4038337817Scy#ifdef CONFIG_MBO 4039337817Scy if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) { 4040337817Scy resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 4041337817Scy goto fail; 4042337817Scy } 4043346981Scy 4044346981Scy if (hapd->iconf->rssi_reject_assoc_rssi && rssi && 4045346981Scy rssi < hapd->iconf->rssi_reject_assoc_rssi && 4046346981Scy (sta->auth_rssi == 0 || 4047346981Scy sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) { 4048346981Scy resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS; 4049346981Scy goto fail; 4050346981Scy } 4051337817Scy#endif /* CONFIG_MBO */ 4052337817Scy 4053337817Scy /* 4054337817Scy * sta->capability is used in check_assoc_ies() for RRM enabled 4055337817Scy * capability element. 4056337817Scy */ 4057337817Scy sta->capability = capab_info; 4058337817Scy 4059346981Scy#ifdef CONFIG_FILS 4060346981Scy if (sta->auth_alg == WLAN_AUTH_FILS_SK || 4061346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4062346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) { 4063346981Scy int res; 4064346981Scy 4065346981Scy /* The end of the payload is encrypted. Need to decrypt it 4066346981Scy * before parsing. */ 4067346981Scy 4068346981Scy tmp = os_memdup(pos, left); 4069346981Scy if (!tmp) { 4070346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 4071346981Scy goto fail; 4072346981Scy } 4073346981Scy 4074346981Scy res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt, 4075346981Scy len, tmp, left); 4076346981Scy if (res < 0) { 4077346981Scy resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 4078346981Scy goto fail; 4079346981Scy } 4080346981Scy pos = tmp; 4081346981Scy left = res; 4082346981Scy } 4083346981Scy#endif /* CONFIG_FILS */ 4084346981Scy 4085214501Srpaulo /* followed by SSID and Supported rates; and HT capabilities if 802.11n 4086214501Srpaulo * is used */ 4087214501Srpaulo resp = check_assoc_ies(hapd, sta, pos, left, reassoc); 4088214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 4089214501Srpaulo goto fail; 4090214501Srpaulo 4091214501Srpaulo if (hostapd_get_aid(hapd, sta) < 0) { 4092214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4093214501Srpaulo HOSTAPD_LEVEL_INFO, "No room for more AIDs"); 4094214501Srpaulo resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 4095214501Srpaulo goto fail; 4096214501Srpaulo } 4097214501Srpaulo 4098214501Srpaulo sta->listen_interval = listen_interval; 4099214501Srpaulo 4100346981Scy if (hapd->iface->current_mode && 4101346981Scy hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 4102214501Srpaulo sta->flags |= WLAN_STA_NONERP; 4103214501Srpaulo for (i = 0; i < sta->supported_rates_len; i++) { 4104214501Srpaulo if ((sta->supported_rates[i] & 0x7f) > 22) { 4105214501Srpaulo sta->flags &= ~WLAN_STA_NONERP; 4106214501Srpaulo break; 4107214501Srpaulo } 4108214501Srpaulo } 4109214501Srpaulo if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) { 4110214501Srpaulo sta->nonerp_set = 1; 4111214501Srpaulo hapd->iface->num_sta_non_erp++; 4112214501Srpaulo if (hapd->iface->num_sta_non_erp == 1) 4113214501Srpaulo ieee802_11_set_beacons(hapd->iface); 4114214501Srpaulo } 4115214501Srpaulo 4116214501Srpaulo if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) && 4117214501Srpaulo !sta->no_short_slot_time_set) { 4118214501Srpaulo sta->no_short_slot_time_set = 1; 4119214501Srpaulo hapd->iface->num_sta_no_short_slot_time++; 4120346981Scy if (hapd->iface->current_mode && 4121346981Scy hapd->iface->current_mode->mode == 4122214501Srpaulo HOSTAPD_MODE_IEEE80211G && 4123214501Srpaulo hapd->iface->num_sta_no_short_slot_time == 1) 4124214501Srpaulo ieee802_11_set_beacons(hapd->iface); 4125214501Srpaulo } 4126214501Srpaulo 4127214501Srpaulo if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) 4128214501Srpaulo sta->flags |= WLAN_STA_SHORT_PREAMBLE; 4129214501Srpaulo else 4130214501Srpaulo sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; 4131214501Srpaulo 4132214501Srpaulo if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && 4133214501Srpaulo !sta->no_short_preamble_set) { 4134214501Srpaulo sta->no_short_preamble_set = 1; 4135214501Srpaulo hapd->iface->num_sta_no_short_preamble++; 4136346981Scy if (hapd->iface->current_mode && 4137346981Scy hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G 4138214501Srpaulo && hapd->iface->num_sta_no_short_preamble == 1) 4139214501Srpaulo ieee802_11_set_beacons(hapd->iface); 4140214501Srpaulo } 4141214501Srpaulo 4142214501Srpaulo#ifdef CONFIG_IEEE80211N 4143214501Srpaulo update_ht_state(hapd, sta); 4144214501Srpaulo#endif /* CONFIG_IEEE80211N */ 4145214501Srpaulo 4146214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4147214501Srpaulo HOSTAPD_LEVEL_DEBUG, 4148214501Srpaulo "association OK (aid %d)", sta->aid); 4149214501Srpaulo /* Station will be marked associated, after it acknowledges AssocResp 4150214501Srpaulo */ 4151252726Srpaulo sta->flags |= WLAN_STA_ASSOC_REQ_OK; 4152214501Srpaulo 4153214501Srpaulo#ifdef CONFIG_IEEE80211W 4154214501Srpaulo if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) { 4155214501Srpaulo wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out " 4156214501Srpaulo "SA Query procedure", reassoc ? "re" : ""); 4157214501Srpaulo /* TODO: Send a protected Disassociate frame to the STA using 4158214501Srpaulo * the old key and Reason Code "Previous Authentication no 4159214501Srpaulo * longer valid". Make sure this is only sent protected since 4160214501Srpaulo * unprotected frame would be received by the STA that is now 4161214501Srpaulo * trying to associate. 4162214501Srpaulo */ 4163214501Srpaulo } 4164214501Srpaulo#endif /* CONFIG_IEEE80211W */ 4165214501Srpaulo 4166214501Srpaulo /* Make sure that the previously registered inactivity timer will not 4167214501Srpaulo * remove the STA immediately. */ 4168214501Srpaulo sta->timeout_next = STA_NULLFUNC; 4169214501Srpaulo 4170337817Scy#ifdef CONFIG_TAXONOMY 4171337817Scy taxonomy_sta_info_assoc_req(hapd, sta, pos, left); 4172337817Scy#endif /* CONFIG_TAXONOMY */ 4173337817Scy 4174346981Scy sta->pending_wds_enable = 0; 4175346981Scy 4176346981Scy#ifdef CONFIG_FILS 4177346981Scy if (sta->auth_alg == WLAN_AUTH_FILS_SK || 4178346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4179346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) { 4180346981Scy if (fils_process_hlp(hapd, sta, pos, left) > 0) 4181346981Scy delay_assoc = 1; 4182346981Scy } 4183346981Scy#endif /* CONFIG_FILS */ 4184346981Scy 4185214501Srpaulo fail: 4186346981Scy os_free(identity); 4187346981Scy os_free(radius_cui); 4188346981Scy hostapd_free_psk_list(psk); 4189346981Scy 4190337817Scy /* 4191337817Scy * In case of a successful response, add the station to the driver. 4192337817Scy * Otherwise, the kernel may ignore Data frames before we process the 4193337817Scy * ACK frame (TX status). In case of a failure, this station will be 4194337817Scy * removed. 4195337817Scy * 4196337817Scy * Note that this is not compliant with the IEEE 802.11 standard that 4197337817Scy * states that a non-AP station should transition into the 4198337817Scy * authenticated/associated state only after the station acknowledges 4199337817Scy * the (Re)Association Response frame. However, still do this as: 4200337817Scy * 4201337817Scy * 1. In case the station does not acknowledge the (Re)Association 4202337817Scy * Response frame, it will be removed. 4203337817Scy * 2. Data frames will be dropped in the kernel until the station is 4204337817Scy * set into authorized state, and there are no significant known 4205337817Scy * issues with processing other non-Data Class 3 frames during this 4206337817Scy * window. 4207337817Scy */ 4208346981Scy if (resp == WLAN_STATUS_SUCCESS && sta && 4209346981Scy add_associated_sta(hapd, sta, reassoc)) 4210337817Scy resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 4211337817Scy 4212346981Scy#ifdef CONFIG_FILS 4213346981Scy if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS && 4214346981Scy eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) && 4215346981Scy sta->fils_pending_assoc_req) { 4216346981Scy /* Do not reschedule fils_hlp_timeout in case the station 4217346981Scy * retransmits (Re)Association Request frame while waiting for 4218346981Scy * the previously started FILS HLP wait, so that the timeout can 4219346981Scy * be determined from the first pending attempt. */ 4220346981Scy wpa_printf(MSG_DEBUG, 4221346981Scy "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to " 4222346981Scy MACSTR, MAC2STR(sta->addr)); 4223346981Scy os_free(tmp); 4224346981Scy return; 4225346981Scy } 4226346981Scy if (sta) { 4227346981Scy eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 4228346981Scy os_free(sta->fils_pending_assoc_req); 4229346981Scy sta->fils_pending_assoc_req = NULL; 4230346981Scy sta->fils_pending_assoc_req_len = 0; 4231346981Scy wpabuf_free(sta->fils_hlp_resp); 4232346981Scy sta->fils_hlp_resp = NULL; 4233346981Scy } 4234346981Scy if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) { 4235346981Scy sta->fils_pending_assoc_req = tmp; 4236346981Scy sta->fils_pending_assoc_req_len = left; 4237346981Scy sta->fils_pending_assoc_is_reassoc = reassoc; 4238346981Scy sta->fils_drv_assoc_finish = 0; 4239346981Scy wpa_printf(MSG_DEBUG, 4240346981Scy "FILS: Waiting for HLP processing before sending (Re)Association Response frame to " 4241346981Scy MACSTR, MAC2STR(sta->addr)); 4242346981Scy eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 4243346981Scy eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024, 4244346981Scy fils_hlp_timeout, hapd, sta); 4245346981Scy return; 4246346981Scy } 4247346981Scy#endif /* CONFIG_FILS */ 4248337817Scy 4249346981Scy reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos, 4250346981Scy left, rssi); 4251346981Scy os_free(tmp); 4252346981Scy 4253337817Scy /* 4254337817Scy * Remove the station in case tranmission of a success response fails 4255337817Scy * (the STA was added associated to the driver) or if the station was 4256337817Scy * previously added unassociated. 4257337817Scy */ 4258346981Scy if (sta && ((reply_res != WLAN_STATUS_SUCCESS && 4259346981Scy resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) { 4260337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 4261337817Scy sta->added_unassoc = 0; 4262337817Scy } 4263214501Srpaulo} 4264214501Srpaulo 4265214501Srpaulo 4266214501Srpaulostatic void handle_disassoc(struct hostapd_data *hapd, 4267214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len) 4268214501Srpaulo{ 4269214501Srpaulo struct sta_info *sta; 4270214501Srpaulo 4271214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { 4272281806Srpaulo wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)", 4273281806Srpaulo (unsigned long) len); 4274214501Srpaulo return; 4275214501Srpaulo } 4276214501Srpaulo 4277214501Srpaulo wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", 4278214501Srpaulo MAC2STR(mgmt->sa), 4279214501Srpaulo le_to_host16(mgmt->u.disassoc.reason_code)); 4280214501Srpaulo 4281214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 4282214501Srpaulo if (sta == NULL) { 4283281806Srpaulo wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated", 4284281806Srpaulo MAC2STR(mgmt->sa)); 4285214501Srpaulo return; 4286214501Srpaulo } 4287214501Srpaulo 4288252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 4289281806Srpaulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 4290252726Srpaulo sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); 4291214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 4292214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4293214501Srpaulo HOSTAPD_LEVEL_INFO, "disassociated"); 4294214501Srpaulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 4295214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 4296214501Srpaulo /* Stop Accounting and IEEE 802.1X sessions, but leave the STA 4297214501Srpaulo * authenticated. */ 4298214501Srpaulo accounting_sta_stop(hapd, sta); 4299337817Scy ieee802_1x_free_station(hapd, sta); 4300281806Srpaulo if (sta->ipaddr) 4301281806Srpaulo hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); 4302281806Srpaulo ap_sta_ip6addr_del(hapd, sta); 4303252726Srpaulo hostapd_drv_sta_remove(hapd, sta->addr); 4304337817Scy sta->added_unassoc = 0; 4305214501Srpaulo 4306214501Srpaulo if (sta->timeout_next == STA_NULLFUNC || 4307214501Srpaulo sta->timeout_next == STA_DISASSOC) { 4308214501Srpaulo sta->timeout_next = STA_DEAUTH; 4309214501Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 4310214501Srpaulo eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, 4311214501Srpaulo hapd, sta); 4312214501Srpaulo } 4313214501Srpaulo 4314214501Srpaulo mlme_disassociate_indication( 4315214501Srpaulo hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code)); 4316346981Scy 4317346981Scy /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon 4318346981Scy * disassociation. */ 4319346981Scy if (hapd->iface->current_mode && 4320346981Scy hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { 4321346981Scy sta->flags &= ~WLAN_STA_AUTH; 4322346981Scy wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); 4323346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4324346981Scy HOSTAPD_LEVEL_DEBUG, "deauthenticated"); 4325346981Scy ap_free_sta(hapd, sta); 4326346981Scy } 4327214501Srpaulo} 4328214501Srpaulo 4329214501Srpaulo 4330214501Srpaulostatic void handle_deauth(struct hostapd_data *hapd, 4331214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len) 4332214501Srpaulo{ 4333214501Srpaulo struct sta_info *sta; 4334214501Srpaulo 4335214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { 4336252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short " 4337252726Srpaulo "payload (len=%lu)", (unsigned long) len); 4338214501Srpaulo return; 4339214501Srpaulo } 4340214501Srpaulo 4341252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR 4342252726Srpaulo " reason_code=%d", 4343252726Srpaulo MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); 4344214501Srpaulo 4345214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 4346214501Srpaulo if (sta == NULL) { 4347252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " 4348252726Srpaulo "to deauthenticate, but it is not authenticated", 4349252726Srpaulo MAC2STR(mgmt->sa)); 4350214501Srpaulo return; 4351214501Srpaulo } 4352214501Srpaulo 4353252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 4354281806Srpaulo sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 4355252726Srpaulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | 4356252726Srpaulo WLAN_STA_ASSOC_REQ_OK); 4357214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); 4358214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4359214501Srpaulo HOSTAPD_LEVEL_DEBUG, "deauthenticated"); 4360214501Srpaulo mlme_deauthenticate_indication( 4361214501Srpaulo hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); 4362214501Srpaulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 4363214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 4364214501Srpaulo ap_free_sta(hapd, sta); 4365214501Srpaulo} 4366214501Srpaulo 4367214501Srpaulo 4368214501Srpaulostatic void handle_beacon(struct hostapd_data *hapd, 4369214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len, 4370214501Srpaulo struct hostapd_frame_info *fi) 4371214501Srpaulo{ 4372214501Srpaulo struct ieee802_11_elems elems; 4373214501Srpaulo 4374214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) { 4375281806Srpaulo wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)", 4376281806Srpaulo (unsigned long) len); 4377214501Srpaulo return; 4378214501Srpaulo } 4379214501Srpaulo 4380214501Srpaulo (void) ieee802_11_parse_elems(mgmt->u.beacon.variable, 4381214501Srpaulo len - (IEEE80211_HDRLEN + 4382214501Srpaulo sizeof(mgmt->u.beacon)), &elems, 4383214501Srpaulo 0); 4384214501Srpaulo 4385214501Srpaulo ap_list_process_beacon(hapd->iface, mgmt, &elems, fi); 4386214501Srpaulo} 4387214501Srpaulo 4388214501Srpaulo 4389214501Srpaulo#ifdef CONFIG_IEEE80211W 4390214501Srpaulostatic int robust_action_frame(u8 category) 4391214501Srpaulo{ 4392214501Srpaulo return category != WLAN_ACTION_PUBLIC && 4393214501Srpaulo category != WLAN_ACTION_HT; 4394214501Srpaulo} 4395214501Srpaulo#endif /* CONFIG_IEEE80211W */ 4396214501Srpaulo 4397214501Srpaulo 4398281806Srpaulostatic int handle_action(struct hostapd_data *hapd, 4399346981Scy const struct ieee80211_mgmt *mgmt, size_t len, 4400346981Scy unsigned int freq) 4401252726Srpaulo{ 4402214501Srpaulo struct sta_info *sta; 4403346981Scy u8 *action __maybe_unused; 4404214501Srpaulo 4405346981Scy if (len < IEEE80211_HDRLEN + 2 + 1) { 4406214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4407214501Srpaulo HOSTAPD_LEVEL_DEBUG, 4408214501Srpaulo "handle_action - too short payload (len=%lu)", 4409214501Srpaulo (unsigned long) len); 4410281806Srpaulo return 0; 4411214501Srpaulo } 4412214501Srpaulo 4413346981Scy action = (u8 *) &mgmt->u.action.u; 4414346981Scy wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR 4415346981Scy " da " MACSTR " len %d freq %u", 4416346981Scy mgmt->u.action.category, *action, 4417346981Scy MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq); 4418346981Scy 4419346981Scy sta = ap_get_sta(hapd, mgmt->sa); 4420346981Scy 4421252726Srpaulo if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && 4422252726Srpaulo (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { 4423252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action " 4424252726Srpaulo "frame (category=%u) from unassociated STA " MACSTR, 4425346981Scy mgmt->u.action.category, MAC2STR(mgmt->sa)); 4426281806Srpaulo return 0; 4427252726Srpaulo } 4428252726Srpaulo 4429214501Srpaulo#ifdef CONFIG_IEEE80211W 4430214501Srpaulo if (sta && (sta->flags & WLAN_STA_MFP) && 4431281806Srpaulo !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) && 4432281806Srpaulo robust_action_frame(mgmt->u.action.category)) { 4433214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4434214501Srpaulo HOSTAPD_LEVEL_DEBUG, 4435214501Srpaulo "Dropped unprotected Robust Action frame from " 4436214501Srpaulo "an MFP STA"); 4437281806Srpaulo return 0; 4438214501Srpaulo } 4439214501Srpaulo#endif /* CONFIG_IEEE80211W */ 4440214501Srpaulo 4441281806Srpaulo if (sta) { 4442281806Srpaulo u16 fc = le_to_host16(mgmt->frame_control); 4443281806Srpaulo u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl); 4444281806Srpaulo 4445281806Srpaulo if ((fc & WLAN_FC_RETRY) && 4446281806Srpaulo sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ && 4447281806Srpaulo sta->last_seq_ctrl == seq_ctrl && 4448281806Srpaulo sta->last_subtype == WLAN_FC_STYPE_ACTION) { 4449281806Srpaulo hostapd_logger(hapd, sta->addr, 4450281806Srpaulo HOSTAPD_MODULE_IEEE80211, 4451281806Srpaulo HOSTAPD_LEVEL_DEBUG, 4452281806Srpaulo "Drop repeated action frame seq_ctrl=0x%x", 4453281806Srpaulo seq_ctrl); 4454281806Srpaulo return 1; 4455281806Srpaulo } 4456281806Srpaulo 4457281806Srpaulo sta->last_seq_ctrl = seq_ctrl; 4458281806Srpaulo sta->last_subtype = WLAN_FC_STYPE_ACTION; 4459281806Srpaulo } 4460281806Srpaulo 4461214501Srpaulo switch (mgmt->u.action.category) { 4462346981Scy#ifdef CONFIG_IEEE80211R_AP 4463214501Srpaulo case WLAN_ACTION_FT: 4464281806Srpaulo if (!sta || 4465281806Srpaulo wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, 4466214501Srpaulo len - IEEE80211_HDRLEN)) 4467214501Srpaulo break; 4468281806Srpaulo return 1; 4469346981Scy#endif /* CONFIG_IEEE80211R_AP */ 4470214501Srpaulo case WLAN_ACTION_WMM: 4471214501Srpaulo hostapd_wmm_action(hapd, mgmt, len); 4472281806Srpaulo return 1; 4473214501Srpaulo#ifdef CONFIG_IEEE80211W 4474214501Srpaulo case WLAN_ACTION_SA_QUERY: 4475346981Scy ieee802_11_sa_query_action(hapd, mgmt, len); 4476346981Scy return 1; 4477214501Srpaulo#endif /* CONFIG_IEEE80211W */ 4478346981Scy#ifdef CONFIG_WNM_AP 4479252726Srpaulo case WLAN_ACTION_WNM: 4480281806Srpaulo ieee802_11_rx_wnm_action_ap(hapd, mgmt, len); 4481281806Srpaulo return 1; 4482346981Scy#endif /* CONFIG_WNM_AP */ 4483289549Srpaulo#ifdef CONFIG_FST 4484289549Srpaulo case WLAN_ACTION_FST: 4485289549Srpaulo if (hapd->iface->fst) 4486289549Srpaulo fst_rx_action(hapd->iface->fst, mgmt, len); 4487289549Srpaulo else 4488289549Srpaulo wpa_printf(MSG_DEBUG, 4489289549Srpaulo "FST: Ignore FST Action frame - no FST attached"); 4490289549Srpaulo return 1; 4491289549Srpaulo#endif /* CONFIG_FST */ 4492214501Srpaulo case WLAN_ACTION_PUBLIC: 4493281806Srpaulo case WLAN_ACTION_PROTECTED_DUAL: 4494281806Srpaulo#ifdef CONFIG_IEEE80211N 4495289549Srpaulo if (len >= IEEE80211_HDRLEN + 2 && 4496289549Srpaulo mgmt->u.action.u.public_action.action == 4497281806Srpaulo WLAN_PA_20_40_BSS_COEX) { 4498281806Srpaulo hostapd_2040_coex_action(hapd, mgmt, len); 4499346981Scy return 1; 4500281806Srpaulo } 4501281806Srpaulo#endif /* CONFIG_IEEE80211N */ 4502346981Scy#ifdef CONFIG_DPP 4503346981Scy if (len >= IEEE80211_HDRLEN + 6 && 4504346981Scy mgmt->u.action.u.vs_public_action.action == 4505346981Scy WLAN_PA_VENDOR_SPECIFIC && 4506346981Scy WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 4507346981Scy OUI_WFA && 4508346981Scy mgmt->u.action.u.vs_public_action.variable[0] == 4509346981Scy DPP_OUI_TYPE) { 4510346981Scy const u8 *pos, *end; 4511346981Scy 4512346981Scy pos = mgmt->u.action.u.vs_public_action.oui; 4513346981Scy end = ((const u8 *) mgmt) + len; 4514346981Scy hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos, 4515346981Scy freq); 4516346981Scy return 1; 4517346981Scy } 4518346981Scy if (len >= IEEE80211_HDRLEN + 2 && 4519346981Scy (mgmt->u.action.u.public_action.action == 4520346981Scy WLAN_PA_GAS_INITIAL_RESP || 4521346981Scy mgmt->u.action.u.public_action.action == 4522346981Scy WLAN_PA_GAS_COMEBACK_RESP)) { 4523346981Scy const u8 *pos, *end; 4524346981Scy 4525346981Scy pos = &mgmt->u.action.u.public_action.action; 4526346981Scy end = ((const u8 *) mgmt) + len; 4527346981Scy gas_query_ap_rx(hapd->gas, mgmt->sa, 4528346981Scy mgmt->u.action.category, 4529346981Scy pos, end - pos, hapd->iface->freq); 4530346981Scy return 1; 4531346981Scy } 4532346981Scy#endif /* CONFIG_DPP */ 4533214501Srpaulo if (hapd->public_action_cb) { 4534214501Srpaulo hapd->public_action_cb(hapd->public_action_cb_ctx, 4535214501Srpaulo (u8 *) mgmt, len, 4536214501Srpaulo hapd->iface->freq); 4537214501Srpaulo } 4538281806Srpaulo if (hapd->public_action_cb2) { 4539281806Srpaulo hapd->public_action_cb2(hapd->public_action_cb2_ctx, 4540281806Srpaulo (u8 *) mgmt, len, 4541281806Srpaulo hapd->iface->freq); 4542281806Srpaulo } 4543281806Srpaulo if (hapd->public_action_cb || hapd->public_action_cb2) 4544281806Srpaulo return 1; 4545214501Srpaulo break; 4546252726Srpaulo case WLAN_ACTION_VENDOR_SPECIFIC: 4547252726Srpaulo if (hapd->vendor_action_cb) { 4548252726Srpaulo if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, 4549252726Srpaulo (u8 *) mgmt, len, 4550252726Srpaulo hapd->iface->freq) == 0) 4551281806Srpaulo return 1; 4552252726Srpaulo } 4553252726Srpaulo break; 4554337817Scy case WLAN_ACTION_RADIO_MEASUREMENT: 4555337817Scy hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len); 4556337817Scy return 1; 4557214501Srpaulo } 4558214501Srpaulo 4559214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4560214501Srpaulo HOSTAPD_LEVEL_DEBUG, 4561214501Srpaulo "handle_action - unknown action category %d or invalid " 4562214501Srpaulo "frame", 4563214501Srpaulo mgmt->u.action.category); 4564337817Scy if (!is_multicast_ether_addr(mgmt->da) && 4565337817Scy !(mgmt->u.action.category & 0x80) && 4566337817Scy !is_multicast_ether_addr(mgmt->sa)) { 4567214501Srpaulo struct ieee80211_mgmt *resp; 4568214501Srpaulo 4569214501Srpaulo /* 4570214501Srpaulo * IEEE 802.11-REVma/D9.0 - 7.3.1.11 4571214501Srpaulo * Return the Action frame to the source without change 4572214501Srpaulo * except that MSB of the Category set to 1. 4573214501Srpaulo */ 4574214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action " 4575214501Srpaulo "frame back to sender"); 4576346981Scy resp = os_memdup(mgmt, len); 4577214501Srpaulo if (resp == NULL) 4578281806Srpaulo return 0; 4579214501Srpaulo os_memcpy(resp->da, resp->sa, ETH_ALEN); 4580214501Srpaulo os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); 4581214501Srpaulo os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); 4582214501Srpaulo resp->u.action.category |= 0x80; 4583214501Srpaulo 4584252726Srpaulo if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) { 4585252726Srpaulo wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send " 4586252726Srpaulo "Action frame"); 4587252726Srpaulo } 4588214501Srpaulo os_free(resp); 4589214501Srpaulo } 4590281806Srpaulo 4591281806Srpaulo return 1; 4592214501Srpaulo} 4593214501Srpaulo 4594214501Srpaulo 4595214501Srpaulo/** 4596214501Srpaulo * ieee802_11_mgmt - process incoming IEEE 802.11 management frames 4597214501Srpaulo * @hapd: hostapd BSS data structure (the BSS to which the management frame was 4598214501Srpaulo * sent to) 4599214501Srpaulo * @buf: management frame data (starting from IEEE 802.11 header) 4600214501Srpaulo * @len: length of frame data in octets 4601214501Srpaulo * @fi: meta data about received frame (signal level, etc.) 4602214501Srpaulo * 4603214501Srpaulo * Process all incoming IEEE 802.11 management frames. This will be called for 4604214501Srpaulo * each frame received from the kernel driver through wlan#ap interface. In 4605214501Srpaulo * addition, it can be called to re-inserted pending frames (e.g., when using 4606214501Srpaulo * external RADIUS server as an MAC ACL). 4607214501Srpaulo */ 4608281806Srpauloint ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, 4609281806Srpaulo struct hostapd_frame_info *fi) 4610214501Srpaulo{ 4611214501Srpaulo struct ieee80211_mgmt *mgmt; 4612214501Srpaulo u16 fc, stype; 4613281806Srpaulo int ret = 0; 4614346981Scy unsigned int freq; 4615346981Scy int ssi_signal = fi ? fi->ssi_signal : 0; 4616214501Srpaulo 4617252726Srpaulo if (len < 24) 4618281806Srpaulo return 0; 4619252726Srpaulo 4620346981Scy if (fi && fi->freq) 4621346981Scy freq = fi->freq; 4622346981Scy else 4623346981Scy freq = hapd->iface->freq; 4624346981Scy 4625214501Srpaulo mgmt = (struct ieee80211_mgmt *) buf; 4626214501Srpaulo fc = le_to_host16(mgmt->frame_control); 4627214501Srpaulo stype = WLAN_FC_GET_STYPE(fc); 4628214501Srpaulo 4629214501Srpaulo if (stype == WLAN_FC_STYPE_BEACON) { 4630214501Srpaulo handle_beacon(hapd, mgmt, len, fi); 4631281806Srpaulo return 1; 4632214501Srpaulo } 4633214501Srpaulo 4634337817Scy if (!is_broadcast_ether_addr(mgmt->bssid) && 4635252726Srpaulo#ifdef CONFIG_P2P 4636252726Srpaulo /* Invitation responses can be sent with the peer MAC as BSSID */ 4637252726Srpaulo !((hapd->conf->p2p & P2P_GROUP_OWNER) && 4638252726Srpaulo stype == WLAN_FC_STYPE_ACTION) && 4639252726Srpaulo#endif /* CONFIG_P2P */ 4640281806Srpaulo#ifdef CONFIG_MESH 4641281806Srpaulo !(hapd->conf->mesh & MESH_ENABLED) && 4642281806Srpaulo#endif /* CONFIG_MESH */ 4643214501Srpaulo os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { 4644281806Srpaulo wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address", 4645281806Srpaulo MAC2STR(mgmt->bssid)); 4646281806Srpaulo return 0; 4647214501Srpaulo } 4648214501Srpaulo 4649214501Srpaulo 4650214501Srpaulo if (stype == WLAN_FC_STYPE_PROBE_REQ) { 4651346981Scy handle_probe_req(hapd, mgmt, len, ssi_signal); 4652281806Srpaulo return 1; 4653214501Srpaulo } 4654214501Srpaulo 4655346981Scy if ((!is_broadcast_ether_addr(mgmt->da) || 4656346981Scy stype != WLAN_FC_STYPE_ACTION) && 4657346981Scy os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { 4658214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4659214501Srpaulo HOSTAPD_LEVEL_DEBUG, 4660214501Srpaulo "MGMT: DA=" MACSTR " not our address", 4661214501Srpaulo MAC2STR(mgmt->da)); 4662281806Srpaulo return 0; 4663214501Srpaulo } 4664214501Srpaulo 4665289549Srpaulo if (hapd->iconf->track_sta_max_num) 4666346981Scy sta_track_add(hapd->iface, mgmt->sa, ssi_signal); 4667289549Srpaulo 4668214501Srpaulo switch (stype) { 4669214501Srpaulo case WLAN_FC_STYPE_AUTH: 4670214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::auth"); 4671346981Scy handle_auth(hapd, mgmt, len, ssi_signal, 0); 4672281806Srpaulo ret = 1; 4673214501Srpaulo break; 4674214501Srpaulo case WLAN_FC_STYPE_ASSOC_REQ: 4675214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); 4676346981Scy handle_assoc(hapd, mgmt, len, 0, ssi_signal); 4677281806Srpaulo ret = 1; 4678214501Srpaulo break; 4679214501Srpaulo case WLAN_FC_STYPE_REASSOC_REQ: 4680214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); 4681346981Scy handle_assoc(hapd, mgmt, len, 1, ssi_signal); 4682281806Srpaulo ret = 1; 4683214501Srpaulo break; 4684214501Srpaulo case WLAN_FC_STYPE_DISASSOC: 4685214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::disassoc"); 4686214501Srpaulo handle_disassoc(hapd, mgmt, len); 4687281806Srpaulo ret = 1; 4688214501Srpaulo break; 4689214501Srpaulo case WLAN_FC_STYPE_DEAUTH: 4690252726Srpaulo wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); 4691214501Srpaulo handle_deauth(hapd, mgmt, len); 4692281806Srpaulo ret = 1; 4693214501Srpaulo break; 4694214501Srpaulo case WLAN_FC_STYPE_ACTION: 4695214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::action"); 4696346981Scy ret = handle_action(hapd, mgmt, len, freq); 4697214501Srpaulo break; 4698214501Srpaulo default: 4699214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4700214501Srpaulo HOSTAPD_LEVEL_DEBUG, 4701214501Srpaulo "unknown mgmt frame subtype %d", stype); 4702214501Srpaulo break; 4703214501Srpaulo } 4704281806Srpaulo 4705281806Srpaulo return ret; 4706214501Srpaulo} 4707214501Srpaulo 4708214501Srpaulo 4709214501Srpaulostatic void handle_auth_cb(struct hostapd_data *hapd, 4710214501Srpaulo const struct ieee80211_mgmt *mgmt, 4711214501Srpaulo size_t len, int ok) 4712214501Srpaulo{ 4713214501Srpaulo u16 auth_alg, auth_transaction, status_code; 4714214501Srpaulo struct sta_info *sta; 4715214501Srpaulo 4716337817Scy sta = ap_get_sta(hapd, mgmt->da); 4717337817Scy if (!sta) { 4718346981Scy wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR 4719346981Scy " not found", 4720337817Scy MAC2STR(mgmt->da)); 4721337817Scy return; 4722337817Scy } 4723337817Scy 4724337817Scy auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 4725337817Scy auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 4726337817Scy status_code = le_to_host16(mgmt->u.auth.status_code); 4727337817Scy 4728214501Srpaulo if (!ok) { 4729214501Srpaulo hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, 4730214501Srpaulo HOSTAPD_LEVEL_NOTICE, 4731214501Srpaulo "did not acknowledge authentication response"); 4732337817Scy goto fail; 4733214501Srpaulo } 4734214501Srpaulo 4735214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { 4736281806Srpaulo wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)", 4737281806Srpaulo (unsigned long) len); 4738337817Scy goto fail; 4739214501Srpaulo } 4740214501Srpaulo 4741214501Srpaulo if (status_code == WLAN_STATUS_SUCCESS && 4742214501Srpaulo ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || 4743214501Srpaulo (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { 4744214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4745214501Srpaulo HOSTAPD_LEVEL_INFO, "authenticated"); 4746214501Srpaulo sta->flags |= WLAN_STA_AUTH; 4747337817Scy if (sta->added_unassoc) 4748337817Scy hostapd_set_sta_flags(hapd, sta); 4749337817Scy return; 4750214501Srpaulo } 4751337817Scy 4752337817Scyfail: 4753337817Scy if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) { 4754337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 4755337817Scy sta->added_unassoc = 0; 4756337817Scy } 4757214501Srpaulo} 4758214501Srpaulo 4759214501Srpaulo 4760281806Srpaulostatic void hostapd_set_wds_encryption(struct hostapd_data *hapd, 4761281806Srpaulo struct sta_info *sta, 4762281806Srpaulo char *ifname_wds) 4763281806Srpaulo{ 4764281806Srpaulo int i; 4765289549Srpaulo struct hostapd_ssid *ssid = &hapd->conf->ssid; 4766281806Srpaulo 4767281806Srpaulo if (hapd->conf->ieee802_1x || hapd->conf->wpa) 4768281806Srpaulo return; 4769281806Srpaulo 4770281806Srpaulo for (i = 0; i < 4; i++) { 4771281806Srpaulo if (ssid->wep.key[i] && 4772281806Srpaulo hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i, 4773281806Srpaulo i == ssid->wep.idx, NULL, 0, 4774281806Srpaulo ssid->wep.key[i], ssid->wep.len[i])) { 4775281806Srpaulo wpa_printf(MSG_WARNING, 4776281806Srpaulo "Could not set WEP keys for WDS interface; %s", 4777281806Srpaulo ifname_wds); 4778281806Srpaulo break; 4779281806Srpaulo } 4780281806Srpaulo } 4781281806Srpaulo} 4782281806Srpaulo 4783281806Srpaulo 4784214501Srpaulostatic void handle_assoc_cb(struct hostapd_data *hapd, 4785214501Srpaulo const struct ieee80211_mgmt *mgmt, 4786214501Srpaulo size_t len, int reassoc, int ok) 4787214501Srpaulo{ 4788214501Srpaulo u16 status; 4789214501Srpaulo struct sta_info *sta; 4790214501Srpaulo int new_assoc = 1; 4791214501Srpaulo 4792214501Srpaulo sta = ap_get_sta(hapd, mgmt->da); 4793214501Srpaulo if (!sta) { 4794281806Srpaulo wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found", 4795281806Srpaulo MAC2STR(mgmt->da)); 4796214501Srpaulo return; 4797214501Srpaulo } 4798214501Srpaulo 4799337817Scy if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : 4800337817Scy sizeof(mgmt->u.assoc_resp))) { 4801337817Scy wpa_printf(MSG_INFO, 4802337817Scy "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)", 4803337817Scy reassoc, (unsigned long) len); 4804337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 4805337817Scy return; 4806337817Scy } 4807337817Scy 4808337817Scy if (reassoc) 4809337817Scy status = le_to_host16(mgmt->u.reassoc_resp.status_code); 4810337817Scy else 4811337817Scy status = le_to_host16(mgmt->u.assoc_resp.status_code); 4812337817Scy 4813252726Srpaulo if (!ok) { 4814252726Srpaulo hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, 4815252726Srpaulo HOSTAPD_LEVEL_DEBUG, 4816252726Srpaulo "did not acknowledge association response"); 4817252726Srpaulo sta->flags &= ~WLAN_STA_ASSOC_REQ_OK; 4818337817Scy /* The STA is added only in case of SUCCESS */ 4819337817Scy if (status == WLAN_STATUS_SUCCESS) 4820337817Scy hostapd_drv_sta_remove(hapd, sta->addr); 4821337817Scy 4822252726Srpaulo return; 4823252726Srpaulo } 4824252726Srpaulo 4825214501Srpaulo if (status != WLAN_STATUS_SUCCESS) 4826281806Srpaulo return; 4827214501Srpaulo 4828214501Srpaulo /* Stop previous accounting session, if one is started, and allocate 4829214501Srpaulo * new session id for the new session. */ 4830214501Srpaulo accounting_sta_stop(hapd, sta); 4831214501Srpaulo 4832214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4833214501Srpaulo HOSTAPD_LEVEL_INFO, 4834214501Srpaulo "associated (aid %d)", 4835214501Srpaulo sta->aid); 4836214501Srpaulo 4837214501Srpaulo if (sta->flags & WLAN_STA_ASSOC) 4838214501Srpaulo new_assoc = 0; 4839214501Srpaulo sta->flags |= WLAN_STA_ASSOC; 4840281806Srpaulo sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 4841346981Scy if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && 4842346981Scy !hapd->conf->osen) || 4843346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK || 4844346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4845346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK || 4846214501Srpaulo sta->auth_alg == WLAN_AUTH_FT) { 4847214501Srpaulo /* 4848346981Scy * Open, static WEP, FT protocol, or FILS; no separate 4849346981Scy * authorization step. 4850214501Srpaulo */ 4851252726Srpaulo ap_sta_set_authorized(hapd, sta, 1); 4852214501Srpaulo } 4853214501Srpaulo 4854214501Srpaulo if (reassoc) 4855214501Srpaulo mlme_reassociate_indication(hapd, sta); 4856214501Srpaulo else 4857214501Srpaulo mlme_associate_indication(hapd, sta); 4858214501Srpaulo 4859214501Srpaulo#ifdef CONFIG_IEEE80211W 4860214501Srpaulo sta->sa_query_timed_out = 0; 4861214501Srpaulo#endif /* CONFIG_IEEE80211W */ 4862214501Srpaulo 4863214501Srpaulo if (sta->eapol_sm == NULL) { 4864214501Srpaulo /* 4865214501Srpaulo * This STA does not use RADIUS server for EAP authentication, 4866214501Srpaulo * so bind it to the selected VLAN interface now, since the 4867214501Srpaulo * interface selection is not going to change anymore. 4868214501Srpaulo */ 4869289549Srpaulo if (ap_sta_bind_vlan(hapd, sta) < 0) 4870281806Srpaulo return; 4871214501Srpaulo } else if (sta->vlan_id) { 4872214501Srpaulo /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ 4873289549Srpaulo if (ap_sta_bind_vlan(hapd, sta) < 0) 4874281806Srpaulo return; 4875214501Srpaulo } 4876214501Srpaulo 4877252726Srpaulo hostapd_set_sta_flags(hapd, sta); 4878214501Srpaulo 4879346981Scy if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) { 4880346981Scy wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA " 4881346981Scy MACSTR " based on pending request", 4882346981Scy MAC2STR(sta->addr)); 4883346981Scy sta->pending_wds_enable = 0; 4884346981Scy sta->flags |= WLAN_STA_WDS; 4885346981Scy } 4886346981Scy 4887346981Scy if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) { 4888346981Scy int ret; 4889346981Scy char ifname_wds[IFNAMSIZ + 1]; 4890346981Scy 4891346981Scy wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA " 4892346981Scy MACSTR " (aid %u)", 4893346981Scy MAC2STR(sta->addr), sta->aid); 4894346981Scy ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr, 4895346981Scy sta->aid, 1); 4896346981Scy if (!ret) 4897346981Scy hostapd_set_wds_encryption(hapd, sta, ifname_wds); 4898346981Scy } 4899346981Scy 4900214501Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) 4901214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 4902214501Srpaulo else 4903214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 4904214501Srpaulo hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); 4905337817Scy ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 4906214501Srpaulo 4907346981Scy#ifdef CONFIG_FILS 4908346981Scy if ((sta->auth_alg == WLAN_AUTH_FILS_SK || 4909346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4910346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) && 4911346981Scy fils_set_tk(sta->wpa_sm) < 0) { 4912346981Scy wpa_printf(MSG_DEBUG, "FILS: TK configuration failed"); 4913346981Scy ap_sta_disconnect(hapd, sta, sta->addr, 4914346981Scy WLAN_REASON_UNSPECIFIED); 4915346981Scy return; 4916346981Scy } 4917346981Scy#endif /* CONFIG_FILS */ 4918346981Scy 4919337817Scy if (sta->pending_eapol_rx) { 4920337817Scy struct os_reltime now, age; 4921337817Scy 4922337817Scy os_get_reltime(&now); 4923337817Scy os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age); 4924337817Scy if (age.sec == 0 && age.usec < 200000) { 4925337817Scy wpa_printf(MSG_DEBUG, 4926337817Scy "Process pending EAPOL frame that was received from " MACSTR " just before association notification", 4927337817Scy MAC2STR(sta->addr)); 4928337817Scy ieee802_1x_receive( 4929337817Scy hapd, mgmt->da, 4930337817Scy wpabuf_head(sta->pending_eapol_rx->buf), 4931337817Scy wpabuf_len(sta->pending_eapol_rx->buf)); 4932337817Scy } 4933337817Scy wpabuf_free(sta->pending_eapol_rx->buf); 4934337817Scy os_free(sta->pending_eapol_rx); 4935337817Scy sta->pending_eapol_rx = NULL; 4936337817Scy } 4937214501Srpaulo} 4938214501Srpaulo 4939214501Srpaulo 4940252726Srpaulostatic void handle_deauth_cb(struct hostapd_data *hapd, 4941252726Srpaulo const struct ieee80211_mgmt *mgmt, 4942252726Srpaulo size_t len, int ok) 4943252726Srpaulo{ 4944252726Srpaulo struct sta_info *sta; 4945337817Scy if (is_multicast_ether_addr(mgmt->da)) 4946252726Srpaulo return; 4947252726Srpaulo sta = ap_get_sta(hapd, mgmt->da); 4948252726Srpaulo if (!sta) { 4949252726Srpaulo wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR 4950252726Srpaulo " not found", MAC2STR(mgmt->da)); 4951252726Srpaulo return; 4952252726Srpaulo } 4953252726Srpaulo if (ok) 4954252726Srpaulo wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth", 4955252726Srpaulo MAC2STR(sta->addr)); 4956252726Srpaulo else 4957252726Srpaulo wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " 4958252726Srpaulo "deauth", MAC2STR(sta->addr)); 4959252726Srpaulo 4960252726Srpaulo ap_sta_deauth_cb(hapd, sta); 4961252726Srpaulo} 4962252726Srpaulo 4963252726Srpaulo 4964252726Srpaulostatic void handle_disassoc_cb(struct hostapd_data *hapd, 4965252726Srpaulo const struct ieee80211_mgmt *mgmt, 4966252726Srpaulo size_t len, int ok) 4967252726Srpaulo{ 4968252726Srpaulo struct sta_info *sta; 4969337817Scy if (is_multicast_ether_addr(mgmt->da)) 4970252726Srpaulo return; 4971252726Srpaulo sta = ap_get_sta(hapd, mgmt->da); 4972252726Srpaulo if (!sta) { 4973252726Srpaulo wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR 4974252726Srpaulo " not found", MAC2STR(mgmt->da)); 4975252726Srpaulo return; 4976252726Srpaulo } 4977252726Srpaulo if (ok) 4978252726Srpaulo wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc", 4979252726Srpaulo MAC2STR(sta->addr)); 4980252726Srpaulo else 4981252726Srpaulo wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " 4982252726Srpaulo "disassoc", MAC2STR(sta->addr)); 4983252726Srpaulo 4984252726Srpaulo ap_sta_disassoc_cb(hapd, sta); 4985252726Srpaulo} 4986252726Srpaulo 4987252726Srpaulo 4988346981Scystatic void handle_action_cb(struct hostapd_data *hapd, 4989346981Scy const struct ieee80211_mgmt *mgmt, 4990346981Scy size_t len, int ok) 4991346981Scy{ 4992346981Scy struct sta_info *sta; 4993346981Scy const struct rrm_measurement_report_element *report; 4994346981Scy 4995346981Scy if (is_multicast_ether_addr(mgmt->da)) 4996346981Scy return; 4997346981Scy#ifdef CONFIG_DPP 4998346981Scy if (len >= IEEE80211_HDRLEN + 6 && 4999346981Scy mgmt->u.action.category == WLAN_ACTION_PUBLIC && 5000346981Scy mgmt->u.action.u.vs_public_action.action == 5001346981Scy WLAN_PA_VENDOR_SPECIFIC && 5002346981Scy WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 5003346981Scy OUI_WFA && 5004346981Scy mgmt->u.action.u.vs_public_action.variable[0] == 5005346981Scy DPP_OUI_TYPE) { 5006346981Scy const u8 *pos, *end; 5007346981Scy 5008346981Scy pos = &mgmt->u.action.u.vs_public_action.variable[1]; 5009346981Scy end = ((const u8 *) mgmt) + len; 5010346981Scy hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok); 5011346981Scy return; 5012346981Scy } 5013346981Scy if (len >= IEEE80211_HDRLEN + 2 && 5014346981Scy mgmt->u.action.category == WLAN_ACTION_PUBLIC && 5015346981Scy (mgmt->u.action.u.public_action.action == 5016346981Scy WLAN_PA_GAS_INITIAL_REQ || 5017346981Scy mgmt->u.action.u.public_action.action == 5018346981Scy WLAN_PA_GAS_COMEBACK_REQ)) { 5019346981Scy const u8 *pos, *end; 5020346981Scy 5021346981Scy pos = mgmt->u.action.u.public_action.variable; 5022346981Scy end = ((const u8 *) mgmt) + len; 5023346981Scy gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok); 5024346981Scy return; 5025346981Scy } 5026346981Scy#endif /* CONFIG_DPP */ 5027346981Scy sta = ap_get_sta(hapd, mgmt->da); 5028346981Scy if (!sta) { 5029346981Scy wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR 5030346981Scy " not found", MAC2STR(mgmt->da)); 5031346981Scy return; 5032346981Scy } 5033346981Scy 5034346981Scy if (len < 24 + 5 + sizeof(*report)) 5035346981Scy return; 5036346981Scy report = (const struct rrm_measurement_report_element *) 5037346981Scy &mgmt->u.action.u.rrm.variable[2]; 5038346981Scy if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT && 5039346981Scy mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST && 5040346981Scy report->eid == WLAN_EID_MEASURE_REQUEST && 5041346981Scy report->len >= 3 && 5042346981Scy report->type == MEASURE_TYPE_BEACON) 5043346981Scy hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok); 5044346981Scy} 5045346981Scy 5046346981Scy 5047214501Srpaulo/** 5048214501Srpaulo * ieee802_11_mgmt_cb - Process management frame TX status callback 5049214501Srpaulo * @hapd: hostapd BSS data structure (the BSS from which the management frame 5050214501Srpaulo * was sent from) 5051214501Srpaulo * @buf: management frame data (starting from IEEE 802.11 header) 5052214501Srpaulo * @len: length of frame data in octets 5053214501Srpaulo * @stype: management frame subtype from frame control field 5054214501Srpaulo * @ok: Whether the frame was ACK'ed 5055214501Srpaulo */ 5056214501Srpaulovoid ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, 5057214501Srpaulo u16 stype, int ok) 5058214501Srpaulo{ 5059214501Srpaulo const struct ieee80211_mgmt *mgmt; 5060214501Srpaulo mgmt = (const struct ieee80211_mgmt *) buf; 5061214501Srpaulo 5062281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 5063281806Srpaulo if (hapd->ext_mgmt_frame_handling) { 5064346981Scy size_t hex_len = 2 * len + 1; 5065346981Scy char *hex = os_malloc(hex_len); 5066346981Scy 5067346981Scy if (hex) { 5068346981Scy wpa_snprintf_hex(hex, hex_len, buf, len); 5069346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 5070346981Scy "MGMT-TX-STATUS stype=%u ok=%d buf=%s", 5071346981Scy stype, ok, hex); 5072346981Scy os_free(hex); 5073346981Scy } 5074281806Srpaulo return; 5075281806Srpaulo } 5076281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 5077281806Srpaulo 5078214501Srpaulo switch (stype) { 5079214501Srpaulo case WLAN_FC_STYPE_AUTH: 5080214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::auth cb"); 5081214501Srpaulo handle_auth_cb(hapd, mgmt, len, ok); 5082214501Srpaulo break; 5083214501Srpaulo case WLAN_FC_STYPE_ASSOC_RESP: 5084214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb"); 5085214501Srpaulo handle_assoc_cb(hapd, mgmt, len, 0, ok); 5086214501Srpaulo break; 5087214501Srpaulo case WLAN_FC_STYPE_REASSOC_RESP: 5088214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb"); 5089214501Srpaulo handle_assoc_cb(hapd, mgmt, len, 1, ok); 5090214501Srpaulo break; 5091214501Srpaulo case WLAN_FC_STYPE_PROBE_RESP: 5092337817Scy wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok); 5093214501Srpaulo break; 5094214501Srpaulo case WLAN_FC_STYPE_DEAUTH: 5095252726Srpaulo wpa_printf(MSG_DEBUG, "mgmt::deauth cb"); 5096252726Srpaulo handle_deauth_cb(hapd, mgmt, len, ok); 5097214501Srpaulo break; 5098252726Srpaulo case WLAN_FC_STYPE_DISASSOC: 5099252726Srpaulo wpa_printf(MSG_DEBUG, "mgmt::disassoc cb"); 5100252726Srpaulo handle_disassoc_cb(hapd, mgmt, len, ok); 5101252726Srpaulo break; 5102214501Srpaulo case WLAN_FC_STYPE_ACTION: 5103337817Scy wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok); 5104346981Scy handle_action_cb(hapd, mgmt, len, ok); 5105214501Srpaulo break; 5106214501Srpaulo default: 5107281806Srpaulo wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype); 5108214501Srpaulo break; 5109214501Srpaulo } 5110214501Srpaulo} 5111214501Srpaulo 5112214501Srpaulo 5113214501Srpauloint ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 5114214501Srpaulo{ 5115214501Srpaulo /* TODO */ 5116214501Srpaulo return 0; 5117214501Srpaulo} 5118214501Srpaulo 5119214501Srpaulo 5120214501Srpauloint ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 5121214501Srpaulo char *buf, size_t buflen) 5122214501Srpaulo{ 5123214501Srpaulo /* TODO */ 5124214501Srpaulo return 0; 5125214501Srpaulo} 5126214501Srpaulo 5127214501Srpaulo 5128214501Srpaulovoid hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, 5129214501Srpaulo const u8 *buf, size_t len, int ack) 5130214501Srpaulo{ 5131214501Srpaulo struct sta_info *sta; 5132214501Srpaulo struct hostapd_iface *iface = hapd->iface; 5133214501Srpaulo 5134214501Srpaulo sta = ap_get_sta(hapd, addr); 5135214501Srpaulo if (sta == NULL && iface->num_bss > 1) { 5136214501Srpaulo size_t j; 5137214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 5138214501Srpaulo hapd = iface->bss[j]; 5139214501Srpaulo sta = ap_get_sta(hapd, addr); 5140214501Srpaulo if (sta) 5141214501Srpaulo break; 5142214501Srpaulo } 5143214501Srpaulo } 5144252726Srpaulo if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) 5145214501Srpaulo return; 5146214501Srpaulo if (sta->flags & WLAN_STA_PENDING_POLL) { 5147214501Srpaulo wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " 5148214501Srpaulo "activity poll", MAC2STR(sta->addr), 5149214501Srpaulo ack ? "ACKed" : "did not ACK"); 5150214501Srpaulo if (ack) 5151214501Srpaulo sta->flags &= ~WLAN_STA_PENDING_POLL; 5152214501Srpaulo } 5153214501Srpaulo 5154214501Srpaulo ieee802_1x_tx_status(hapd, sta, buf, len, ack); 5155214501Srpaulo} 5156214501Srpaulo 5157214501Srpaulo 5158252726Srpaulovoid hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, 5159252726Srpaulo const u8 *data, size_t len, int ack) 5160252726Srpaulo{ 5161252726Srpaulo struct sta_info *sta; 5162252726Srpaulo struct hostapd_iface *iface = hapd->iface; 5163252726Srpaulo 5164252726Srpaulo sta = ap_get_sta(hapd, dst); 5165252726Srpaulo if (sta == NULL && iface->num_bss > 1) { 5166252726Srpaulo size_t j; 5167252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 5168252726Srpaulo hapd = iface->bss[j]; 5169252726Srpaulo sta = ap_get_sta(hapd, dst); 5170252726Srpaulo if (sta) 5171252726Srpaulo break; 5172252726Srpaulo } 5173252726Srpaulo } 5174252726Srpaulo if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { 5175252726Srpaulo wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA " 5176252726Srpaulo MACSTR " that is not currently associated", 5177252726Srpaulo MAC2STR(dst)); 5178252726Srpaulo return; 5179252726Srpaulo } 5180252726Srpaulo 5181252726Srpaulo ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); 5182252726Srpaulo} 5183252726Srpaulo 5184252726Srpaulo 5185252726Srpaulovoid hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr) 5186252726Srpaulo{ 5187252726Srpaulo struct sta_info *sta; 5188252726Srpaulo struct hostapd_iface *iface = hapd->iface; 5189252726Srpaulo 5190252726Srpaulo sta = ap_get_sta(hapd, addr); 5191252726Srpaulo if (sta == NULL && iface->num_bss > 1) { 5192252726Srpaulo size_t j; 5193252726Srpaulo for (j = 0; j < iface->num_bss; j++) { 5194252726Srpaulo hapd = iface->bss[j]; 5195252726Srpaulo sta = ap_get_sta(hapd, addr); 5196252726Srpaulo if (sta) 5197252726Srpaulo break; 5198252726Srpaulo } 5199252726Srpaulo } 5200252726Srpaulo if (sta == NULL) 5201252726Srpaulo return; 5202337817Scy wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR, 5203337817Scy MAC2STR(sta->addr)); 5204252726Srpaulo if (!(sta->flags & WLAN_STA_PENDING_POLL)) 5205252726Srpaulo return; 5206252726Srpaulo 5207252726Srpaulo wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending " 5208252726Srpaulo "activity poll", MAC2STR(sta->addr)); 5209252726Srpaulo sta->flags &= ~WLAN_STA_PENDING_POLL; 5210252726Srpaulo} 5211252726Srpaulo 5212252726Srpaulo 5213214501Srpaulovoid ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, 5214214501Srpaulo int wds) 5215214501Srpaulo{ 5216214501Srpaulo struct sta_info *sta; 5217214501Srpaulo 5218214501Srpaulo sta = ap_get_sta(hapd, src); 5219346981Scy if (sta && 5220346981Scy ((sta->flags & WLAN_STA_ASSOC) || 5221346981Scy ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) { 5222252726Srpaulo if (!hapd->conf->wds_sta) 5223252726Srpaulo return; 5224252726Srpaulo 5225346981Scy if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) == 5226346981Scy WLAN_STA_ASSOC_REQ_OK) { 5227346981Scy wpa_printf(MSG_DEBUG, 5228346981Scy "Postpone 4-address WDS mode enabling for STA " 5229346981Scy MACSTR " since TX status for AssocResp is not yet known", 5230346981Scy MAC2STR(sta->addr)); 5231346981Scy sta->pending_wds_enable = 1; 5232346981Scy return; 5233346981Scy } 5234346981Scy 5235214501Srpaulo if (wds && !(sta->flags & WLAN_STA_WDS)) { 5236281806Srpaulo int ret; 5237281806Srpaulo char ifname_wds[IFNAMSIZ + 1]; 5238281806Srpaulo 5239214501Srpaulo wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " 5240214501Srpaulo "STA " MACSTR " (aid %u)", 5241214501Srpaulo MAC2STR(sta->addr), sta->aid); 5242214501Srpaulo sta->flags |= WLAN_STA_WDS; 5243281806Srpaulo ret = hostapd_set_wds_sta(hapd, ifname_wds, 5244281806Srpaulo sta->addr, sta->aid, 1); 5245281806Srpaulo if (!ret) 5246281806Srpaulo hostapd_set_wds_encryption(hapd, sta, 5247281806Srpaulo ifname_wds); 5248214501Srpaulo } 5249214501Srpaulo return; 5250214501Srpaulo } 5251214501Srpaulo 5252214501Srpaulo wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " 5253214501Srpaulo MACSTR, MAC2STR(src)); 5254337817Scy if (is_multicast_ether_addr(src)) { 5255252726Srpaulo /* Broadcast bit set in SA?! Ignore the frame silently. */ 5256252726Srpaulo return; 5257252726Srpaulo } 5258252726Srpaulo 5259252726Srpaulo if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) { 5260252726Srpaulo wpa_printf(MSG_DEBUG, "Association Response to the STA has " 5261252726Srpaulo "already been sent, but no TX status yet known - " 5262252726Srpaulo "ignore Class 3 frame issue with " MACSTR, 5263252726Srpaulo MAC2STR(src)); 5264252726Srpaulo return; 5265252726Srpaulo } 5266252726Srpaulo 5267214501Srpaulo if (sta && (sta->flags & WLAN_STA_AUTH)) 5268252726Srpaulo hostapd_drv_sta_disassoc( 5269214501Srpaulo hapd, src, 5270214501Srpaulo WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); 5271214501Srpaulo else 5272252726Srpaulo hostapd_drv_sta_deauth( 5273214501Srpaulo hapd, src, 5274214501Srpaulo WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); 5275214501Srpaulo} 5276214501Srpaulo 5277214501Srpaulo 5278214501Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */ 5279