1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * hostapd / IEEE 802.11 Management 3e5b75505Sopenharmony_ci * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "utils/includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#ifndef CONFIG_NATIVE_WINDOWS 12e5b75505Sopenharmony_ci 13e5b75505Sopenharmony_ci#include "utils/common.h" 14e5b75505Sopenharmony_ci#include "utils/eloop.h" 15e5b75505Sopenharmony_ci#include "crypto/crypto.h" 16e5b75505Sopenharmony_ci#include "crypto/sha256.h" 17e5b75505Sopenharmony_ci#include "crypto/sha384.h" 18e5b75505Sopenharmony_ci#include "crypto/sha512.h" 19e5b75505Sopenharmony_ci#include "crypto/random.h" 20e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 21e5b75505Sopenharmony_ci#include "common/ieee802_11_common.h" 22e5b75505Sopenharmony_ci#include "common/wpa_ctrl.h" 23e5b75505Sopenharmony_ci#include "common/sae.h" 24e5b75505Sopenharmony_ci#include "common/dpp.h" 25e5b75505Sopenharmony_ci#include "common/ocv.h" 26e5b75505Sopenharmony_ci#include "common/wpa_common.h" 27e5b75505Sopenharmony_ci#include "radius/radius.h" 28e5b75505Sopenharmony_ci#include "radius/radius_client.h" 29e5b75505Sopenharmony_ci#include "p2p/p2p.h" 30e5b75505Sopenharmony_ci#include "wps/wps.h" 31e5b75505Sopenharmony_ci#include "fst/fst.h" 32e5b75505Sopenharmony_ci#include "hostapd.h" 33e5b75505Sopenharmony_ci#include "beacon.h" 34e5b75505Sopenharmony_ci#include "ieee802_11_auth.h" 35e5b75505Sopenharmony_ci#include "sta_info.h" 36e5b75505Sopenharmony_ci#include "ieee802_1x.h" 37e5b75505Sopenharmony_ci#include "wpa_auth.h" 38e5b75505Sopenharmony_ci#include "pmksa_cache_auth.h" 39e5b75505Sopenharmony_ci#include "wmm.h" 40e5b75505Sopenharmony_ci#include "ap_list.h" 41e5b75505Sopenharmony_ci#include "accounting.h" 42e5b75505Sopenharmony_ci#include "ap_config.h" 43e5b75505Sopenharmony_ci#include "ap_mlme.h" 44e5b75505Sopenharmony_ci#include "p2p_hostapd.h" 45e5b75505Sopenharmony_ci#include "ap_drv_ops.h" 46e5b75505Sopenharmony_ci#include "wnm_ap.h" 47e5b75505Sopenharmony_ci#include "hw_features.h" 48e5b75505Sopenharmony_ci#include "ieee802_11.h" 49e5b75505Sopenharmony_ci#include "dfs.h" 50e5b75505Sopenharmony_ci#include "mbo_ap.h" 51e5b75505Sopenharmony_ci#include "rrm.h" 52e5b75505Sopenharmony_ci#include "taxonomy.h" 53e5b75505Sopenharmony_ci#include "fils_hlp.h" 54e5b75505Sopenharmony_ci#include "dpp_hostapd.h" 55e5b75505Sopenharmony_ci#include "gas_query_ap.h" 56e5b75505Sopenharmony_ci 57e5b75505Sopenharmony_ci 58e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 59e5b75505Sopenharmony_cistatic struct wpabuf * 60e5b75505Sopenharmony_ciprepare_auth_resp_fils(struct hostapd_data *hapd, 61e5b75505Sopenharmony_ci struct sta_info *sta, u16 *resp, 62e5b75505Sopenharmony_ci struct rsn_pmksa_cache_entry *pmksa, 63e5b75505Sopenharmony_ci struct wpabuf *erp_resp, 64e5b75505Sopenharmony_ci const u8 *msk, size_t msk_len, 65e5b75505Sopenharmony_ci int *is_pub); 66e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 67e5b75505Sopenharmony_cistatic void handle_auth(struct hostapd_data *hapd, 68e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len, 69e5b75505Sopenharmony_ci int rssi, int from_queue); 70e5b75505Sopenharmony_ci 71e5b75505Sopenharmony_ci 72e5b75505Sopenharmony_ciu8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid) 73e5b75505Sopenharmony_ci{ 74e5b75505Sopenharmony_ci u8 multi_ap_val = 0; 75e5b75505Sopenharmony_ci 76e5b75505Sopenharmony_ci if (!hapd->conf->multi_ap) 77e5b75505Sopenharmony_ci return eid; 78e5b75505Sopenharmony_ci if (hapd->conf->multi_ap & BACKHAUL_BSS) 79e5b75505Sopenharmony_ci multi_ap_val |= MULTI_AP_BACKHAUL_BSS; 80e5b75505Sopenharmony_ci if (hapd->conf->multi_ap & FRONTHAUL_BSS) 81e5b75505Sopenharmony_ci multi_ap_val |= MULTI_AP_FRONTHAUL_BSS; 82e5b75505Sopenharmony_ci 83e5b75505Sopenharmony_ci return eid + add_multi_ap_ie(eid, 9, multi_ap_val); 84e5b75505Sopenharmony_ci} 85e5b75505Sopenharmony_ci 86e5b75505Sopenharmony_ci 87e5b75505Sopenharmony_ciu8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) 88e5b75505Sopenharmony_ci{ 89e5b75505Sopenharmony_ci u8 *pos = eid; 90e5b75505Sopenharmony_ci int i, num, count; 91e5b75505Sopenharmony_ci 92e5b75505Sopenharmony_ci if (hapd->iface->current_rates == NULL) 93e5b75505Sopenharmony_ci return eid; 94e5b75505Sopenharmony_ci 95e5b75505Sopenharmony_ci *pos++ = WLAN_EID_SUPP_RATES; 96e5b75505Sopenharmony_ci num = hapd->iface->num_rates; 97e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) 98e5b75505Sopenharmony_ci num++; 99e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) 100e5b75505Sopenharmony_ci num++; 101e5b75505Sopenharmony_ci if (num > 8) { 102e5b75505Sopenharmony_ci /* rest of the rates are encoded in Extended supported 103e5b75505Sopenharmony_ci * rates element */ 104e5b75505Sopenharmony_ci num = 8; 105e5b75505Sopenharmony_ci } 106e5b75505Sopenharmony_ci 107e5b75505Sopenharmony_ci *pos++ = num; 108e5b75505Sopenharmony_ci for (i = 0, count = 0; i < hapd->iface->num_rates && count < num; 109e5b75505Sopenharmony_ci i++) { 110e5b75505Sopenharmony_ci count++; 111e5b75505Sopenharmony_ci *pos = hapd->iface->current_rates[i].rate / 5; 112e5b75505Sopenharmony_ci if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) 113e5b75505Sopenharmony_ci *pos |= 0x80; 114e5b75505Sopenharmony_ci pos++; 115e5b75505Sopenharmony_ci } 116e5b75505Sopenharmony_ci 117e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) { 118e5b75505Sopenharmony_ci count++; 119e5b75505Sopenharmony_ci *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; 120e5b75505Sopenharmony_ci } 121e5b75505Sopenharmony_ci 122e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) { 123e5b75505Sopenharmony_ci count++; 124e5b75505Sopenharmony_ci *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; 125e5b75505Sopenharmony_ci } 126e5b75505Sopenharmony_ci 127e5b75505Sopenharmony_ci return pos; 128e5b75505Sopenharmony_ci} 129e5b75505Sopenharmony_ci 130e5b75505Sopenharmony_ci 131e5b75505Sopenharmony_ciu8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) 132e5b75505Sopenharmony_ci{ 133e5b75505Sopenharmony_ci u8 *pos = eid; 134e5b75505Sopenharmony_ci int i, num, count; 135e5b75505Sopenharmony_ci 136e5b75505Sopenharmony_ci if (hapd->iface->current_rates == NULL) 137e5b75505Sopenharmony_ci return eid; 138e5b75505Sopenharmony_ci 139e5b75505Sopenharmony_ci num = hapd->iface->num_rates; 140e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) 141e5b75505Sopenharmony_ci num++; 142e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) 143e5b75505Sopenharmony_ci num++; 144e5b75505Sopenharmony_ci if (num <= 8) 145e5b75505Sopenharmony_ci return eid; 146e5b75505Sopenharmony_ci num -= 8; 147e5b75505Sopenharmony_ci 148e5b75505Sopenharmony_ci *pos++ = WLAN_EID_EXT_SUPP_RATES; 149e5b75505Sopenharmony_ci *pos++ = num; 150e5b75505Sopenharmony_ci for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8; 151e5b75505Sopenharmony_ci i++) { 152e5b75505Sopenharmony_ci count++; 153e5b75505Sopenharmony_ci if (count <= 8) 154e5b75505Sopenharmony_ci continue; /* already in SuppRates IE */ 155e5b75505Sopenharmony_ci *pos = hapd->iface->current_rates[i].rate / 5; 156e5b75505Sopenharmony_ci if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) 157e5b75505Sopenharmony_ci *pos |= 0x80; 158e5b75505Sopenharmony_ci pos++; 159e5b75505Sopenharmony_ci } 160e5b75505Sopenharmony_ci 161e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) { 162e5b75505Sopenharmony_ci count++; 163e5b75505Sopenharmony_ci if (count > 8) 164e5b75505Sopenharmony_ci *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY; 165e5b75505Sopenharmony_ci } 166e5b75505Sopenharmony_ci 167e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) { 168e5b75505Sopenharmony_ci count++; 169e5b75505Sopenharmony_ci if (count > 8) 170e5b75505Sopenharmony_ci *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; 171e5b75505Sopenharmony_ci } 172e5b75505Sopenharmony_ci 173e5b75505Sopenharmony_ci return pos; 174e5b75505Sopenharmony_ci} 175e5b75505Sopenharmony_ci 176e5b75505Sopenharmony_ci 177e5b75505Sopenharmony_ciu16 hostapd_own_capab_info(struct hostapd_data *hapd) 178e5b75505Sopenharmony_ci{ 179e5b75505Sopenharmony_ci int capab = WLAN_CAPABILITY_ESS; 180e5b75505Sopenharmony_ci int privacy; 181e5b75505Sopenharmony_ci int dfs; 182e5b75505Sopenharmony_ci int i; 183e5b75505Sopenharmony_ci 184e5b75505Sopenharmony_ci /* Check if any of configured channels require DFS */ 185e5b75505Sopenharmony_ci dfs = hostapd_is_dfs_required(hapd->iface); 186e5b75505Sopenharmony_ci if (dfs < 0) { 187e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, "Failed to check if DFS is required; ret=%d", 188e5b75505Sopenharmony_ci dfs); 189e5b75505Sopenharmony_ci dfs = 0; 190e5b75505Sopenharmony_ci } 191e5b75505Sopenharmony_ci 192e5b75505Sopenharmony_ci if (hapd->iface->num_sta_no_short_preamble == 0 && 193e5b75505Sopenharmony_ci hapd->iconf->preamble == SHORT_PREAMBLE) 194e5b75505Sopenharmony_ci capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; 195e5b75505Sopenharmony_ci 196e5b75505Sopenharmony_ci privacy = hapd->conf->ssid.wep.keys_set; 197e5b75505Sopenharmony_ci 198e5b75505Sopenharmony_ci if (hapd->conf->ieee802_1x && 199e5b75505Sopenharmony_ci (hapd->conf->default_wep_key_len || 200e5b75505Sopenharmony_ci hapd->conf->individual_wep_key_len)) 201e5b75505Sopenharmony_ci privacy = 1; 202e5b75505Sopenharmony_ci 203e5b75505Sopenharmony_ci if (hapd->conf->wpa) 204e5b75505Sopenharmony_ci privacy = 1; 205e5b75505Sopenharmony_ci 206e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 207e5b75505Sopenharmony_ci if (hapd->conf->osen) 208e5b75505Sopenharmony_ci privacy = 1; 209e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 210e5b75505Sopenharmony_ci 211e5b75505Sopenharmony_ci if (privacy) 212e5b75505Sopenharmony_ci capab |= WLAN_CAPABILITY_PRIVACY; 213e5b75505Sopenharmony_ci 214e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 215e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && 216e5b75505Sopenharmony_ci hapd->iface->num_sta_no_short_slot_time == 0) 217e5b75505Sopenharmony_ci capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; 218e5b75505Sopenharmony_ci 219e5b75505Sopenharmony_ci /* 220e5b75505Sopenharmony_ci * Currently, Spectrum Management capability bit is set when directly 221e5b75505Sopenharmony_ci * requested in configuration by spectrum_mgmt_required or when AP is 222e5b75505Sopenharmony_ci * running on DFS channel. 223e5b75505Sopenharmony_ci * TODO: Also consider driver support for TPC to set Spectrum Mgmt bit 224e5b75505Sopenharmony_ci */ 225e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 226e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && 227e5b75505Sopenharmony_ci (hapd->iconf->spectrum_mgmt_required || dfs)) 228e5b75505Sopenharmony_ci capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; 229e5b75505Sopenharmony_ci 230e5b75505Sopenharmony_ci for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) { 231e5b75505Sopenharmony_ci if (hapd->conf->radio_measurements[i]) { 232e5b75505Sopenharmony_ci capab |= IEEE80211_CAP_RRM; 233e5b75505Sopenharmony_ci break; 234e5b75505Sopenharmony_ci } 235e5b75505Sopenharmony_ci } 236e5b75505Sopenharmony_ci 237e5b75505Sopenharmony_ci return capab; 238e5b75505Sopenharmony_ci} 239e5b75505Sopenharmony_ci 240e5b75505Sopenharmony_ci 241e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RC4 242e5b75505Sopenharmony_cistatic u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, 243e5b75505Sopenharmony_ci u16 auth_transaction, const u8 *challenge, 244e5b75505Sopenharmony_ci int iswep) 245e5b75505Sopenharmony_ci{ 246e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 247e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 248e5b75505Sopenharmony_ci "authentication (shared key, transaction %d)", 249e5b75505Sopenharmony_ci auth_transaction); 250e5b75505Sopenharmony_ci 251e5b75505Sopenharmony_ci if (auth_transaction == 1) { 252e5b75505Sopenharmony_ci if (!sta->challenge) { 253e5b75505Sopenharmony_ci /* Generate a pseudo-random challenge */ 254e5b75505Sopenharmony_ci u8 key[8]; 255e5b75505Sopenharmony_ci 256e5b75505Sopenharmony_ci sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN); 257e5b75505Sopenharmony_ci if (sta->challenge == NULL) 258e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 259e5b75505Sopenharmony_ci 260e5b75505Sopenharmony_ci if (os_get_random(key, sizeof(key)) < 0) { 261e5b75505Sopenharmony_ci os_free(sta->challenge); 262e5b75505Sopenharmony_ci sta->challenge = NULL; 263e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 264e5b75505Sopenharmony_ci } 265e5b75505Sopenharmony_ci 266e5b75505Sopenharmony_ci rc4_skip(key, sizeof(key), 0, 267e5b75505Sopenharmony_ci sta->challenge, WLAN_AUTH_CHALLENGE_LEN); 268e5b75505Sopenharmony_ci } 269e5b75505Sopenharmony_ci return 0; 270e5b75505Sopenharmony_ci } 271e5b75505Sopenharmony_ci 272e5b75505Sopenharmony_ci if (auth_transaction != 3) 273e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 274e5b75505Sopenharmony_ci 275e5b75505Sopenharmony_ci /* Transaction 3 */ 276e5b75505Sopenharmony_ci if (!iswep || !sta->challenge || !challenge || 277e5b75505Sopenharmony_ci os_memcmp_const(sta->challenge, challenge, 278e5b75505Sopenharmony_ci WLAN_AUTH_CHALLENGE_LEN)) { 279e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 280e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 281e5b75505Sopenharmony_ci "shared key authentication - invalid " 282e5b75505Sopenharmony_ci "challenge-response"); 283e5b75505Sopenharmony_ci return WLAN_STATUS_CHALLENGE_FAIL; 284e5b75505Sopenharmony_ci } 285e5b75505Sopenharmony_ci 286e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 287e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 288e5b75505Sopenharmony_ci "authentication OK (shared key)"); 289e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 290e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 291e5b75505Sopenharmony_ci os_free(sta->challenge); 292e5b75505Sopenharmony_ci sta->challenge = NULL; 293e5b75505Sopenharmony_ci 294e5b75505Sopenharmony_ci return 0; 295e5b75505Sopenharmony_ci} 296e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RC4 */ 297e5b75505Sopenharmony_ci 298e5b75505Sopenharmony_ci 299e5b75505Sopenharmony_cistatic int send_auth_reply(struct hostapd_data *hapd, 300e5b75505Sopenharmony_ci const u8 *dst, const u8 *bssid, 301e5b75505Sopenharmony_ci u16 auth_alg, u16 auth_transaction, u16 resp, 302e5b75505Sopenharmony_ci const u8 *ies, size_t ies_len, const char *dbg) 303e5b75505Sopenharmony_ci{ 304e5b75505Sopenharmony_ci struct ieee80211_mgmt *reply; 305e5b75505Sopenharmony_ci u8 *buf; 306e5b75505Sopenharmony_ci size_t rlen; 307e5b75505Sopenharmony_ci int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE; 308e5b75505Sopenharmony_ci 309e5b75505Sopenharmony_ci rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len; 310e5b75505Sopenharmony_ci buf = os_zalloc(rlen); 311e5b75505Sopenharmony_ci if (buf == NULL) 312e5b75505Sopenharmony_ci return -1; 313e5b75505Sopenharmony_ci 314e5b75505Sopenharmony_ci reply = (struct ieee80211_mgmt *) buf; 315e5b75505Sopenharmony_ci reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 316e5b75505Sopenharmony_ci WLAN_FC_STYPE_AUTH); 317e5b75505Sopenharmony_ci os_memcpy(reply->da, dst, ETH_ALEN); 318e5b75505Sopenharmony_ci os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); 319e5b75505Sopenharmony_ci os_memcpy(reply->bssid, bssid, ETH_ALEN); 320e5b75505Sopenharmony_ci 321e5b75505Sopenharmony_ci reply->u.auth.auth_alg = host_to_le16(auth_alg); 322e5b75505Sopenharmony_ci reply->u.auth.auth_transaction = host_to_le16(auth_transaction); 323e5b75505Sopenharmony_ci reply->u.auth.status_code = host_to_le16(resp); 324e5b75505Sopenharmony_ci 325e5b75505Sopenharmony_ci if (ies && ies_len) 326e5b75505Sopenharmony_ci os_memcpy(reply->u.auth.variable, ies, ies_len); 327e5b75505Sopenharmony_ci 328e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR 329e5b75505Sopenharmony_ci " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)", 330e5b75505Sopenharmony_ci MAC2STR(dst), auth_alg, auth_transaction, 331e5b75505Sopenharmony_ci resp, (unsigned long) ies_len, dbg); 332e5b75505Sopenharmony_ci if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0) 333e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "send_auth_reply: send failed"); 334e5b75505Sopenharmony_ci else 335e5b75505Sopenharmony_ci reply_res = WLAN_STATUS_SUCCESS; 336e5b75505Sopenharmony_ci 337e5b75505Sopenharmony_ci os_free(buf); 338e5b75505Sopenharmony_ci 339e5b75505Sopenharmony_ci return reply_res; 340e5b75505Sopenharmony_ci} 341e5b75505Sopenharmony_ci 342e5b75505Sopenharmony_ci 343e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 344e5b75505Sopenharmony_cistatic void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, 345e5b75505Sopenharmony_ci u16 auth_transaction, u16 status, 346e5b75505Sopenharmony_ci const u8 *ies, size_t ies_len) 347e5b75505Sopenharmony_ci{ 348e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 349e5b75505Sopenharmony_ci struct sta_info *sta; 350e5b75505Sopenharmony_ci int reply_res; 351e5b75505Sopenharmony_ci 352e5b75505Sopenharmony_ci reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, 353e5b75505Sopenharmony_ci auth_transaction, status, ies, ies_len, 354e5b75505Sopenharmony_ci "auth-ft-finish"); 355e5b75505Sopenharmony_ci 356e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, dst); 357e5b75505Sopenharmony_ci if (sta == NULL) 358e5b75505Sopenharmony_ci return; 359e5b75505Sopenharmony_ci 360e5b75505Sopenharmony_ci if (sta->added_unassoc && (reply_res != WLAN_STATUS_SUCCESS || 361e5b75505Sopenharmony_ci status != WLAN_STATUS_SUCCESS)) { 362e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 363e5b75505Sopenharmony_ci sta->added_unassoc = 0; 364e5b75505Sopenharmony_ci return; 365e5b75505Sopenharmony_ci } 366e5b75505Sopenharmony_ci 367e5b75505Sopenharmony_ci if (status != WLAN_STATUS_SUCCESS) 368e5b75505Sopenharmony_ci return; 369e5b75505Sopenharmony_ci 370e5b75505Sopenharmony_ci hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 371e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 372e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 373e5b75505Sopenharmony_ci mlme_authenticate_indication(hapd, sta); 374e5b75505Sopenharmony_ci} 375e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 376e5b75505Sopenharmony_ci 377e5b75505Sopenharmony_ci 378e5b75505Sopenharmony_ci#ifdef CONFIG_SAE 379e5b75505Sopenharmony_ci 380e5b75505Sopenharmony_cistatic void sae_set_state(struct sta_info *sta, enum sae_state state, 381e5b75505Sopenharmony_ci const char *reason) 382e5b75505Sopenharmony_ci{ 383e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: State %s -> %s for peer " MACSTR " (%s)", 384e5b75505Sopenharmony_ci sae_state_txt(sta->sae->state), sae_state_txt(state), 385e5b75505Sopenharmony_ci MAC2STR(sta->addr), reason); 386e5b75505Sopenharmony_ci sta->sae->state = state; 387e5b75505Sopenharmony_ci} 388e5b75505Sopenharmony_ci 389e5b75505Sopenharmony_ci 390e5b75505Sopenharmony_cistatic struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, 391e5b75505Sopenharmony_ci struct sta_info *sta, int update) 392e5b75505Sopenharmony_ci{ 393e5b75505Sopenharmony_ci struct wpabuf *buf; 394e5b75505Sopenharmony_ci const char *password = NULL; 395e5b75505Sopenharmony_ci struct sae_password_entry *pw; 396e5b75505Sopenharmony_ci const char *rx_id = NULL; 397e5b75505Sopenharmony_ci 398e5b75505Sopenharmony_ci if (sta->sae->tmp) 399e5b75505Sopenharmony_ci rx_id = sta->sae->tmp->pw_id; 400e5b75505Sopenharmony_ci 401e5b75505Sopenharmony_ci for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) { 402e5b75505Sopenharmony_ci if (!is_broadcast_ether_addr(pw->peer_addr) && 403e5b75505Sopenharmony_ci os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0) 404e5b75505Sopenharmony_ci continue; 405e5b75505Sopenharmony_ci if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier)) 406e5b75505Sopenharmony_ci continue; 407e5b75505Sopenharmony_ci if (rx_id && pw->identifier && 408e5b75505Sopenharmony_ci os_strcmp(rx_id, pw->identifier) != 0) 409e5b75505Sopenharmony_ci continue; 410e5b75505Sopenharmony_ci password = pw->password; 411e5b75505Sopenharmony_ci break; 412e5b75505Sopenharmony_ci } 413e5b75505Sopenharmony_ci if (!password) 414e5b75505Sopenharmony_ci password = hapd->conf->ssid.wpa_passphrase; 415e5b75505Sopenharmony_ci if (!password) { 416e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: No password available"); 417e5b75505Sopenharmony_ci return NULL; 418e5b75505Sopenharmony_ci } 419e5b75505Sopenharmony_ci 420e5b75505Sopenharmony_ci if (update && 421e5b75505Sopenharmony_ci sae_prepare_commit(hapd->own_addr, sta->addr, 422e5b75505Sopenharmony_ci (u8 *) password, os_strlen(password), rx_id, 423e5b75505Sopenharmony_ci sta->sae) < 0) { 424e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); 425e5b75505Sopenharmony_ci return NULL; 426e5b75505Sopenharmony_ci } 427e5b75505Sopenharmony_ci 428e5b75505Sopenharmony_ci if (pw && pw->vlan_id) { 429e5b75505Sopenharmony_ci if (!sta->sae->tmp) { 430e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 431e5b75505Sopenharmony_ci "SAE: No temporary data allocated - cannot store VLAN ID"); 432e5b75505Sopenharmony_ci return NULL; 433e5b75505Sopenharmony_ci } 434e5b75505Sopenharmony_ci sta->sae->tmp->vlan_id = pw->vlan_id; 435e5b75505Sopenharmony_ci } 436e5b75505Sopenharmony_ci 437e5b75505Sopenharmony_ci buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN + 438e5b75505Sopenharmony_ci (rx_id ? 3 + os_strlen(rx_id) : 0)); 439e5b75505Sopenharmony_ci if (buf == NULL) 440e5b75505Sopenharmony_ci return NULL; 441e5b75505Sopenharmony_ci sae_write_commit(sta->sae, buf, sta->sae->tmp ? 442e5b75505Sopenharmony_ci sta->sae->tmp->anti_clogging_token : NULL, rx_id); 443e5b75505Sopenharmony_ci 444e5b75505Sopenharmony_ci return buf; 445e5b75505Sopenharmony_ci} 446e5b75505Sopenharmony_ci 447e5b75505Sopenharmony_ci 448e5b75505Sopenharmony_cistatic struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, 449e5b75505Sopenharmony_ci struct sta_info *sta) 450e5b75505Sopenharmony_ci{ 451e5b75505Sopenharmony_ci struct wpabuf *buf; 452e5b75505Sopenharmony_ci 453e5b75505Sopenharmony_ci buf = wpabuf_alloc(SAE_CONFIRM_MAX_LEN); 454e5b75505Sopenharmony_ci if (buf == NULL) 455e5b75505Sopenharmony_ci return NULL; 456e5b75505Sopenharmony_ci 457e5b75505Sopenharmony_ci sae_write_confirm(sta->sae, buf); 458e5b75505Sopenharmony_ci 459e5b75505Sopenharmony_ci return buf; 460e5b75505Sopenharmony_ci} 461e5b75505Sopenharmony_ci 462e5b75505Sopenharmony_ci 463e5b75505Sopenharmony_cistatic int auth_sae_send_commit(struct hostapd_data *hapd, 464e5b75505Sopenharmony_ci struct sta_info *sta, 465e5b75505Sopenharmony_ci const u8 *bssid, int update) 466e5b75505Sopenharmony_ci{ 467e5b75505Sopenharmony_ci struct wpabuf *data; 468e5b75505Sopenharmony_ci int reply_res; 469e5b75505Sopenharmony_ci 470e5b75505Sopenharmony_ci data = auth_build_sae_commit(hapd, sta, update); 471e5b75505Sopenharmony_ci if (!data && sta->sae->tmp && sta->sae->tmp->pw_id) 472e5b75505Sopenharmony_ci return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER; 473e5b75505Sopenharmony_ci if (data == NULL) 474e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 475e5b75505Sopenharmony_ci 476e5b75505Sopenharmony_ci reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1, 477e5b75505Sopenharmony_ci WLAN_STATUS_SUCCESS, wpabuf_head(data), 478e5b75505Sopenharmony_ci wpabuf_len(data), "sae-send-commit"); 479e5b75505Sopenharmony_ci 480e5b75505Sopenharmony_ci wpabuf_free(data); 481e5b75505Sopenharmony_ci 482e5b75505Sopenharmony_ci return reply_res; 483e5b75505Sopenharmony_ci} 484e5b75505Sopenharmony_ci 485e5b75505Sopenharmony_ci 486e5b75505Sopenharmony_cistatic int auth_sae_send_confirm(struct hostapd_data *hapd, 487e5b75505Sopenharmony_ci struct sta_info *sta, 488e5b75505Sopenharmony_ci const u8 *bssid) 489e5b75505Sopenharmony_ci{ 490e5b75505Sopenharmony_ci struct wpabuf *data; 491e5b75505Sopenharmony_ci int reply_res; 492e5b75505Sopenharmony_ci 493e5b75505Sopenharmony_ci data = auth_build_sae_confirm(hapd, sta); 494e5b75505Sopenharmony_ci if (data == NULL) 495e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 496e5b75505Sopenharmony_ci 497e5b75505Sopenharmony_ci reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2, 498e5b75505Sopenharmony_ci WLAN_STATUS_SUCCESS, wpabuf_head(data), 499e5b75505Sopenharmony_ci wpabuf_len(data), "sae-send-confirm"); 500e5b75505Sopenharmony_ci 501e5b75505Sopenharmony_ci wpabuf_free(data); 502e5b75505Sopenharmony_ci 503e5b75505Sopenharmony_ci return reply_res; 504e5b75505Sopenharmony_ci} 505e5b75505Sopenharmony_ci 506e5b75505Sopenharmony_ci 507e5b75505Sopenharmony_cistatic int use_sae_anti_clogging(struct hostapd_data *hapd) 508e5b75505Sopenharmony_ci{ 509e5b75505Sopenharmony_ci struct sta_info *sta; 510e5b75505Sopenharmony_ci unsigned int open = 0; 511e5b75505Sopenharmony_ci 512e5b75505Sopenharmony_ci if (hapd->conf->sae_anti_clogging_threshold == 0) 513e5b75505Sopenharmony_ci return 1; 514e5b75505Sopenharmony_ci 515e5b75505Sopenharmony_ci for (sta = hapd->sta_list; sta; sta = sta->next) { 516e5b75505Sopenharmony_ci if (!sta->sae) 517e5b75505Sopenharmony_ci continue; 518e5b75505Sopenharmony_ci if (sta->sae->state != SAE_COMMITTED && 519e5b75505Sopenharmony_ci sta->sae->state != SAE_CONFIRMED) 520e5b75505Sopenharmony_ci continue; 521e5b75505Sopenharmony_ci open++; 522e5b75505Sopenharmony_ci if (open >= hapd->conf->sae_anti_clogging_threshold) 523e5b75505Sopenharmony_ci return 1; 524e5b75505Sopenharmony_ci } 525e5b75505Sopenharmony_ci 526e5b75505Sopenharmony_ci /* In addition to already existing open SAE sessions, check whether 527e5b75505Sopenharmony_ci * there are enough pending commit messages in the processing queue to 528e5b75505Sopenharmony_ci * potentially result in too many open sessions. */ 529e5b75505Sopenharmony_ci if (open + dl_list_len(&hapd->sae_commit_queue) >= 530e5b75505Sopenharmony_ci hapd->conf->sae_anti_clogging_threshold) 531e5b75505Sopenharmony_ci return 1; 532e5b75505Sopenharmony_ci 533e5b75505Sopenharmony_ci return 0; 534e5b75505Sopenharmony_ci} 535e5b75505Sopenharmony_ci 536e5b75505Sopenharmony_ci 537e5b75505Sopenharmony_cistatic u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr) 538e5b75505Sopenharmony_ci{ 539e5b75505Sopenharmony_ci u8 hash[SHA256_MAC_LEN]; 540e5b75505Sopenharmony_ci 541e5b75505Sopenharmony_ci hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), 542e5b75505Sopenharmony_ci addr, ETH_ALEN, hash); 543e5b75505Sopenharmony_ci return hash[0]; 544e5b75505Sopenharmony_ci} 545e5b75505Sopenharmony_ci 546e5b75505Sopenharmony_ci 547e5b75505Sopenharmony_cistatic int check_sae_token(struct hostapd_data *hapd, const u8 *addr, 548e5b75505Sopenharmony_ci const u8 *token, size_t token_len) 549e5b75505Sopenharmony_ci{ 550e5b75505Sopenharmony_ci u8 mac[SHA256_MAC_LEN]; 551e5b75505Sopenharmony_ci const u8 *addrs[2]; 552e5b75505Sopenharmony_ci size_t len[2]; 553e5b75505Sopenharmony_ci u16 token_idx; 554e5b75505Sopenharmony_ci u8 idx; 555e5b75505Sopenharmony_ci 556e5b75505Sopenharmony_ci if (token_len != SHA256_MAC_LEN) 557e5b75505Sopenharmony_ci return -1; 558e5b75505Sopenharmony_ci idx = sae_token_hash(hapd, addr); 559e5b75505Sopenharmony_ci token_idx = hapd->sae_pending_token_idx[idx]; 560e5b75505Sopenharmony_ci if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) { 561e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from " 562e5b75505Sopenharmony_ci MACSTR " - token_idx 0x%04x, expected 0x%04x", 563e5b75505Sopenharmony_ci MAC2STR(addr), WPA_GET_BE16(token), token_idx); 564e5b75505Sopenharmony_ci return -1; 565e5b75505Sopenharmony_ci } 566e5b75505Sopenharmony_ci 567e5b75505Sopenharmony_ci addrs[0] = addr; 568e5b75505Sopenharmony_ci len[0] = ETH_ALEN; 569e5b75505Sopenharmony_ci addrs[1] = token; 570e5b75505Sopenharmony_ci len[1] = 2; 571e5b75505Sopenharmony_ci if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key), 572e5b75505Sopenharmony_ci 2, addrs, len, mac) < 0 || 573e5b75505Sopenharmony_ci os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0) 574e5b75505Sopenharmony_ci return -1; 575e5b75505Sopenharmony_ci 576e5b75505Sopenharmony_ci hapd->sae_pending_token_idx[idx] = 0; /* invalidate used token */ 577e5b75505Sopenharmony_ci 578e5b75505Sopenharmony_ci return 0; 579e5b75505Sopenharmony_ci} 580e5b75505Sopenharmony_ci 581e5b75505Sopenharmony_ci 582e5b75505Sopenharmony_cistatic struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, 583e5b75505Sopenharmony_ci int group, const u8 *addr) 584e5b75505Sopenharmony_ci{ 585e5b75505Sopenharmony_ci struct wpabuf *buf; 586e5b75505Sopenharmony_ci u8 *token; 587e5b75505Sopenharmony_ci struct os_reltime now; 588e5b75505Sopenharmony_ci u8 idx[2]; 589e5b75505Sopenharmony_ci const u8 *addrs[2]; 590e5b75505Sopenharmony_ci size_t len[2]; 591e5b75505Sopenharmony_ci u8 p_idx; 592e5b75505Sopenharmony_ci u16 token_idx; 593e5b75505Sopenharmony_ci 594e5b75505Sopenharmony_ci os_get_reltime(&now); 595e5b75505Sopenharmony_ci if (!os_reltime_initialized(&hapd->last_sae_token_key_update) || 596e5b75505Sopenharmony_ci os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60) || 597e5b75505Sopenharmony_ci hapd->sae_token_idx == 0xffff) { 598e5b75505Sopenharmony_ci if (random_get_bytes(hapd->sae_token_key, 599e5b75505Sopenharmony_ci sizeof(hapd->sae_token_key)) < 0) 600e5b75505Sopenharmony_ci return NULL; 601e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "SAE: Updated token key", 602e5b75505Sopenharmony_ci hapd->sae_token_key, sizeof(hapd->sae_token_key)); 603e5b75505Sopenharmony_ci hapd->last_sae_token_key_update = now; 604e5b75505Sopenharmony_ci hapd->sae_token_idx = 0; 605e5b75505Sopenharmony_ci os_memset(hapd->sae_pending_token_idx, 0, 606e5b75505Sopenharmony_ci sizeof(hapd->sae_pending_token_idx)); 607e5b75505Sopenharmony_ci } 608e5b75505Sopenharmony_ci 609e5b75505Sopenharmony_ci buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN); 610e5b75505Sopenharmony_ci if (buf == NULL) 611e5b75505Sopenharmony_ci return NULL; 612e5b75505Sopenharmony_ci 613e5b75505Sopenharmony_ci wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ 614e5b75505Sopenharmony_ci 615e5b75505Sopenharmony_ci p_idx = sae_token_hash(hapd, addr); 616e5b75505Sopenharmony_ci token_idx = hapd->sae_pending_token_idx[p_idx]; 617e5b75505Sopenharmony_ci if (!token_idx) { 618e5b75505Sopenharmony_ci hapd->sae_token_idx++; 619e5b75505Sopenharmony_ci token_idx = hapd->sae_token_idx; 620e5b75505Sopenharmony_ci hapd->sae_pending_token_idx[p_idx] = token_idx; 621e5b75505Sopenharmony_ci } 622e5b75505Sopenharmony_ci WPA_PUT_BE16(idx, token_idx); 623e5b75505Sopenharmony_ci token = wpabuf_put(buf, SHA256_MAC_LEN); 624e5b75505Sopenharmony_ci addrs[0] = addr; 625e5b75505Sopenharmony_ci len[0] = ETH_ALEN; 626e5b75505Sopenharmony_ci addrs[1] = idx; 627e5b75505Sopenharmony_ci len[1] = sizeof(idx); 628e5b75505Sopenharmony_ci if (hmac_sha256_vector(hapd->sae_token_key, sizeof(hapd->sae_token_key), 629e5b75505Sopenharmony_ci 2, addrs, len, token) < 0) { 630e5b75505Sopenharmony_ci wpabuf_free(buf); 631e5b75505Sopenharmony_ci return NULL; 632e5b75505Sopenharmony_ci } 633e5b75505Sopenharmony_ci WPA_PUT_BE16(token, token_idx); 634e5b75505Sopenharmony_ci 635e5b75505Sopenharmony_ci return buf; 636e5b75505Sopenharmony_ci} 637e5b75505Sopenharmony_ci 638e5b75505Sopenharmony_ci 639e5b75505Sopenharmony_cistatic int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta) 640e5b75505Sopenharmony_ci{ 641e5b75505Sopenharmony_ci if (sta->sae->sync > hapd->conf->sae_sync) { 642e5b75505Sopenharmony_ci sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync"); 643e5b75505Sopenharmony_ci sta->sae->sync = 0; 644e5b75505Sopenharmony_ci return -1; 645e5b75505Sopenharmony_ci } 646e5b75505Sopenharmony_ci return 0; 647e5b75505Sopenharmony_ci} 648e5b75505Sopenharmony_ci 649e5b75505Sopenharmony_ci 650e5b75505Sopenharmony_cistatic void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data) 651e5b75505Sopenharmony_ci{ 652e5b75505Sopenharmony_ci struct hostapd_data *hapd = eloop_ctx; 653e5b75505Sopenharmony_ci struct sta_info *sta = eloop_data; 654e5b75505Sopenharmony_ci int ret; 655e5b75505Sopenharmony_ci 656e5b75505Sopenharmony_ci if (sae_check_big_sync(hapd, sta)) 657e5b75505Sopenharmony_ci return; 658e5b75505Sopenharmony_ci sta->sae->sync++; 659e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR 660e5b75505Sopenharmony_ci " (sync=%d state=%s)", 661e5b75505Sopenharmony_ci MAC2STR(sta->addr), sta->sae->sync, 662e5b75505Sopenharmony_ci sae_state_txt(sta->sae->state)); 663e5b75505Sopenharmony_ci 664e5b75505Sopenharmony_ci switch (sta->sae->state) { 665e5b75505Sopenharmony_ci case SAE_COMMITTED: 666e5b75505Sopenharmony_ci ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0); 667e5b75505Sopenharmony_ci eloop_register_timeout(0, 668e5b75505Sopenharmony_ci hapd->dot11RSNASAERetransPeriod * 1000, 669e5b75505Sopenharmony_ci auth_sae_retransmit_timer, hapd, sta); 670e5b75505Sopenharmony_ci break; 671e5b75505Sopenharmony_ci case SAE_CONFIRMED: 672e5b75505Sopenharmony_ci ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr); 673e5b75505Sopenharmony_ci eloop_register_timeout(0, 674e5b75505Sopenharmony_ci hapd->dot11RSNASAERetransPeriod * 1000, 675e5b75505Sopenharmony_ci auth_sae_retransmit_timer, hapd, sta); 676e5b75505Sopenharmony_ci break; 677e5b75505Sopenharmony_ci default: 678e5b75505Sopenharmony_ci ret = -1; 679e5b75505Sopenharmony_ci break; 680e5b75505Sopenharmony_ci } 681e5b75505Sopenharmony_ci 682e5b75505Sopenharmony_ci if (ret != WLAN_STATUS_SUCCESS) 683e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret); 684e5b75505Sopenharmony_ci} 685e5b75505Sopenharmony_ci 686e5b75505Sopenharmony_ci 687e5b75505Sopenharmony_civoid sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta) 688e5b75505Sopenharmony_ci{ 689e5b75505Sopenharmony_ci eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta); 690e5b75505Sopenharmony_ci} 691e5b75505Sopenharmony_ci 692e5b75505Sopenharmony_ci 693e5b75505Sopenharmony_cistatic void sae_set_retransmit_timer(struct hostapd_data *hapd, 694e5b75505Sopenharmony_ci struct sta_info *sta) 695e5b75505Sopenharmony_ci{ 696e5b75505Sopenharmony_ci if (!(hapd->conf->mesh & MESH_ENABLED)) 697e5b75505Sopenharmony_ci return; 698e5b75505Sopenharmony_ci 699e5b75505Sopenharmony_ci eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta); 700e5b75505Sopenharmony_ci eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000, 701e5b75505Sopenharmony_ci auth_sae_retransmit_timer, hapd, sta); 702e5b75505Sopenharmony_ci} 703e5b75505Sopenharmony_ci 704e5b75505Sopenharmony_ci 705e5b75505Sopenharmony_cistatic void sae_sme_send_external_auth_status(struct hostapd_data *hapd, 706e5b75505Sopenharmony_ci struct sta_info *sta, u16 status) 707e5b75505Sopenharmony_ci{ 708e5b75505Sopenharmony_ci struct external_auth params; 709e5b75505Sopenharmony_ci 710e5b75505Sopenharmony_ci os_memset(¶ms, 0, sizeof(params)); 711e5b75505Sopenharmony_ci params.status = status; 712e5b75505Sopenharmony_ci params.bssid = sta->addr; 713e5b75505Sopenharmony_ci if (status == WLAN_STATUS_SUCCESS && sta->sae && 714e5b75505Sopenharmony_ci !hapd->conf->disable_pmksa_caching) 715e5b75505Sopenharmony_ci params.pmkid = sta->sae->pmkid; 716e5b75505Sopenharmony_ci 717e5b75505Sopenharmony_ci hostapd_drv_send_external_auth_status(hapd, ¶ms); 718e5b75505Sopenharmony_ci} 719e5b75505Sopenharmony_ci 720e5b75505Sopenharmony_ci 721e5b75505Sopenharmony_civoid sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta) 722e5b75505Sopenharmony_ci{ 723e5b75505Sopenharmony_ci#ifndef CONFIG_NO_VLAN 724e5b75505Sopenharmony_ci struct vlan_description vlan_desc; 725e5b75505Sopenharmony_ci 726e5b75505Sopenharmony_ci if (sta->sae->tmp && sta->sae->tmp->vlan_id > 0) { 727e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Assign STA " MACSTR 728e5b75505Sopenharmony_ci " to VLAN ID %d", 729e5b75505Sopenharmony_ci MAC2STR(sta->addr), sta->sae->tmp->vlan_id); 730e5b75505Sopenharmony_ci 731e5b75505Sopenharmony_ci os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 732e5b75505Sopenharmony_ci vlan_desc.notempty = 1; 733e5b75505Sopenharmony_ci vlan_desc.untagged = sta->sae->tmp->vlan_id; 734e5b75505Sopenharmony_ci if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 735e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 736e5b75505Sopenharmony_ci "Invalid VLAN ID %d in sae_password", 737e5b75505Sopenharmony_ci sta->sae->tmp->vlan_id); 738e5b75505Sopenharmony_ci return; 739e5b75505Sopenharmony_ci } 740e5b75505Sopenharmony_ci 741e5b75505Sopenharmony_ci if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 || 742e5b75505Sopenharmony_ci ap_sta_bind_vlan(hapd, sta) < 0) { 743e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 744e5b75505Sopenharmony_ci "Failed to assign VLAN ID %d from sae_password to " 745e5b75505Sopenharmony_ci MACSTR, sta->sae->tmp->vlan_id, 746e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 747e5b75505Sopenharmony_ci return; 748e5b75505Sopenharmony_ci } 749e5b75505Sopenharmony_ci } 750e5b75505Sopenharmony_ci#endif /* CONFIG_NO_VLAN */ 751e5b75505Sopenharmony_ci 752e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 753e5b75505Sopenharmony_ci sta->auth_alg = WLAN_AUTH_SAE; 754e5b75505Sopenharmony_ci mlme_authenticate_indication(hapd, sta); 755e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 756e5b75505Sopenharmony_ci sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm"); 757e5b75505Sopenharmony_ci wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr, 758e5b75505Sopenharmony_ci sta->sae->pmk, sta->sae->pmkid); 759e5b75505Sopenharmony_ci sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS); 760e5b75505Sopenharmony_ci} 761e5b75505Sopenharmony_ci 762e5b75505Sopenharmony_ci 763e5b75505Sopenharmony_cistatic int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, 764e5b75505Sopenharmony_ci const u8 *bssid, u8 auth_transaction, int allow_reuse, 765e5b75505Sopenharmony_ci int *sta_removed) 766e5b75505Sopenharmony_ci{ 767e5b75505Sopenharmony_ci int ret; 768e5b75505Sopenharmony_ci 769e5b75505Sopenharmony_ci *sta_removed = 0; 770e5b75505Sopenharmony_ci 771e5b75505Sopenharmony_ci if (auth_transaction != 1 && auth_transaction != 2) 772e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 773e5b75505Sopenharmony_ci 774e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR " state=%s auth_trans=%u", 775e5b75505Sopenharmony_ci MAC2STR(sta->addr), sae_state_txt(sta->sae->state), 776e5b75505Sopenharmony_ci auth_transaction); 777e5b75505Sopenharmony_ci switch (sta->sae->state) { 778e5b75505Sopenharmony_ci case SAE_NOTHING: 779e5b75505Sopenharmony_ci if (auth_transaction == 1) { 780e5b75505Sopenharmony_ci ret = auth_sae_send_commit(hapd, sta, bssid, 781e5b75505Sopenharmony_ci !allow_reuse); 782e5b75505Sopenharmony_ci if (ret) 783e5b75505Sopenharmony_ci return ret; 784e5b75505Sopenharmony_ci sae_set_state(sta, SAE_COMMITTED, "Sent Commit"); 785e5b75505Sopenharmony_ci 786e5b75505Sopenharmony_ci if (sae_process_commit(sta->sae) < 0) 787e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 788e5b75505Sopenharmony_ci 789e5b75505Sopenharmony_ci /* 790e5b75505Sopenharmony_ci * In mesh case, both Commit and Confirm can be sent 791e5b75505Sopenharmony_ci * immediately. In infrastructure BSS, only a single 792e5b75505Sopenharmony_ci * Authentication frame (Commit) is expected from the AP 793e5b75505Sopenharmony_ci * here and the second one (Confirm) will be sent once 794e5b75505Sopenharmony_ci * the STA has sent its second Authentication frame 795e5b75505Sopenharmony_ci * (Confirm). 796e5b75505Sopenharmony_ci */ 797e5b75505Sopenharmony_ci if (hapd->conf->mesh & MESH_ENABLED) { 798e5b75505Sopenharmony_ci /* 799e5b75505Sopenharmony_ci * Send both Commit and Confirm immediately 800e5b75505Sopenharmony_ci * based on SAE finite state machine 801e5b75505Sopenharmony_ci * Nothing -> Confirm transition. 802e5b75505Sopenharmony_ci */ 803e5b75505Sopenharmony_ci ret = auth_sae_send_confirm(hapd, sta, bssid); 804e5b75505Sopenharmony_ci if (ret) 805e5b75505Sopenharmony_ci return ret; 806e5b75505Sopenharmony_ci sae_set_state(sta, SAE_CONFIRMED, 807e5b75505Sopenharmony_ci "Sent Confirm (mesh)"); 808e5b75505Sopenharmony_ci } else { 809e5b75505Sopenharmony_ci /* 810e5b75505Sopenharmony_ci * For infrastructure BSS, send only the Commit 811e5b75505Sopenharmony_ci * message now to get alternating sequence of 812e5b75505Sopenharmony_ci * Authentication frames between the AP and STA. 813e5b75505Sopenharmony_ci * Confirm will be sent in 814e5b75505Sopenharmony_ci * Committed -> Confirmed/Accepted transition 815e5b75505Sopenharmony_ci * when receiving Confirm from STA. 816e5b75505Sopenharmony_ci */ 817e5b75505Sopenharmony_ci } 818e5b75505Sopenharmony_ci sta->sae->sync = 0; 819e5b75505Sopenharmony_ci sae_set_retransmit_timer(hapd, sta); 820e5b75505Sopenharmony_ci } else { 821e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 822e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 823e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 824e5b75505Sopenharmony_ci "SAE confirm before commit"); 825e5b75505Sopenharmony_ci } 826e5b75505Sopenharmony_ci break; 827e5b75505Sopenharmony_ci case SAE_COMMITTED: 828e5b75505Sopenharmony_ci sae_clear_retransmit_timer(hapd, sta); 829e5b75505Sopenharmony_ci if (auth_transaction == 1) { 830e5b75505Sopenharmony_ci if (sae_process_commit(sta->sae) < 0) 831e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 832e5b75505Sopenharmony_ci 833e5b75505Sopenharmony_ci ret = auth_sae_send_confirm(hapd, sta, bssid); 834e5b75505Sopenharmony_ci if (ret) 835e5b75505Sopenharmony_ci return ret; 836e5b75505Sopenharmony_ci sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm"); 837e5b75505Sopenharmony_ci sta->sae->sync = 0; 838e5b75505Sopenharmony_ci sae_set_retransmit_timer(hapd, sta); 839e5b75505Sopenharmony_ci } else if (hapd->conf->mesh & MESH_ENABLED) { 840e5b75505Sopenharmony_ci /* 841e5b75505Sopenharmony_ci * In mesh case, follow SAE finite state machine and 842e5b75505Sopenharmony_ci * send Commit now, if sync count allows. 843e5b75505Sopenharmony_ci */ 844e5b75505Sopenharmony_ci if (sae_check_big_sync(hapd, sta)) 845e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 846e5b75505Sopenharmony_ci sta->sae->sync++; 847e5b75505Sopenharmony_ci 848e5b75505Sopenharmony_ci ret = auth_sae_send_commit(hapd, sta, bssid, 0); 849e5b75505Sopenharmony_ci if (ret) 850e5b75505Sopenharmony_ci return ret; 851e5b75505Sopenharmony_ci 852e5b75505Sopenharmony_ci sae_set_retransmit_timer(hapd, sta); 853e5b75505Sopenharmony_ci } else { 854e5b75505Sopenharmony_ci /* 855e5b75505Sopenharmony_ci * For instructure BSS, send the postponed Confirm from 856e5b75505Sopenharmony_ci * Nothing -> Confirmed transition that was reduced to 857e5b75505Sopenharmony_ci * Nothing -> Committed above. 858e5b75505Sopenharmony_ci */ 859e5b75505Sopenharmony_ci ret = auth_sae_send_confirm(hapd, sta, bssid); 860e5b75505Sopenharmony_ci if (ret) 861e5b75505Sopenharmony_ci return ret; 862e5b75505Sopenharmony_ci 863e5b75505Sopenharmony_ci sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm"); 864e5b75505Sopenharmony_ci 865e5b75505Sopenharmony_ci /* 866e5b75505Sopenharmony_ci * Since this was triggered on Confirm RX, run another 867e5b75505Sopenharmony_ci * step to get to Accepted without waiting for 868e5b75505Sopenharmony_ci * additional events. 869e5b75505Sopenharmony_ci */ 870e5b75505Sopenharmony_ci return sae_sm_step(hapd, sta, bssid, auth_transaction, 871e5b75505Sopenharmony_ci 0, sta_removed); 872e5b75505Sopenharmony_ci } 873e5b75505Sopenharmony_ci break; 874e5b75505Sopenharmony_ci case SAE_CONFIRMED: 875e5b75505Sopenharmony_ci sae_clear_retransmit_timer(hapd, sta); 876e5b75505Sopenharmony_ci if (auth_transaction == 1) { 877e5b75505Sopenharmony_ci if (sae_check_big_sync(hapd, sta)) 878e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 879e5b75505Sopenharmony_ci sta->sae->sync++; 880e5b75505Sopenharmony_ci 881e5b75505Sopenharmony_ci ret = auth_sae_send_commit(hapd, sta, bssid, 1); 882e5b75505Sopenharmony_ci if (ret) 883e5b75505Sopenharmony_ci return ret; 884e5b75505Sopenharmony_ci 885e5b75505Sopenharmony_ci if (sae_process_commit(sta->sae) < 0) 886e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 887e5b75505Sopenharmony_ci 888e5b75505Sopenharmony_ci ret = auth_sae_send_confirm(hapd, sta, bssid); 889e5b75505Sopenharmony_ci if (ret) 890e5b75505Sopenharmony_ci return ret; 891e5b75505Sopenharmony_ci 892e5b75505Sopenharmony_ci sae_set_retransmit_timer(hapd, sta); 893e5b75505Sopenharmony_ci } else { 894e5b75505Sopenharmony_ci sta->sae->send_confirm = 0xffff; 895e5b75505Sopenharmony_ci sae_accept_sta(hapd, sta); 896e5b75505Sopenharmony_ci } 897e5b75505Sopenharmony_ci break; 898e5b75505Sopenharmony_ci case SAE_ACCEPTED: 899e5b75505Sopenharmony_ci if (auth_transaction == 1 && 900e5b75505Sopenharmony_ci (hapd->conf->mesh & MESH_ENABLED)) { 901e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR 902e5b75505Sopenharmony_ci ") doing reauthentication", 903e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 904e5b75505Sopenharmony_ci wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 905e5b75505Sopenharmony_ci ap_free_sta(hapd, sta); 906e5b75505Sopenharmony_ci *sta_removed = 1; 907e5b75505Sopenharmony_ci } else if (auth_transaction == 1) { 908e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Start reauthentication"); 909e5b75505Sopenharmony_ci ret = auth_sae_send_commit(hapd, sta, bssid, 1); 910e5b75505Sopenharmony_ci if (ret) 911e5b75505Sopenharmony_ci return ret; 912e5b75505Sopenharmony_ci sae_set_state(sta, SAE_COMMITTED, "Sent Commit"); 913e5b75505Sopenharmony_ci 914e5b75505Sopenharmony_ci if (sae_process_commit(sta->sae) < 0) 915e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 916e5b75505Sopenharmony_ci sta->sae->sync = 0; 917e5b75505Sopenharmony_ci sae_set_retransmit_timer(hapd, sta); 918e5b75505Sopenharmony_ci } else { 919e5b75505Sopenharmony_ci if (sae_check_big_sync(hapd, sta)) 920e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 921e5b75505Sopenharmony_ci sta->sae->sync++; 922e5b75505Sopenharmony_ci 923e5b75505Sopenharmony_ci ret = auth_sae_send_confirm(hapd, sta, bssid); 924e5b75505Sopenharmony_ci sae_clear_temp_data(sta->sae); 925e5b75505Sopenharmony_ci if (ret) 926e5b75505Sopenharmony_ci return ret; 927e5b75505Sopenharmony_ci } 928e5b75505Sopenharmony_ci break; 929e5b75505Sopenharmony_ci default: 930e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "SAE: invalid state %d", 931e5b75505Sopenharmony_ci sta->sae->state); 932e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 933e5b75505Sopenharmony_ci } 934e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 935e5b75505Sopenharmony_ci} 936e5b75505Sopenharmony_ci 937e5b75505Sopenharmony_ci 938e5b75505Sopenharmony_cistatic void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta) 939e5b75505Sopenharmony_ci{ 940e5b75505Sopenharmony_ci struct sae_data *sae = sta->sae; 941e5b75505Sopenharmony_ci int i, *groups = hapd->conf->sae_groups; 942e5b75505Sopenharmony_ci int default_groups[] = { 19, 0 }; 943e5b75505Sopenharmony_ci 944e5b75505Sopenharmony_ci if (sae->state != SAE_COMMITTED) 945e5b75505Sopenharmony_ci return; 946e5b75505Sopenharmony_ci 947e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group); 948e5b75505Sopenharmony_ci 949e5b75505Sopenharmony_ci if (!groups) 950e5b75505Sopenharmony_ci groups = default_groups; 951e5b75505Sopenharmony_ci for (i = 0; groups[i] > 0; i++) { 952e5b75505Sopenharmony_ci if (sae->group == groups[i]) 953e5b75505Sopenharmony_ci break; 954e5b75505Sopenharmony_ci } 955e5b75505Sopenharmony_ci 956e5b75505Sopenharmony_ci if (groups[i] <= 0) { 957e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 958e5b75505Sopenharmony_ci "SAE: Previously selected group not found from the current configuration"); 959e5b75505Sopenharmony_ci return; 960e5b75505Sopenharmony_ci } 961e5b75505Sopenharmony_ci 962e5b75505Sopenharmony_ci for (;;) { 963e5b75505Sopenharmony_ci i++; 964e5b75505Sopenharmony_ci if (groups[i] <= 0) { 965e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 966e5b75505Sopenharmony_ci "SAE: No alternative group enabled"); 967e5b75505Sopenharmony_ci return; 968e5b75505Sopenharmony_ci } 969e5b75505Sopenharmony_ci 970e5b75505Sopenharmony_ci if (sae_set_group(sae, groups[i]) < 0) 971e5b75505Sopenharmony_ci continue; 972e5b75505Sopenharmony_ci 973e5b75505Sopenharmony_ci break; 974e5b75505Sopenharmony_ci } 975e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]); 976e5b75505Sopenharmony_ci} 977e5b75505Sopenharmony_ci 978e5b75505Sopenharmony_ci 979e5b75505Sopenharmony_cistatic void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, 980e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len, 981e5b75505Sopenharmony_ci u16 auth_transaction, u16 status_code) 982e5b75505Sopenharmony_ci{ 983e5b75505Sopenharmony_ci int resp = WLAN_STATUS_SUCCESS; 984e5b75505Sopenharmony_ci struct wpabuf *data = NULL; 985e5b75505Sopenharmony_ci int *groups = hapd->conf->sae_groups; 986e5b75505Sopenharmony_ci int default_groups[] = { 19, 0 }; 987e5b75505Sopenharmony_ci const u8 *pos, *end; 988e5b75505Sopenharmony_ci int sta_removed = 0; 989e5b75505Sopenharmony_ci 990e5b75505Sopenharmony_ci if (!groups) 991e5b75505Sopenharmony_ci groups = default_groups; 992e5b75505Sopenharmony_ci 993e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 994e5b75505Sopenharmony_ci if (hapd->conf->sae_reflection_attack && auth_transaction == 1) { 995e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack"); 996e5b75505Sopenharmony_ci pos = mgmt->u.auth.variable; 997e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 998e5b75505Sopenharmony_ci send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, 999e5b75505Sopenharmony_ci auth_transaction, resp, pos, end - pos, 1000e5b75505Sopenharmony_ci "auth-sae-reflection-attack"); 1001e5b75505Sopenharmony_ci goto remove_sta; 1002e5b75505Sopenharmony_ci } 1003e5b75505Sopenharmony_ci 1004e5b75505Sopenharmony_ci if (hapd->conf->sae_commit_override && auth_transaction == 1) { 1005e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override"); 1006e5b75505Sopenharmony_ci send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, 1007e5b75505Sopenharmony_ci auth_transaction, resp, 1008e5b75505Sopenharmony_ci wpabuf_head(hapd->conf->sae_commit_override), 1009e5b75505Sopenharmony_ci wpabuf_len(hapd->conf->sae_commit_override), 1010e5b75505Sopenharmony_ci "sae-commit-override"); 1011e5b75505Sopenharmony_ci goto remove_sta; 1012e5b75505Sopenharmony_ci } 1013e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 1014e5b75505Sopenharmony_ci if (!sta->sae) { 1015e5b75505Sopenharmony_ci if (auth_transaction != 1 || 1016e5b75505Sopenharmony_ci status_code != WLAN_STATUS_SUCCESS) { 1017e5b75505Sopenharmony_ci resp = -1; 1018e5b75505Sopenharmony_ci goto remove_sta; 1019e5b75505Sopenharmony_ci } 1020e5b75505Sopenharmony_ci sta->sae = os_zalloc(sizeof(*sta->sae)); 1021e5b75505Sopenharmony_ci if (!sta->sae) { 1022e5b75505Sopenharmony_ci resp = -1; 1023e5b75505Sopenharmony_ci goto remove_sta; 1024e5b75505Sopenharmony_ci } 1025e5b75505Sopenharmony_ci sae_set_state(sta, SAE_NOTHING, "Init"); 1026e5b75505Sopenharmony_ci sta->sae->sync = 0; 1027e5b75505Sopenharmony_ci } 1028e5b75505Sopenharmony_ci 1029e5b75505Sopenharmony_ci if (sta->mesh_sae_pmksa_caching) { 1030e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1031e5b75505Sopenharmony_ci "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication"); 1032e5b75505Sopenharmony_ci wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); 1033e5b75505Sopenharmony_ci sta->mesh_sae_pmksa_caching = 0; 1034e5b75505Sopenharmony_ci } 1035e5b75505Sopenharmony_ci 1036e5b75505Sopenharmony_ci if (auth_transaction == 1) { 1037e5b75505Sopenharmony_ci const u8 *token = NULL; 1038e5b75505Sopenharmony_ci size_t token_len = 0; 1039e5b75505Sopenharmony_ci int allow_reuse = 0; 1040e5b75505Sopenharmony_ci 1041e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1042e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 1043e5b75505Sopenharmony_ci "start SAE authentication (RX commit, status=%u (%s))", 1044e5b75505Sopenharmony_ci status_code, status2str(status_code)); 1045e5b75505Sopenharmony_ci 1046e5b75505Sopenharmony_ci if ((hapd->conf->mesh & MESH_ENABLED) && 1047e5b75505Sopenharmony_ci status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ && 1048e5b75505Sopenharmony_ci sta->sae->tmp) { 1049e5b75505Sopenharmony_ci pos = mgmt->u.auth.variable; 1050e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 1051e5b75505Sopenharmony_ci if (pos + sizeof(le16) > end) { 1052e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1053e5b75505Sopenharmony_ci "SAE: Too short anti-clogging token request"); 1054e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1055e5b75505Sopenharmony_ci goto reply; 1056e5b75505Sopenharmony_ci } 1057e5b75505Sopenharmony_ci resp = sae_group_allowed(sta->sae, groups, 1058e5b75505Sopenharmony_ci WPA_GET_LE16(pos)); 1059e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) { 1060e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1061e5b75505Sopenharmony_ci "SAE: Invalid group in anti-clogging token request"); 1062e5b75505Sopenharmony_ci goto reply; 1063e5b75505Sopenharmony_ci } 1064e5b75505Sopenharmony_ci pos += sizeof(le16); 1065e5b75505Sopenharmony_ci 1066e5b75505Sopenharmony_ci wpabuf_free(sta->sae->tmp->anti_clogging_token); 1067e5b75505Sopenharmony_ci sta->sae->tmp->anti_clogging_token = 1068e5b75505Sopenharmony_ci wpabuf_alloc_copy(pos, end - pos); 1069e5b75505Sopenharmony_ci if (sta->sae->tmp->anti_clogging_token == NULL) { 1070e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1071e5b75505Sopenharmony_ci "SAE: Failed to alloc for anti-clogging token"); 1072e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1073e5b75505Sopenharmony_ci goto remove_sta; 1074e5b75505Sopenharmony_ci } 1075e5b75505Sopenharmony_ci 1076e5b75505Sopenharmony_ci /* 1077e5b75505Sopenharmony_ci * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code 1078e5b75505Sopenharmony_ci * is 76, a new Commit Message shall be constructed 1079e5b75505Sopenharmony_ci * with the Anti-Clogging Token from the received 1080e5b75505Sopenharmony_ci * Authentication frame, and the commit-scalar and 1081e5b75505Sopenharmony_ci * COMMIT-ELEMENT previously sent. 1082e5b75505Sopenharmony_ci */ 1083e5b75505Sopenharmony_ci resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0); 1084e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) { 1085e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1086e5b75505Sopenharmony_ci "SAE: Failed to send commit message"); 1087e5b75505Sopenharmony_ci goto remove_sta; 1088e5b75505Sopenharmony_ci } 1089e5b75505Sopenharmony_ci sae_set_state(sta, SAE_COMMITTED, 1090e5b75505Sopenharmony_ci "Sent Commit (anti-clogging token case in mesh)"); 1091e5b75505Sopenharmony_ci sta->sae->sync = 0; 1092e5b75505Sopenharmony_ci sae_set_retransmit_timer(hapd, sta); 1093e5b75505Sopenharmony_ci return; 1094e5b75505Sopenharmony_ci } 1095e5b75505Sopenharmony_ci 1096e5b75505Sopenharmony_ci if ((hapd->conf->mesh & MESH_ENABLED) && 1097e5b75505Sopenharmony_ci status_code == 1098e5b75505Sopenharmony_ci WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && 1099e5b75505Sopenharmony_ci sta->sae->tmp) { 1100e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1101e5b75505Sopenharmony_ci "SAE: Peer did not accept our SAE group"); 1102e5b75505Sopenharmony_ci sae_pick_next_group(hapd, sta); 1103e5b75505Sopenharmony_ci goto remove_sta; 1104e5b75505Sopenharmony_ci } 1105e5b75505Sopenharmony_ci 1106e5b75505Sopenharmony_ci if (status_code != WLAN_STATUS_SUCCESS) 1107e5b75505Sopenharmony_ci goto remove_sta; 1108e5b75505Sopenharmony_ci 1109e5b75505Sopenharmony_ci if (!(hapd->conf->mesh & MESH_ENABLED) && 1110e5b75505Sopenharmony_ci sta->sae->state == SAE_COMMITTED) { 1111e5b75505Sopenharmony_ci /* This is needed in the infrastructure BSS case to 1112e5b75505Sopenharmony_ci * address a sequence where a STA entry may remain in 1113e5b75505Sopenharmony_ci * hostapd across two attempts to do SAE authentication 1114e5b75505Sopenharmony_ci * by the same STA. The second attempt may end up trying 1115e5b75505Sopenharmony_ci * to use a different group and that would not be 1116e5b75505Sopenharmony_ci * allowed if we remain in Committed state with the 1117e5b75505Sopenharmony_ci * previously set parameters. */ 1118e5b75505Sopenharmony_ci pos = mgmt->u.auth.variable; 1119e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 1120e5b75505Sopenharmony_ci if (end - pos >= (int) sizeof(le16) && 1121e5b75505Sopenharmony_ci sae_group_allowed(sta->sae, groups, 1122e5b75505Sopenharmony_ci WPA_GET_LE16(pos)) == 1123e5b75505Sopenharmony_ci WLAN_STATUS_SUCCESS) { 1124e5b75505Sopenharmony_ci /* Do not waste resources deriving the same PWE 1125e5b75505Sopenharmony_ci * again since the same group is reused. */ 1126e5b75505Sopenharmony_ci sae_set_state(sta, SAE_NOTHING, 1127e5b75505Sopenharmony_ci "Allow previous PWE to be reused"); 1128e5b75505Sopenharmony_ci allow_reuse = 1; 1129e5b75505Sopenharmony_ci } else { 1130e5b75505Sopenharmony_ci sae_set_state(sta, SAE_NOTHING, 1131e5b75505Sopenharmony_ci "Clear existing state to allow restart"); 1132e5b75505Sopenharmony_ci sae_clear_data(sta->sae); 1133e5b75505Sopenharmony_ci } 1134e5b75505Sopenharmony_ci } 1135e5b75505Sopenharmony_ci 1136e5b75505Sopenharmony_ci resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable, 1137e5b75505Sopenharmony_ci ((const u8 *) mgmt) + len - 1138e5b75505Sopenharmony_ci mgmt->u.auth.variable, &token, 1139e5b75505Sopenharmony_ci &token_len, groups); 1140e5b75505Sopenharmony_ci if (resp == SAE_SILENTLY_DISCARD) { 1141e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1142e5b75505Sopenharmony_ci "SAE: Drop commit message from " MACSTR " due to reflection attack", 1143e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 1144e5b75505Sopenharmony_ci goto remove_sta; 1145e5b75505Sopenharmony_ci } 1146e5b75505Sopenharmony_ci 1147e5b75505Sopenharmony_ci if (resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER) { 1148e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_INFO, 1149e5b75505Sopenharmony_ci WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER 1150e5b75505Sopenharmony_ci MACSTR, MAC2STR(sta->addr)); 1151e5b75505Sopenharmony_ci sae_clear_retransmit_timer(hapd, sta); 1152e5b75505Sopenharmony_ci sae_set_state(sta, SAE_NOTHING, 1153e5b75505Sopenharmony_ci "Unknown Password Identifier"); 1154e5b75505Sopenharmony_ci goto remove_sta; 1155e5b75505Sopenharmony_ci } 1156e5b75505Sopenharmony_ci 1157e5b75505Sopenharmony_ci if (token && check_sae_token(hapd, sta->addr, token, token_len) 1158e5b75505Sopenharmony_ci < 0) { 1159e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " 1160e5b75505Sopenharmony_ci "incorrect token from " MACSTR, 1161e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 1162e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1163e5b75505Sopenharmony_ci goto remove_sta; 1164e5b75505Sopenharmony_ci } 1165e5b75505Sopenharmony_ci 1166e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 1167e5b75505Sopenharmony_ci goto reply; 1168e5b75505Sopenharmony_ci 1169e5b75505Sopenharmony_ci if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) { 1170e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1171e5b75505Sopenharmony_ci "SAE: Request anti-clogging token from " 1172e5b75505Sopenharmony_ci MACSTR, MAC2STR(sta->addr)); 1173e5b75505Sopenharmony_ci data = auth_build_token_req(hapd, sta->sae->group, 1174e5b75505Sopenharmony_ci sta->addr); 1175e5b75505Sopenharmony_ci resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ; 1176e5b75505Sopenharmony_ci if (hapd->conf->mesh & MESH_ENABLED) 1177e5b75505Sopenharmony_ci sae_set_state(sta, SAE_NOTHING, 1178e5b75505Sopenharmony_ci "Request anti-clogging token case in mesh"); 1179e5b75505Sopenharmony_ci goto reply; 1180e5b75505Sopenharmony_ci } 1181e5b75505Sopenharmony_ci 1182e5b75505Sopenharmony_ci resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 1183e5b75505Sopenharmony_ci allow_reuse, &sta_removed); 1184e5b75505Sopenharmony_ci } else if (auth_transaction == 2) { 1185e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1186e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 1187e5b75505Sopenharmony_ci "SAE authentication (RX confirm, status=%u (%s))", 1188e5b75505Sopenharmony_ci status_code, status2str(status_code)); 1189e5b75505Sopenharmony_ci if (status_code != WLAN_STATUS_SUCCESS) 1190e5b75505Sopenharmony_ci goto remove_sta; 1191e5b75505Sopenharmony_ci if (sta->sae->state >= SAE_CONFIRMED || 1192e5b75505Sopenharmony_ci !(hapd->conf->mesh & MESH_ENABLED)) { 1193e5b75505Sopenharmony_ci const u8 *var; 1194e5b75505Sopenharmony_ci size_t var_len; 1195e5b75505Sopenharmony_ci u16 peer_send_confirm; 1196e5b75505Sopenharmony_ci 1197e5b75505Sopenharmony_ci var = mgmt->u.auth.variable; 1198e5b75505Sopenharmony_ci var_len = ((u8 *) mgmt) + len - mgmt->u.auth.variable; 1199e5b75505Sopenharmony_ci if (var_len < 2) { 1200e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1201e5b75505Sopenharmony_ci goto reply; 1202e5b75505Sopenharmony_ci } 1203e5b75505Sopenharmony_ci 1204e5b75505Sopenharmony_ci peer_send_confirm = WPA_GET_LE16(var); 1205e5b75505Sopenharmony_ci 1206e5b75505Sopenharmony_ci if (sta->sae->state == SAE_ACCEPTED && 1207e5b75505Sopenharmony_ci (peer_send_confirm <= sta->sae->rc || 1208e5b75505Sopenharmony_ci peer_send_confirm == 0xffff)) { 1209e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1210e5b75505Sopenharmony_ci "SAE: Silently ignore unexpected Confirm from peer " 1211e5b75505Sopenharmony_ci MACSTR 1212e5b75505Sopenharmony_ci " (peer-send-confirm=%u Rc=%u)", 1213e5b75505Sopenharmony_ci MAC2STR(sta->addr), 1214e5b75505Sopenharmony_ci peer_send_confirm, sta->sae->rc); 1215e5b75505Sopenharmony_ci return; 1216e5b75505Sopenharmony_ci } 1217e5b75505Sopenharmony_ci 1218e5b75505Sopenharmony_ci if (sae_check_confirm(sta->sae, var, var_len) < 0) { 1219e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1220e5b75505Sopenharmony_ci goto reply; 1221e5b75505Sopenharmony_ci } 1222e5b75505Sopenharmony_ci sta->sae->rc = peer_send_confirm; 1223e5b75505Sopenharmony_ci } 1224e5b75505Sopenharmony_ci resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0, 1225e5b75505Sopenharmony_ci &sta_removed); 1226e5b75505Sopenharmony_ci } else { 1227e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1228e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 1229e5b75505Sopenharmony_ci "unexpected SAE authentication transaction %u (status=%u (%s))", 1230e5b75505Sopenharmony_ci auth_transaction, status_code, 1231e5b75505Sopenharmony_ci status2str(status_code)); 1232e5b75505Sopenharmony_ci if (status_code != WLAN_STATUS_SUCCESS) 1233e5b75505Sopenharmony_ci goto remove_sta; 1234e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; 1235e5b75505Sopenharmony_ci } 1236e5b75505Sopenharmony_ci 1237e5b75505Sopenharmony_cireply: 1238e5b75505Sopenharmony_ci if (!sta_removed && resp != WLAN_STATUS_SUCCESS) { 1239e5b75505Sopenharmony_ci pos = mgmt->u.auth.variable; 1240e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 1241e5b75505Sopenharmony_ci 1242e5b75505Sopenharmony_ci /* Copy the Finite Cyclic Group field from the request if we 1243e5b75505Sopenharmony_ci * rejected it as unsupported group. */ 1244e5b75505Sopenharmony_ci if (resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && 1245e5b75505Sopenharmony_ci !data && end - pos >= 2) 1246e5b75505Sopenharmony_ci data = wpabuf_alloc_copy(pos, 2); 1247e5b75505Sopenharmony_ci 1248e5b75505Sopenharmony_ci sae_sme_send_external_auth_status(hapd, sta, resp); 1249e5b75505Sopenharmony_ci send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, 1250e5b75505Sopenharmony_ci auth_transaction, resp, 1251e5b75505Sopenharmony_ci data ? wpabuf_head(data) : (u8 *) "", 1252e5b75505Sopenharmony_ci data ? wpabuf_len(data) : 0, "auth-sae"); 1253e5b75505Sopenharmony_ci } 1254e5b75505Sopenharmony_ci 1255e5b75505Sopenharmony_ciremove_sta: 1256e5b75505Sopenharmony_ci if (!sta_removed && sta->added_unassoc && 1257e5b75505Sopenharmony_ci (resp != WLAN_STATUS_SUCCESS || 1258e5b75505Sopenharmony_ci status_code != WLAN_STATUS_SUCCESS)) { 1259e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 1260e5b75505Sopenharmony_ci sta->added_unassoc = 0; 1261e5b75505Sopenharmony_ci } 1262e5b75505Sopenharmony_ci wpabuf_free(data); 1263e5b75505Sopenharmony_ci} 1264e5b75505Sopenharmony_ci 1265e5b75505Sopenharmony_ci 1266e5b75505Sopenharmony_ci/** 1267e5b75505Sopenharmony_ci * auth_sae_init_committed - Send COMMIT and start SAE in committed state 1268e5b75505Sopenharmony_ci * @hapd: BSS data for the device initiating the authentication 1269e5b75505Sopenharmony_ci * @sta: the peer to which commit authentication frame is sent 1270e5b75505Sopenharmony_ci * 1271e5b75505Sopenharmony_ci * This function implements Init event handling (IEEE Std 802.11-2012, 1272e5b75505Sopenharmony_ci * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the 1273e5b75505Sopenharmony_ci * sta->sae structure should be initialized appropriately via a call to 1274e5b75505Sopenharmony_ci * sae_prepare_commit(). 1275e5b75505Sopenharmony_ci */ 1276e5b75505Sopenharmony_ciint auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta) 1277e5b75505Sopenharmony_ci{ 1278e5b75505Sopenharmony_ci int ret; 1279e5b75505Sopenharmony_ci 1280e5b75505Sopenharmony_ci if (!sta->sae || !sta->sae->tmp) 1281e5b75505Sopenharmony_ci return -1; 1282e5b75505Sopenharmony_ci 1283e5b75505Sopenharmony_ci if (sta->sae->state != SAE_NOTHING) 1284e5b75505Sopenharmony_ci return -1; 1285e5b75505Sopenharmony_ci 1286e5b75505Sopenharmony_ci ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0); 1287e5b75505Sopenharmony_ci if (ret) 1288e5b75505Sopenharmony_ci return -1; 1289e5b75505Sopenharmony_ci 1290e5b75505Sopenharmony_ci sae_set_state(sta, SAE_COMMITTED, "Init and sent commit"); 1291e5b75505Sopenharmony_ci sta->sae->sync = 0; 1292e5b75505Sopenharmony_ci sae_set_retransmit_timer(hapd, sta); 1293e5b75505Sopenharmony_ci 1294e5b75505Sopenharmony_ci return 0; 1295e5b75505Sopenharmony_ci} 1296e5b75505Sopenharmony_ci 1297e5b75505Sopenharmony_ci 1298e5b75505Sopenharmony_civoid auth_sae_process_commit(void *eloop_ctx, void *user_ctx) 1299e5b75505Sopenharmony_ci{ 1300e5b75505Sopenharmony_ci struct hostapd_data *hapd = eloop_ctx; 1301e5b75505Sopenharmony_ci struct hostapd_sae_commit_queue *q; 1302e5b75505Sopenharmony_ci unsigned int queue_len; 1303e5b75505Sopenharmony_ci 1304e5b75505Sopenharmony_ci q = dl_list_first(&hapd->sae_commit_queue, 1305e5b75505Sopenharmony_ci struct hostapd_sae_commit_queue, list); 1306e5b75505Sopenharmony_ci if (!q) 1307e5b75505Sopenharmony_ci return; 1308e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1309e5b75505Sopenharmony_ci "SAE: Process next available message from queue"); 1310e5b75505Sopenharmony_ci dl_list_del(&q->list); 1311e5b75505Sopenharmony_ci handle_auth(hapd, (const struct ieee80211_mgmt *) q->msg, q->len, 1312e5b75505Sopenharmony_ci q->rssi, 1); 1313e5b75505Sopenharmony_ci os_free(q); 1314e5b75505Sopenharmony_ci 1315e5b75505Sopenharmony_ci if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL)) 1316e5b75505Sopenharmony_ci return; 1317e5b75505Sopenharmony_ci queue_len = dl_list_len(&hapd->sae_commit_queue); 1318e5b75505Sopenharmony_ci eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit, 1319e5b75505Sopenharmony_ci hapd, NULL); 1320e5b75505Sopenharmony_ci} 1321e5b75505Sopenharmony_ci 1322e5b75505Sopenharmony_ci 1323e5b75505Sopenharmony_cistatic void auth_sae_queue(struct hostapd_data *hapd, 1324e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len, 1325e5b75505Sopenharmony_ci int rssi) 1326e5b75505Sopenharmony_ci{ 1327e5b75505Sopenharmony_ci struct hostapd_sae_commit_queue *q, *q2; 1328e5b75505Sopenharmony_ci unsigned int queue_len; 1329e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt2; 1330e5b75505Sopenharmony_ci 1331e5b75505Sopenharmony_ci queue_len = dl_list_len(&hapd->sae_commit_queue); 1332e5b75505Sopenharmony_ci if (queue_len >= 15) { 1333e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1334e5b75505Sopenharmony_ci "SAE: No more room in message queue - drop the new frame from " 1335e5b75505Sopenharmony_ci MACSTR, MAC2STR(mgmt->sa)); 1336e5b75505Sopenharmony_ci return; 1337e5b75505Sopenharmony_ci } 1338e5b75505Sopenharmony_ci 1339e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: Queue Authentication message from " 1340e5b75505Sopenharmony_ci MACSTR " for processing (queue_len %u)", MAC2STR(mgmt->sa), 1341e5b75505Sopenharmony_ci queue_len); 1342e5b75505Sopenharmony_ci q = os_zalloc(sizeof(*q) + len); 1343e5b75505Sopenharmony_ci if (!q) 1344e5b75505Sopenharmony_ci return; 1345e5b75505Sopenharmony_ci q->rssi = rssi; 1346e5b75505Sopenharmony_ci q->len = len; 1347e5b75505Sopenharmony_ci os_memcpy(q->msg, mgmt, len); 1348e5b75505Sopenharmony_ci 1349e5b75505Sopenharmony_ci /* Check whether there is already a queued Authentication frame from the 1350e5b75505Sopenharmony_ci * same station with the same transaction number and if so, replace that 1351e5b75505Sopenharmony_ci * queue entry with the new one. This avoids issues with a peer that 1352e5b75505Sopenharmony_ci * sends multiple times (e.g., due to frequent SAE retries). There is no 1353e5b75505Sopenharmony_ci * point in us trying to process the old attempts after a new one has 1354e5b75505Sopenharmony_ci * obsoleted them. */ 1355e5b75505Sopenharmony_ci dl_list_for_each(q2, &hapd->sae_commit_queue, 1356e5b75505Sopenharmony_ci struct hostapd_sae_commit_queue, list) { 1357e5b75505Sopenharmony_ci mgmt2 = (const struct ieee80211_mgmt *) q2->msg; 1358e5b75505Sopenharmony_ci if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 && 1359e5b75505Sopenharmony_ci mgmt->u.auth.auth_transaction == 1360e5b75505Sopenharmony_ci mgmt2->u.auth.auth_transaction) { 1361e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1362e5b75505Sopenharmony_ci "SAE: Replace queued message from same STA with same transaction number"); 1363e5b75505Sopenharmony_ci dl_list_add(&q2->list, &q->list); 1364e5b75505Sopenharmony_ci dl_list_del(&q2->list); 1365e5b75505Sopenharmony_ci os_free(q2); 1366e5b75505Sopenharmony_ci goto queued; 1367e5b75505Sopenharmony_ci } 1368e5b75505Sopenharmony_ci } 1369e5b75505Sopenharmony_ci 1370e5b75505Sopenharmony_ci /* No pending identical entry, so add to the end of the queue */ 1371e5b75505Sopenharmony_ci dl_list_add_tail(&hapd->sae_commit_queue, &q->list); 1372e5b75505Sopenharmony_ci 1373e5b75505Sopenharmony_ciqueued: 1374e5b75505Sopenharmony_ci if (eloop_is_timeout_registered(auth_sae_process_commit, hapd, NULL)) 1375e5b75505Sopenharmony_ci return; 1376e5b75505Sopenharmony_ci eloop_register_timeout(0, queue_len * 10000, auth_sae_process_commit, 1377e5b75505Sopenharmony_ci hapd, NULL); 1378e5b75505Sopenharmony_ci} 1379e5b75505Sopenharmony_ci 1380e5b75505Sopenharmony_ci 1381e5b75505Sopenharmony_cistatic int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr) 1382e5b75505Sopenharmony_ci{ 1383e5b75505Sopenharmony_ci struct hostapd_sae_commit_queue *q; 1384e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt; 1385e5b75505Sopenharmony_ci 1386e5b75505Sopenharmony_ci dl_list_for_each(q, &hapd->sae_commit_queue, 1387e5b75505Sopenharmony_ci struct hostapd_sae_commit_queue, list) { 1388e5b75505Sopenharmony_ci mgmt = (const struct ieee80211_mgmt *) q->msg; 1389e5b75505Sopenharmony_ci if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0) 1390e5b75505Sopenharmony_ci return 1; 1391e5b75505Sopenharmony_ci } 1392e5b75505Sopenharmony_ci 1393e5b75505Sopenharmony_ci return 0; 1394e5b75505Sopenharmony_ci} 1395e5b75505Sopenharmony_ci 1396e5b75505Sopenharmony_ci#endif /* CONFIG_SAE */ 1397e5b75505Sopenharmony_ci 1398e5b75505Sopenharmony_ci 1399e5b75505Sopenharmony_cistatic u16 wpa_res_to_status_code(int res) 1400e5b75505Sopenharmony_ci{ 1401e5b75505Sopenharmony_ci if (res == WPA_INVALID_GROUP) 1402e5b75505Sopenharmony_ci return WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 1403e5b75505Sopenharmony_ci if (res == WPA_INVALID_PAIRWISE) 1404e5b75505Sopenharmony_ci return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 1405e5b75505Sopenharmony_ci if (res == WPA_INVALID_AKMP) 1406e5b75505Sopenharmony_ci return WLAN_STATUS_AKMP_NOT_VALID; 1407e5b75505Sopenharmony_ci if (res == WPA_ALLOC_FAIL) 1408e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 1409e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 1410e5b75505Sopenharmony_ci if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) 1411e5b75505Sopenharmony_ci return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; 1412e5b75505Sopenharmony_ci if (res == WPA_INVALID_MGMT_GROUP_CIPHER) 1413e5b75505Sopenharmony_ci return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 1414e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 1415e5b75505Sopenharmony_ci if (res == WPA_INVALID_MDIE) 1416e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_MDIE; 1417e5b75505Sopenharmony_ci if (res == WPA_INVALID_PMKID) 1418e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_PMKID; 1419e5b75505Sopenharmony_ci if (res != WPA_IE_OK) 1420e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_IE; 1421e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 1422e5b75505Sopenharmony_ci} 1423e5b75505Sopenharmony_ci 1424e5b75505Sopenharmony_ci 1425e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 1426e5b75505Sopenharmony_ci 1427e5b75505Sopenharmony_cistatic void handle_auth_fils_finish(struct hostapd_data *hapd, 1428e5b75505Sopenharmony_ci struct sta_info *sta, u16 resp, 1429e5b75505Sopenharmony_ci struct wpabuf *data, int pub); 1430e5b75505Sopenharmony_ci 1431e5b75505Sopenharmony_civoid handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, 1432e5b75505Sopenharmony_ci const u8 *pos, size_t len, u16 auth_alg, 1433e5b75505Sopenharmony_ci u16 auth_transaction, u16 status_code, 1434e5b75505Sopenharmony_ci void (*cb)(struct hostapd_data *hapd, 1435e5b75505Sopenharmony_ci struct sta_info *sta, u16 resp, 1436e5b75505Sopenharmony_ci struct wpabuf *data, int pub)) 1437e5b75505Sopenharmony_ci{ 1438e5b75505Sopenharmony_ci u16 resp = WLAN_STATUS_SUCCESS; 1439e5b75505Sopenharmony_ci const u8 *end; 1440e5b75505Sopenharmony_ci struct ieee802_11_elems elems; 1441e5b75505Sopenharmony_ci int res; 1442e5b75505Sopenharmony_ci struct wpa_ie_data rsn; 1443e5b75505Sopenharmony_ci struct rsn_pmksa_cache_entry *pmksa = NULL; 1444e5b75505Sopenharmony_ci 1445e5b75505Sopenharmony_ci if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS) 1446e5b75505Sopenharmony_ci return; 1447e5b75505Sopenharmony_ci 1448e5b75505Sopenharmony_ci end = pos + len; 1449e5b75505Sopenharmony_ci 1450e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields", 1451e5b75505Sopenharmony_ci pos, end - pos); 1452e5b75505Sopenharmony_ci 1453e5b75505Sopenharmony_ci /* TODO: FILS PK */ 1454e5b75505Sopenharmony_ci#ifdef CONFIG_FILS_SK_PFS 1455e5b75505Sopenharmony_ci if (auth_alg == WLAN_AUTH_FILS_SK_PFS) { 1456e5b75505Sopenharmony_ci u16 group; 1457e5b75505Sopenharmony_ci struct wpabuf *pub; 1458e5b75505Sopenharmony_ci size_t elem_len; 1459e5b75505Sopenharmony_ci 1460e5b75505Sopenharmony_ci /* Using FILS PFS */ 1461e5b75505Sopenharmony_ci 1462e5b75505Sopenharmony_ci /* Finite Cyclic Group */ 1463e5b75505Sopenharmony_ci if (end - pos < 2) { 1464e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1465e5b75505Sopenharmony_ci "FILS: No room for Finite Cyclic Group"); 1466e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1467e5b75505Sopenharmony_ci goto fail; 1468e5b75505Sopenharmony_ci } 1469e5b75505Sopenharmony_ci group = WPA_GET_LE16(pos); 1470e5b75505Sopenharmony_ci pos += 2; 1471e5b75505Sopenharmony_ci if (group != hapd->conf->fils_dh_group) { 1472e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1473e5b75505Sopenharmony_ci "FILS: Unsupported Finite Cyclic Group: %u (expected %u)", 1474e5b75505Sopenharmony_ci group, hapd->conf->fils_dh_group); 1475e5b75505Sopenharmony_ci resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 1476e5b75505Sopenharmony_ci goto fail; 1477e5b75505Sopenharmony_ci } 1478e5b75505Sopenharmony_ci 1479e5b75505Sopenharmony_ci crypto_ecdh_deinit(sta->fils_ecdh); 1480e5b75505Sopenharmony_ci sta->fils_ecdh = crypto_ecdh_init(group); 1481e5b75505Sopenharmony_ci if (!sta->fils_ecdh) { 1482e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 1483e5b75505Sopenharmony_ci "FILS: Could not initialize ECDH with group %d", 1484e5b75505Sopenharmony_ci group); 1485e5b75505Sopenharmony_ci resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 1486e5b75505Sopenharmony_ci goto fail; 1487e5b75505Sopenharmony_ci } 1488e5b75505Sopenharmony_ci 1489e5b75505Sopenharmony_ci pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1); 1490e5b75505Sopenharmony_ci if (!pub) { 1491e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1492e5b75505Sopenharmony_ci "FILS: Failed to derive ECDH public key"); 1493e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1494e5b75505Sopenharmony_ci goto fail; 1495e5b75505Sopenharmony_ci } 1496e5b75505Sopenharmony_ci elem_len = wpabuf_len(pub); 1497e5b75505Sopenharmony_ci wpabuf_free(pub); 1498e5b75505Sopenharmony_ci 1499e5b75505Sopenharmony_ci /* Element */ 1500e5b75505Sopenharmony_ci if ((size_t) (end - pos) < elem_len) { 1501e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: No room for Element"); 1502e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1503e5b75505Sopenharmony_ci goto fail; 1504e5b75505Sopenharmony_ci } 1505e5b75505Sopenharmony_ci 1506e5b75505Sopenharmony_ci wpabuf_free(sta->fils_g_sta); 1507e5b75505Sopenharmony_ci sta->fils_g_sta = wpabuf_alloc_copy(pos, elem_len); 1508e5b75505Sopenharmony_ci wpabuf_clear_free(sta->fils_dh_ss); 1509e5b75505Sopenharmony_ci sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1, 1510e5b75505Sopenharmony_ci pos, elem_len); 1511e5b75505Sopenharmony_ci if (!sta->fils_dh_ss) { 1512e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed"); 1513e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1514e5b75505Sopenharmony_ci goto fail; 1515e5b75505Sopenharmony_ci } 1516e5b75505Sopenharmony_ci wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss); 1517e5b75505Sopenharmony_ci pos += elem_len; 1518e5b75505Sopenharmony_ci } else { 1519e5b75505Sopenharmony_ci crypto_ecdh_deinit(sta->fils_ecdh); 1520e5b75505Sopenharmony_ci sta->fils_ecdh = NULL; 1521e5b75505Sopenharmony_ci wpabuf_clear_free(sta->fils_dh_ss); 1522e5b75505Sopenharmony_ci sta->fils_dh_ss = NULL; 1523e5b75505Sopenharmony_ci } 1524e5b75505Sopenharmony_ci#endif /* CONFIG_FILS_SK_PFS */ 1525e5b75505Sopenharmony_ci 1526e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos); 1527e5b75505Sopenharmony_ci if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) { 1528e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: Could not parse elements"); 1529e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1530e5b75505Sopenharmony_ci goto fail; 1531e5b75505Sopenharmony_ci } 1532e5b75505Sopenharmony_ci 1533e5b75505Sopenharmony_ci /* RSNE */ 1534e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: RSN element", 1535e5b75505Sopenharmony_ci elems.rsn_ie, elems.rsn_ie_len); 1536e5b75505Sopenharmony_ci if (!elems.rsn_ie || 1537e5b75505Sopenharmony_ci wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2, 1538e5b75505Sopenharmony_ci &rsn) < 0) { 1539e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: No valid RSN element"); 1540e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1541e5b75505Sopenharmony_ci goto fail; 1542e5b75505Sopenharmony_ci } 1543e5b75505Sopenharmony_ci 1544e5b75505Sopenharmony_ci if (!sta->wpa_sm) 1545e5b75505Sopenharmony_ci sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, 1546e5b75505Sopenharmony_ci NULL); 1547e5b75505Sopenharmony_ci if (!sta->wpa_sm) { 1548e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1549e5b75505Sopenharmony_ci "FILS: Failed to initialize RSN state machine"); 1550e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1551e5b75505Sopenharmony_ci goto fail; 1552e5b75505Sopenharmony_ci } 1553e5b75505Sopenharmony_ci 1554e5b75505Sopenharmony_ci res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 1555e5b75505Sopenharmony_ci hapd->iface->freq, 1556e5b75505Sopenharmony_ci elems.rsn_ie - 2, elems.rsn_ie_len + 2, 1557e5b75505Sopenharmony_ci elems.mdie, elems.mdie_len, NULL, 0); 1558e5b75505Sopenharmony_ci resp = wpa_res_to_status_code(res); 1559e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 1560e5b75505Sopenharmony_ci goto fail; 1561e5b75505Sopenharmony_ci 1562e5b75505Sopenharmony_ci if (!elems.fils_nonce) { 1563e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field"); 1564e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1565e5b75505Sopenharmony_ci goto fail; 1566e5b75505Sopenharmony_ci } 1567e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: SNonce", elems.fils_nonce, 1568e5b75505Sopenharmony_ci FILS_NONCE_LEN); 1569e5b75505Sopenharmony_ci os_memcpy(sta->fils_snonce, elems.fils_nonce, FILS_NONCE_LEN); 1570e5b75505Sopenharmony_ci 1571e5b75505Sopenharmony_ci /* PMKID List */ 1572e5b75505Sopenharmony_ci if (rsn.pmkid && rsn.num_pmkid > 0) { 1573e5b75505Sopenharmony_ci u8 num; 1574e5b75505Sopenharmony_ci const u8 *pmkid; 1575e5b75505Sopenharmony_ci 1576e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: PMKID List", 1577e5b75505Sopenharmony_ci rsn.pmkid, rsn.num_pmkid * PMKID_LEN); 1578e5b75505Sopenharmony_ci 1579e5b75505Sopenharmony_ci pmkid = rsn.pmkid; 1580e5b75505Sopenharmony_ci num = rsn.num_pmkid; 1581e5b75505Sopenharmony_ci while (num) { 1582e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: PMKID", pmkid, PMKID_LEN); 1583e5b75505Sopenharmony_ci pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr, 1584e5b75505Sopenharmony_ci pmkid); 1585e5b75505Sopenharmony_ci if (pmksa) 1586e5b75505Sopenharmony_ci break; 1587e5b75505Sopenharmony_ci pmksa = wpa_auth_pmksa_get_fils_cache_id(hapd->wpa_auth, 1588e5b75505Sopenharmony_ci sta->addr, 1589e5b75505Sopenharmony_ci pmkid); 1590e5b75505Sopenharmony_ci if (pmksa) 1591e5b75505Sopenharmony_ci break; 1592e5b75505Sopenharmony_ci pmkid += PMKID_LEN; 1593e5b75505Sopenharmony_ci num--; 1594e5b75505Sopenharmony_ci } 1595e5b75505Sopenharmony_ci } 1596e5b75505Sopenharmony_ci if (pmksa && wpa_auth_sta_key_mgmt(sta->wpa_sm) != pmksa->akmp) { 1597e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1598e5b75505Sopenharmony_ci "FILS: Matching PMKSA cache entry has different AKMP (0x%x != 0x%x) - ignore", 1599e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm), pmksa->akmp); 1600e5b75505Sopenharmony_ci pmksa = NULL; 1601e5b75505Sopenharmony_ci } 1602e5b75505Sopenharmony_ci if (pmksa) 1603e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: Found matching PMKSA cache entry"); 1604e5b75505Sopenharmony_ci 1605e5b75505Sopenharmony_ci /* FILS Session */ 1606e5b75505Sopenharmony_ci if (!elems.fils_session) { 1607e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: No FILS Session element"); 1608e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1609e5b75505Sopenharmony_ci goto fail; 1610e5b75505Sopenharmony_ci } 1611e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: FILS Session", elems.fils_session, 1612e5b75505Sopenharmony_ci FILS_SESSION_LEN); 1613e5b75505Sopenharmony_ci os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN); 1614e5b75505Sopenharmony_ci 1615e5b75505Sopenharmony_ci /* FILS Wrapped Data */ 1616e5b75505Sopenharmony_ci if (elems.fils_wrapped_data) { 1617e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data", 1618e5b75505Sopenharmony_ci elems.fils_wrapped_data, 1619e5b75505Sopenharmony_ci elems.fils_wrapped_data_len); 1620e5b75505Sopenharmony_ci if (!pmksa) { 1621e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RADIUS 1622e5b75505Sopenharmony_ci if (!sta->eapol_sm) { 1623e5b75505Sopenharmony_ci sta->eapol_sm = 1624e5b75505Sopenharmony_ci ieee802_1x_alloc_eapol_sm(hapd, sta); 1625e5b75505Sopenharmony_ci } 1626e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1627e5b75505Sopenharmony_ci "FILS: Forward EAP-Initiate/Re-auth to authentication server"); 1628e5b75505Sopenharmony_ci ieee802_1x_encapsulate_radius( 1629e5b75505Sopenharmony_ci hapd, sta, elems.fils_wrapped_data, 1630e5b75505Sopenharmony_ci elems.fils_wrapped_data_len); 1631e5b75505Sopenharmony_ci sta->fils_pending_cb = cb; 1632e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1633e5b75505Sopenharmony_ci "FILS: Will send Authentication frame once the response from authentication server is available"); 1634e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_PENDING_FILS_ERP; 1635e5b75505Sopenharmony_ci /* Calculate pending PMKID here so that we do not need 1636e5b75505Sopenharmony_ci * to maintain a copy of the EAP-Initiate/Reauth 1637e5b75505Sopenharmony_ci * message. */ 1638e5b75505Sopenharmony_ci if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm), 1639e5b75505Sopenharmony_ci elems.fils_wrapped_data, 1640e5b75505Sopenharmony_ci elems.fils_wrapped_data_len, 1641e5b75505Sopenharmony_ci sta->fils_erp_pmkid) == 0) 1642e5b75505Sopenharmony_ci sta->fils_erp_pmkid_set = 1; 1643e5b75505Sopenharmony_ci return; 1644e5b75505Sopenharmony_ci#else /* CONFIG_NO_RADIUS */ 1645e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1646e5b75505Sopenharmony_ci goto fail; 1647e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RADIUS */ 1648e5b75505Sopenharmony_ci } 1649e5b75505Sopenharmony_ci } 1650e5b75505Sopenharmony_ci 1651e5b75505Sopenharmony_cifail: 1652e5b75505Sopenharmony_ci if (cb) { 1653e5b75505Sopenharmony_ci struct wpabuf *data; 1654e5b75505Sopenharmony_ci int pub = 0; 1655e5b75505Sopenharmony_ci 1656e5b75505Sopenharmony_ci data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, NULL, 1657e5b75505Sopenharmony_ci NULL, 0, &pub); 1658e5b75505Sopenharmony_ci if (!data) { 1659e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1660e5b75505Sopenharmony_ci "%s: prepare_auth_resp_fils() returned failure", 1661e5b75505Sopenharmony_ci __func__); 1662e5b75505Sopenharmony_ci } 1663e5b75505Sopenharmony_ci 1664e5b75505Sopenharmony_ci cb(hapd, sta, resp, data, pub); 1665e5b75505Sopenharmony_ci } 1666e5b75505Sopenharmony_ci} 1667e5b75505Sopenharmony_ci 1668e5b75505Sopenharmony_ci 1669e5b75505Sopenharmony_cistatic struct wpabuf * 1670e5b75505Sopenharmony_ciprepare_auth_resp_fils(struct hostapd_data *hapd, 1671e5b75505Sopenharmony_ci struct sta_info *sta, u16 *resp, 1672e5b75505Sopenharmony_ci struct rsn_pmksa_cache_entry *pmksa, 1673e5b75505Sopenharmony_ci struct wpabuf *erp_resp, 1674e5b75505Sopenharmony_ci const u8 *msk, size_t msk_len, 1675e5b75505Sopenharmony_ci int *is_pub) 1676e5b75505Sopenharmony_ci{ 1677e5b75505Sopenharmony_ci u8 fils_nonce[FILS_NONCE_LEN]; 1678e5b75505Sopenharmony_ci size_t ielen; 1679e5b75505Sopenharmony_ci struct wpabuf *data = NULL; 1680e5b75505Sopenharmony_ci const u8 *ie; 1681e5b75505Sopenharmony_ci u8 *ie_buf = NULL; 1682e5b75505Sopenharmony_ci const u8 *pmk = NULL; 1683e5b75505Sopenharmony_ci size_t pmk_len = 0; 1684e5b75505Sopenharmony_ci u8 pmk_buf[PMK_LEN_MAX]; 1685e5b75505Sopenharmony_ci struct wpabuf *pub = NULL; 1686e5b75505Sopenharmony_ci 1687e5b75505Sopenharmony_ci if (*resp != WLAN_STATUS_SUCCESS) 1688e5b75505Sopenharmony_ci goto fail; 1689e5b75505Sopenharmony_ci 1690e5b75505Sopenharmony_ci ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); 1691e5b75505Sopenharmony_ci if (!ie) { 1692e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1693e5b75505Sopenharmony_ci goto fail; 1694e5b75505Sopenharmony_ci } 1695e5b75505Sopenharmony_ci 1696e5b75505Sopenharmony_ci if (pmksa) { 1697e5b75505Sopenharmony_ci /* Add PMKID of the selected PMKSA into RSNE */ 1698e5b75505Sopenharmony_ci ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN); 1699e5b75505Sopenharmony_ci if (!ie_buf) { 1700e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1701e5b75505Sopenharmony_ci goto fail; 1702e5b75505Sopenharmony_ci } 1703e5b75505Sopenharmony_ci 1704e5b75505Sopenharmony_ci os_memcpy(ie_buf, ie, ielen); 1705e5b75505Sopenharmony_ci if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) { 1706e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1707e5b75505Sopenharmony_ci goto fail; 1708e5b75505Sopenharmony_ci } 1709e5b75505Sopenharmony_ci ie = ie_buf; 1710e5b75505Sopenharmony_ci } 1711e5b75505Sopenharmony_ci 1712e5b75505Sopenharmony_ci if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) { 1713e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1714e5b75505Sopenharmony_ci goto fail; 1715e5b75505Sopenharmony_ci } 1716e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce", 1717e5b75505Sopenharmony_ci fils_nonce, FILS_NONCE_LEN); 1718e5b75505Sopenharmony_ci 1719e5b75505Sopenharmony_ci#ifdef CONFIG_FILS_SK_PFS 1720e5b75505Sopenharmony_ci if (sta->fils_dh_ss && sta->fils_ecdh) { 1721e5b75505Sopenharmony_ci pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1); 1722e5b75505Sopenharmony_ci if (!pub) { 1723e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1724e5b75505Sopenharmony_ci goto fail; 1725e5b75505Sopenharmony_ci } 1726e5b75505Sopenharmony_ci } 1727e5b75505Sopenharmony_ci#endif /* CONFIG_FILS_SK_PFS */ 1728e5b75505Sopenharmony_ci 1729e5b75505Sopenharmony_ci data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0)); 1730e5b75505Sopenharmony_ci if (!data) { 1731e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1732e5b75505Sopenharmony_ci goto fail; 1733e5b75505Sopenharmony_ci } 1734e5b75505Sopenharmony_ci 1735e5b75505Sopenharmony_ci /* TODO: FILS PK */ 1736e5b75505Sopenharmony_ci#ifdef CONFIG_FILS_SK_PFS 1737e5b75505Sopenharmony_ci if (pub) { 1738e5b75505Sopenharmony_ci /* Finite Cyclic Group */ 1739e5b75505Sopenharmony_ci wpabuf_put_le16(data, hapd->conf->fils_dh_group); 1740e5b75505Sopenharmony_ci 1741e5b75505Sopenharmony_ci /* Element */ 1742e5b75505Sopenharmony_ci wpabuf_put_buf(data, pub); 1743e5b75505Sopenharmony_ci } 1744e5b75505Sopenharmony_ci#endif /* CONFIG_FILS_SK_PFS */ 1745e5b75505Sopenharmony_ci 1746e5b75505Sopenharmony_ci /* RSNE */ 1747e5b75505Sopenharmony_ci wpabuf_put_data(data, ie, ielen); 1748e5b75505Sopenharmony_ci 1749e5b75505Sopenharmony_ci /* MDE when using FILS+FT (already included in ie,ielen with RSNE) */ 1750e5b75505Sopenharmony_ci 1751e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 1752e5b75505Sopenharmony_ci if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) { 1753e5b75505Sopenharmony_ci /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */ 1754e5b75505Sopenharmony_ci int res; 1755e5b75505Sopenharmony_ci int use_sha384 = wpa_key_mgmt_sha384( 1756e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm)); 1757e5b75505Sopenharmony_ci 1758e5b75505Sopenharmony_ci res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384, 1759e5b75505Sopenharmony_ci wpabuf_put(data, 0), 1760e5b75505Sopenharmony_ci wpabuf_tailroom(data)); 1761e5b75505Sopenharmony_ci if (res < 0) { 1762e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1763e5b75505Sopenharmony_ci goto fail; 1764e5b75505Sopenharmony_ci } 1765e5b75505Sopenharmony_ci wpabuf_put(data, res); 1766e5b75505Sopenharmony_ci } 1767e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 1768e5b75505Sopenharmony_ci 1769e5b75505Sopenharmony_ci /* FILS Nonce */ 1770e5b75505Sopenharmony_ci wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ 1771e5b75505Sopenharmony_ci wpabuf_put_u8(data, 1 + FILS_NONCE_LEN); /* Length */ 1772e5b75505Sopenharmony_ci /* Element ID Extension */ 1773e5b75505Sopenharmony_ci wpabuf_put_u8(data, WLAN_EID_EXT_FILS_NONCE); 1774e5b75505Sopenharmony_ci wpabuf_put_data(data, fils_nonce, FILS_NONCE_LEN); 1775e5b75505Sopenharmony_ci 1776e5b75505Sopenharmony_ci /* FILS Session */ 1777e5b75505Sopenharmony_ci wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ 1778e5b75505Sopenharmony_ci wpabuf_put_u8(data, 1 + FILS_SESSION_LEN); /* Length */ 1779e5b75505Sopenharmony_ci /* Element ID Extension */ 1780e5b75505Sopenharmony_ci wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION); 1781e5b75505Sopenharmony_ci wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN); 1782e5b75505Sopenharmony_ci 1783e5b75505Sopenharmony_ci /* FILS Wrapped Data */ 1784e5b75505Sopenharmony_ci if (!pmksa && erp_resp) { 1785e5b75505Sopenharmony_ci wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ 1786e5b75505Sopenharmony_ci wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */ 1787e5b75505Sopenharmony_ci /* Element ID Extension */ 1788e5b75505Sopenharmony_ci wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA); 1789e5b75505Sopenharmony_ci wpabuf_put_buf(data, erp_resp); 1790e5b75505Sopenharmony_ci 1791e5b75505Sopenharmony_ci if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm), 1792e5b75505Sopenharmony_ci msk, msk_len, sta->fils_snonce, fils_nonce, 1793e5b75505Sopenharmony_ci sta->fils_dh_ss ? 1794e5b75505Sopenharmony_ci wpabuf_head(sta->fils_dh_ss) : NULL, 1795e5b75505Sopenharmony_ci sta->fils_dh_ss ? 1796e5b75505Sopenharmony_ci wpabuf_len(sta->fils_dh_ss) : 0, 1797e5b75505Sopenharmony_ci pmk_buf, &pmk_len)) { 1798e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK"); 1799e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1800e5b75505Sopenharmony_ci wpabuf_free(data); 1801e5b75505Sopenharmony_ci data = NULL; 1802e5b75505Sopenharmony_ci goto fail; 1803e5b75505Sopenharmony_ci } 1804e5b75505Sopenharmony_ci pmk = pmk_buf; 1805e5b75505Sopenharmony_ci 1806e5b75505Sopenharmony_ci /* Don't use DHss in PTK derivation if PMKSA caching is not 1807e5b75505Sopenharmony_ci * used. */ 1808e5b75505Sopenharmony_ci wpabuf_clear_free(sta->fils_dh_ss); 1809e5b75505Sopenharmony_ci sta->fils_dh_ss = NULL; 1810e5b75505Sopenharmony_ci 1811e5b75505Sopenharmony_ci if (sta->fils_erp_pmkid_set) { 1812e5b75505Sopenharmony_ci /* TODO: get PMKLifetime from WPA parameters */ 1813e5b75505Sopenharmony_ci unsigned int dot11RSNAConfigPMKLifetime = 43200; 1814e5b75505Sopenharmony_ci int session_timeout; 1815e5b75505Sopenharmony_ci 1816e5b75505Sopenharmony_ci session_timeout = dot11RSNAConfigPMKLifetime; 1817e5b75505Sopenharmony_ci if (sta->session_timeout_set) { 1818e5b75505Sopenharmony_ci struct os_reltime now, diff; 1819e5b75505Sopenharmony_ci 1820e5b75505Sopenharmony_ci os_get_reltime(&now); 1821e5b75505Sopenharmony_ci os_reltime_sub(&sta->session_timeout, &now, 1822e5b75505Sopenharmony_ci &diff); 1823e5b75505Sopenharmony_ci session_timeout = diff.sec; 1824e5b75505Sopenharmony_ci } 1825e5b75505Sopenharmony_ci 1826e5b75505Sopenharmony_ci sta->fils_erp_pmkid_set = 0; 1827e5b75505Sopenharmony_ci wpa_auth_add_fils_pmk_pmkid(sta->wpa_sm, pmk, pmk_len, 1828e5b75505Sopenharmony_ci sta->fils_erp_pmkid); 1829e5b75505Sopenharmony_ci if (!hapd->conf->disable_pmksa_caching && 1830e5b75505Sopenharmony_ci wpa_auth_pmksa_add2( 1831e5b75505Sopenharmony_ci hapd->wpa_auth, sta->addr, 1832e5b75505Sopenharmony_ci pmk, pmk_len, 1833e5b75505Sopenharmony_ci sta->fils_erp_pmkid, 1834e5b75505Sopenharmony_ci session_timeout, 1835e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) { 1836e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 1837e5b75505Sopenharmony_ci "FILS: Failed to add PMKSA cache entry based on ERP"); 1838e5b75505Sopenharmony_ci } 1839e5b75505Sopenharmony_ci } 1840e5b75505Sopenharmony_ci } else if (pmksa) { 1841e5b75505Sopenharmony_ci pmk = pmksa->pmk; 1842e5b75505Sopenharmony_ci pmk_len = pmksa->pmk_len; 1843e5b75505Sopenharmony_ci } 1844e5b75505Sopenharmony_ci 1845e5b75505Sopenharmony_ci if (!pmk) { 1846e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: No PMK available"); 1847e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1848e5b75505Sopenharmony_ci wpabuf_free(data); 1849e5b75505Sopenharmony_ci data = NULL; 1850e5b75505Sopenharmony_ci goto fail; 1851e5b75505Sopenharmony_ci } 1852e5b75505Sopenharmony_ci 1853e5b75505Sopenharmony_ci if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len, 1854e5b75505Sopenharmony_ci sta->fils_snonce, fils_nonce, 1855e5b75505Sopenharmony_ci sta->fils_dh_ss ? 1856e5b75505Sopenharmony_ci wpabuf_head(sta->fils_dh_ss) : NULL, 1857e5b75505Sopenharmony_ci sta->fils_dh_ss ? 1858e5b75505Sopenharmony_ci wpabuf_len(sta->fils_dh_ss) : 0, 1859e5b75505Sopenharmony_ci sta->fils_g_sta, pub) < 0) { 1860e5b75505Sopenharmony_ci *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1861e5b75505Sopenharmony_ci wpabuf_free(data); 1862e5b75505Sopenharmony_ci data = NULL; 1863e5b75505Sopenharmony_ci goto fail; 1864e5b75505Sopenharmony_ci } 1865e5b75505Sopenharmony_ci 1866e5b75505Sopenharmony_cifail: 1867e5b75505Sopenharmony_ci if (is_pub) 1868e5b75505Sopenharmony_ci *is_pub = pub != NULL; 1869e5b75505Sopenharmony_ci os_free(ie_buf); 1870e5b75505Sopenharmony_ci wpabuf_free(pub); 1871e5b75505Sopenharmony_ci wpabuf_clear_free(sta->fils_dh_ss); 1872e5b75505Sopenharmony_ci sta->fils_dh_ss = NULL; 1873e5b75505Sopenharmony_ci#ifdef CONFIG_FILS_SK_PFS 1874e5b75505Sopenharmony_ci crypto_ecdh_deinit(sta->fils_ecdh); 1875e5b75505Sopenharmony_ci sta->fils_ecdh = NULL; 1876e5b75505Sopenharmony_ci#endif /* CONFIG_FILS_SK_PFS */ 1877e5b75505Sopenharmony_ci return data; 1878e5b75505Sopenharmony_ci} 1879e5b75505Sopenharmony_ci 1880e5b75505Sopenharmony_ci 1881e5b75505Sopenharmony_cistatic void handle_auth_fils_finish(struct hostapd_data *hapd, 1882e5b75505Sopenharmony_ci struct sta_info *sta, u16 resp, 1883e5b75505Sopenharmony_ci struct wpabuf *data, int pub) 1884e5b75505Sopenharmony_ci{ 1885e5b75505Sopenharmony_ci u16 auth_alg; 1886e5b75505Sopenharmony_ci 1887e5b75505Sopenharmony_ci auth_alg = (pub || 1888e5b75505Sopenharmony_ci resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ? 1889e5b75505Sopenharmony_ci WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK; 1890e5b75505Sopenharmony_ci send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp, 1891e5b75505Sopenharmony_ci data ? wpabuf_head(data) : (u8 *) "", 1892e5b75505Sopenharmony_ci data ? wpabuf_len(data) : 0, "auth-fils-finish"); 1893e5b75505Sopenharmony_ci wpabuf_free(data); 1894e5b75505Sopenharmony_ci 1895e5b75505Sopenharmony_ci if (resp == WLAN_STATUS_SUCCESS) { 1896e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1897e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 1898e5b75505Sopenharmony_ci "authentication OK (FILS)"); 1899e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 1900e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 1901e5b75505Sopenharmony_ci sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK; 1902e5b75505Sopenharmony_ci mlme_authenticate_indication(hapd, sta); 1903e5b75505Sopenharmony_ci } 1904e5b75505Sopenharmony_ci} 1905e5b75505Sopenharmony_ci 1906e5b75505Sopenharmony_ci 1907e5b75505Sopenharmony_civoid ieee802_11_finish_fils_auth(struct hostapd_data *hapd, 1908e5b75505Sopenharmony_ci struct sta_info *sta, int success, 1909e5b75505Sopenharmony_ci struct wpabuf *erp_resp, 1910e5b75505Sopenharmony_ci const u8 *msk, size_t msk_len) 1911e5b75505Sopenharmony_ci{ 1912e5b75505Sopenharmony_ci struct wpabuf *data; 1913e5b75505Sopenharmony_ci int pub = 0; 1914e5b75505Sopenharmony_ci u16 resp; 1915e5b75505Sopenharmony_ci 1916e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_PENDING_FILS_ERP; 1917e5b75505Sopenharmony_ci 1918e5b75505Sopenharmony_ci if (!sta->fils_pending_cb) 1919e5b75505Sopenharmony_ci return; 1920e5b75505Sopenharmony_ci resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE; 1921e5b75505Sopenharmony_ci data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp, 1922e5b75505Sopenharmony_ci msk, msk_len, &pub); 1923e5b75505Sopenharmony_ci if (!data) { 1924e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1925e5b75505Sopenharmony_ci "%s: prepare_auth_resp_fils() returned failure", 1926e5b75505Sopenharmony_ci __func__); 1927e5b75505Sopenharmony_ci } 1928e5b75505Sopenharmony_ci sta->fils_pending_cb(hapd, sta, resp, data, pub); 1929e5b75505Sopenharmony_ci} 1930e5b75505Sopenharmony_ci 1931e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 1932e5b75505Sopenharmony_ci 1933e5b75505Sopenharmony_ci 1934e5b75505Sopenharmony_ciint 1935e5b75505Sopenharmony_ciieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, 1936e5b75505Sopenharmony_ci const u8 *msg, size_t len, u32 *session_timeout, 1937e5b75505Sopenharmony_ci u32 *acct_interim_interval, 1938e5b75505Sopenharmony_ci struct vlan_description *vlan_id, 1939e5b75505Sopenharmony_ci struct hostapd_sta_wpa_psk_short **psk, 1940e5b75505Sopenharmony_ci char **identity, char **radius_cui, int is_probe_req) 1941e5b75505Sopenharmony_ci{ 1942e5b75505Sopenharmony_ci int res; 1943e5b75505Sopenharmony_ci 1944e5b75505Sopenharmony_ci os_memset(vlan_id, 0, sizeof(*vlan_id)); 1945e5b75505Sopenharmony_ci res = hostapd_allowed_address(hapd, addr, msg, len, 1946e5b75505Sopenharmony_ci session_timeout, acct_interim_interval, 1947e5b75505Sopenharmony_ci vlan_id, psk, identity, radius_cui, 1948e5b75505Sopenharmony_ci is_probe_req); 1949e5b75505Sopenharmony_ci 1950e5b75505Sopenharmony_ci if (res == HOSTAPD_ACL_REJECT) { 1951e5b75505Sopenharmony_ci if (!is_probe_req) 1952e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1953e5b75505Sopenharmony_ci "Station " MACSTR 1954e5b75505Sopenharmony_ci " not allowed to authenticate", 1955e5b75505Sopenharmony_ci MAC2STR(addr)); 1956e5b75505Sopenharmony_ci return HOSTAPD_ACL_REJECT; 1957e5b75505Sopenharmony_ci } 1958e5b75505Sopenharmony_ci 1959e5b75505Sopenharmony_ci if (res == HOSTAPD_ACL_PENDING) { 1960e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR 1961e5b75505Sopenharmony_ci " waiting for an external authentication", 1962e5b75505Sopenharmony_ci MAC2STR(addr)); 1963e5b75505Sopenharmony_ci /* Authentication code will re-send the authentication frame 1964e5b75505Sopenharmony_ci * after it has received (and cached) information from the 1965e5b75505Sopenharmony_ci * external source. */ 1966e5b75505Sopenharmony_ci return HOSTAPD_ACL_PENDING; 1967e5b75505Sopenharmony_ci } 1968e5b75505Sopenharmony_ci 1969e5b75505Sopenharmony_ci return res; 1970e5b75505Sopenharmony_ci} 1971e5b75505Sopenharmony_ci 1972e5b75505Sopenharmony_ci 1973e5b75505Sopenharmony_cistatic int 1974e5b75505Sopenharmony_ciieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, 1975e5b75505Sopenharmony_ci int res, u32 session_timeout, 1976e5b75505Sopenharmony_ci u32 acct_interim_interval, 1977e5b75505Sopenharmony_ci struct vlan_description *vlan_id, 1978e5b75505Sopenharmony_ci struct hostapd_sta_wpa_psk_short **psk, 1979e5b75505Sopenharmony_ci char **identity, char **radius_cui) 1980e5b75505Sopenharmony_ci{ 1981e5b75505Sopenharmony_ci if (vlan_id->notempty && 1982e5b75505Sopenharmony_ci !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) { 1983e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 1984e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 1985e5b75505Sopenharmony_ci "Invalid VLAN %d%s received from RADIUS server", 1986e5b75505Sopenharmony_ci vlan_id->untagged, 1987e5b75505Sopenharmony_ci vlan_id->tagged[0] ? "+" : ""); 1988e5b75505Sopenharmony_ci return -1; 1989e5b75505Sopenharmony_ci } 1990e5b75505Sopenharmony_ci if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0) 1991e5b75505Sopenharmony_ci return -1; 1992e5b75505Sopenharmony_ci if (sta->vlan_id) 1993e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 1994e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); 1995e5b75505Sopenharmony_ci 1996e5b75505Sopenharmony_ci hostapd_free_psk_list(sta->psk); 1997e5b75505Sopenharmony_ci if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { 1998e5b75505Sopenharmony_ci sta->psk = *psk; 1999e5b75505Sopenharmony_ci *psk = NULL; 2000e5b75505Sopenharmony_ci } else { 2001e5b75505Sopenharmony_ci sta->psk = NULL; 2002e5b75505Sopenharmony_ci } 2003e5b75505Sopenharmony_ci 2004e5b75505Sopenharmony_ci os_free(sta->identity); 2005e5b75505Sopenharmony_ci sta->identity = *identity; 2006e5b75505Sopenharmony_ci *identity = NULL; 2007e5b75505Sopenharmony_ci 2008e5b75505Sopenharmony_ci os_free(sta->radius_cui); 2009e5b75505Sopenharmony_ci sta->radius_cui = *radius_cui; 2010e5b75505Sopenharmony_ci *radius_cui = NULL; 2011e5b75505Sopenharmony_ci 2012e5b75505Sopenharmony_ci if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval) 2013e5b75505Sopenharmony_ci sta->acct_interim_interval = acct_interim_interval; 2014e5b75505Sopenharmony_ci if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) { 2015e5b75505Sopenharmony_ci sta->session_timeout_set = 1; 2016e5b75505Sopenharmony_ci os_get_reltime(&sta->session_timeout); 2017e5b75505Sopenharmony_ci sta->session_timeout.sec += session_timeout; 2018e5b75505Sopenharmony_ci ap_sta_session_timeout(hapd, sta, session_timeout); 2019e5b75505Sopenharmony_ci } else { 2020e5b75505Sopenharmony_ci sta->session_timeout_set = 0; 2021e5b75505Sopenharmony_ci ap_sta_no_session_timeout(hapd, sta); 2022e5b75505Sopenharmony_ci } 2023e5b75505Sopenharmony_ci 2024e5b75505Sopenharmony_ci return 0; 2025e5b75505Sopenharmony_ci} 2026e5b75505Sopenharmony_ci 2027e5b75505Sopenharmony_ci 2028e5b75505Sopenharmony_cistatic void handle_auth(struct hostapd_data *hapd, 2029e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len, 2030e5b75505Sopenharmony_ci int rssi, int from_queue) 2031e5b75505Sopenharmony_ci{ 2032e5b75505Sopenharmony_ci u16 auth_alg, auth_transaction, status_code; 2033e5b75505Sopenharmony_ci u16 resp = WLAN_STATUS_SUCCESS; 2034e5b75505Sopenharmony_ci struct sta_info *sta = NULL; 2035e5b75505Sopenharmony_ci int res, reply_res; 2036e5b75505Sopenharmony_ci u16 fc; 2037e5b75505Sopenharmony_ci const u8 *challenge = NULL; 2038e5b75505Sopenharmony_ci u32 session_timeout, acct_interim_interval; 2039e5b75505Sopenharmony_ci struct vlan_description vlan_id; 2040e5b75505Sopenharmony_ci struct hostapd_sta_wpa_psk_short *psk = NULL; 2041e5b75505Sopenharmony_ci u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 2042e5b75505Sopenharmony_ci size_t resp_ies_len = 0; 2043e5b75505Sopenharmony_ci char *identity = NULL; 2044e5b75505Sopenharmony_ci char *radius_cui = NULL; 2045e5b75505Sopenharmony_ci u16 seq_ctrl; 2046e5b75505Sopenharmony_ci 2047e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { 2048e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", 2049e5b75505Sopenharmony_ci (unsigned long) len); 2050e5b75505Sopenharmony_ci return; 2051e5b75505Sopenharmony_ci } 2052e5b75505Sopenharmony_ci 2053e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 2054e5b75505Sopenharmony_ci if (hapd->iconf->ignore_auth_probability > 0.0 && 2055e5b75505Sopenharmony_ci drand48() < hapd->iconf->ignore_auth_probability) { 2056e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2057e5b75505Sopenharmony_ci "TESTING: ignoring auth frame from " MACSTR, 2058e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 2059e5b75505Sopenharmony_ci return; 2060e5b75505Sopenharmony_ci } 2061e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 2062e5b75505Sopenharmony_ci 2063e5b75505Sopenharmony_ci auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 2064e5b75505Sopenharmony_ci auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 2065e5b75505Sopenharmony_ci status_code = le_to_host16(mgmt->u.auth.status_code); 2066e5b75505Sopenharmony_ci fc = le_to_host16(mgmt->frame_control); 2067e5b75505Sopenharmony_ci seq_ctrl = le_to_host16(mgmt->seq_ctrl); 2068e5b75505Sopenharmony_ci 2069e5b75505Sopenharmony_ci if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) + 2070e5b75505Sopenharmony_ci 2 + WLAN_AUTH_CHALLENGE_LEN && 2071e5b75505Sopenharmony_ci mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE && 2072e5b75505Sopenharmony_ci mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN) 2073e5b75505Sopenharmony_ci challenge = &mgmt->u.auth.variable[2]; 2074e5b75505Sopenharmony_ci 2075e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d " 2076e5b75505Sopenharmony_ci "auth_transaction=%d status_code=%d wep=%d%s " 2077e5b75505Sopenharmony_ci "seq_ctrl=0x%x%s%s", 2078e5b75505Sopenharmony_ci MAC2STR(mgmt->sa), auth_alg, auth_transaction, 2079e5b75505Sopenharmony_ci status_code, !!(fc & WLAN_FC_ISWEP), 2080e5b75505Sopenharmony_ci challenge ? " challenge" : "", 2081e5b75505Sopenharmony_ci seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "", 2082e5b75505Sopenharmony_ci from_queue ? " (from queue)" : ""); 2083e5b75505Sopenharmony_ci 2084e5b75505Sopenharmony_ci#ifdef CONFIG_NO_RC4 2085e5b75505Sopenharmony_ci if (auth_alg == WLAN_AUTH_SHARED_KEY) { 2086e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 2087e5b75505Sopenharmony_ci "Unsupported authentication algorithm (%d)", 2088e5b75505Sopenharmony_ci auth_alg); 2089e5b75505Sopenharmony_ci resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 2090e5b75505Sopenharmony_ci goto fail; 2091e5b75505Sopenharmony_ci } 2092e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RC4 */ 2093e5b75505Sopenharmony_ci 2094e5b75505Sopenharmony_ci if (hapd->tkip_countermeasures) { 2095e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2096e5b75505Sopenharmony_ci "Ongoing TKIP countermeasures (Michael MIC failure) - reject authentication"); 2097e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2098e5b75505Sopenharmony_ci goto fail; 2099e5b75505Sopenharmony_ci } 2100e5b75505Sopenharmony_ci 2101e5b75505Sopenharmony_ci if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && 2102e5b75505Sopenharmony_ci auth_alg == WLAN_AUTH_OPEN) || 2103e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 2104e5b75505Sopenharmony_ci (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && 2105e5b75505Sopenharmony_ci auth_alg == WLAN_AUTH_FT) || 2106e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 2107e5b75505Sopenharmony_ci#ifdef CONFIG_SAE 2108e5b75505Sopenharmony_ci (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && 2109e5b75505Sopenharmony_ci auth_alg == WLAN_AUTH_SAE) || 2110e5b75505Sopenharmony_ci#endif /* CONFIG_SAE */ 2111e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 2112e5b75505Sopenharmony_ci (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) && 2113e5b75505Sopenharmony_ci auth_alg == WLAN_AUTH_FILS_SK) || 2114e5b75505Sopenharmony_ci (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) && 2115e5b75505Sopenharmony_ci hapd->conf->fils_dh_group && 2116e5b75505Sopenharmony_ci auth_alg == WLAN_AUTH_FILS_SK_PFS) || 2117e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 2118e5b75505Sopenharmony_ci ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && 2119e5b75505Sopenharmony_ci auth_alg == WLAN_AUTH_SHARED_KEY))) { 2120e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)", 2121e5b75505Sopenharmony_ci auth_alg); 2122e5b75505Sopenharmony_ci resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 2123e5b75505Sopenharmony_ci goto fail; 2124e5b75505Sopenharmony_ci } 2125e5b75505Sopenharmony_ci 2126e5b75505Sopenharmony_ci if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE || 2127e5b75505Sopenharmony_ci (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { 2128e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)", 2129e5b75505Sopenharmony_ci auth_transaction); 2130e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; 2131e5b75505Sopenharmony_ci goto fail; 2132e5b75505Sopenharmony_ci } 2133e5b75505Sopenharmony_ci 2134e5b75505Sopenharmony_ci if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { 2135e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate", 2136e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 2137e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2138e5b75505Sopenharmony_ci goto fail; 2139e5b75505Sopenharmony_ci } 2140e5b75505Sopenharmony_ci 2141e5b75505Sopenharmony_ci if (hapd->conf->no_auth_if_seen_on) { 2142e5b75505Sopenharmony_ci struct hostapd_data *other; 2143e5b75505Sopenharmony_ci 2144e5b75505Sopenharmony_ci other = sta_track_seen_on(hapd->iface, mgmt->sa, 2145e5b75505Sopenharmony_ci hapd->conf->no_auth_if_seen_on); 2146e5b75505Sopenharmony_ci if (other) { 2147e5b75505Sopenharmony_ci u8 *pos; 2148e5b75505Sopenharmony_ci u32 info; 2149e5b75505Sopenharmony_ci u8 op_class, channel, phytype; 2150e5b75505Sopenharmony_ci 2151e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Reject authentication from " 2152e5b75505Sopenharmony_ci MACSTR " since STA has been seen on %s", 2153e5b75505Sopenharmony_ci hapd->conf->iface, MAC2STR(mgmt->sa), 2154e5b75505Sopenharmony_ci hapd->conf->no_auth_if_seen_on); 2155e5b75505Sopenharmony_ci 2156e5b75505Sopenharmony_ci resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION; 2157e5b75505Sopenharmony_ci pos = &resp_ies[0]; 2158e5b75505Sopenharmony_ci *pos++ = WLAN_EID_NEIGHBOR_REPORT; 2159e5b75505Sopenharmony_ci *pos++ = 13; 2160e5b75505Sopenharmony_ci os_memcpy(pos, other->own_addr, ETH_ALEN); 2161e5b75505Sopenharmony_ci pos += ETH_ALEN; 2162e5b75505Sopenharmony_ci info = 0; /* TODO: BSSID Information */ 2163e5b75505Sopenharmony_ci WPA_PUT_LE32(pos, info); 2164e5b75505Sopenharmony_ci pos += 4; 2165e5b75505Sopenharmony_ci if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD) 2166e5b75505Sopenharmony_ci phytype = 8; /* dmg */ 2167e5b75505Sopenharmony_ci else if (other->iconf->ieee80211ac) 2168e5b75505Sopenharmony_ci phytype = 9; /* vht */ 2169e5b75505Sopenharmony_ci else if (other->iconf->ieee80211n) 2170e5b75505Sopenharmony_ci phytype = 7; /* ht */ 2171e5b75505Sopenharmony_ci else if (other->iconf->hw_mode == 2172e5b75505Sopenharmony_ci HOSTAPD_MODE_IEEE80211A) 2173e5b75505Sopenharmony_ci phytype = 4; /* ofdm */ 2174e5b75505Sopenharmony_ci else if (other->iconf->hw_mode == 2175e5b75505Sopenharmony_ci HOSTAPD_MODE_IEEE80211G) 2176e5b75505Sopenharmony_ci phytype = 6; /* erp */ 2177e5b75505Sopenharmony_ci else 2178e5b75505Sopenharmony_ci phytype = 5; /* hrdsss */ 2179e5b75505Sopenharmony_ci if (ieee80211_freq_to_channel_ext( 2180e5b75505Sopenharmony_ci hostapd_hw_get_freq(other, 2181e5b75505Sopenharmony_ci other->iconf->channel), 2182e5b75505Sopenharmony_ci other->iconf->secondary_channel, 2183e5b75505Sopenharmony_ci other->iconf->ieee80211ac, 2184e5b75505Sopenharmony_ci &op_class, &channel) == NUM_HOSTAPD_MODES) { 2185e5b75505Sopenharmony_ci op_class = 0; 2186e5b75505Sopenharmony_ci channel = other->iconf->channel; 2187e5b75505Sopenharmony_ci } 2188e5b75505Sopenharmony_ci *pos++ = op_class; 2189e5b75505Sopenharmony_ci *pos++ = channel; 2190e5b75505Sopenharmony_ci *pos++ = phytype; 2191e5b75505Sopenharmony_ci resp_ies_len = pos - &resp_ies[0]; 2192e5b75505Sopenharmony_ci goto fail; 2193e5b75505Sopenharmony_ci } 2194e5b75505Sopenharmony_ci } 2195e5b75505Sopenharmony_ci 2196e5b75505Sopenharmony_ci res = ieee802_11_allowed_address( 2197e5b75505Sopenharmony_ci hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout, 2198e5b75505Sopenharmony_ci &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui, 2199e5b75505Sopenharmony_ci 0); 2200e5b75505Sopenharmony_ci if (res == HOSTAPD_ACL_REJECT) { 2201e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_DEBUG, 2202e5b75505Sopenharmony_ci "Ignore Authentication frame from " MACSTR 2203e5b75505Sopenharmony_ci " due to ACL reject", MAC2STR(mgmt->sa)); 2204e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2205e5b75505Sopenharmony_ci goto fail; 2206e5b75505Sopenharmony_ci } 2207e5b75505Sopenharmony_ci if (res == HOSTAPD_ACL_PENDING) 2208e5b75505Sopenharmony_ci return; 2209e5b75505Sopenharmony_ci 2210e5b75505Sopenharmony_ci#ifdef CONFIG_SAE 2211e5b75505Sopenharmony_ci if (auth_alg == WLAN_AUTH_SAE && !from_queue && 2212e5b75505Sopenharmony_ci (auth_transaction == 1 || 2213e5b75505Sopenharmony_ci (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) { 2214e5b75505Sopenharmony_ci /* Handle SAE Authentication commit message through a queue to 2215e5b75505Sopenharmony_ci * provide more control for postponing the needed heavy 2216e5b75505Sopenharmony_ci * processing under a possible DoS attack scenario. In addition, 2217e5b75505Sopenharmony_ci * queue SAE Authentication confirm message if there happens to 2218e5b75505Sopenharmony_ci * be a queued commit message from the same peer. This is needed 2219e5b75505Sopenharmony_ci * to avoid reordering Authentication frames within the same 2220e5b75505Sopenharmony_ci * SAE exchange. */ 2221e5b75505Sopenharmony_ci auth_sae_queue(hapd, mgmt, len, rssi); 2222e5b75505Sopenharmony_ci return; 2223e5b75505Sopenharmony_ci } 2224e5b75505Sopenharmony_ci#endif /* CONFIG_SAE */ 2225e5b75505Sopenharmony_ci 2226e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->sa); 2227e5b75505Sopenharmony_ci if (sta) { 2228e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_PENDING_FILS_ERP; 2229e5b75505Sopenharmony_ci sta->ft_over_ds = 0; 2230e5b75505Sopenharmony_ci if ((fc & WLAN_FC_RETRY) && 2231e5b75505Sopenharmony_ci sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ && 2232e5b75505Sopenharmony_ci sta->last_seq_ctrl == seq_ctrl && 2233e5b75505Sopenharmony_ci sta->last_subtype == WLAN_FC_STYPE_AUTH) { 2234e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 2235e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 2236e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2237e5b75505Sopenharmony_ci "Drop repeated authentication frame seq_ctrl=0x%x", 2238e5b75505Sopenharmony_ci seq_ctrl); 2239e5b75505Sopenharmony_ci return; 2240e5b75505Sopenharmony_ci } 2241e5b75505Sopenharmony_ci#ifdef CONFIG_MESH 2242e5b75505Sopenharmony_ci if ((hapd->conf->mesh & MESH_ENABLED) && 2243e5b75505Sopenharmony_ci sta->plink_state == PLINK_BLOCKED) { 2244e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR 2245e5b75505Sopenharmony_ci " is blocked - drop Authentication frame", 2246e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 2247e5b75505Sopenharmony_ci return; 2248e5b75505Sopenharmony_ci } 2249e5b75505Sopenharmony_ci#endif /* CONFIG_MESH */ 2250e5b75505Sopenharmony_ci } else { 2251e5b75505Sopenharmony_ci#ifdef CONFIG_MESH 2252e5b75505Sopenharmony_ci if (hapd->conf->mesh & MESH_ENABLED) { 2253e5b75505Sopenharmony_ci /* if the mesh peer is not available, we don't do auth. 2254e5b75505Sopenharmony_ci */ 2255e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR 2256e5b75505Sopenharmony_ci " not yet known - drop Authentication frame", 2257e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 2258e5b75505Sopenharmony_ci /* 2259e5b75505Sopenharmony_ci * Save a copy of the frame so that it can be processed 2260e5b75505Sopenharmony_ci * if a new peer entry is added shortly after this. 2261e5b75505Sopenharmony_ci */ 2262e5b75505Sopenharmony_ci wpabuf_free(hapd->mesh_pending_auth); 2263e5b75505Sopenharmony_ci hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len); 2264e5b75505Sopenharmony_ci os_get_reltime(&hapd->mesh_pending_auth_time); 2265e5b75505Sopenharmony_ci return; 2266e5b75505Sopenharmony_ci } 2267e5b75505Sopenharmony_ci#endif /* CONFIG_MESH */ 2268e5b75505Sopenharmony_ci 2269e5b75505Sopenharmony_ci sta = ap_sta_add(hapd, mgmt->sa); 2270e5b75505Sopenharmony_ci if (!sta) { 2271e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ap_sta_add() failed"); 2272e5b75505Sopenharmony_ci resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 2273e5b75505Sopenharmony_ci goto fail; 2274e5b75505Sopenharmony_ci } 2275e5b75505Sopenharmony_ci } 2276e5b75505Sopenharmony_ci sta->last_seq_ctrl = seq_ctrl; 2277e5b75505Sopenharmony_ci sta->last_subtype = WLAN_FC_STYPE_AUTH; 2278e5b75505Sopenharmony_ci#ifdef CONFIG_MBO 2279e5b75505Sopenharmony_ci sta->auth_rssi = rssi; 2280e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */ 2281e5b75505Sopenharmony_ci 2282e5b75505Sopenharmony_ci res = ieee802_11_set_radius_info( 2283e5b75505Sopenharmony_ci hapd, sta, res, session_timeout, acct_interim_interval, 2284e5b75505Sopenharmony_ci &vlan_id, &psk, &identity, &radius_cui); 2285e5b75505Sopenharmony_ci if (res) { 2286e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed"); 2287e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2288e5b75505Sopenharmony_ci goto fail; 2289e5b75505Sopenharmony_ci } 2290e5b75505Sopenharmony_ci 2291e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_PREAUTH; 2292e5b75505Sopenharmony_ci ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 2293e5b75505Sopenharmony_ci 2294e5b75505Sopenharmony_ci /* 2295e5b75505Sopenharmony_ci * If the driver supports full AP client state, add a station to the 2296e5b75505Sopenharmony_ci * driver before sending authentication reply to make sure the driver 2297e5b75505Sopenharmony_ci * has resources, and not to go through the entire authentication and 2298e5b75505Sopenharmony_ci * association handshake, and fail it at the end. 2299e5b75505Sopenharmony_ci * 2300e5b75505Sopenharmony_ci * If this is not the first transaction, in a multi-step authentication 2301e5b75505Sopenharmony_ci * algorithm, the station already exists in the driver 2302e5b75505Sopenharmony_ci * (sta->added_unassoc = 1) so skip it. 2303e5b75505Sopenharmony_ci * 2304e5b75505Sopenharmony_ci * In mesh mode, the station was already added to the driver when the 2305e5b75505Sopenharmony_ci * NEW_PEER_CANDIDATE event is received. 2306e5b75505Sopenharmony_ci * 2307e5b75505Sopenharmony_ci * If PMF was negotiated for the existing association, skip this to 2308e5b75505Sopenharmony_ci * avoid dropping the STA entry and the associated keys. This is needed 2309e5b75505Sopenharmony_ci * to allow the original connection work until the attempt can complete 2310e5b75505Sopenharmony_ci * (re)association, so that unprotected Authentication frame cannot be 2311e5b75505Sopenharmony_ci * used to bypass PMF protection. 2312e5b75505Sopenharmony_ci */ 2313e5b75505Sopenharmony_ci if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) && 2314e5b75505Sopenharmony_ci (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) && 2315e5b75505Sopenharmony_ci !(hapd->conf->mesh & MESH_ENABLED) && 2316e5b75505Sopenharmony_ci !(sta->added_unassoc)) { 2317e5b75505Sopenharmony_ci /* 2318e5b75505Sopenharmony_ci * If a station that is already associated to the AP, is trying 2319e5b75505Sopenharmony_ci * to authenticate again, remove the STA entry, in order to make 2320e5b75505Sopenharmony_ci * sure the STA PS state gets cleared and configuration gets 2321e5b75505Sopenharmony_ci * updated. To handle this, station's added_unassoc flag is 2322e5b75505Sopenharmony_ci * cleared once the station has completed association. 2323e5b75505Sopenharmony_ci */ 2324e5b75505Sopenharmony_ci ap_sta_set_authorized(hapd, sta, 0); 2325e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 2326e5b75505Sopenharmony_ci sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | 2327e5b75505Sopenharmony_ci WLAN_STA_AUTHORIZED); 2328e5b75505Sopenharmony_ci 2329e5b75505Sopenharmony_ci if (hostapd_sta_add(hapd, sta->addr, 0, 0, 2330e5b75505Sopenharmony_ci sta->supported_rates, 2331e5b75505Sopenharmony_ci sta->supported_rates_len, 2332e5b75505Sopenharmony_ci 0, NULL, NULL, NULL, 0, 2333e5b75505Sopenharmony_ci sta->flags, 0, 0, 0, 0)) { 2334e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 2335e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 2336e5b75505Sopenharmony_ci HOSTAPD_LEVEL_NOTICE, 2337e5b75505Sopenharmony_ci "Could not add STA to kernel driver"); 2338e5b75505Sopenharmony_ci resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 2339e5b75505Sopenharmony_ci goto fail; 2340e5b75505Sopenharmony_ci } 2341e5b75505Sopenharmony_ci 2342e5b75505Sopenharmony_ci sta->added_unassoc = 1; 2343e5b75505Sopenharmony_ci } 2344e5b75505Sopenharmony_ci 2345e5b75505Sopenharmony_ci switch (auth_alg) { 2346e5b75505Sopenharmony_ci case WLAN_AUTH_OPEN: 2347e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2348e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2349e5b75505Sopenharmony_ci "authentication OK (open system)"); 2350e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 2351e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 2352e5b75505Sopenharmony_ci sta->auth_alg = WLAN_AUTH_OPEN; 2353e5b75505Sopenharmony_ci mlme_authenticate_indication(hapd, sta); 2354e5b75505Sopenharmony_ci break; 2355e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RC4 2356e5b75505Sopenharmony_ci case WLAN_AUTH_SHARED_KEY: 2357e5b75505Sopenharmony_ci resp = auth_shared_key(hapd, sta, auth_transaction, challenge, 2358e5b75505Sopenharmony_ci fc & WLAN_FC_ISWEP); 2359e5b75505Sopenharmony_ci if (resp != 0) 2360e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2361e5b75505Sopenharmony_ci "auth_shared_key() failed: status=%d", resp); 2362e5b75505Sopenharmony_ci sta->auth_alg = WLAN_AUTH_SHARED_KEY; 2363e5b75505Sopenharmony_ci mlme_authenticate_indication(hapd, sta); 2364e5b75505Sopenharmony_ci if (sta->challenge && auth_transaction == 1) { 2365e5b75505Sopenharmony_ci resp_ies[0] = WLAN_EID_CHALLENGE; 2366e5b75505Sopenharmony_ci resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN; 2367e5b75505Sopenharmony_ci os_memcpy(resp_ies + 2, sta->challenge, 2368e5b75505Sopenharmony_ci WLAN_AUTH_CHALLENGE_LEN); 2369e5b75505Sopenharmony_ci resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN; 2370e5b75505Sopenharmony_ci } 2371e5b75505Sopenharmony_ci break; 2372e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RC4 */ 2373e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 2374e5b75505Sopenharmony_ci case WLAN_AUTH_FT: 2375e5b75505Sopenharmony_ci sta->auth_alg = WLAN_AUTH_FT; 2376e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) 2377e5b75505Sopenharmony_ci sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 2378e5b75505Sopenharmony_ci sta->addr, NULL); 2379e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) { 2380e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " 2381e5b75505Sopenharmony_ci "state machine"); 2382e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2383e5b75505Sopenharmony_ci goto fail; 2384e5b75505Sopenharmony_ci } 2385e5b75505Sopenharmony_ci wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid, 2386e5b75505Sopenharmony_ci auth_transaction, mgmt->u.auth.variable, 2387e5b75505Sopenharmony_ci len - IEEE80211_HDRLEN - 2388e5b75505Sopenharmony_ci sizeof(mgmt->u.auth), 2389e5b75505Sopenharmony_ci handle_auth_ft_finish, hapd); 2390e5b75505Sopenharmony_ci /* handle_auth_ft_finish() callback will complete auth. */ 2391e5b75505Sopenharmony_ci return; 2392e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 2393e5b75505Sopenharmony_ci#ifdef CONFIG_SAE 2394e5b75505Sopenharmony_ci case WLAN_AUTH_SAE: 2395e5b75505Sopenharmony_ci#ifdef CONFIG_MESH 2396e5b75505Sopenharmony_ci if (status_code == WLAN_STATUS_SUCCESS && 2397e5b75505Sopenharmony_ci hapd->conf->mesh & MESH_ENABLED) { 2398e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) 2399e5b75505Sopenharmony_ci sta->wpa_sm = 2400e5b75505Sopenharmony_ci wpa_auth_sta_init(hapd->wpa_auth, 2401e5b75505Sopenharmony_ci sta->addr, NULL); 2402e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) { 2403e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2404e5b75505Sopenharmony_ci "SAE: Failed to initialize WPA state machine"); 2405e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 2406e5b75505Sopenharmony_ci goto fail; 2407e5b75505Sopenharmony_ci } 2408e5b75505Sopenharmony_ci } 2409e5b75505Sopenharmony_ci#endif /* CONFIG_MESH */ 2410e5b75505Sopenharmony_ci handle_auth_sae(hapd, sta, mgmt, len, auth_transaction, 2411e5b75505Sopenharmony_ci status_code); 2412e5b75505Sopenharmony_ci return; 2413e5b75505Sopenharmony_ci#endif /* CONFIG_SAE */ 2414e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 2415e5b75505Sopenharmony_ci case WLAN_AUTH_FILS_SK: 2416e5b75505Sopenharmony_ci case WLAN_AUTH_FILS_SK_PFS: 2417e5b75505Sopenharmony_ci handle_auth_fils(hapd, sta, mgmt->u.auth.variable, 2418e5b75505Sopenharmony_ci len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth), 2419e5b75505Sopenharmony_ci auth_alg, auth_transaction, status_code, 2420e5b75505Sopenharmony_ci handle_auth_fils_finish); 2421e5b75505Sopenharmony_ci return; 2422e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 2423e5b75505Sopenharmony_ci } 2424e5b75505Sopenharmony_ci 2425e5b75505Sopenharmony_ci fail: 2426e5b75505Sopenharmony_ci os_free(identity); 2427e5b75505Sopenharmony_ci os_free(radius_cui); 2428e5b75505Sopenharmony_ci hostapd_free_psk_list(psk); 2429e5b75505Sopenharmony_ci 2430e5b75505Sopenharmony_ci reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, 2431e5b75505Sopenharmony_ci auth_transaction + 1, resp, resp_ies, 2432e5b75505Sopenharmony_ci resp_ies_len, "handle-auth"); 2433e5b75505Sopenharmony_ci 2434e5b75505Sopenharmony_ci if (sta && sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS || 2435e5b75505Sopenharmony_ci reply_res != WLAN_STATUS_SUCCESS)) { 2436e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 2437e5b75505Sopenharmony_ci sta->added_unassoc = 0; 2438e5b75505Sopenharmony_ci } 2439e5b75505Sopenharmony_ci} 2440e5b75505Sopenharmony_ci 2441e5b75505Sopenharmony_ci 2442e5b75505Sopenharmony_ciint hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) 2443e5b75505Sopenharmony_ci{ 2444e5b75505Sopenharmony_ci int i, j = 32, aid; 2445e5b75505Sopenharmony_ci 2446e5b75505Sopenharmony_ci /* get a unique AID */ 2447e5b75505Sopenharmony_ci if (sta->aid > 0) { 2448e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " old AID %d", sta->aid); 2449e5b75505Sopenharmony_ci return 0; 2450e5b75505Sopenharmony_ci } 2451e5b75505Sopenharmony_ci 2452e5b75505Sopenharmony_ci if (TEST_FAIL()) 2453e5b75505Sopenharmony_ci return -1; 2454e5b75505Sopenharmony_ci 2455e5b75505Sopenharmony_ci for (i = 0; i < AID_WORDS; i++) { 2456e5b75505Sopenharmony_ci if (hapd->sta_aid[i] == (u32) -1) 2457e5b75505Sopenharmony_ci continue; 2458e5b75505Sopenharmony_ci for (j = 0; j < 32; j++) { 2459e5b75505Sopenharmony_ci if (!(hapd->sta_aid[i] & BIT(j))) 2460e5b75505Sopenharmony_ci break; 2461e5b75505Sopenharmony_ci } 2462e5b75505Sopenharmony_ci if (j < 32) 2463e5b75505Sopenharmony_ci break; 2464e5b75505Sopenharmony_ci } 2465e5b75505Sopenharmony_ci if (j == 32) 2466e5b75505Sopenharmony_ci return -1; 2467e5b75505Sopenharmony_ci aid = i * 32 + j + 1; 2468e5b75505Sopenharmony_ci if (aid > 2007) 2469e5b75505Sopenharmony_ci return -1; 2470e5b75505Sopenharmony_ci 2471e5b75505Sopenharmony_ci sta->aid = aid; 2472e5b75505Sopenharmony_ci hapd->sta_aid[i] |= BIT(j); 2473e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " new AID %d", sta->aid); 2474e5b75505Sopenharmony_ci return 0; 2475e5b75505Sopenharmony_ci} 2476e5b75505Sopenharmony_ci 2477e5b75505Sopenharmony_ci 2478e5b75505Sopenharmony_cistatic u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta, 2479e5b75505Sopenharmony_ci const u8 *ssid_ie, size_t ssid_ie_len) 2480e5b75505Sopenharmony_ci{ 2481e5b75505Sopenharmony_ci if (ssid_ie == NULL) 2482e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2483e5b75505Sopenharmony_ci 2484e5b75505Sopenharmony_ci if (ssid_ie_len != hapd->conf->ssid.ssid_len || 2485e5b75505Sopenharmony_ci os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) { 2486e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2487e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 2488e5b75505Sopenharmony_ci "Station tried to associate with unknown SSID " 2489e5b75505Sopenharmony_ci "'%s'", wpa_ssid_txt(ssid_ie, ssid_ie_len)); 2490e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2491e5b75505Sopenharmony_ci } 2492e5b75505Sopenharmony_ci 2493e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2494e5b75505Sopenharmony_ci} 2495e5b75505Sopenharmony_ci 2496e5b75505Sopenharmony_ci 2497e5b75505Sopenharmony_cistatic u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, 2498e5b75505Sopenharmony_ci const u8 *wmm_ie, size_t wmm_ie_len) 2499e5b75505Sopenharmony_ci{ 2500e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_WMM; 2501e5b75505Sopenharmony_ci sta->qosinfo = 0; 2502e5b75505Sopenharmony_ci if (wmm_ie && hapd->conf->wmm_enabled) { 2503e5b75505Sopenharmony_ci struct wmm_information_element *wmm; 2504e5b75505Sopenharmony_ci 2505e5b75505Sopenharmony_ci if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) { 2506e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 2507e5b75505Sopenharmony_ci HOSTAPD_MODULE_WPA, 2508e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2509e5b75505Sopenharmony_ci "invalid WMM element in association " 2510e5b75505Sopenharmony_ci "request"); 2511e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2512e5b75505Sopenharmony_ci } 2513e5b75505Sopenharmony_ci 2514e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_WMM; 2515e5b75505Sopenharmony_ci wmm = (struct wmm_information_element *) wmm_ie; 2516e5b75505Sopenharmony_ci sta->qosinfo = wmm->qos_info; 2517e5b75505Sopenharmony_ci } 2518e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2519e5b75505Sopenharmony_ci} 2520e5b75505Sopenharmony_ci 2521e5b75505Sopenharmony_cistatic u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta, 2522e5b75505Sopenharmony_ci const u8 *multi_ap_ie, size_t multi_ap_len) 2523e5b75505Sopenharmony_ci{ 2524e5b75505Sopenharmony_ci u8 multi_ap_value = 0; 2525e5b75505Sopenharmony_ci 2526e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_MULTI_AP; 2527e5b75505Sopenharmony_ci 2528e5b75505Sopenharmony_ci if (!hapd->conf->multi_ap) 2529e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2530e5b75505Sopenharmony_ci 2531e5b75505Sopenharmony_ci if (multi_ap_ie) { 2532e5b75505Sopenharmony_ci const u8 *multi_ap_subelem; 2533e5b75505Sopenharmony_ci 2534e5b75505Sopenharmony_ci multi_ap_subelem = get_ie(multi_ap_ie + 4, 2535e5b75505Sopenharmony_ci multi_ap_len - 4, 2536e5b75505Sopenharmony_ci MULTI_AP_SUB_ELEM_TYPE); 2537e5b75505Sopenharmony_ci if (multi_ap_subelem && multi_ap_subelem[1] == 1) { 2538e5b75505Sopenharmony_ci multi_ap_value = multi_ap_subelem[2]; 2539e5b75505Sopenharmony_ci } else { 2540e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 2541e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 2542e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 2543e5b75505Sopenharmony_ci "Multi-AP IE has missing or invalid Multi-AP subelement"); 2544e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_IE; 2545e5b75505Sopenharmony_ci } 2546e5b75505Sopenharmony_ci } 2547e5b75505Sopenharmony_ci 2548e5b75505Sopenharmony_ci if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA) 2549e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2550e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 2551e5b75505Sopenharmony_ci "Multi-AP IE with unexpected value 0x%02x", 2552e5b75505Sopenharmony_ci multi_ap_value); 2553e5b75505Sopenharmony_ci 2554e5b75505Sopenharmony_ci if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) { 2555e5b75505Sopenharmony_ci if (hapd->conf->multi_ap & FRONTHAUL_BSS) 2556e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2557e5b75505Sopenharmony_ci 2558e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 2559e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 2560e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 2561e5b75505Sopenharmony_ci "Non-Multi-AP STA tries to associate with backhaul-only BSS"); 2562e5b75505Sopenharmony_ci return WLAN_STATUS_ASSOC_DENIED_UNSPEC; 2563e5b75505Sopenharmony_ci } 2564e5b75505Sopenharmony_ci 2565e5b75505Sopenharmony_ci if (!(hapd->conf->multi_ap & BACKHAUL_BSS)) 2566e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2567e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2568e5b75505Sopenharmony_ci "Backhaul STA tries to associate with fronthaul-only BSS"); 2569e5b75505Sopenharmony_ci 2570e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_MULTI_AP; 2571e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2572e5b75505Sopenharmony_ci} 2573e5b75505Sopenharmony_ci 2574e5b75505Sopenharmony_ci 2575e5b75505Sopenharmony_cistatic u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, 2576e5b75505Sopenharmony_ci struct ieee802_11_elems *elems) 2577e5b75505Sopenharmony_ci{ 2578e5b75505Sopenharmony_ci /* Supported rates not used in IEEE 802.11ad/DMG */ 2579e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 2580e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) 2581e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2582e5b75505Sopenharmony_ci 2583e5b75505Sopenharmony_ci if (!elems->supp_rates) { 2584e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2585e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2586e5b75505Sopenharmony_ci "No supported rates element in AssocReq"); 2587e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2588e5b75505Sopenharmony_ci } 2589e5b75505Sopenharmony_ci 2590e5b75505Sopenharmony_ci if (elems->supp_rates_len + elems->ext_supp_rates_len > 2591e5b75505Sopenharmony_ci sizeof(sta->supported_rates)) { 2592e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2593e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2594e5b75505Sopenharmony_ci "Invalid supported rates element length %d+%d", 2595e5b75505Sopenharmony_ci elems->supp_rates_len, 2596e5b75505Sopenharmony_ci elems->ext_supp_rates_len); 2597e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2598e5b75505Sopenharmony_ci } 2599e5b75505Sopenharmony_ci 2600e5b75505Sopenharmony_ci sta->supported_rates_len = merge_byte_arrays( 2601e5b75505Sopenharmony_ci sta->supported_rates, sizeof(sta->supported_rates), 2602e5b75505Sopenharmony_ci elems->supp_rates, elems->supp_rates_len, 2603e5b75505Sopenharmony_ci elems->ext_supp_rates, elems->ext_supp_rates_len); 2604e5b75505Sopenharmony_ci 2605e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2606e5b75505Sopenharmony_ci} 2607e5b75505Sopenharmony_ci 2608e5b75505Sopenharmony_ci 2609e5b75505Sopenharmony_cistatic u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, 2610e5b75505Sopenharmony_ci const u8 *ext_capab_ie, size_t ext_capab_ie_len) 2611e5b75505Sopenharmony_ci{ 2612e5b75505Sopenharmony_ci#ifdef CONFIG_INTERWORKING 2613e5b75505Sopenharmony_ci /* check for QoS Map support */ 2614e5b75505Sopenharmony_ci if (ext_capab_ie_len >= 5) { 2615e5b75505Sopenharmony_ci if (ext_capab_ie[4] & 0x01) 2616e5b75505Sopenharmony_ci sta->qos_map_enabled = 1; 2617e5b75505Sopenharmony_ci } 2618e5b75505Sopenharmony_ci#endif /* CONFIG_INTERWORKING */ 2619e5b75505Sopenharmony_ci 2620e5b75505Sopenharmony_ci if (ext_capab_ie_len > 0) { 2621e5b75505Sopenharmony_ci sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); 2622e5b75505Sopenharmony_ci os_free(sta->ext_capability); 2623e5b75505Sopenharmony_ci sta->ext_capability = os_malloc(1 + ext_capab_ie_len); 2624e5b75505Sopenharmony_ci if (sta->ext_capability) { 2625e5b75505Sopenharmony_ci sta->ext_capability[0] = ext_capab_ie_len; 2626e5b75505Sopenharmony_ci os_memcpy(sta->ext_capability + 1, ext_capab_ie, 2627e5b75505Sopenharmony_ci ext_capab_ie_len); 2628e5b75505Sopenharmony_ci } 2629e5b75505Sopenharmony_ci } 2630e5b75505Sopenharmony_ci 2631e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2632e5b75505Sopenharmony_ci} 2633e5b75505Sopenharmony_ci 2634e5b75505Sopenharmony_ci 2635e5b75505Sopenharmony_ci#ifdef CONFIG_OWE 2636e5b75505Sopenharmony_ci 2637e5b75505Sopenharmony_cistatic int owe_group_supported(struct hostapd_data *hapd, u16 group) 2638e5b75505Sopenharmony_ci{ 2639e5b75505Sopenharmony_ci int i; 2640e5b75505Sopenharmony_ci int *groups = hapd->conf->owe_groups; 2641e5b75505Sopenharmony_ci 2642e5b75505Sopenharmony_ci if (group != 19 && group != 20 && group != 21) 2643e5b75505Sopenharmony_ci return 0; 2644e5b75505Sopenharmony_ci 2645e5b75505Sopenharmony_ci if (!groups) 2646e5b75505Sopenharmony_ci return 1; 2647e5b75505Sopenharmony_ci 2648e5b75505Sopenharmony_ci for (i = 0; groups[i] > 0; i++) { 2649e5b75505Sopenharmony_ci if (groups[i] == group) 2650e5b75505Sopenharmony_ci return 1; 2651e5b75505Sopenharmony_ci } 2652e5b75505Sopenharmony_ci 2653e5b75505Sopenharmony_ci return 0; 2654e5b75505Sopenharmony_ci} 2655e5b75505Sopenharmony_ci 2656e5b75505Sopenharmony_ci 2657e5b75505Sopenharmony_cistatic u16 owe_process_assoc_req(struct hostapd_data *hapd, 2658e5b75505Sopenharmony_ci struct sta_info *sta, const u8 *owe_dh, 2659e5b75505Sopenharmony_ci u8 owe_dh_len) 2660e5b75505Sopenharmony_ci{ 2661e5b75505Sopenharmony_ci struct wpabuf *secret, *pub, *hkey; 2662e5b75505Sopenharmony_ci int res; 2663e5b75505Sopenharmony_ci u8 prk[SHA512_MAC_LEN], pmkid[SHA512_MAC_LEN]; 2664e5b75505Sopenharmony_ci const char *info = "OWE Key Generation"; 2665e5b75505Sopenharmony_ci const u8 *addr[2]; 2666e5b75505Sopenharmony_ci size_t len[2]; 2667e5b75505Sopenharmony_ci u16 group; 2668e5b75505Sopenharmony_ci size_t hash_len, prime_len; 2669e5b75505Sopenharmony_ci 2670e5b75505Sopenharmony_ci if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) { 2671e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching"); 2672e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2673e5b75505Sopenharmony_ci } 2674e5b75505Sopenharmony_ci 2675e5b75505Sopenharmony_ci group = WPA_GET_LE16(owe_dh); 2676e5b75505Sopenharmony_ci if (!owe_group_supported(hapd, group)) { 2677e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Unsupported DH group %u", group); 2678e5b75505Sopenharmony_ci return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 2679e5b75505Sopenharmony_ci } 2680e5b75505Sopenharmony_ci if (group == 19) 2681e5b75505Sopenharmony_ci prime_len = 32; 2682e5b75505Sopenharmony_ci else if (group == 20) 2683e5b75505Sopenharmony_ci prime_len = 48; 2684e5b75505Sopenharmony_ci else if (group == 21) 2685e5b75505Sopenharmony_ci prime_len = 66; 2686e5b75505Sopenharmony_ci else 2687e5b75505Sopenharmony_ci return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 2688e5b75505Sopenharmony_ci 2689e5b75505Sopenharmony_ci crypto_ecdh_deinit(sta->owe_ecdh); 2690e5b75505Sopenharmony_ci sta->owe_ecdh = crypto_ecdh_init(group); 2691e5b75505Sopenharmony_ci if (!sta->owe_ecdh) 2692e5b75505Sopenharmony_ci return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 2693e5b75505Sopenharmony_ci sta->owe_group = group; 2694e5b75505Sopenharmony_ci 2695e5b75505Sopenharmony_ci secret = crypto_ecdh_set_peerkey(sta->owe_ecdh, 0, owe_dh + 2, 2696e5b75505Sopenharmony_ci owe_dh_len - 2); 2697e5b75505Sopenharmony_ci secret = wpabuf_zeropad(secret, prime_len); 2698e5b75505Sopenharmony_ci if (!secret) { 2699e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Invalid peer DH public key"); 2700e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2701e5b75505Sopenharmony_ci } 2702e5b75505Sopenharmony_ci wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", secret); 2703e5b75505Sopenharmony_ci 2704e5b75505Sopenharmony_ci /* prk = HKDF-extract(C | A | group, z) */ 2705e5b75505Sopenharmony_ci 2706e5b75505Sopenharmony_ci pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 2707e5b75505Sopenharmony_ci if (!pub) { 2708e5b75505Sopenharmony_ci wpabuf_clear_free(secret); 2709e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2710e5b75505Sopenharmony_ci } 2711e5b75505Sopenharmony_ci 2712e5b75505Sopenharmony_ci /* PMKID = Truncate-128(Hash(C | A)) */ 2713e5b75505Sopenharmony_ci addr[0] = owe_dh + 2; 2714e5b75505Sopenharmony_ci len[0] = owe_dh_len - 2; 2715e5b75505Sopenharmony_ci addr[1] = wpabuf_head(pub); 2716e5b75505Sopenharmony_ci len[1] = wpabuf_len(pub); 2717e5b75505Sopenharmony_ci if (group == 19) { 2718e5b75505Sopenharmony_ci res = sha256_vector(2, addr, len, pmkid); 2719e5b75505Sopenharmony_ci hash_len = SHA256_MAC_LEN; 2720e5b75505Sopenharmony_ci } else if (group == 20) { 2721e5b75505Sopenharmony_ci res = sha384_vector(2, addr, len, pmkid); 2722e5b75505Sopenharmony_ci hash_len = SHA384_MAC_LEN; 2723e5b75505Sopenharmony_ci } else if (group == 21) { 2724e5b75505Sopenharmony_ci res = sha512_vector(2, addr, len, pmkid); 2725e5b75505Sopenharmony_ci hash_len = SHA512_MAC_LEN; 2726e5b75505Sopenharmony_ci } else { 2727e5b75505Sopenharmony_ci wpabuf_free(pub); 2728e5b75505Sopenharmony_ci wpabuf_clear_free(secret); 2729e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2730e5b75505Sopenharmony_ci } 2731e5b75505Sopenharmony_ci pub = wpabuf_zeropad(pub, prime_len); 2732e5b75505Sopenharmony_ci if (res < 0 || !pub) { 2733e5b75505Sopenharmony_ci wpabuf_free(pub); 2734e5b75505Sopenharmony_ci wpabuf_clear_free(secret); 2735e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2736e5b75505Sopenharmony_ci } 2737e5b75505Sopenharmony_ci 2738e5b75505Sopenharmony_ci hkey = wpabuf_alloc(owe_dh_len - 2 + wpabuf_len(pub) + 2); 2739e5b75505Sopenharmony_ci if (!hkey) { 2740e5b75505Sopenharmony_ci wpabuf_free(pub); 2741e5b75505Sopenharmony_ci wpabuf_clear_free(secret); 2742e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2743e5b75505Sopenharmony_ci } 2744e5b75505Sopenharmony_ci 2745e5b75505Sopenharmony_ci wpabuf_put_data(hkey, owe_dh + 2, owe_dh_len - 2); /* C */ 2746e5b75505Sopenharmony_ci wpabuf_put_buf(hkey, pub); /* A */ 2747e5b75505Sopenharmony_ci wpabuf_free(pub); 2748e5b75505Sopenharmony_ci wpabuf_put_le16(hkey, group); /* group */ 2749e5b75505Sopenharmony_ci if (group == 19) 2750e5b75505Sopenharmony_ci res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey), 2751e5b75505Sopenharmony_ci wpabuf_head(secret), wpabuf_len(secret), prk); 2752e5b75505Sopenharmony_ci else if (group == 20) 2753e5b75505Sopenharmony_ci res = hmac_sha384(wpabuf_head(hkey), wpabuf_len(hkey), 2754e5b75505Sopenharmony_ci wpabuf_head(secret), wpabuf_len(secret), prk); 2755e5b75505Sopenharmony_ci else if (group == 21) 2756e5b75505Sopenharmony_ci res = hmac_sha512(wpabuf_head(hkey), wpabuf_len(hkey), 2757e5b75505Sopenharmony_ci wpabuf_head(secret), wpabuf_len(secret), prk); 2758e5b75505Sopenharmony_ci wpabuf_clear_free(hkey); 2759e5b75505Sopenharmony_ci wpabuf_clear_free(secret); 2760e5b75505Sopenharmony_ci if (res < 0) 2761e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2762e5b75505Sopenharmony_ci 2763e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len); 2764e5b75505Sopenharmony_ci 2765e5b75505Sopenharmony_ci /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */ 2766e5b75505Sopenharmony_ci 2767e5b75505Sopenharmony_ci os_free(sta->owe_pmk); 2768e5b75505Sopenharmony_ci sta->owe_pmk = os_malloc(hash_len); 2769e5b75505Sopenharmony_ci if (!sta->owe_pmk) { 2770e5b75505Sopenharmony_ci os_memset(prk, 0, SHA512_MAC_LEN); 2771e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2772e5b75505Sopenharmony_ci } 2773e5b75505Sopenharmony_ci 2774e5b75505Sopenharmony_ci if (group == 19) 2775e5b75505Sopenharmony_ci res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *) info, 2776e5b75505Sopenharmony_ci os_strlen(info), sta->owe_pmk, hash_len); 2777e5b75505Sopenharmony_ci else if (group == 20) 2778e5b75505Sopenharmony_ci res = hmac_sha384_kdf(prk, hash_len, NULL, (const u8 *) info, 2779e5b75505Sopenharmony_ci os_strlen(info), sta->owe_pmk, hash_len); 2780e5b75505Sopenharmony_ci else if (group == 21) 2781e5b75505Sopenharmony_ci res = hmac_sha512_kdf(prk, hash_len, NULL, (const u8 *) info, 2782e5b75505Sopenharmony_ci os_strlen(info), sta->owe_pmk, hash_len); 2783e5b75505Sopenharmony_ci os_memset(prk, 0, SHA512_MAC_LEN); 2784e5b75505Sopenharmony_ci if (res < 0) { 2785e5b75505Sopenharmony_ci os_free(sta->owe_pmk); 2786e5b75505Sopenharmony_ci sta->owe_pmk = NULL; 2787e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2788e5b75505Sopenharmony_ci } 2789e5b75505Sopenharmony_ci sta->owe_pmk_len = hash_len; 2790e5b75505Sopenharmony_ci 2791e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len); 2792e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN); 2793e5b75505Sopenharmony_ci wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk, 2794e5b75505Sopenharmony_ci sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE); 2795e5b75505Sopenharmony_ci 2796e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2797e5b75505Sopenharmony_ci} 2798e5b75505Sopenharmony_ci 2799e5b75505Sopenharmony_ci 2800e5b75505Sopenharmony_ciu16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, 2801e5b75505Sopenharmony_ci const u8 *rsn_ie, size_t rsn_ie_len, 2802e5b75505Sopenharmony_ci const u8 *owe_dh, size_t owe_dh_len) 2803e5b75505Sopenharmony_ci{ 2804e5b75505Sopenharmony_ci struct wpa_ie_data data; 2805e5b75505Sopenharmony_ci int res; 2806e5b75505Sopenharmony_ci 2807e5b75505Sopenharmony_ci if (!rsn_ie || rsn_ie_len < 2) { 2808e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR, 2809e5b75505Sopenharmony_ci MAC2STR(peer)); 2810e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_IE; 2811e5b75505Sopenharmony_ci } 2812e5b75505Sopenharmony_ci rsn_ie -= 2; 2813e5b75505Sopenharmony_ci rsn_ie_len += 2; 2814e5b75505Sopenharmony_ci 2815e5b75505Sopenharmony_ci res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data); 2816e5b75505Sopenharmony_ci if (res) { 2817e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR 2818e5b75505Sopenharmony_ci " (res=%d)", MAC2STR(peer), res); 2819e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len); 2820e5b75505Sopenharmony_ci return wpa_res_to_status_code(res); 2821e5b75505Sopenharmony_ci } 2822e5b75505Sopenharmony_ci if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) { 2823e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2824e5b75505Sopenharmony_ci "OWE: Unexpected key mgmt 0x%x from " MACSTR, 2825e5b75505Sopenharmony_ci (unsigned int) data.key_mgmt, MAC2STR(peer)); 2826e5b75505Sopenharmony_ci return WLAN_STATUS_AKMP_NOT_VALID; 2827e5b75505Sopenharmony_ci } 2828e5b75505Sopenharmony_ci if (!owe_dh) { 2829e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2830e5b75505Sopenharmony_ci "OWE: No Diffie-Hellman Parameter element from " 2831e5b75505Sopenharmony_ci MACSTR, MAC2STR(peer)); 2832e5b75505Sopenharmony_ci return WLAN_STATUS_AKMP_NOT_VALID; 2833e5b75505Sopenharmony_ci } 2834e5b75505Sopenharmony_ci 2835e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 2836e5b75505Sopenharmony_ci} 2837e5b75505Sopenharmony_ci 2838e5b75505Sopenharmony_ci 2839e5b75505Sopenharmony_ciu16 owe_process_rsn_ie(struct hostapd_data *hapd, 2840e5b75505Sopenharmony_ci struct sta_info *sta, 2841e5b75505Sopenharmony_ci const u8 *rsn_ie, size_t rsn_ie_len, 2842e5b75505Sopenharmony_ci const u8 *owe_dh, size_t owe_dh_len) 2843e5b75505Sopenharmony_ci{ 2844e5b75505Sopenharmony_ci u16 status; 2845e5b75505Sopenharmony_ci u8 *owe_buf, ie[256 * 2]; 2846e5b75505Sopenharmony_ci size_t ie_len = 0; 2847e5b75505Sopenharmony_ci int res; 2848e5b75505Sopenharmony_ci 2849e5b75505Sopenharmony_ci if (!rsn_ie || rsn_ie_len < 2) { 2850e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq"); 2851e5b75505Sopenharmony_ci status = WLAN_STATUS_INVALID_IE; 2852e5b75505Sopenharmony_ci goto end; 2853e5b75505Sopenharmony_ci } 2854e5b75505Sopenharmony_ci 2855e5b75505Sopenharmony_ci if (!sta->wpa_sm) 2856e5b75505Sopenharmony_ci sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, 2857e5b75505Sopenharmony_ci NULL); 2858e5b75505Sopenharmony_ci if (!sta->wpa_sm) { 2859e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, 2860e5b75505Sopenharmony_ci "OWE: Failed to initialize WPA state machine"); 2861e5b75505Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2862e5b75505Sopenharmony_ci goto end; 2863e5b75505Sopenharmony_ci } 2864e5b75505Sopenharmony_ci rsn_ie -= 2; 2865e5b75505Sopenharmony_ci rsn_ie_len += 2; 2866e5b75505Sopenharmony_ci res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 2867e5b75505Sopenharmony_ci hapd->iface->freq, rsn_ie, rsn_ie_len, 2868e5b75505Sopenharmony_ci NULL, 0, owe_dh, owe_dh_len); 2869e5b75505Sopenharmony_ci status = wpa_res_to_status_code(res); 2870e5b75505Sopenharmony_ci if (status != WLAN_STATUS_SUCCESS) 2871e5b75505Sopenharmony_ci goto end; 2872e5b75505Sopenharmony_ci status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len); 2873e5b75505Sopenharmony_ci if (status != WLAN_STATUS_SUCCESS) 2874e5b75505Sopenharmony_ci goto end; 2875e5b75505Sopenharmony_ci owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie), 2876e5b75505Sopenharmony_ci NULL, 0); 2877e5b75505Sopenharmony_ci if (!owe_buf) { 2878e5b75505Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2879e5b75505Sopenharmony_ci goto end; 2880e5b75505Sopenharmony_ci } 2881e5b75505Sopenharmony_ci 2882e5b75505Sopenharmony_ci if (sta->owe_ecdh) { 2883e5b75505Sopenharmony_ci struct wpabuf *pub; 2884e5b75505Sopenharmony_ci 2885e5b75505Sopenharmony_ci pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 2886e5b75505Sopenharmony_ci if (!pub) { 2887e5b75505Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2888e5b75505Sopenharmony_ci goto end; 2889e5b75505Sopenharmony_ci } 2890e5b75505Sopenharmony_ci 2891e5b75505Sopenharmony_ci /* OWE Diffie-Hellman Parameter element */ 2892e5b75505Sopenharmony_ci *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */ 2893e5b75505Sopenharmony_ci *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */ 2894e5b75505Sopenharmony_ci *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension 2895e5b75505Sopenharmony_ci */ 2896e5b75505Sopenharmony_ci WPA_PUT_LE16(owe_buf, sta->owe_group); 2897e5b75505Sopenharmony_ci owe_buf += 2; 2898e5b75505Sopenharmony_ci os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub)); 2899e5b75505Sopenharmony_ci owe_buf += wpabuf_len(pub); 2900e5b75505Sopenharmony_ci wpabuf_free(pub); 2901e5b75505Sopenharmony_ci sta->external_dh_updated = 1; 2902e5b75505Sopenharmony_ci } 2903e5b75505Sopenharmony_ci ie_len = owe_buf - ie; 2904e5b75505Sopenharmony_ci 2905e5b75505Sopenharmony_ciend: 2906e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer " 2907e5b75505Sopenharmony_ci MACSTR, status, (unsigned int) ie_len, 2908e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 2909e5b75505Sopenharmony_ci hostapd_drv_update_dh_ie(hapd, sta->addr, status, 2910e5b75505Sopenharmony_ci status == WLAN_STATUS_SUCCESS ? ie : NULL, 2911e5b75505Sopenharmony_ci ie_len); 2912e5b75505Sopenharmony_ci 2913e5b75505Sopenharmony_ci return status; 2914e5b75505Sopenharmony_ci} 2915e5b75505Sopenharmony_ci 2916e5b75505Sopenharmony_ci#endif /* CONFIG_OWE */ 2917e5b75505Sopenharmony_ci 2918e5b75505Sopenharmony_ci 2919e5b75505Sopenharmony_cistatic u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, 2920e5b75505Sopenharmony_ci const u8 *ies, size_t ies_len, int reassoc) 2921e5b75505Sopenharmony_ci{ 2922e5b75505Sopenharmony_ci struct ieee802_11_elems elems; 2923e5b75505Sopenharmony_ci u16 resp; 2924e5b75505Sopenharmony_ci const u8 *wpa_ie; 2925e5b75505Sopenharmony_ci size_t wpa_ie_len; 2926e5b75505Sopenharmony_ci const u8 *p2p_dev_addr = NULL; 2927e5b75505Sopenharmony_ci 2928e5b75505Sopenharmony_ci if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { 2929e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2930e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, "Station sent an invalid " 2931e5b75505Sopenharmony_ci "association request"); 2932e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 2933e5b75505Sopenharmony_ci } 2934e5b75505Sopenharmony_ci 2935e5b75505Sopenharmony_ci resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len); 2936e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2937e5b75505Sopenharmony_ci return resp; 2938e5b75505Sopenharmony_ci resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len); 2939e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2940e5b75505Sopenharmony_ci return resp; 2941e5b75505Sopenharmony_ci resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len); 2942e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2943e5b75505Sopenharmony_ci return resp; 2944e5b75505Sopenharmony_ci resp = copy_supp_rates(hapd, sta, &elems); 2945e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2946e5b75505Sopenharmony_ci return resp; 2947e5b75505Sopenharmony_ci 2948e5b75505Sopenharmony_ci resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len); 2949e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2950e5b75505Sopenharmony_ci return resp; 2951e5b75505Sopenharmony_ci 2952e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N 2953e5b75505Sopenharmony_ci resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities); 2954e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2955e5b75505Sopenharmony_ci return resp; 2956e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && 2957e5b75505Sopenharmony_ci !(sta->flags & WLAN_STA_HT)) { 2958e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2959e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, "Station does not support " 2960e5b75505Sopenharmony_ci "mandatory HT PHY - reject association"); 2961e5b75505Sopenharmony_ci return WLAN_STATUS_ASSOC_DENIED_NO_HT; 2962e5b75505Sopenharmony_ci } 2963e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */ 2964e5b75505Sopenharmony_ci 2965e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211AC 2966e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ac) { 2967e5b75505Sopenharmony_ci resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities); 2968e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2969e5b75505Sopenharmony_ci return resp; 2970e5b75505Sopenharmony_ci 2971e5b75505Sopenharmony_ci resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif); 2972e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2973e5b75505Sopenharmony_ci return resp; 2974e5b75505Sopenharmony_ci } 2975e5b75505Sopenharmony_ci 2976e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && 2977e5b75505Sopenharmony_ci !(sta->flags & WLAN_STA_VHT)) { 2978e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 2979e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, "Station does not support " 2980e5b75505Sopenharmony_ci "mandatory VHT PHY - reject association"); 2981e5b75505Sopenharmony_ci return WLAN_STATUS_ASSOC_DENIED_NO_VHT; 2982e5b75505Sopenharmony_ci } 2983e5b75505Sopenharmony_ci 2984e5b75505Sopenharmony_ci if (hapd->conf->vendor_vht && !elems.vht_capabilities) { 2985e5b75505Sopenharmony_ci resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht, 2986e5b75505Sopenharmony_ci elems.vendor_vht_len); 2987e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2988e5b75505Sopenharmony_ci return resp; 2989e5b75505Sopenharmony_ci } 2990e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211AC */ 2991e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211AX 2992e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ax) { 2993e5b75505Sopenharmony_ci resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP, 2994e5b75505Sopenharmony_ci elems.he_capabilities, 2995e5b75505Sopenharmony_ci elems.he_capabilities_len); 2996e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 2997e5b75505Sopenharmony_ci return resp; 2998e5b75505Sopenharmony_ci } 2999e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211AX */ 3000e5b75505Sopenharmony_ci 3001e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 3002e5b75505Sopenharmony_ci if (elems.p2p) { 3003e5b75505Sopenharmony_ci wpabuf_free(sta->p2p_ie); 3004e5b75505Sopenharmony_ci sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, 3005e5b75505Sopenharmony_ci P2P_IE_VENDOR_TYPE); 3006e5b75505Sopenharmony_ci if (sta->p2p_ie) 3007e5b75505Sopenharmony_ci p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 3008e5b75505Sopenharmony_ci } else { 3009e5b75505Sopenharmony_ci wpabuf_free(sta->p2p_ie); 3010e5b75505Sopenharmony_ci sta->p2p_ie = NULL; 3011e5b75505Sopenharmony_ci } 3012e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 3013e5b75505Sopenharmony_ci 3014e5b75505Sopenharmony_ci if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) { 3015e5b75505Sopenharmony_ci wpa_ie = elems.rsn_ie; 3016e5b75505Sopenharmony_ci wpa_ie_len = elems.rsn_ie_len; 3017e5b75505Sopenharmony_ci } else if ((hapd->conf->wpa & WPA_PROTO_WPA) && 3018e5b75505Sopenharmony_ci elems.wpa_ie) { 3019e5b75505Sopenharmony_ci wpa_ie = elems.wpa_ie; 3020e5b75505Sopenharmony_ci wpa_ie_len = elems.wpa_ie_len; 3021e5b75505Sopenharmony_ci } else { 3022e5b75505Sopenharmony_ci wpa_ie = NULL; 3023e5b75505Sopenharmony_ci wpa_ie_len = 0; 3024e5b75505Sopenharmony_ci } 3025e5b75505Sopenharmony_ci 3026e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 3027e5b75505Sopenharmony_ci sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 3028e5b75505Sopenharmony_ci if (hapd->conf->wps_state && elems.wps_ie) { 3029e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " 3030e5b75505Sopenharmony_ci "Request - assume WPS is used"); 3031e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_WPS; 3032e5b75505Sopenharmony_ci wpabuf_free(sta->wps_ie); 3033e5b75505Sopenharmony_ci sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, 3034e5b75505Sopenharmony_ci WPS_IE_VENDOR_TYPE); 3035e5b75505Sopenharmony_ci if (sta->wps_ie && wps_is_20(sta->wps_ie)) { 3036e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); 3037e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_WPS2; 3038e5b75505Sopenharmony_ci } 3039e5b75505Sopenharmony_ci wpa_ie = NULL; 3040e5b75505Sopenharmony_ci wpa_ie_len = 0; 3041e5b75505Sopenharmony_ci if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) { 3042e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in " 3043e5b75505Sopenharmony_ci "(Re)Association Request - reject"); 3044e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_IE; 3045e5b75505Sopenharmony_ci } 3046e5b75505Sopenharmony_ci } else if (hapd->conf->wps_state && wpa_ie == NULL) { 3047e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in " 3048e5b75505Sopenharmony_ci "(Re)Association Request - possible WPS use"); 3049e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_MAYBE_WPS; 3050e5b75505Sopenharmony_ci } else 3051e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 3052e5b75505Sopenharmony_ci if (hapd->conf->wpa && wpa_ie == NULL) { 3053e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 3054e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 3055e5b75505Sopenharmony_ci "No WPA/RSN IE in association request"); 3056e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_IE; 3057e5b75505Sopenharmony_ci } 3058e5b75505Sopenharmony_ci 3059e5b75505Sopenharmony_ci if (hapd->conf->wpa && wpa_ie) { 3060e5b75505Sopenharmony_ci int res; 3061e5b75505Sopenharmony_ci wpa_ie -= 2; 3062e5b75505Sopenharmony_ci wpa_ie_len += 2; 3063e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) 3064e5b75505Sopenharmony_ci sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 3065e5b75505Sopenharmony_ci sta->addr, 3066e5b75505Sopenharmony_ci p2p_dev_addr); 3067e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) { 3068e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, "Failed to initialize WPA " 3069e5b75505Sopenharmony_ci "state machine"); 3070e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3071e5b75505Sopenharmony_ci } 3072e5b75505Sopenharmony_ci wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg); 3073e5b75505Sopenharmony_ci res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 3074e5b75505Sopenharmony_ci hapd->iface->freq, 3075e5b75505Sopenharmony_ci wpa_ie, wpa_ie_len, 3076e5b75505Sopenharmony_ci elems.mdie, elems.mdie_len, 3077e5b75505Sopenharmony_ci elems.owe_dh, elems.owe_dh_len); 3078e5b75505Sopenharmony_ci resp = wpa_res_to_status_code(res); 3079e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 3080e5b75505Sopenharmony_ci return resp; 3081e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 3082e5b75505Sopenharmony_ci if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 3083e5b75505Sopenharmony_ci (WLAN_STA_ASSOC | WLAN_STA_MFP) && 3084e5b75505Sopenharmony_ci !sta->sa_query_timed_out && 3085e5b75505Sopenharmony_ci sta->sa_query_count > 0) 3086e5b75505Sopenharmony_ci ap_check_sa_query_timeout(hapd, sta); 3087e5b75505Sopenharmony_ci if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 3088e5b75505Sopenharmony_ci (WLAN_STA_ASSOC | WLAN_STA_MFP) && 3089e5b75505Sopenharmony_ci !sta->sa_query_timed_out && 3090e5b75505Sopenharmony_ci (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) { 3091e5b75505Sopenharmony_ci /* 3092e5b75505Sopenharmony_ci * STA has already been associated with MFP and SA 3093e5b75505Sopenharmony_ci * Query timeout has not been reached. Reject the 3094e5b75505Sopenharmony_ci * association attempt temporarily and start SA Query, 3095e5b75505Sopenharmony_ci * if one is not pending. 3096e5b75505Sopenharmony_ci */ 3097e5b75505Sopenharmony_ci 3098e5b75505Sopenharmony_ci if (sta->sa_query_count == 0) 3099e5b75505Sopenharmony_ci ap_sta_start_sa_query(hapd, sta); 3100e5b75505Sopenharmony_ci 3101e5b75505Sopenharmony_ci return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 3102e5b75505Sopenharmony_ci } 3103e5b75505Sopenharmony_ci 3104e5b75505Sopenharmony_ci if (wpa_auth_uses_mfp(sta->wpa_sm)) 3105e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_MFP; 3106e5b75505Sopenharmony_ci else 3107e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_MFP; 3108e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 3109e5b75505Sopenharmony_ci 3110e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 3111e5b75505Sopenharmony_ci if (sta->auth_alg == WLAN_AUTH_FT) { 3112e5b75505Sopenharmony_ci if (!reassoc) { 3113e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried " 3114e5b75505Sopenharmony_ci "to use association (not " 3115e5b75505Sopenharmony_ci "re-association) with FT auth_alg", 3116e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 3117e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3118e5b75505Sopenharmony_ci } 3119e5b75505Sopenharmony_ci 3120e5b75505Sopenharmony_ci resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies, 3121e5b75505Sopenharmony_ci ies_len); 3122e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 3123e5b75505Sopenharmony_ci return resp; 3124e5b75505Sopenharmony_ci } 3125e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 3126e5b75505Sopenharmony_ci 3127e5b75505Sopenharmony_ci#ifdef CONFIG_SAE 3128e5b75505Sopenharmony_ci if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae && 3129e5b75505Sopenharmony_ci sta->sae->state == SAE_ACCEPTED) 3130e5b75505Sopenharmony_ci wpa_auth_add_sae_pmkid(sta->wpa_sm, sta->sae->pmkid); 3131e5b75505Sopenharmony_ci 3132e5b75505Sopenharmony_ci if (wpa_auth_uses_sae(sta->wpa_sm) && 3133e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_OPEN) { 3134e5b75505Sopenharmony_ci struct rsn_pmksa_cache_entry *sa; 3135e5b75505Sopenharmony_ci sa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 3136e5b75505Sopenharmony_ci if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) { 3137e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3138e5b75505Sopenharmony_ci "SAE: No PMKSA cache entry found for " 3139e5b75505Sopenharmony_ci MACSTR, MAC2STR(sta->addr)); 3140e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_PMKID; 3141e5b75505Sopenharmony_ci } 3142e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: " MACSTR 3143e5b75505Sopenharmony_ci " using PMKSA caching", MAC2STR(sta->addr)); 3144e5b75505Sopenharmony_ci } else if (wpa_auth_uses_sae(sta->wpa_sm) && 3145e5b75505Sopenharmony_ci sta->auth_alg != WLAN_AUTH_SAE && 3146e5b75505Sopenharmony_ci !(sta->auth_alg == WLAN_AUTH_FT && 3147e5b75505Sopenharmony_ci wpa_auth_uses_ft_sae(sta->wpa_sm))) { 3148e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use " 3149e5b75505Sopenharmony_ci "SAE AKM after non-SAE auth_alg %u", 3150e5b75505Sopenharmony_ci MAC2STR(sta->addr), sta->auth_alg); 3151e5b75505Sopenharmony_ci return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 3152e5b75505Sopenharmony_ci } 3153e5b75505Sopenharmony_ci#endif /* CONFIG_SAE */ 3154e5b75505Sopenharmony_ci 3155e5b75505Sopenharmony_ci#ifdef CONFIG_OWE 3156e5b75505Sopenharmony_ci if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 3157e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && 3158e5b75505Sopenharmony_ci elems.owe_dh) { 3159e5b75505Sopenharmony_ci resp = owe_process_assoc_req(hapd, sta, elems.owe_dh, 3160e5b75505Sopenharmony_ci elems.owe_dh_len); 3161e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 3162e5b75505Sopenharmony_ci return resp; 3163e5b75505Sopenharmony_ci } 3164e5b75505Sopenharmony_ci#endif /* CONFIG_OWE */ 3165e5b75505Sopenharmony_ci 3166e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 3167e5b75505Sopenharmony_ci dpp_pfs_free(sta->dpp_pfs); 3168e5b75505Sopenharmony_ci sta->dpp_pfs = NULL; 3169e5b75505Sopenharmony_ci 3170e5b75505Sopenharmony_ci if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && 3171e5b75505Sopenharmony_ci hapd->conf->dpp_netaccesskey && sta->wpa_sm && 3172e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && 3173e5b75505Sopenharmony_ci elems.owe_dh) { 3174e5b75505Sopenharmony_ci sta->dpp_pfs = dpp_pfs_init( 3175e5b75505Sopenharmony_ci wpabuf_head(hapd->conf->dpp_netaccesskey), 3176e5b75505Sopenharmony_ci wpabuf_len(hapd->conf->dpp_netaccesskey)); 3177e5b75505Sopenharmony_ci if (!sta->dpp_pfs) { 3178e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3179e5b75505Sopenharmony_ci "DPP: Could not initialize PFS"); 3180e5b75505Sopenharmony_ci /* Try to continue without PFS */ 3181e5b75505Sopenharmony_ci goto pfs_fail; 3182e5b75505Sopenharmony_ci } 3183e5b75505Sopenharmony_ci 3184e5b75505Sopenharmony_ci if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, 3185e5b75505Sopenharmony_ci elems.owe_dh_len) < 0) { 3186e5b75505Sopenharmony_ci dpp_pfs_free(sta->dpp_pfs); 3187e5b75505Sopenharmony_ci sta->dpp_pfs = NULL; 3188e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3189e5b75505Sopenharmony_ci } 3190e5b75505Sopenharmony_ci } 3191e5b75505Sopenharmony_ci 3192e5b75505Sopenharmony_ci wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? 3193e5b75505Sopenharmony_ci sta->dpp_pfs->secret : NULL); 3194e5b75505Sopenharmony_ci pfs_fail: 3195e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 3196e5b75505Sopenharmony_ci 3197e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N 3198e5b75505Sopenharmony_ci if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) && 3199e5b75505Sopenharmony_ci wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { 3200e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 3201e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 3202e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 3203e5b75505Sopenharmony_ci "Station tried to use TKIP with HT " 3204e5b75505Sopenharmony_ci "association"); 3205e5b75505Sopenharmony_ci return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 3206e5b75505Sopenharmony_ci } 3207e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */ 3208e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 3209e5b75505Sopenharmony_ci } else if (hapd->conf->osen) { 3210e5b75505Sopenharmony_ci if (elems.osen == NULL) { 3211e5b75505Sopenharmony_ci hostapd_logger( 3212e5b75505Sopenharmony_ci hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 3213e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 3214e5b75505Sopenharmony_ci "No HS 2.0 OSEN element in association request"); 3215e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_IE; 3216e5b75505Sopenharmony_ci } 3217e5b75505Sopenharmony_ci 3218e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); 3219e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) 3220e5b75505Sopenharmony_ci sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 3221e5b75505Sopenharmony_ci sta->addr, NULL); 3222e5b75505Sopenharmony_ci if (sta->wpa_sm == NULL) { 3223e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, "Failed to initialize WPA " 3224e5b75505Sopenharmony_ci "state machine"); 3225e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3226e5b75505Sopenharmony_ci } 3227e5b75505Sopenharmony_ci if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, 3228e5b75505Sopenharmony_ci elems.osen - 2, elems.osen_len + 2) < 0) 3229e5b75505Sopenharmony_ci return WLAN_STATUS_INVALID_IE; 3230e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 3231e5b75505Sopenharmony_ci } else 3232e5b75505Sopenharmony_ci wpa_auth_sta_no_wpa(sta->wpa_sm); 3233e5b75505Sopenharmony_ci 3234e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 3235e5b75505Sopenharmony_ci p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len); 3236e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 3237e5b75505Sopenharmony_ci 3238e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 3239e5b75505Sopenharmony_ci wpabuf_free(sta->hs20_ie); 3240e5b75505Sopenharmony_ci if (elems.hs20 && elems.hs20_len > 4) { 3241e5b75505Sopenharmony_ci int release; 3242e5b75505Sopenharmony_ci 3243e5b75505Sopenharmony_ci sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, 3244e5b75505Sopenharmony_ci elems.hs20_len - 4); 3245e5b75505Sopenharmony_ci release = ((elems.hs20[4] >> 4) & 0x0f) + 1; 3246e5b75505Sopenharmony_ci if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm)) { 3247e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3248e5b75505Sopenharmony_ci "HS 2.0: PMF not negotiated by release %d station " 3249e5b75505Sopenharmony_ci MACSTR, release, MAC2STR(sta->addr)); 3250e5b75505Sopenharmony_ci return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; 3251e5b75505Sopenharmony_ci } 3252e5b75505Sopenharmony_ci } else { 3253e5b75505Sopenharmony_ci sta->hs20_ie = NULL; 3254e5b75505Sopenharmony_ci } 3255e5b75505Sopenharmony_ci 3256e5b75505Sopenharmony_ci wpabuf_free(sta->roaming_consortium); 3257e5b75505Sopenharmony_ci if (elems.roaming_cons_sel) 3258e5b75505Sopenharmony_ci sta->roaming_consortium = wpabuf_alloc_copy( 3259e5b75505Sopenharmony_ci elems.roaming_cons_sel + 4, 3260e5b75505Sopenharmony_ci elems.roaming_cons_sel_len - 4); 3261e5b75505Sopenharmony_ci else 3262e5b75505Sopenharmony_ci sta->roaming_consortium = NULL; 3263e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 3264e5b75505Sopenharmony_ci 3265e5b75505Sopenharmony_ci#ifdef CONFIG_FST 3266e5b75505Sopenharmony_ci wpabuf_free(sta->mb_ies); 3267e5b75505Sopenharmony_ci if (hapd->iface->fst) 3268e5b75505Sopenharmony_ci sta->mb_ies = mb_ies_by_info(&elems.mb_ies); 3269e5b75505Sopenharmony_ci else 3270e5b75505Sopenharmony_ci sta->mb_ies = NULL; 3271e5b75505Sopenharmony_ci#endif /* CONFIG_FST */ 3272e5b75505Sopenharmony_ci 3273e5b75505Sopenharmony_ci#ifdef CONFIG_MBO 3274e5b75505Sopenharmony_ci mbo_ap_check_sta_assoc(hapd, sta, &elems); 3275e5b75505Sopenharmony_ci 3276e5b75505Sopenharmony_ci if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && 3277e5b75505Sopenharmony_ci elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && 3278e5b75505Sopenharmony_ci hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 3279e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3280e5b75505Sopenharmony_ci "MBO: Reject WPA2 association without PMF"); 3281e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3282e5b75505Sopenharmony_ci } 3283e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */ 3284e5b75505Sopenharmony_ci 3285e5b75505Sopenharmony_ci#if defined(CONFIG_FILS) && defined(CONFIG_OCV) 3286e5b75505Sopenharmony_ci if (wpa_auth_uses_ocv(sta->wpa_sm) && 3287e5b75505Sopenharmony_ci (sta->auth_alg == WLAN_AUTH_FILS_SK || 3288e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 3289e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK)) { 3290e5b75505Sopenharmony_ci struct wpa_channel_info ci; 3291e5b75505Sopenharmony_ci int tx_chanwidth; 3292e5b75505Sopenharmony_ci int tx_seg1_idx; 3293e5b75505Sopenharmony_ci 3294e5b75505Sopenharmony_ci if (hostapd_drv_channel_info(hapd, &ci) != 0) { 3295e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, 3296e5b75505Sopenharmony_ci "Failed to get channel info to validate received OCI in FILS (Re)Association Request frame"); 3297e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3298e5b75505Sopenharmony_ci } 3299e5b75505Sopenharmony_ci 3300e5b75505Sopenharmony_ci if (get_sta_tx_parameters(sta->wpa_sm, 3301e5b75505Sopenharmony_ci channel_width_to_int(ci.chanwidth), 3302e5b75505Sopenharmony_ci ci.seg1_idx, &tx_chanwidth, 3303e5b75505Sopenharmony_ci &tx_seg1_idx) < 0) 3304e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3305e5b75505Sopenharmony_ci 3306e5b75505Sopenharmony_ci if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, 3307e5b75505Sopenharmony_ci tx_chanwidth, tx_seg1_idx) != 0) { 3308e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, "FILS: %s", ocv_errorstr); 3309e5b75505Sopenharmony_ci return WLAN_STATUS_UNSPECIFIED_FAILURE; 3310e5b75505Sopenharmony_ci } 3311e5b75505Sopenharmony_ci } 3312e5b75505Sopenharmony_ci#endif /* CONFIG_FILS && CONFIG_OCV */ 3313e5b75505Sopenharmony_ci 3314e5b75505Sopenharmony_ci ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes, 3315e5b75505Sopenharmony_ci elems.supp_op_classes_len); 3316e5b75505Sopenharmony_ci 3317e5b75505Sopenharmony_ci if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) && 3318e5b75505Sopenharmony_ci elems.rrm_enabled && 3319e5b75505Sopenharmony_ci elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa)) 3320e5b75505Sopenharmony_ci os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled, 3321e5b75505Sopenharmony_ci sizeof(sta->rrm_enabled_capa)); 3322e5b75505Sopenharmony_ci 3323e5b75505Sopenharmony_ci if (elems.power_capab) { 3324e5b75505Sopenharmony_ci sta->min_tx_power = elems.power_capab[0]; 3325e5b75505Sopenharmony_ci sta->max_tx_power = elems.power_capab[1]; 3326e5b75505Sopenharmony_ci sta->power_capab = 1; 3327e5b75505Sopenharmony_ci } else { 3328e5b75505Sopenharmony_ci sta->power_capab = 0; 3329e5b75505Sopenharmony_ci } 3330e5b75505Sopenharmony_ci 3331e5b75505Sopenharmony_ci return WLAN_STATUS_SUCCESS; 3332e5b75505Sopenharmony_ci} 3333e5b75505Sopenharmony_ci 3334e5b75505Sopenharmony_ci 3335e5b75505Sopenharmony_cistatic void send_deauth(struct hostapd_data *hapd, const u8 *addr, 3336e5b75505Sopenharmony_ci u16 reason_code) 3337e5b75505Sopenharmony_ci{ 3338e5b75505Sopenharmony_ci int send_len; 3339e5b75505Sopenharmony_ci struct ieee80211_mgmt reply; 3340e5b75505Sopenharmony_ci 3341e5b75505Sopenharmony_ci os_memset(&reply, 0, sizeof(reply)); 3342e5b75505Sopenharmony_ci reply.frame_control = 3343e5b75505Sopenharmony_ci IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); 3344e5b75505Sopenharmony_ci os_memcpy(reply.da, addr, ETH_ALEN); 3345e5b75505Sopenharmony_ci os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN); 3346e5b75505Sopenharmony_ci os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN); 3347e5b75505Sopenharmony_ci 3348e5b75505Sopenharmony_ci send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); 3349e5b75505Sopenharmony_ci reply.u.deauth.reason_code = host_to_le16(reason_code); 3350e5b75505Sopenharmony_ci 3351e5b75505Sopenharmony_ci if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0) 3352e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Failed to send deauth: %s", 3353e5b75505Sopenharmony_ci strerror(errno)); 3354e5b75505Sopenharmony_ci} 3355e5b75505Sopenharmony_ci 3356e5b75505Sopenharmony_ci 3357e5b75505Sopenharmony_cistatic int add_associated_sta(struct hostapd_data *hapd, 3358e5b75505Sopenharmony_ci struct sta_info *sta, int reassoc) 3359e5b75505Sopenharmony_ci{ 3360e5b75505Sopenharmony_ci struct ieee80211_ht_capabilities ht_cap; 3361e5b75505Sopenharmony_ci struct ieee80211_vht_capabilities vht_cap; 3362e5b75505Sopenharmony_ci struct ieee80211_he_capabilities he_cap; 3363e5b75505Sopenharmony_ci int set = 1; 3364e5b75505Sopenharmony_ci 3365e5b75505Sopenharmony_ci /* 3366e5b75505Sopenharmony_ci * Remove the STA entry to ensure the STA PS state gets cleared and 3367e5b75505Sopenharmony_ci * configuration gets updated. This is relevant for cases, such as 3368e5b75505Sopenharmony_ci * FT-over-the-DS, where a station re-associates back to the same AP but 3369e5b75505Sopenharmony_ci * skips the authentication flow, or if working with a driver that 3370e5b75505Sopenharmony_ci * does not support full AP client state. 3371e5b75505Sopenharmony_ci * 3372e5b75505Sopenharmony_ci * Skip this if the STA has already completed FT reassociation and the 3373e5b75505Sopenharmony_ci * TK has been configured since the TX/RX PN must not be reset to 0 for 3374e5b75505Sopenharmony_ci * the same key. 3375e5b75505Sopenharmony_ci * 3376e5b75505Sopenharmony_ci * FT-over-the-DS has a special case where the STA entry (and as such, 3377e5b75505Sopenharmony_ci * the TK) has not yet been configured to the driver depending on which 3378e5b75505Sopenharmony_ci * driver interface is used. For that case, allow add-STA operation to 3379e5b75505Sopenharmony_ci * be used (instead of set-STA). This is needed to allow mac80211-based 3380e5b75505Sopenharmony_ci * drivers to accept the STA parameter configuration. Since this is 3381e5b75505Sopenharmony_ci * after a new FT-over-DS exchange, a new TK has been derived, so key 3382e5b75505Sopenharmony_ci * reinstallation is not a concern for this case. 3383e5b75505Sopenharmony_ci */ 3384e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR 3385e5b75505Sopenharmony_ci " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)", 3386e5b75505Sopenharmony_ci MAC2STR(sta->addr), sta->added_unassoc, sta->auth_alg, 3387e5b75505Sopenharmony_ci sta->ft_over_ds, reassoc, 3388e5b75505Sopenharmony_ci !!(sta->flags & WLAN_STA_AUTHORIZED), 3389e5b75505Sopenharmony_ci wpa_auth_sta_ft_tk_already_set(sta->wpa_sm), 3390e5b75505Sopenharmony_ci wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)); 3391e5b75505Sopenharmony_ci 3392e5b75505Sopenharmony_ci if (!sta->added_unassoc && 3393e5b75505Sopenharmony_ci (!(sta->flags & WLAN_STA_AUTHORIZED) || 3394e5b75505Sopenharmony_ci (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) || 3395e5b75505Sopenharmony_ci (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) && 3396e5b75505Sopenharmony_ci !wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)))) { 3397e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 3398e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_DRV_STA_REMOVED); 3399e5b75505Sopenharmony_ci set = 0; 3400e5b75505Sopenharmony_ci 3401e5b75505Sopenharmony_ci /* Do not allow the FT-over-DS exception to be used more than 3402e5b75505Sopenharmony_ci * once per authentication exchange to guarantee a new TK is 3403e5b75505Sopenharmony_ci * used here */ 3404e5b75505Sopenharmony_ci sta->ft_over_ds = 0; 3405e5b75505Sopenharmony_ci } 3406e5b75505Sopenharmony_ci 3407e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N 3408e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_HT) 3409e5b75505Sopenharmony_ci hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); 3410e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */ 3411e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211AC 3412e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_VHT) 3413e5b75505Sopenharmony_ci hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap); 3414e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211AC */ 3415e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211AX 3416e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_HE) { 3417e5b75505Sopenharmony_ci hostapd_get_he_capab(hapd, sta->he_capab, &he_cap, 3418e5b75505Sopenharmony_ci sta->he_capab_len); 3419e5b75505Sopenharmony_ci } 3420e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211AX */ 3421e5b75505Sopenharmony_ci 3422e5b75505Sopenharmony_ci /* 3423e5b75505Sopenharmony_ci * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags 3424e5b75505Sopenharmony_ci * will be set when the ACK frame for the (Re)Association Response frame 3425e5b75505Sopenharmony_ci * is processed (TX status driver event). 3426e5b75505Sopenharmony_ci */ 3427e5b75505Sopenharmony_ci if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, 3428e5b75505Sopenharmony_ci sta->supported_rates, sta->supported_rates_len, 3429e5b75505Sopenharmony_ci sta->listen_interval, 3430e5b75505Sopenharmony_ci sta->flags & WLAN_STA_HT ? &ht_cap : NULL, 3431e5b75505Sopenharmony_ci sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, 3432e5b75505Sopenharmony_ci sta->flags & WLAN_STA_HE ? &he_cap : NULL, 3433e5b75505Sopenharmony_ci sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0, 3434e5b75505Sopenharmony_ci sta->flags | WLAN_STA_ASSOC, sta->qosinfo, 3435e5b75505Sopenharmony_ci sta->vht_opmode, sta->p2p_ie ? 1 : 0, 3436e5b75505Sopenharmony_ci set)) { 3437e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 3438e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, 3439e5b75505Sopenharmony_ci "Could not %s STA to kernel driver", 3440e5b75505Sopenharmony_ci set ? "set" : "add"); 3441e5b75505Sopenharmony_ci 3442e5b75505Sopenharmony_ci if (sta->added_unassoc) { 3443e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 3444e5b75505Sopenharmony_ci sta->added_unassoc = 0; 3445e5b75505Sopenharmony_ci } 3446e5b75505Sopenharmony_ci 3447e5b75505Sopenharmony_ci return -1; 3448e5b75505Sopenharmony_ci } 3449e5b75505Sopenharmony_ci 3450e5b75505Sopenharmony_ci sta->added_unassoc = 0; 3451e5b75505Sopenharmony_ci 3452e5b75505Sopenharmony_ci return 0; 3453e5b75505Sopenharmony_ci} 3454e5b75505Sopenharmony_ci 3455e5b75505Sopenharmony_ci 3456e5b75505Sopenharmony_cistatic u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, 3457e5b75505Sopenharmony_ci const u8 *addr, u16 status_code, int reassoc, 3458e5b75505Sopenharmony_ci const u8 *ies, size_t ies_len, int rssi) 3459e5b75505Sopenharmony_ci{ 3460e5b75505Sopenharmony_ci int send_len; 3461e5b75505Sopenharmony_ci u8 *buf; 3462e5b75505Sopenharmony_ci size_t buflen; 3463e5b75505Sopenharmony_ci struct ieee80211_mgmt *reply; 3464e5b75505Sopenharmony_ci u8 *p; 3465e5b75505Sopenharmony_ci u16 res = WLAN_STATUS_SUCCESS; 3466e5b75505Sopenharmony_ci 3467e5b75505Sopenharmony_ci buflen = sizeof(struct ieee80211_mgmt) + 1024; 3468e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 3469e5b75505Sopenharmony_ci if (sta && sta->fils_hlp_resp) 3470e5b75505Sopenharmony_ci buflen += wpabuf_len(sta->fils_hlp_resp); 3471e5b75505Sopenharmony_ci if (sta) 3472e5b75505Sopenharmony_ci buflen += 150; 3473e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 3474e5b75505Sopenharmony_ci#ifdef CONFIG_OWE 3475e5b75505Sopenharmony_ci if (sta && (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) 3476e5b75505Sopenharmony_ci buflen += 150; 3477e5b75505Sopenharmony_ci#endif /* CONFIG_OWE */ 3478e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 3479e5b75505Sopenharmony_ci if (sta && sta->dpp_pfs) 3480e5b75505Sopenharmony_ci buflen += 5 + sta->dpp_pfs->curve->prime_len; 3481e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 3482e5b75505Sopenharmony_ci buf = os_zalloc(buflen); 3483e5b75505Sopenharmony_ci if (!buf) { 3484e5b75505Sopenharmony_ci res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3485e5b75505Sopenharmony_ci goto done; 3486e5b75505Sopenharmony_ci } 3487e5b75505Sopenharmony_ci reply = (struct ieee80211_mgmt *) buf; 3488e5b75505Sopenharmony_ci reply->frame_control = 3489e5b75505Sopenharmony_ci IEEE80211_FC(WLAN_FC_TYPE_MGMT, 3490e5b75505Sopenharmony_ci (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : 3491e5b75505Sopenharmony_ci WLAN_FC_STYPE_ASSOC_RESP)); 3492e5b75505Sopenharmony_ci os_memcpy(reply->da, addr, ETH_ALEN); 3493e5b75505Sopenharmony_ci os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); 3494e5b75505Sopenharmony_ci os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN); 3495e5b75505Sopenharmony_ci 3496e5b75505Sopenharmony_ci send_len = IEEE80211_HDRLEN; 3497e5b75505Sopenharmony_ci send_len += sizeof(reply->u.assoc_resp); 3498e5b75505Sopenharmony_ci reply->u.assoc_resp.capab_info = 3499e5b75505Sopenharmony_ci host_to_le16(hostapd_own_capab_info(hapd)); 3500e5b75505Sopenharmony_ci reply->u.assoc_resp.status_code = host_to_le16(status_code); 3501e5b75505Sopenharmony_ci 3502e5b75505Sopenharmony_ci reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) | 3503e5b75505Sopenharmony_ci BIT(14) | BIT(15)); 3504e5b75505Sopenharmony_ci /* Supported rates */ 3505e5b75505Sopenharmony_ci p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable); 3506e5b75505Sopenharmony_ci /* Extended supported rates */ 3507e5b75505Sopenharmony_ci p = hostapd_eid_ext_supp_rates(hapd, p); 3508e5b75505Sopenharmony_ci 3509e5b75505Sopenharmony_ci#ifdef CONFIG_MBO 3510e5b75505Sopenharmony_ci if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS && 3511e5b75505Sopenharmony_ci rssi != 0) { 3512e5b75505Sopenharmony_ci int delta = hapd->iconf->rssi_reject_assoc_rssi - rssi; 3513e5b75505Sopenharmony_ci 3514e5b75505Sopenharmony_ci p = hostapd_eid_mbo_rssi_assoc_rej(hapd, p, buf + buflen - p, 3515e5b75505Sopenharmony_ci delta); 3516e5b75505Sopenharmony_ci } 3517e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */ 3518e5b75505Sopenharmony_ci 3519e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 3520e5b75505Sopenharmony_ci if (sta && status_code == WLAN_STATUS_SUCCESS) { 3521e5b75505Sopenharmony_ci /* IEEE 802.11r: Mobility Domain Information, Fast BSS 3522e5b75505Sopenharmony_ci * Transition Information, RSN, [RIC Response] */ 3523e5b75505Sopenharmony_ci p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, 3524e5b75505Sopenharmony_ci buf + buflen - p, 3525e5b75505Sopenharmony_ci sta->auth_alg, ies, ies_len); 3526e5b75505Sopenharmony_ci if (!p) { 3527e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3528e5b75505Sopenharmony_ci "FT: Failed to write AssocResp IEs"); 3529e5b75505Sopenharmony_ci res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3530e5b75505Sopenharmony_ci goto done; 3531e5b75505Sopenharmony_ci } 3532e5b75505Sopenharmony_ci } 3533e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 3534e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 3535e5b75505Sopenharmony_ci if (sta && status_code == WLAN_STATUS_SUCCESS && 3536e5b75505Sopenharmony_ci (sta->auth_alg == WLAN_AUTH_FILS_SK || 3537e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 3538e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK)) 3539e5b75505Sopenharmony_ci p = wpa_auth_write_assoc_resp_fils(sta->wpa_sm, p, 3540e5b75505Sopenharmony_ci buf + buflen - p, 3541e5b75505Sopenharmony_ci ies, ies_len); 3542e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 3543e5b75505Sopenharmony_ci 3544e5b75505Sopenharmony_ci#ifdef CONFIG_OWE 3545e5b75505Sopenharmony_ci if (sta && status_code == WLAN_STATUS_SUCCESS && 3546e5b75505Sopenharmony_ci (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) 3547e5b75505Sopenharmony_ci p = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, p, 3548e5b75505Sopenharmony_ci buf + buflen - p, 3549e5b75505Sopenharmony_ci ies, ies_len); 3550e5b75505Sopenharmony_ci#endif /* CONFIG_OWE */ 3551e5b75505Sopenharmony_ci 3552e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 3553e5b75505Sopenharmony_ci if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) 3554e5b75505Sopenharmony_ci p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 3555e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 3556e5b75505Sopenharmony_ci 3557e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N 3558e5b75505Sopenharmony_ci p = hostapd_eid_ht_capabilities(hapd, p); 3559e5b75505Sopenharmony_ci p = hostapd_eid_ht_operation(hapd, p); 3560e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */ 3561e5b75505Sopenharmony_ci 3562e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211AC 3563e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { 3564e5b75505Sopenharmony_ci u32 nsts = 0, sta_nsts; 3565e5b75505Sopenharmony_ci 3566e5b75505Sopenharmony_ci if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) { 3567e5b75505Sopenharmony_ci struct ieee80211_vht_capabilities *capa; 3568e5b75505Sopenharmony_ci 3569e5b75505Sopenharmony_ci nsts = (hapd->iface->conf->vht_capab >> 3570e5b75505Sopenharmony_ci VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7; 3571e5b75505Sopenharmony_ci capa = sta->vht_capabilities; 3572e5b75505Sopenharmony_ci sta_nsts = (le_to_host32(capa->vht_capabilities_info) >> 3573e5b75505Sopenharmony_ci VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7; 3574e5b75505Sopenharmony_ci 3575e5b75505Sopenharmony_ci if (nsts < sta_nsts) 3576e5b75505Sopenharmony_ci nsts = 0; 3577e5b75505Sopenharmony_ci else 3578e5b75505Sopenharmony_ci nsts = sta_nsts; 3579e5b75505Sopenharmony_ci } 3580e5b75505Sopenharmony_ci p = hostapd_eid_vht_capabilities(hapd, p, nsts); 3581e5b75505Sopenharmony_ci p = hostapd_eid_vht_operation(hapd, p); 3582e5b75505Sopenharmony_ci } 3583e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211AC */ 3584e5b75505Sopenharmony_ci 3585e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211AX 3586e5b75505Sopenharmony_ci if (hapd->iconf->ieee80211ax) { 3587e5b75505Sopenharmony_ci p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP); 3588e5b75505Sopenharmony_ci p = hostapd_eid_he_operation(hapd, p); 3589e5b75505Sopenharmony_ci p = hostapd_eid_spatial_reuse(hapd, p); 3590e5b75505Sopenharmony_ci p = hostapd_eid_he_mu_edca_parameter_set(hapd, p); 3591e5b75505Sopenharmony_ci } 3592e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211AX */ 3593e5b75505Sopenharmony_ci 3594e5b75505Sopenharmony_ci p = hostapd_eid_ext_capab(hapd, p); 3595e5b75505Sopenharmony_ci p = hostapd_eid_bss_max_idle_period(hapd, p); 3596e5b75505Sopenharmony_ci if (sta && sta->qos_map_enabled) 3597e5b75505Sopenharmony_ci p = hostapd_eid_qos_map_set(hapd, p); 3598e5b75505Sopenharmony_ci 3599e5b75505Sopenharmony_ci#ifdef CONFIG_FST 3600e5b75505Sopenharmony_ci if (hapd->iface->fst_ies) { 3601e5b75505Sopenharmony_ci os_memcpy(p, wpabuf_head(hapd->iface->fst_ies), 3602e5b75505Sopenharmony_ci wpabuf_len(hapd->iface->fst_ies)); 3603e5b75505Sopenharmony_ci p += wpabuf_len(hapd->iface->fst_ies); 3604e5b75505Sopenharmony_ci } 3605e5b75505Sopenharmony_ci#endif /* CONFIG_FST */ 3606e5b75505Sopenharmony_ci 3607e5b75505Sopenharmony_ci#ifdef CONFIG_OWE 3608e5b75505Sopenharmony_ci if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 3609e5b75505Sopenharmony_ci sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS && 3610e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE) { 3611e5b75505Sopenharmony_ci struct wpabuf *pub; 3612e5b75505Sopenharmony_ci 3613e5b75505Sopenharmony_ci pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 3614e5b75505Sopenharmony_ci if (!pub) { 3615e5b75505Sopenharmony_ci res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3616e5b75505Sopenharmony_ci goto done; 3617e5b75505Sopenharmony_ci } 3618e5b75505Sopenharmony_ci /* OWE Diffie-Hellman Parameter element */ 3619e5b75505Sopenharmony_ci *p++ = WLAN_EID_EXTENSION; /* Element ID */ 3620e5b75505Sopenharmony_ci *p++ = 1 + 2 + wpabuf_len(pub); /* Length */ 3621e5b75505Sopenharmony_ci *p++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension */ 3622e5b75505Sopenharmony_ci WPA_PUT_LE16(p, sta->owe_group); 3623e5b75505Sopenharmony_ci p += 2; 3624e5b75505Sopenharmony_ci os_memcpy(p, wpabuf_head(pub), wpabuf_len(pub)); 3625e5b75505Sopenharmony_ci p += wpabuf_len(pub); 3626e5b75505Sopenharmony_ci wpabuf_free(pub); 3627e5b75505Sopenharmony_ci } 3628e5b75505Sopenharmony_ci#endif /* CONFIG_OWE */ 3629e5b75505Sopenharmony_ci 3630e5b75505Sopenharmony_ci#ifdef CONFIG_DPP2 3631e5b75505Sopenharmony_ci if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && 3632e5b75505Sopenharmony_ci sta && sta->dpp_pfs && status_code == WLAN_STATUS_SUCCESS && 3633e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP) { 3634e5b75505Sopenharmony_ci os_memcpy(p, wpabuf_head(sta->dpp_pfs->ie), 3635e5b75505Sopenharmony_ci wpabuf_len(sta->dpp_pfs->ie)); 3636e5b75505Sopenharmony_ci p += wpabuf_len(sta->dpp_pfs->ie); 3637e5b75505Sopenharmony_ci } 3638e5b75505Sopenharmony_ci#endif /* CONFIG_DPP2 */ 3639e5b75505Sopenharmony_ci 3640e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211AC 3641e5b75505Sopenharmony_ci if (sta && hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT)) 3642e5b75505Sopenharmony_ci p = hostapd_eid_vendor_vht(hapd, p); 3643e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211AC */ 3644e5b75505Sopenharmony_ci 3645e5b75505Sopenharmony_ci if (sta && (sta->flags & WLAN_STA_WMM)) 3646e5b75505Sopenharmony_ci p = hostapd_eid_wmm(hapd, p); 3647e5b75505Sopenharmony_ci 3648e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 3649e5b75505Sopenharmony_ci if (sta && 3650e5b75505Sopenharmony_ci ((sta->flags & WLAN_STA_WPS) || 3651e5b75505Sopenharmony_ci ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa))) { 3652e5b75505Sopenharmony_ci struct wpabuf *wps = wps_build_assoc_resp_ie(); 3653e5b75505Sopenharmony_ci if (wps) { 3654e5b75505Sopenharmony_ci os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); 3655e5b75505Sopenharmony_ci p += wpabuf_len(wps); 3656e5b75505Sopenharmony_ci wpabuf_free(wps); 3657e5b75505Sopenharmony_ci } 3658e5b75505Sopenharmony_ci } 3659e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 3660e5b75505Sopenharmony_ci 3661e5b75505Sopenharmony_ci if (sta && (sta->flags & WLAN_STA_MULTI_AP)) 3662e5b75505Sopenharmony_ci p = hostapd_eid_multi_ap(hapd, p); 3663e5b75505Sopenharmony_ci 3664e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 3665e5b75505Sopenharmony_ci if (sta && sta->p2p_ie && hapd->p2p_group) { 3666e5b75505Sopenharmony_ci struct wpabuf *p2p_resp_ie; 3667e5b75505Sopenharmony_ci enum p2p_status_code status; 3668e5b75505Sopenharmony_ci switch (status_code) { 3669e5b75505Sopenharmony_ci case WLAN_STATUS_SUCCESS: 3670e5b75505Sopenharmony_ci status = P2P_SC_SUCCESS; 3671e5b75505Sopenharmony_ci break; 3672e5b75505Sopenharmony_ci case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA: 3673e5b75505Sopenharmony_ci status = P2P_SC_FAIL_LIMIT_REACHED; 3674e5b75505Sopenharmony_ci break; 3675e5b75505Sopenharmony_ci default: 3676e5b75505Sopenharmony_ci status = P2P_SC_FAIL_INVALID_PARAMS; 3677e5b75505Sopenharmony_ci break; 3678e5b75505Sopenharmony_ci } 3679e5b75505Sopenharmony_ci p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status); 3680e5b75505Sopenharmony_ci if (p2p_resp_ie) { 3681e5b75505Sopenharmony_ci os_memcpy(p, wpabuf_head(p2p_resp_ie), 3682e5b75505Sopenharmony_ci wpabuf_len(p2p_resp_ie)); 3683e5b75505Sopenharmony_ci p += wpabuf_len(p2p_resp_ie); 3684e5b75505Sopenharmony_ci wpabuf_free(p2p_resp_ie); 3685e5b75505Sopenharmony_ci } 3686e5b75505Sopenharmony_ci } 3687e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 3688e5b75505Sopenharmony_ci 3689e5b75505Sopenharmony_ci#ifdef CONFIG_P2P_MANAGER 3690e5b75505Sopenharmony_ci if (hapd->conf->p2p & P2P_MANAGE) 3691e5b75505Sopenharmony_ci p = hostapd_eid_p2p_manage(hapd, p); 3692e5b75505Sopenharmony_ci#endif /* CONFIG_P2P_MANAGER */ 3693e5b75505Sopenharmony_ci 3694e5b75505Sopenharmony_ci p = hostapd_eid_mbo(hapd, p, buf + buflen - p); 3695e5b75505Sopenharmony_ci 3696e5b75505Sopenharmony_ci if (hapd->conf->assocresp_elements && 3697e5b75505Sopenharmony_ci (size_t) (buf + buflen - p) >= 3698e5b75505Sopenharmony_ci wpabuf_len(hapd->conf->assocresp_elements)) { 3699e5b75505Sopenharmony_ci os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements), 3700e5b75505Sopenharmony_ci wpabuf_len(hapd->conf->assocresp_elements)); 3701e5b75505Sopenharmony_ci p += wpabuf_len(hapd->conf->assocresp_elements); 3702e5b75505Sopenharmony_ci } 3703e5b75505Sopenharmony_ci 3704e5b75505Sopenharmony_ci send_len += p - reply->u.assoc_resp.variable; 3705e5b75505Sopenharmony_ci 3706e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 3707e5b75505Sopenharmony_ci if (sta && 3708e5b75505Sopenharmony_ci (sta->auth_alg == WLAN_AUTH_FILS_SK || 3709e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 3710e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK) && 3711e5b75505Sopenharmony_ci status_code == WLAN_STATUS_SUCCESS) { 3712e5b75505Sopenharmony_ci struct ieee802_11_elems elems; 3713e5b75505Sopenharmony_ci 3714e5b75505Sopenharmony_ci if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == 3715e5b75505Sopenharmony_ci ParseFailed || !elems.fils_session) { 3716e5b75505Sopenharmony_ci res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3717e5b75505Sopenharmony_ci goto done; 3718e5b75505Sopenharmony_ci } 3719e5b75505Sopenharmony_ci 3720e5b75505Sopenharmony_ci /* FILS Session */ 3721e5b75505Sopenharmony_ci *p++ = WLAN_EID_EXTENSION; /* Element ID */ 3722e5b75505Sopenharmony_ci *p++ = 1 + FILS_SESSION_LEN; /* Length */ 3723e5b75505Sopenharmony_ci *p++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */ 3724e5b75505Sopenharmony_ci os_memcpy(p, elems.fils_session, FILS_SESSION_LEN); 3725e5b75505Sopenharmony_ci send_len += 2 + 1 + FILS_SESSION_LEN; 3726e5b75505Sopenharmony_ci 3727e5b75505Sopenharmony_ci send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len, 3728e5b75505Sopenharmony_ci buflen, sta->fils_hlp_resp); 3729e5b75505Sopenharmony_ci if (send_len < 0) { 3730e5b75505Sopenharmony_ci res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3731e5b75505Sopenharmony_ci goto done; 3732e5b75505Sopenharmony_ci } 3733e5b75505Sopenharmony_ci } 3734e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 3735e5b75505Sopenharmony_ci 3736e5b75505Sopenharmony_ci if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) { 3737e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", 3738e5b75505Sopenharmony_ci strerror(errno)); 3739e5b75505Sopenharmony_ci res = WLAN_STATUS_UNSPECIFIED_FAILURE; 3740e5b75505Sopenharmony_ci } 3741e5b75505Sopenharmony_ci 3742e5b75505Sopenharmony_cidone: 3743e5b75505Sopenharmony_ci os_free(buf); 3744e5b75505Sopenharmony_ci return res; 3745e5b75505Sopenharmony_ci} 3746e5b75505Sopenharmony_ci 3747e5b75505Sopenharmony_ci 3748e5b75505Sopenharmony_ci#ifdef CONFIG_OWE 3749e5b75505Sopenharmony_ciu8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, 3750e5b75505Sopenharmony_ci const u8 *owe_dh, u8 owe_dh_len, 3751e5b75505Sopenharmony_ci u8 *owe_buf, size_t owe_buf_len, u16 *reason) 3752e5b75505Sopenharmony_ci{ 3753e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3754e5b75505Sopenharmony_ci if (hapd->conf->own_ie_override) { 3755e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Using IE override"); 3756e5b75505Sopenharmony_ci *reason = WLAN_STATUS_SUCCESS; 3757e5b75505Sopenharmony_ci return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, 3758e5b75505Sopenharmony_ci owe_buf_len, NULL, 0); 3759e5b75505Sopenharmony_ci } 3760e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3761e5b75505Sopenharmony_ci 3762e5b75505Sopenharmony_ci if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) { 3763e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching"); 3764e5b75505Sopenharmony_ci owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, 3765e5b75505Sopenharmony_ci owe_buf_len, NULL, 0); 3766e5b75505Sopenharmony_ci *reason = WLAN_STATUS_SUCCESS; 3767e5b75505Sopenharmony_ci return owe_buf; 3768e5b75505Sopenharmony_ci } 3769e5b75505Sopenharmony_ci 3770e5b75505Sopenharmony_ci if (sta->owe_pmk && sta->external_dh_updated) { 3771e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK"); 3772e5b75505Sopenharmony_ci *reason = WLAN_STATUS_SUCCESS; 3773e5b75505Sopenharmony_ci return owe_buf; 3774e5b75505Sopenharmony_ci } 3775e5b75505Sopenharmony_ci 3776e5b75505Sopenharmony_ci *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len); 3777e5b75505Sopenharmony_ci if (*reason != WLAN_STATUS_SUCCESS) 3778e5b75505Sopenharmony_ci return NULL; 3779e5b75505Sopenharmony_ci 3780e5b75505Sopenharmony_ci owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, 3781e5b75505Sopenharmony_ci owe_buf_len, NULL, 0); 3782e5b75505Sopenharmony_ci 3783e5b75505Sopenharmony_ci if (sta->owe_ecdh && owe_buf) { 3784e5b75505Sopenharmony_ci struct wpabuf *pub; 3785e5b75505Sopenharmony_ci 3786e5b75505Sopenharmony_ci pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); 3787e5b75505Sopenharmony_ci if (!pub) { 3788e5b75505Sopenharmony_ci *reason = WLAN_STATUS_UNSPECIFIED_FAILURE; 3789e5b75505Sopenharmony_ci return owe_buf; 3790e5b75505Sopenharmony_ci } 3791e5b75505Sopenharmony_ci 3792e5b75505Sopenharmony_ci /* OWE Diffie-Hellman Parameter element */ 3793e5b75505Sopenharmony_ci *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */ 3794e5b75505Sopenharmony_ci *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */ 3795e5b75505Sopenharmony_ci *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension 3796e5b75505Sopenharmony_ci */ 3797e5b75505Sopenharmony_ci WPA_PUT_LE16(owe_buf, sta->owe_group); 3798e5b75505Sopenharmony_ci owe_buf += 2; 3799e5b75505Sopenharmony_ci os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub)); 3800e5b75505Sopenharmony_ci owe_buf += wpabuf_len(pub); 3801e5b75505Sopenharmony_ci wpabuf_free(pub); 3802e5b75505Sopenharmony_ci } 3803e5b75505Sopenharmony_ci 3804e5b75505Sopenharmony_ci return owe_buf; 3805e5b75505Sopenharmony_ci} 3806e5b75505Sopenharmony_ci#endif /* CONFIG_OWE */ 3807e5b75505Sopenharmony_ci 3808e5b75505Sopenharmony_ci 3809e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 3810e5b75505Sopenharmony_ci 3811e5b75505Sopenharmony_civoid fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta) 3812e5b75505Sopenharmony_ci{ 3813e5b75505Sopenharmony_ci u16 reply_res; 3814e5b75505Sopenharmony_ci 3815e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR, 3816e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 3817e5b75505Sopenharmony_ci eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 3818e5b75505Sopenharmony_ci if (!sta->fils_pending_assoc_req) 3819e5b75505Sopenharmony_ci return; 3820e5b75505Sopenharmony_ci reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS, 3821e5b75505Sopenharmony_ci sta->fils_pending_assoc_is_reassoc, 3822e5b75505Sopenharmony_ci sta->fils_pending_assoc_req, 3823e5b75505Sopenharmony_ci sta->fils_pending_assoc_req_len, 0); 3824e5b75505Sopenharmony_ci os_free(sta->fils_pending_assoc_req); 3825e5b75505Sopenharmony_ci sta->fils_pending_assoc_req = NULL; 3826e5b75505Sopenharmony_ci sta->fils_pending_assoc_req_len = 0; 3827e5b75505Sopenharmony_ci wpabuf_free(sta->fils_hlp_resp); 3828e5b75505Sopenharmony_ci sta->fils_hlp_resp = NULL; 3829e5b75505Sopenharmony_ci wpabuf_free(sta->hlp_dhcp_discover); 3830e5b75505Sopenharmony_ci sta->hlp_dhcp_discover = NULL; 3831e5b75505Sopenharmony_ci 3832e5b75505Sopenharmony_ci /* 3833e5b75505Sopenharmony_ci * Remove the station in case transmission of a success response fails. 3834e5b75505Sopenharmony_ci * At this point the station was already added associated to the driver. 3835e5b75505Sopenharmony_ci */ 3836e5b75505Sopenharmony_ci if (reply_res != WLAN_STATUS_SUCCESS) 3837e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 3838e5b75505Sopenharmony_ci} 3839e5b75505Sopenharmony_ci 3840e5b75505Sopenharmony_ci 3841e5b75505Sopenharmony_civoid fils_hlp_timeout(void *eloop_ctx, void *eloop_data) 3842e5b75505Sopenharmony_ci{ 3843e5b75505Sopenharmony_ci struct hostapd_data *hapd = eloop_ctx; 3844e5b75505Sopenharmony_ci struct sta_info *sta = eloop_data; 3845e5b75505Sopenharmony_ci 3846e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 3847e5b75505Sopenharmony_ci "FILS: HLP response timeout - continue with association response for " 3848e5b75505Sopenharmony_ci MACSTR, MAC2STR(sta->addr)); 3849e5b75505Sopenharmony_ci if (sta->fils_drv_assoc_finish) 3850e5b75505Sopenharmony_ci hostapd_notify_assoc_fils_finish(hapd, sta); 3851e5b75505Sopenharmony_ci else 3852e5b75505Sopenharmony_ci fils_hlp_finish_assoc(hapd, sta); 3853e5b75505Sopenharmony_ci} 3854e5b75505Sopenharmony_ci 3855e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 3856e5b75505Sopenharmony_ci 3857e5b75505Sopenharmony_ci 3858e5b75505Sopenharmony_cistatic void handle_assoc(struct hostapd_data *hapd, 3859e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len, 3860e5b75505Sopenharmony_ci int reassoc, int rssi) 3861e5b75505Sopenharmony_ci{ 3862e5b75505Sopenharmony_ci u16 capab_info, listen_interval, seq_ctrl, fc; 3863e5b75505Sopenharmony_ci u16 resp = WLAN_STATUS_SUCCESS, reply_res; 3864e5b75505Sopenharmony_ci const u8 *pos; 3865e5b75505Sopenharmony_ci int left, i; 3866e5b75505Sopenharmony_ci struct sta_info *sta; 3867e5b75505Sopenharmony_ci u8 *tmp = NULL; 3868e5b75505Sopenharmony_ci struct hostapd_sta_wpa_psk_short *psk = NULL; 3869e5b75505Sopenharmony_ci char *identity = NULL; 3870e5b75505Sopenharmony_ci char *radius_cui = NULL; 3871e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 3872e5b75505Sopenharmony_ci int delay_assoc = 0; 3873e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 3874e5b75505Sopenharmony_ci 3875e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : 3876e5b75505Sopenharmony_ci sizeof(mgmt->u.assoc_req))) { 3877e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "handle_assoc(reassoc=%d) - too short payload (len=%lu)", 3878e5b75505Sopenharmony_ci reassoc, (unsigned long) len); 3879e5b75505Sopenharmony_ci return; 3880e5b75505Sopenharmony_ci } 3881e5b75505Sopenharmony_ci 3882e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 3883e5b75505Sopenharmony_ci if (reassoc) { 3884e5b75505Sopenharmony_ci if (hapd->iconf->ignore_reassoc_probability > 0.0 && 3885e5b75505Sopenharmony_ci drand48() < hapd->iconf->ignore_reassoc_probability) { 3886e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3887e5b75505Sopenharmony_ci "TESTING: ignoring reassoc request from " 3888e5b75505Sopenharmony_ci MACSTR, MAC2STR(mgmt->sa)); 3889e5b75505Sopenharmony_ci return; 3890e5b75505Sopenharmony_ci } 3891e5b75505Sopenharmony_ci } else { 3892e5b75505Sopenharmony_ci if (hapd->iconf->ignore_assoc_probability > 0.0 && 3893e5b75505Sopenharmony_ci drand48() < hapd->iconf->ignore_assoc_probability) { 3894e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 3895e5b75505Sopenharmony_ci "TESTING: ignoring assoc request from " 3896e5b75505Sopenharmony_ci MACSTR, MAC2STR(mgmt->sa)); 3897e5b75505Sopenharmony_ci return; 3898e5b75505Sopenharmony_ci } 3899e5b75505Sopenharmony_ci } 3900e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 3901e5b75505Sopenharmony_ci 3902e5b75505Sopenharmony_ci fc = le_to_host16(mgmt->frame_control); 3903e5b75505Sopenharmony_ci seq_ctrl = le_to_host16(mgmt->seq_ctrl); 3904e5b75505Sopenharmony_ci 3905e5b75505Sopenharmony_ci if (reassoc) { 3906e5b75505Sopenharmony_ci capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info); 3907e5b75505Sopenharmony_ci listen_interval = le_to_host16( 3908e5b75505Sopenharmony_ci mgmt->u.reassoc_req.listen_interval); 3909e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR 3910e5b75505Sopenharmony_ci " capab_info=0x%02x listen_interval=%d current_ap=" 3911e5b75505Sopenharmony_ci MACSTR " seq_ctrl=0x%x%s", 3912e5b75505Sopenharmony_ci MAC2STR(mgmt->sa), capab_info, listen_interval, 3913e5b75505Sopenharmony_ci MAC2STR(mgmt->u.reassoc_req.current_ap), 3914e5b75505Sopenharmony_ci seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : ""); 3915e5b75505Sopenharmony_ci left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); 3916e5b75505Sopenharmony_ci pos = mgmt->u.reassoc_req.variable; 3917e5b75505Sopenharmony_ci } else { 3918e5b75505Sopenharmony_ci capab_info = le_to_host16(mgmt->u.assoc_req.capab_info); 3919e5b75505Sopenharmony_ci listen_interval = le_to_host16( 3920e5b75505Sopenharmony_ci mgmt->u.assoc_req.listen_interval); 3921e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR 3922e5b75505Sopenharmony_ci " capab_info=0x%02x listen_interval=%d " 3923e5b75505Sopenharmony_ci "seq_ctrl=0x%x%s", 3924e5b75505Sopenharmony_ci MAC2STR(mgmt->sa), capab_info, listen_interval, 3925e5b75505Sopenharmony_ci seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : ""); 3926e5b75505Sopenharmony_ci left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); 3927e5b75505Sopenharmony_ci pos = mgmt->u.assoc_req.variable; 3928e5b75505Sopenharmony_ci } 3929e5b75505Sopenharmony_ci 3930e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->sa); 3931e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 3932e5b75505Sopenharmony_ci if (sta && sta->auth_alg == WLAN_AUTH_FT && 3933e5b75505Sopenharmony_ci (sta->flags & WLAN_STA_AUTH) == 0) { 3934e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate " 3935e5b75505Sopenharmony_ci "prior to authentication since it is using " 3936e5b75505Sopenharmony_ci "over-the-DS FT", MAC2STR(mgmt->sa)); 3937e5b75505Sopenharmony_ci 3938e5b75505Sopenharmony_ci /* 3939e5b75505Sopenharmony_ci * Mark station as authenticated, to avoid adding station 3940e5b75505Sopenharmony_ci * entry in the driver as associated and not authenticated 3941e5b75505Sopenharmony_ci */ 3942e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 3943e5b75505Sopenharmony_ci } else 3944e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 3945e5b75505Sopenharmony_ci if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { 3946e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 3947e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == 3948e5b75505Sopenharmony_ci HOSTAPD_MODE_IEEE80211AD) { 3949e5b75505Sopenharmony_ci int acl_res; 3950e5b75505Sopenharmony_ci u32 session_timeout, acct_interim_interval; 3951e5b75505Sopenharmony_ci struct vlan_description vlan_id; 3952e5b75505Sopenharmony_ci 3953e5b75505Sopenharmony_ci acl_res = ieee802_11_allowed_address( 3954e5b75505Sopenharmony_ci hapd, mgmt->sa, (const u8 *) mgmt, len, 3955e5b75505Sopenharmony_ci &session_timeout, &acct_interim_interval, 3956e5b75505Sopenharmony_ci &vlan_id, &psk, &identity, &radius_cui, 0); 3957e5b75505Sopenharmony_ci if (acl_res == HOSTAPD_ACL_REJECT) { 3958e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_DEBUG, 3959e5b75505Sopenharmony_ci "Ignore Association Request frame from " 3960e5b75505Sopenharmony_ci MACSTR " due to ACL reject", 3961e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 3962e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 3963e5b75505Sopenharmony_ci goto fail; 3964e5b75505Sopenharmony_ci } 3965e5b75505Sopenharmony_ci if (acl_res == HOSTAPD_ACL_PENDING) 3966e5b75505Sopenharmony_ci return; 3967e5b75505Sopenharmony_ci 3968e5b75505Sopenharmony_ci /* DMG/IEEE 802.11ad does not use authentication. 3969e5b75505Sopenharmony_ci * Allocate sta entry upon association. */ 3970e5b75505Sopenharmony_ci sta = ap_sta_add(hapd, mgmt->sa); 3971e5b75505Sopenharmony_ci if (!sta) { 3972e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, 3973e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 3974e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 3975e5b75505Sopenharmony_ci "Failed to add STA"); 3976e5b75505Sopenharmony_ci resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 3977e5b75505Sopenharmony_ci goto fail; 3978e5b75505Sopenharmony_ci } 3979e5b75505Sopenharmony_ci 3980e5b75505Sopenharmony_ci acl_res = ieee802_11_set_radius_info( 3981e5b75505Sopenharmony_ci hapd, sta, acl_res, session_timeout, 3982e5b75505Sopenharmony_ci acct_interim_interval, &vlan_id, &psk, 3983e5b75505Sopenharmony_ci &identity, &radius_cui); 3984e5b75505Sopenharmony_ci if (acl_res) { 3985e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 3986e5b75505Sopenharmony_ci goto fail; 3987e5b75505Sopenharmony_ci } 3988e5b75505Sopenharmony_ci 3989e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 3990e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 3991e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 3992e5b75505Sopenharmony_ci "Skip authentication for DMG/IEEE 802.11ad"); 3993e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 3994e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 3995e5b75505Sopenharmony_ci sta->auth_alg = WLAN_AUTH_OPEN; 3996e5b75505Sopenharmony_ci } else { 3997e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, 3998e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 3999e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 4000e5b75505Sopenharmony_ci "Station tried to associate before authentication (aid=%d flags=0x%x)", 4001e5b75505Sopenharmony_ci sta ? sta->aid : -1, 4002e5b75505Sopenharmony_ci sta ? sta->flags : 0); 4003e5b75505Sopenharmony_ci send_deauth(hapd, mgmt->sa, 4004e5b75505Sopenharmony_ci WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); 4005e5b75505Sopenharmony_ci return; 4006e5b75505Sopenharmony_ci } 4007e5b75505Sopenharmony_ci } 4008e5b75505Sopenharmony_ci 4009e5b75505Sopenharmony_ci if ((fc & WLAN_FC_RETRY) && 4010e5b75505Sopenharmony_ci sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ && 4011e5b75505Sopenharmony_ci sta->last_seq_ctrl == seq_ctrl && 4012e5b75505Sopenharmony_ci sta->last_subtype == (reassoc ? WLAN_FC_STYPE_REASSOC_REQ : 4013e5b75505Sopenharmony_ci WLAN_FC_STYPE_ASSOC_REQ)) { 4014e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4015e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4016e5b75505Sopenharmony_ci "Drop repeated association frame seq_ctrl=0x%x", 4017e5b75505Sopenharmony_ci seq_ctrl); 4018e5b75505Sopenharmony_ci return; 4019e5b75505Sopenharmony_ci } 4020e5b75505Sopenharmony_ci sta->last_seq_ctrl = seq_ctrl; 4021e5b75505Sopenharmony_ci sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ : 4022e5b75505Sopenharmony_ci WLAN_FC_STYPE_ASSOC_REQ; 4023e5b75505Sopenharmony_ci 4024e5b75505Sopenharmony_ci if (hapd->tkip_countermeasures) { 4025e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 4026e5b75505Sopenharmony_ci goto fail; 4027e5b75505Sopenharmony_ci } 4028e5b75505Sopenharmony_ci 4029e5b75505Sopenharmony_ci if (listen_interval > hapd->conf->max_listen_interval) { 4030e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4031e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4032e5b75505Sopenharmony_ci "Too large Listen Interval (%d)", 4033e5b75505Sopenharmony_ci listen_interval); 4034e5b75505Sopenharmony_ci resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE; 4035e5b75505Sopenharmony_ci goto fail; 4036e5b75505Sopenharmony_ci } 4037e5b75505Sopenharmony_ci 4038e5b75505Sopenharmony_ci#ifdef CONFIG_MBO 4039e5b75505Sopenharmony_ci if (hapd->conf->mbo_enabled && hapd->mbo_assoc_disallow) { 4040e5b75505Sopenharmony_ci resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 4041e5b75505Sopenharmony_ci goto fail; 4042e5b75505Sopenharmony_ci } 4043e5b75505Sopenharmony_ci 4044e5b75505Sopenharmony_ci if (hapd->iconf->rssi_reject_assoc_rssi && rssi && 4045e5b75505Sopenharmony_ci rssi < hapd->iconf->rssi_reject_assoc_rssi && 4046e5b75505Sopenharmony_ci (sta->auth_rssi == 0 || 4047e5b75505Sopenharmony_ci sta->auth_rssi < hapd->iconf->rssi_reject_assoc_rssi)) { 4048e5b75505Sopenharmony_ci resp = WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS; 4049e5b75505Sopenharmony_ci goto fail; 4050e5b75505Sopenharmony_ci } 4051e5b75505Sopenharmony_ci#endif /* CONFIG_MBO */ 4052e5b75505Sopenharmony_ci 4053e5b75505Sopenharmony_ci /* 4054e5b75505Sopenharmony_ci * sta->capability is used in check_assoc_ies() for RRM enabled 4055e5b75505Sopenharmony_ci * capability element. 4056e5b75505Sopenharmony_ci */ 4057e5b75505Sopenharmony_ci sta->capability = capab_info; 4058e5b75505Sopenharmony_ci 4059e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 4060e5b75505Sopenharmony_ci if (sta->auth_alg == WLAN_AUTH_FILS_SK || 4061e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4062e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK) { 4063e5b75505Sopenharmony_ci int res; 4064e5b75505Sopenharmony_ci 4065e5b75505Sopenharmony_ci /* The end of the payload is encrypted. Need to decrypt it 4066e5b75505Sopenharmony_ci * before parsing. */ 4067e5b75505Sopenharmony_ci 4068e5b75505Sopenharmony_ci tmp = os_memdup(pos, left); 4069e5b75505Sopenharmony_ci if (!tmp) { 4070e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 4071e5b75505Sopenharmony_ci goto fail; 4072e5b75505Sopenharmony_ci } 4073e5b75505Sopenharmony_ci 4074e5b75505Sopenharmony_ci res = fils_decrypt_assoc(sta->wpa_sm, sta->fils_session, mgmt, 4075e5b75505Sopenharmony_ci len, tmp, left); 4076e5b75505Sopenharmony_ci if (res < 0) { 4077e5b75505Sopenharmony_ci resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 4078e5b75505Sopenharmony_ci goto fail; 4079e5b75505Sopenharmony_ci } 4080e5b75505Sopenharmony_ci pos = tmp; 4081e5b75505Sopenharmony_ci left = res; 4082e5b75505Sopenharmony_ci } 4083e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 4084e5b75505Sopenharmony_ci 4085e5b75505Sopenharmony_ci /* followed by SSID and Supported rates; and HT capabilities if 802.11n 4086e5b75505Sopenharmony_ci * is used */ 4087e5b75505Sopenharmony_ci resp = check_assoc_ies(hapd, sta, pos, left, reassoc); 4088e5b75505Sopenharmony_ci if (resp != WLAN_STATUS_SUCCESS) 4089e5b75505Sopenharmony_ci goto fail; 4090e5b75505Sopenharmony_ci 4091e5b75505Sopenharmony_ci if (hostapd_get_aid(hapd, sta) < 0) { 4092e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4093e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, "No room for more AIDs"); 4094e5b75505Sopenharmony_ci resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 4095e5b75505Sopenharmony_ci goto fail; 4096e5b75505Sopenharmony_ci } 4097e5b75505Sopenharmony_ci 4098e5b75505Sopenharmony_ci sta->listen_interval = listen_interval; 4099e5b75505Sopenharmony_ci 4100e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 4101e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 4102e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_NONERP; 4103e5b75505Sopenharmony_ci for (i = 0; i < sta->supported_rates_len; i++) { 4104e5b75505Sopenharmony_ci if ((sta->supported_rates[i] & 0x7f) > 22) { 4105e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_NONERP; 4106e5b75505Sopenharmony_ci break; 4107e5b75505Sopenharmony_ci } 4108e5b75505Sopenharmony_ci } 4109e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) { 4110e5b75505Sopenharmony_ci sta->nonerp_set = 1; 4111e5b75505Sopenharmony_ci hapd->iface->num_sta_non_erp++; 4112e5b75505Sopenharmony_ci if (hapd->iface->num_sta_non_erp == 1) 4113e5b75505Sopenharmony_ci ieee802_11_set_beacons(hapd->iface); 4114e5b75505Sopenharmony_ci } 4115e5b75505Sopenharmony_ci 4116e5b75505Sopenharmony_ci if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) && 4117e5b75505Sopenharmony_ci !sta->no_short_slot_time_set) { 4118e5b75505Sopenharmony_ci sta->no_short_slot_time_set = 1; 4119e5b75505Sopenharmony_ci hapd->iface->num_sta_no_short_slot_time++; 4120e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 4121e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == 4122e5b75505Sopenharmony_ci HOSTAPD_MODE_IEEE80211G && 4123e5b75505Sopenharmony_ci hapd->iface->num_sta_no_short_slot_time == 1) 4124e5b75505Sopenharmony_ci ieee802_11_set_beacons(hapd->iface); 4125e5b75505Sopenharmony_ci } 4126e5b75505Sopenharmony_ci 4127e5b75505Sopenharmony_ci if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) 4128e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_SHORT_PREAMBLE; 4129e5b75505Sopenharmony_ci else 4130e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; 4131e5b75505Sopenharmony_ci 4132e5b75505Sopenharmony_ci if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && 4133e5b75505Sopenharmony_ci !sta->no_short_preamble_set) { 4134e5b75505Sopenharmony_ci sta->no_short_preamble_set = 1; 4135e5b75505Sopenharmony_ci hapd->iface->num_sta_no_short_preamble++; 4136e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 4137e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G 4138e5b75505Sopenharmony_ci && hapd->iface->num_sta_no_short_preamble == 1) 4139e5b75505Sopenharmony_ci ieee802_11_set_beacons(hapd->iface); 4140e5b75505Sopenharmony_ci } 4141e5b75505Sopenharmony_ci 4142e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N 4143e5b75505Sopenharmony_ci update_ht_state(hapd, sta); 4144e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */ 4145e5b75505Sopenharmony_ci 4146e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4147e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4148e5b75505Sopenharmony_ci "association OK (aid %d)", sta->aid); 4149e5b75505Sopenharmony_ci /* Station will be marked associated, after it acknowledges AssocResp 4150e5b75505Sopenharmony_ci */ 4151e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_ASSOC_REQ_OK; 4152e5b75505Sopenharmony_ci 4153e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 4154e5b75505Sopenharmony_ci if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) { 4155e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out " 4156e5b75505Sopenharmony_ci "SA Query procedure", reassoc ? "re" : ""); 4157e5b75505Sopenharmony_ci /* TODO: Send a protected Disassociate frame to the STA using 4158e5b75505Sopenharmony_ci * the old key and Reason Code "Previous Authentication no 4159e5b75505Sopenharmony_ci * longer valid". Make sure this is only sent protected since 4160e5b75505Sopenharmony_ci * unprotected frame would be received by the STA that is now 4161e5b75505Sopenharmony_ci * trying to associate. 4162e5b75505Sopenharmony_ci */ 4163e5b75505Sopenharmony_ci } 4164e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 4165e5b75505Sopenharmony_ci 4166e5b75505Sopenharmony_ci /* Make sure that the previously registered inactivity timer will not 4167e5b75505Sopenharmony_ci * remove the STA immediately. */ 4168e5b75505Sopenharmony_ci sta->timeout_next = STA_NULLFUNC; 4169e5b75505Sopenharmony_ci 4170e5b75505Sopenharmony_ci#ifdef CONFIG_TAXONOMY 4171e5b75505Sopenharmony_ci taxonomy_sta_info_assoc_req(hapd, sta, pos, left); 4172e5b75505Sopenharmony_ci#endif /* CONFIG_TAXONOMY */ 4173e5b75505Sopenharmony_ci 4174e5b75505Sopenharmony_ci sta->pending_wds_enable = 0; 4175e5b75505Sopenharmony_ci 4176e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 4177e5b75505Sopenharmony_ci if (sta->auth_alg == WLAN_AUTH_FILS_SK || 4178e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4179e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK) { 4180e5b75505Sopenharmony_ci if (fils_process_hlp(hapd, sta, pos, left) > 0) 4181e5b75505Sopenharmony_ci delay_assoc = 1; 4182e5b75505Sopenharmony_ci } 4183e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 4184e5b75505Sopenharmony_ci 4185e5b75505Sopenharmony_ci fail: 4186e5b75505Sopenharmony_ci os_free(identity); 4187e5b75505Sopenharmony_ci os_free(radius_cui); 4188e5b75505Sopenharmony_ci hostapd_free_psk_list(psk); 4189e5b75505Sopenharmony_ci 4190e5b75505Sopenharmony_ci /* 4191e5b75505Sopenharmony_ci * In case of a successful response, add the station to the driver. 4192e5b75505Sopenharmony_ci * Otherwise, the kernel may ignore Data frames before we process the 4193e5b75505Sopenharmony_ci * ACK frame (TX status). In case of a failure, this station will be 4194e5b75505Sopenharmony_ci * removed. 4195e5b75505Sopenharmony_ci * 4196e5b75505Sopenharmony_ci * Note that this is not compliant with the IEEE 802.11 standard that 4197e5b75505Sopenharmony_ci * states that a non-AP station should transition into the 4198e5b75505Sopenharmony_ci * authenticated/associated state only after the station acknowledges 4199e5b75505Sopenharmony_ci * the (Re)Association Response frame. However, still do this as: 4200e5b75505Sopenharmony_ci * 4201e5b75505Sopenharmony_ci * 1. In case the station does not acknowledge the (Re)Association 4202e5b75505Sopenharmony_ci * Response frame, it will be removed. 4203e5b75505Sopenharmony_ci * 2. Data frames will be dropped in the kernel until the station is 4204e5b75505Sopenharmony_ci * set into authorized state, and there are no significant known 4205e5b75505Sopenharmony_ci * issues with processing other non-Data Class 3 frames during this 4206e5b75505Sopenharmony_ci * window. 4207e5b75505Sopenharmony_ci */ 4208e5b75505Sopenharmony_ci if (resp == WLAN_STATUS_SUCCESS && sta && 4209e5b75505Sopenharmony_ci add_associated_sta(hapd, sta, reassoc)) 4210e5b75505Sopenharmony_ci resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 4211e5b75505Sopenharmony_ci 4212e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 4213e5b75505Sopenharmony_ci if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS && 4214e5b75505Sopenharmony_ci eloop_is_timeout_registered(fils_hlp_timeout, hapd, sta) && 4215e5b75505Sopenharmony_ci sta->fils_pending_assoc_req) { 4216e5b75505Sopenharmony_ci /* Do not reschedule fils_hlp_timeout in case the station 4217e5b75505Sopenharmony_ci * retransmits (Re)Association Request frame while waiting for 4218e5b75505Sopenharmony_ci * the previously started FILS HLP wait, so that the timeout can 4219e5b75505Sopenharmony_ci * be determined from the first pending attempt. */ 4220e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4221e5b75505Sopenharmony_ci "FILS: Continue waiting for HLP processing before sending (Re)Association Response frame to " 4222e5b75505Sopenharmony_ci MACSTR, MAC2STR(sta->addr)); 4223e5b75505Sopenharmony_ci os_free(tmp); 4224e5b75505Sopenharmony_ci return; 4225e5b75505Sopenharmony_ci } 4226e5b75505Sopenharmony_ci if (sta) { 4227e5b75505Sopenharmony_ci eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 4228e5b75505Sopenharmony_ci os_free(sta->fils_pending_assoc_req); 4229e5b75505Sopenharmony_ci sta->fils_pending_assoc_req = NULL; 4230e5b75505Sopenharmony_ci sta->fils_pending_assoc_req_len = 0; 4231e5b75505Sopenharmony_ci wpabuf_free(sta->fils_hlp_resp); 4232e5b75505Sopenharmony_ci sta->fils_hlp_resp = NULL; 4233e5b75505Sopenharmony_ci } 4234e5b75505Sopenharmony_ci if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) { 4235e5b75505Sopenharmony_ci sta->fils_pending_assoc_req = tmp; 4236e5b75505Sopenharmony_ci sta->fils_pending_assoc_req_len = left; 4237e5b75505Sopenharmony_ci sta->fils_pending_assoc_is_reassoc = reassoc; 4238e5b75505Sopenharmony_ci sta->fils_drv_assoc_finish = 0; 4239e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4240e5b75505Sopenharmony_ci "FILS: Waiting for HLP processing before sending (Re)Association Response frame to " 4241e5b75505Sopenharmony_ci MACSTR, MAC2STR(sta->addr)); 4242e5b75505Sopenharmony_ci eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 4243e5b75505Sopenharmony_ci eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024, 4244e5b75505Sopenharmony_ci fils_hlp_timeout, hapd, sta); 4245e5b75505Sopenharmony_ci return; 4246e5b75505Sopenharmony_ci } 4247e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 4248e5b75505Sopenharmony_ci 4249e5b75505Sopenharmony_ci reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos, 4250e5b75505Sopenharmony_ci left, rssi); 4251e5b75505Sopenharmony_ci os_free(tmp); 4252e5b75505Sopenharmony_ci 4253e5b75505Sopenharmony_ci /* 4254e5b75505Sopenharmony_ci * Remove the station in case tranmission of a success response fails 4255e5b75505Sopenharmony_ci * (the STA was added associated to the driver) or if the station was 4256e5b75505Sopenharmony_ci * previously added unassociated. 4257e5b75505Sopenharmony_ci */ 4258e5b75505Sopenharmony_ci if (sta && ((reply_res != WLAN_STATUS_SUCCESS && 4259e5b75505Sopenharmony_ci resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc)) { 4260e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 4261e5b75505Sopenharmony_ci sta->added_unassoc = 0; 4262e5b75505Sopenharmony_ci } 4263e5b75505Sopenharmony_ci} 4264e5b75505Sopenharmony_ci 4265e5b75505Sopenharmony_ci 4266e5b75505Sopenharmony_cistatic void handle_disassoc(struct hostapd_data *hapd, 4267e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len) 4268e5b75505Sopenharmony_ci{ 4269e5b75505Sopenharmony_ci struct sta_info *sta; 4270e5b75505Sopenharmony_ci 4271e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { 4272e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)", 4273e5b75505Sopenharmony_ci (unsigned long) len); 4274e5b75505Sopenharmony_ci return; 4275e5b75505Sopenharmony_ci } 4276e5b75505Sopenharmony_ci 4277e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", 4278e5b75505Sopenharmony_ci MAC2STR(mgmt->sa), 4279e5b75505Sopenharmony_ci le_to_host16(mgmt->u.disassoc.reason_code)); 4280e5b75505Sopenharmony_ci 4281e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->sa); 4282e5b75505Sopenharmony_ci if (sta == NULL) { 4283e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Station " MACSTR " trying to disassociate, but it is not associated", 4284e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 4285e5b75505Sopenharmony_ci return; 4286e5b75505Sopenharmony_ci } 4287e5b75505Sopenharmony_ci 4288e5b75505Sopenharmony_ci ap_sta_set_authorized(hapd, sta, 0); 4289e5b75505Sopenharmony_ci sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 4290e5b75505Sopenharmony_ci sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); 4291e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 4292e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4293e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, "disassociated"); 4294e5b75505Sopenharmony_ci sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 4295e5b75505Sopenharmony_ci ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 4296e5b75505Sopenharmony_ci /* Stop Accounting and IEEE 802.1X sessions, but leave the STA 4297e5b75505Sopenharmony_ci * authenticated. */ 4298e5b75505Sopenharmony_ci accounting_sta_stop(hapd, sta); 4299e5b75505Sopenharmony_ci ieee802_1x_free_station(hapd, sta); 4300e5b75505Sopenharmony_ci if (sta->ipaddr) 4301e5b75505Sopenharmony_ci hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); 4302e5b75505Sopenharmony_ci ap_sta_ip6addr_del(hapd, sta); 4303e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 4304e5b75505Sopenharmony_ci sta->added_unassoc = 0; 4305e5b75505Sopenharmony_ci 4306e5b75505Sopenharmony_ci if (sta->timeout_next == STA_NULLFUNC || 4307e5b75505Sopenharmony_ci sta->timeout_next == STA_DISASSOC) { 4308e5b75505Sopenharmony_ci sta->timeout_next = STA_DEAUTH; 4309e5b75505Sopenharmony_ci eloop_cancel_timeout(ap_handle_timer, hapd, sta); 4310e5b75505Sopenharmony_ci eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, 4311e5b75505Sopenharmony_ci hapd, sta); 4312e5b75505Sopenharmony_ci } 4313e5b75505Sopenharmony_ci 4314e5b75505Sopenharmony_ci mlme_disassociate_indication( 4315e5b75505Sopenharmony_ci hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code)); 4316e5b75505Sopenharmony_ci 4317e5b75505Sopenharmony_ci /* DMG/IEEE 802.11ad does not use deauthication. Deallocate sta upon 4318e5b75505Sopenharmony_ci * disassociation. */ 4319e5b75505Sopenharmony_ci if (hapd->iface->current_mode && 4320e5b75505Sopenharmony_ci hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { 4321e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_AUTH; 4322e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); 4323e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4324e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "deauthenticated"); 4325e5b75505Sopenharmony_ci ap_free_sta(hapd, sta); 4326e5b75505Sopenharmony_ci } 4327e5b75505Sopenharmony_ci} 4328e5b75505Sopenharmony_ci 4329e5b75505Sopenharmony_ci 4330e5b75505Sopenharmony_cistatic void handle_deauth(struct hostapd_data *hapd, 4331e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len) 4332e5b75505Sopenharmony_ci{ 4333e5b75505Sopenharmony_ci struct sta_info *sta; 4334e5b75505Sopenharmony_ci 4335e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { 4336e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short " 4337e5b75505Sopenharmony_ci "payload (len=%lu)", (unsigned long) len); 4338e5b75505Sopenharmony_ci return; 4339e5b75505Sopenharmony_ci } 4340e5b75505Sopenharmony_ci 4341e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR 4342e5b75505Sopenharmony_ci " reason_code=%d", 4343e5b75505Sopenharmony_ci MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); 4344e5b75505Sopenharmony_ci 4345e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->sa); 4346e5b75505Sopenharmony_ci if (sta == NULL) { 4347e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " 4348e5b75505Sopenharmony_ci "to deauthenticate, but it is not authenticated", 4349e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 4350e5b75505Sopenharmony_ci return; 4351e5b75505Sopenharmony_ci } 4352e5b75505Sopenharmony_ci 4353e5b75505Sopenharmony_ci ap_sta_set_authorized(hapd, sta, 0); 4354e5b75505Sopenharmony_ci sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; 4355e5b75505Sopenharmony_ci sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | 4356e5b75505Sopenharmony_ci WLAN_STA_ASSOC_REQ_OK); 4357e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); 4358e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4359e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "deauthenticated"); 4360e5b75505Sopenharmony_ci mlme_deauthenticate_indication( 4361e5b75505Sopenharmony_ci hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); 4362e5b75505Sopenharmony_ci sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 4363e5b75505Sopenharmony_ci ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 4364e5b75505Sopenharmony_ci ap_free_sta(hapd, sta); 4365e5b75505Sopenharmony_ci} 4366e5b75505Sopenharmony_ci 4367e5b75505Sopenharmony_ci 4368e5b75505Sopenharmony_cistatic void handle_beacon(struct hostapd_data *hapd, 4369e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len, 4370e5b75505Sopenharmony_ci struct hostapd_frame_info *fi) 4371e5b75505Sopenharmony_ci{ 4372e5b75505Sopenharmony_ci struct ieee802_11_elems elems; 4373e5b75505Sopenharmony_ci 4374e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) { 4375e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "handle_beacon - too short payload (len=%lu)", 4376e5b75505Sopenharmony_ci (unsigned long) len); 4377e5b75505Sopenharmony_ci return; 4378e5b75505Sopenharmony_ci } 4379e5b75505Sopenharmony_ci 4380e5b75505Sopenharmony_ci (void) ieee802_11_parse_elems(mgmt->u.beacon.variable, 4381e5b75505Sopenharmony_ci len - (IEEE80211_HDRLEN + 4382e5b75505Sopenharmony_ci sizeof(mgmt->u.beacon)), &elems, 4383e5b75505Sopenharmony_ci 0); 4384e5b75505Sopenharmony_ci 4385e5b75505Sopenharmony_ci ap_list_process_beacon(hapd->iface, mgmt, &elems, fi); 4386e5b75505Sopenharmony_ci} 4387e5b75505Sopenharmony_ci 4388e5b75505Sopenharmony_ci 4389e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 4390e5b75505Sopenharmony_cistatic int robust_action_frame(u8 category) 4391e5b75505Sopenharmony_ci{ 4392e5b75505Sopenharmony_ci return category != WLAN_ACTION_PUBLIC && 4393e5b75505Sopenharmony_ci category != WLAN_ACTION_HT; 4394e5b75505Sopenharmony_ci} 4395e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 4396e5b75505Sopenharmony_ci 4397e5b75505Sopenharmony_ci 4398e5b75505Sopenharmony_cistatic int handle_action(struct hostapd_data *hapd, 4399e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, size_t len, 4400e5b75505Sopenharmony_ci unsigned int freq) 4401e5b75505Sopenharmony_ci{ 4402e5b75505Sopenharmony_ci struct sta_info *sta; 4403e5b75505Sopenharmony_ci u8 *action __maybe_unused; 4404e5b75505Sopenharmony_ci 4405e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + 2 + 1) { 4406e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4407e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4408e5b75505Sopenharmony_ci "handle_action - too short payload (len=%lu)", 4409e5b75505Sopenharmony_ci (unsigned long) len); 4410e5b75505Sopenharmony_ci return 0; 4411e5b75505Sopenharmony_ci } 4412e5b75505Sopenharmony_ci 4413e5b75505Sopenharmony_ci action = (u8 *) &mgmt->u.action.u; 4414e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR 4415e5b75505Sopenharmony_ci " da " MACSTR " len %d freq %u", 4416e5b75505Sopenharmony_ci mgmt->u.action.category, *action, 4417e5b75505Sopenharmony_ci MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) len, freq); 4418e5b75505Sopenharmony_ci 4419e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->sa); 4420e5b75505Sopenharmony_ci 4421e5b75505Sopenharmony_ci if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && 4422e5b75505Sopenharmony_ci (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { 4423e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action " 4424e5b75505Sopenharmony_ci "frame (category=%u) from unassociated STA " MACSTR, 4425e5b75505Sopenharmony_ci mgmt->u.action.category, MAC2STR(mgmt->sa)); 4426e5b75505Sopenharmony_ci return 0; 4427e5b75505Sopenharmony_ci } 4428e5b75505Sopenharmony_ci 4429e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 4430e5b75505Sopenharmony_ci if (sta && (sta->flags & WLAN_STA_MFP) && 4431e5b75505Sopenharmony_ci !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP)) && 4432e5b75505Sopenharmony_ci robust_action_frame(mgmt->u.action.category)) { 4433e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4434e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4435e5b75505Sopenharmony_ci "Dropped unprotected Robust Action frame from " 4436e5b75505Sopenharmony_ci "an MFP STA"); 4437e5b75505Sopenharmony_ci return 0; 4438e5b75505Sopenharmony_ci } 4439e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 4440e5b75505Sopenharmony_ci 4441e5b75505Sopenharmony_ci if (sta) { 4442e5b75505Sopenharmony_ci u16 fc = le_to_host16(mgmt->frame_control); 4443e5b75505Sopenharmony_ci u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl); 4444e5b75505Sopenharmony_ci 4445e5b75505Sopenharmony_ci if ((fc & WLAN_FC_RETRY) && 4446e5b75505Sopenharmony_ci sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ && 4447e5b75505Sopenharmony_ci sta->last_seq_ctrl == seq_ctrl && 4448e5b75505Sopenharmony_ci sta->last_subtype == WLAN_FC_STYPE_ACTION) { 4449e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 4450e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE80211, 4451e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4452e5b75505Sopenharmony_ci "Drop repeated action frame seq_ctrl=0x%x", 4453e5b75505Sopenharmony_ci seq_ctrl); 4454e5b75505Sopenharmony_ci return 1; 4455e5b75505Sopenharmony_ci } 4456e5b75505Sopenharmony_ci 4457e5b75505Sopenharmony_ci sta->last_seq_ctrl = seq_ctrl; 4458e5b75505Sopenharmony_ci sta->last_subtype = WLAN_FC_STYPE_ACTION; 4459e5b75505Sopenharmony_ci } 4460e5b75505Sopenharmony_ci 4461e5b75505Sopenharmony_ci switch (mgmt->u.action.category) { 4462e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 4463e5b75505Sopenharmony_ci case WLAN_ACTION_FT: 4464e5b75505Sopenharmony_ci if (!sta || 4465e5b75505Sopenharmony_ci wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, 4466e5b75505Sopenharmony_ci len - IEEE80211_HDRLEN)) 4467e5b75505Sopenharmony_ci break; 4468e5b75505Sopenharmony_ci return 1; 4469e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 4470e5b75505Sopenharmony_ci case WLAN_ACTION_WMM: 4471e5b75505Sopenharmony_ci hostapd_wmm_action(hapd, mgmt, len); 4472e5b75505Sopenharmony_ci return 1; 4473e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 4474e5b75505Sopenharmony_ci case WLAN_ACTION_SA_QUERY: 4475e5b75505Sopenharmony_ci ieee802_11_sa_query_action(hapd, mgmt, len); 4476e5b75505Sopenharmony_ci return 1; 4477e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 4478e5b75505Sopenharmony_ci#ifdef CONFIG_WNM_AP 4479e5b75505Sopenharmony_ci case WLAN_ACTION_WNM: 4480e5b75505Sopenharmony_ci ieee802_11_rx_wnm_action_ap(hapd, mgmt, len); 4481e5b75505Sopenharmony_ci return 1; 4482e5b75505Sopenharmony_ci#endif /* CONFIG_WNM_AP */ 4483e5b75505Sopenharmony_ci#ifdef CONFIG_FST 4484e5b75505Sopenharmony_ci case WLAN_ACTION_FST: 4485e5b75505Sopenharmony_ci if (hapd->iface->fst) 4486e5b75505Sopenharmony_ci fst_rx_action(hapd->iface->fst, mgmt, len); 4487e5b75505Sopenharmony_ci else 4488e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4489e5b75505Sopenharmony_ci "FST: Ignore FST Action frame - no FST attached"); 4490e5b75505Sopenharmony_ci return 1; 4491e5b75505Sopenharmony_ci#endif /* CONFIG_FST */ 4492e5b75505Sopenharmony_ci case WLAN_ACTION_PUBLIC: 4493e5b75505Sopenharmony_ci case WLAN_ACTION_PROTECTED_DUAL: 4494e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211N 4495e5b75505Sopenharmony_ci if (len >= IEEE80211_HDRLEN + 2 && 4496e5b75505Sopenharmony_ci mgmt->u.action.u.public_action.action == 4497e5b75505Sopenharmony_ci WLAN_PA_20_40_BSS_COEX) { 4498e5b75505Sopenharmony_ci hostapd_2040_coex_action(hapd, mgmt, len); 4499e5b75505Sopenharmony_ci return 1; 4500e5b75505Sopenharmony_ci } 4501e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211N */ 4502e5b75505Sopenharmony_ci#ifdef CONFIG_DPP 4503e5b75505Sopenharmony_ci if (len >= IEEE80211_HDRLEN + 6 && 4504e5b75505Sopenharmony_ci mgmt->u.action.u.vs_public_action.action == 4505e5b75505Sopenharmony_ci WLAN_PA_VENDOR_SPECIFIC && 4506e5b75505Sopenharmony_ci WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 4507e5b75505Sopenharmony_ci OUI_WFA && 4508e5b75505Sopenharmony_ci mgmt->u.action.u.vs_public_action.variable[0] == 4509e5b75505Sopenharmony_ci DPP_OUI_TYPE) { 4510e5b75505Sopenharmony_ci const u8 *pos, *end; 4511e5b75505Sopenharmony_ci 4512e5b75505Sopenharmony_ci pos = mgmt->u.action.u.vs_public_action.oui; 4513e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 4514e5b75505Sopenharmony_ci hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos, 4515e5b75505Sopenharmony_ci freq); 4516e5b75505Sopenharmony_ci return 1; 4517e5b75505Sopenharmony_ci } 4518e5b75505Sopenharmony_ci if (len >= IEEE80211_HDRLEN + 2 && 4519e5b75505Sopenharmony_ci (mgmt->u.action.u.public_action.action == 4520e5b75505Sopenharmony_ci WLAN_PA_GAS_INITIAL_RESP || 4521e5b75505Sopenharmony_ci mgmt->u.action.u.public_action.action == 4522e5b75505Sopenharmony_ci WLAN_PA_GAS_COMEBACK_RESP)) { 4523e5b75505Sopenharmony_ci const u8 *pos, *end; 4524e5b75505Sopenharmony_ci 4525e5b75505Sopenharmony_ci pos = &mgmt->u.action.u.public_action.action; 4526e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 4527e5b75505Sopenharmony_ci gas_query_ap_rx(hapd->gas, mgmt->sa, 4528e5b75505Sopenharmony_ci mgmt->u.action.category, 4529e5b75505Sopenharmony_ci pos, end - pos, hapd->iface->freq); 4530e5b75505Sopenharmony_ci return 1; 4531e5b75505Sopenharmony_ci } 4532e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */ 4533e5b75505Sopenharmony_ci if (hapd->public_action_cb) { 4534e5b75505Sopenharmony_ci hapd->public_action_cb(hapd->public_action_cb_ctx, 4535e5b75505Sopenharmony_ci (u8 *) mgmt, len, 4536e5b75505Sopenharmony_ci hapd->iface->freq); 4537e5b75505Sopenharmony_ci } 4538e5b75505Sopenharmony_ci if (hapd->public_action_cb2) { 4539e5b75505Sopenharmony_ci hapd->public_action_cb2(hapd->public_action_cb2_ctx, 4540e5b75505Sopenharmony_ci (u8 *) mgmt, len, 4541e5b75505Sopenharmony_ci hapd->iface->freq); 4542e5b75505Sopenharmony_ci } 4543e5b75505Sopenharmony_ci if (hapd->public_action_cb || hapd->public_action_cb2) 4544e5b75505Sopenharmony_ci return 1; 4545e5b75505Sopenharmony_ci break; 4546e5b75505Sopenharmony_ci case WLAN_ACTION_VENDOR_SPECIFIC: 4547e5b75505Sopenharmony_ci if (hapd->vendor_action_cb) { 4548e5b75505Sopenharmony_ci if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, 4549e5b75505Sopenharmony_ci (u8 *) mgmt, len, 4550e5b75505Sopenharmony_ci hapd->iface->freq) == 0) 4551e5b75505Sopenharmony_ci return 1; 4552e5b75505Sopenharmony_ci } 4553e5b75505Sopenharmony_ci break; 4554e5b75505Sopenharmony_ci case WLAN_ACTION_RADIO_MEASUREMENT: 4555e5b75505Sopenharmony_ci hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len); 4556e5b75505Sopenharmony_ci return 1; 4557e5b75505Sopenharmony_ci } 4558e5b75505Sopenharmony_ci 4559e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4560e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4561e5b75505Sopenharmony_ci "handle_action - unknown action category %d or invalid " 4562e5b75505Sopenharmony_ci "frame", 4563e5b75505Sopenharmony_ci mgmt->u.action.category); 4564e5b75505Sopenharmony_ci if (!is_multicast_ether_addr(mgmt->da) && 4565e5b75505Sopenharmony_ci !(mgmt->u.action.category & 0x80) && 4566e5b75505Sopenharmony_ci !is_multicast_ether_addr(mgmt->sa)) { 4567e5b75505Sopenharmony_ci struct ieee80211_mgmt *resp; 4568e5b75505Sopenharmony_ci 4569e5b75505Sopenharmony_ci /* 4570e5b75505Sopenharmony_ci * IEEE 802.11-REVma/D9.0 - 7.3.1.11 4571e5b75505Sopenharmony_ci * Return the Action frame to the source without change 4572e5b75505Sopenharmony_ci * except that MSB of the Category set to 1. 4573e5b75505Sopenharmony_ci */ 4574e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action " 4575e5b75505Sopenharmony_ci "frame back to sender"); 4576e5b75505Sopenharmony_ci resp = os_memdup(mgmt, len); 4577e5b75505Sopenharmony_ci if (resp == NULL) 4578e5b75505Sopenharmony_ci return 0; 4579e5b75505Sopenharmony_ci os_memcpy(resp->da, resp->sa, ETH_ALEN); 4580e5b75505Sopenharmony_ci os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); 4581e5b75505Sopenharmony_ci os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); 4582e5b75505Sopenharmony_ci resp->u.action.category |= 0x80; 4583e5b75505Sopenharmony_ci 4584e5b75505Sopenharmony_ci if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) { 4585e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send " 4586e5b75505Sopenharmony_ci "Action frame"); 4587e5b75505Sopenharmony_ci } 4588e5b75505Sopenharmony_ci os_free(resp); 4589e5b75505Sopenharmony_ci } 4590e5b75505Sopenharmony_ci 4591e5b75505Sopenharmony_ci return 1; 4592e5b75505Sopenharmony_ci} 4593e5b75505Sopenharmony_ci 4594e5b75505Sopenharmony_ci 4595e5b75505Sopenharmony_ci/** 4596e5b75505Sopenharmony_ci * ieee802_11_mgmt - process incoming IEEE 802.11 management frames 4597e5b75505Sopenharmony_ci * @hapd: hostapd BSS data structure (the BSS to which the management frame was 4598e5b75505Sopenharmony_ci * sent to) 4599e5b75505Sopenharmony_ci * @buf: management frame data (starting from IEEE 802.11 header) 4600e5b75505Sopenharmony_ci * @len: length of frame data in octets 4601e5b75505Sopenharmony_ci * @fi: meta data about received frame (signal level, etc.) 4602e5b75505Sopenharmony_ci * 4603e5b75505Sopenharmony_ci * Process all incoming IEEE 802.11 management frames. This will be called for 4604e5b75505Sopenharmony_ci * each frame received from the kernel driver through wlan#ap interface. In 4605e5b75505Sopenharmony_ci * addition, it can be called to re-inserted pending frames (e.g., when using 4606e5b75505Sopenharmony_ci * external RADIUS server as an MAC ACL). 4607e5b75505Sopenharmony_ci */ 4608e5b75505Sopenharmony_ciint ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, 4609e5b75505Sopenharmony_ci struct hostapd_frame_info *fi) 4610e5b75505Sopenharmony_ci{ 4611e5b75505Sopenharmony_ci struct ieee80211_mgmt *mgmt; 4612e5b75505Sopenharmony_ci u16 fc, stype; 4613e5b75505Sopenharmony_ci int ret = 0; 4614e5b75505Sopenharmony_ci unsigned int freq; 4615e5b75505Sopenharmony_ci int ssi_signal = fi ? fi->ssi_signal : 0; 4616e5b75505Sopenharmony_ci 4617e5b75505Sopenharmony_ci if (len < 24) 4618e5b75505Sopenharmony_ci return 0; 4619e5b75505Sopenharmony_ci 4620e5b75505Sopenharmony_ci if (fi && fi->freq) 4621e5b75505Sopenharmony_ci freq = fi->freq; 4622e5b75505Sopenharmony_ci else 4623e5b75505Sopenharmony_ci freq = hapd->iface->freq; 4624e5b75505Sopenharmony_ci 4625e5b75505Sopenharmony_ci mgmt = (struct ieee80211_mgmt *) buf; 4626e5b75505Sopenharmony_ci fc = le_to_host16(mgmt->frame_control); 4627e5b75505Sopenharmony_ci stype = WLAN_FC_GET_STYPE(fc); 4628e5b75505Sopenharmony_ci 4629e5b75505Sopenharmony_ci if (is_multicast_ether_addr(mgmt->sa) || 4630e5b75505Sopenharmony_ci is_zero_ether_addr(mgmt->sa) || 4631e5b75505Sopenharmony_ci os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { 4632e5b75505Sopenharmony_ci /* Do not process any frames with unexpected/invalid SA so that 4633e5b75505Sopenharmony_ci * we do not add any state for unexpected STA addresses or end 4634e5b75505Sopenharmony_ci * up sending out frames to unexpected destination. */ 4635e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "MGMT: Invalid SA=" MACSTR 4636e5b75505Sopenharmony_ci " in received frame - ignore this frame silently", 4637e5b75505Sopenharmony_ci MAC2STR(mgmt->sa)); 4638e5b75505Sopenharmony_ci return 0; 4639e5b75505Sopenharmony_ci } 4640e5b75505Sopenharmony_ci 4641e5b75505Sopenharmony_ci if (stype == WLAN_FC_STYPE_BEACON) { 4642e5b75505Sopenharmony_ci handle_beacon(hapd, mgmt, len, fi); 4643e5b75505Sopenharmony_ci return 1; 4644e5b75505Sopenharmony_ci } 4645e5b75505Sopenharmony_ci 4646e5b75505Sopenharmony_ci if (!is_broadcast_ether_addr(mgmt->bssid) && 4647e5b75505Sopenharmony_ci#ifdef CONFIG_P2P 4648e5b75505Sopenharmony_ci /* Invitation responses can be sent with the peer MAC as BSSID */ 4649e5b75505Sopenharmony_ci !((hapd->conf->p2p & P2P_GROUP_OWNER) && 4650e5b75505Sopenharmony_ci stype == WLAN_FC_STYPE_ACTION) && 4651e5b75505Sopenharmony_ci#endif /* CONFIG_P2P */ 4652e5b75505Sopenharmony_ci#ifdef CONFIG_MESH 4653e5b75505Sopenharmony_ci !(hapd->conf->mesh & MESH_ENABLED) && 4654e5b75505Sopenharmony_ci#endif /* CONFIG_MESH */ 4655e5b75505Sopenharmony_ci os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { 4656e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address", 4657e5b75505Sopenharmony_ci MAC2STR(mgmt->bssid)); 4658e5b75505Sopenharmony_ci return 0; 4659e5b75505Sopenharmony_ci } 4660e5b75505Sopenharmony_ci 4661e5b75505Sopenharmony_ci 4662e5b75505Sopenharmony_ci if (stype == WLAN_FC_STYPE_PROBE_REQ) { 4663e5b75505Sopenharmony_ci handle_probe_req(hapd, mgmt, len, ssi_signal); 4664e5b75505Sopenharmony_ci return 1; 4665e5b75505Sopenharmony_ci } 4666e5b75505Sopenharmony_ci 4667e5b75505Sopenharmony_ci if ((!is_broadcast_ether_addr(mgmt->da) || 4668e5b75505Sopenharmony_ci stype != WLAN_FC_STYPE_ACTION) && 4669e5b75505Sopenharmony_ci os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { 4670e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4671e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4672e5b75505Sopenharmony_ci "MGMT: DA=" MACSTR " not our address", 4673e5b75505Sopenharmony_ci MAC2STR(mgmt->da)); 4674e5b75505Sopenharmony_ci return 0; 4675e5b75505Sopenharmony_ci } 4676e5b75505Sopenharmony_ci 4677e5b75505Sopenharmony_ci if (hapd->iconf->track_sta_max_num) 4678e5b75505Sopenharmony_ci sta_track_add(hapd->iface, mgmt->sa, ssi_signal); 4679e5b75505Sopenharmony_ci 4680e5b75505Sopenharmony_ci switch (stype) { 4681e5b75505Sopenharmony_ci case WLAN_FC_STYPE_AUTH: 4682e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::auth"); 4683e5b75505Sopenharmony_ci handle_auth(hapd, mgmt, len, ssi_signal, 0); 4684e5b75505Sopenharmony_ci ret = 1; 4685e5b75505Sopenharmony_ci break; 4686e5b75505Sopenharmony_ci case WLAN_FC_STYPE_ASSOC_REQ: 4687e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); 4688e5b75505Sopenharmony_ci handle_assoc(hapd, mgmt, len, 0, ssi_signal); 4689e5b75505Sopenharmony_ci ret = 1; 4690e5b75505Sopenharmony_ci break; 4691e5b75505Sopenharmony_ci case WLAN_FC_STYPE_REASSOC_REQ: 4692e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); 4693e5b75505Sopenharmony_ci handle_assoc(hapd, mgmt, len, 1, ssi_signal); 4694e5b75505Sopenharmony_ci ret = 1; 4695e5b75505Sopenharmony_ci break; 4696e5b75505Sopenharmony_ci case WLAN_FC_STYPE_DISASSOC: 4697e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::disassoc"); 4698e5b75505Sopenharmony_ci handle_disassoc(hapd, mgmt, len); 4699e5b75505Sopenharmony_ci ret = 1; 4700e5b75505Sopenharmony_ci break; 4701e5b75505Sopenharmony_ci case WLAN_FC_STYPE_DEAUTH: 4702e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth"); 4703e5b75505Sopenharmony_ci handle_deauth(hapd, mgmt, len); 4704e5b75505Sopenharmony_ci ret = 1; 4705e5b75505Sopenharmony_ci break; 4706e5b75505Sopenharmony_ci case WLAN_FC_STYPE_ACTION: 4707e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::action"); 4708e5b75505Sopenharmony_ci ret = handle_action(hapd, mgmt, len, freq); 4709e5b75505Sopenharmony_ci break; 4710e5b75505Sopenharmony_ci default: 4711e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 4712e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4713e5b75505Sopenharmony_ci "unknown mgmt frame subtype %d", stype); 4714e5b75505Sopenharmony_ci break; 4715e5b75505Sopenharmony_ci } 4716e5b75505Sopenharmony_ci 4717e5b75505Sopenharmony_ci return ret; 4718e5b75505Sopenharmony_ci} 4719e5b75505Sopenharmony_ci 4720e5b75505Sopenharmony_ci 4721e5b75505Sopenharmony_cistatic void handle_auth_cb(struct hostapd_data *hapd, 4722e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, 4723e5b75505Sopenharmony_ci size_t len, int ok) 4724e5b75505Sopenharmony_ci{ 4725e5b75505Sopenharmony_ci u16 auth_alg, auth_transaction, status_code; 4726e5b75505Sopenharmony_ci struct sta_info *sta; 4727e5b75505Sopenharmony_ci 4728e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->da); 4729e5b75505Sopenharmony_ci if (!sta) { 4730e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "handle_auth_cb: STA " MACSTR 4731e5b75505Sopenharmony_ci " not found", 4732e5b75505Sopenharmony_ci MAC2STR(mgmt->da)); 4733e5b75505Sopenharmony_ci return; 4734e5b75505Sopenharmony_ci } 4735e5b75505Sopenharmony_ci 4736e5b75505Sopenharmony_ci auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 4737e5b75505Sopenharmony_ci auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 4738e5b75505Sopenharmony_ci status_code = le_to_host16(mgmt->u.auth.status_code); 4739e5b75505Sopenharmony_ci 4740e5b75505Sopenharmony_ci if (!ok) { 4741e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, 4742e5b75505Sopenharmony_ci HOSTAPD_LEVEL_NOTICE, 4743e5b75505Sopenharmony_ci "did not acknowledge authentication response"); 4744e5b75505Sopenharmony_ci goto fail; 4745e5b75505Sopenharmony_ci } 4746e5b75505Sopenharmony_ci 4747e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { 4748e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)", 4749e5b75505Sopenharmony_ci (unsigned long) len); 4750e5b75505Sopenharmony_ci goto fail; 4751e5b75505Sopenharmony_ci } 4752e5b75505Sopenharmony_ci 4753e5b75505Sopenharmony_ci if (status_code == WLAN_STATUS_SUCCESS && 4754e5b75505Sopenharmony_ci ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || 4755e5b75505Sopenharmony_ci (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { 4756e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4757e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, "authenticated"); 4758e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_AUTH; 4759e5b75505Sopenharmony_ci if (sta->added_unassoc) 4760e5b75505Sopenharmony_ci hostapd_set_sta_flags(hapd, sta); 4761e5b75505Sopenharmony_ci return; 4762e5b75505Sopenharmony_ci } 4763e5b75505Sopenharmony_ci 4764e5b75505Sopenharmony_cifail: 4765e5b75505Sopenharmony_ci if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) { 4766e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 4767e5b75505Sopenharmony_ci sta->added_unassoc = 0; 4768e5b75505Sopenharmony_ci } 4769e5b75505Sopenharmony_ci} 4770e5b75505Sopenharmony_ci 4771e5b75505Sopenharmony_ci 4772e5b75505Sopenharmony_cistatic void hostapd_set_wds_encryption(struct hostapd_data *hapd, 4773e5b75505Sopenharmony_ci struct sta_info *sta, 4774e5b75505Sopenharmony_ci char *ifname_wds) 4775e5b75505Sopenharmony_ci{ 4776e5b75505Sopenharmony_ci int i; 4777e5b75505Sopenharmony_ci struct hostapd_ssid *ssid = &hapd->conf->ssid; 4778e5b75505Sopenharmony_ci 4779e5b75505Sopenharmony_ci if (hapd->conf->ieee802_1x || hapd->conf->wpa) 4780e5b75505Sopenharmony_ci return; 4781e5b75505Sopenharmony_ci 4782e5b75505Sopenharmony_ci for (i = 0; i < 4; i++) { 4783e5b75505Sopenharmony_ci if (ssid->wep.key[i] && 4784e5b75505Sopenharmony_ci hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i, 4785e5b75505Sopenharmony_ci i == ssid->wep.idx, NULL, 0, 4786e5b75505Sopenharmony_ci ssid->wep.key[i], ssid->wep.len[i])) { 4787e5b75505Sopenharmony_ci wpa_printf(MSG_WARNING, 4788e5b75505Sopenharmony_ci "Could not set WEP keys for WDS interface; %s", 4789e5b75505Sopenharmony_ci ifname_wds); 4790e5b75505Sopenharmony_ci break; 4791e5b75505Sopenharmony_ci } 4792e5b75505Sopenharmony_ci } 4793e5b75505Sopenharmony_ci} 4794e5b75505Sopenharmony_ci 4795e5b75505Sopenharmony_ci 4796e5b75505Sopenharmony_cistatic void handle_assoc_cb(struct hostapd_data *hapd, 4797e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, 4798e5b75505Sopenharmony_ci size_t len, int reassoc, int ok) 4799e5b75505Sopenharmony_ci{ 4800e5b75505Sopenharmony_ci u16 status; 4801e5b75505Sopenharmony_ci struct sta_info *sta; 4802e5b75505Sopenharmony_ci int new_assoc = 1; 4803e5b75505Sopenharmony_ci 4804e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->da); 4805e5b75505Sopenharmony_ci if (!sta) { 4806e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "handle_assoc_cb: STA " MACSTR " not found", 4807e5b75505Sopenharmony_ci MAC2STR(mgmt->da)); 4808e5b75505Sopenharmony_ci return; 4809e5b75505Sopenharmony_ci } 4810e5b75505Sopenharmony_ci 4811e5b75505Sopenharmony_ci if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : 4812e5b75505Sopenharmony_ci sizeof(mgmt->u.assoc_resp))) { 4813e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 4814e5b75505Sopenharmony_ci "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)", 4815e5b75505Sopenharmony_ci reassoc, (unsigned long) len); 4816e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 4817e5b75505Sopenharmony_ci return; 4818e5b75505Sopenharmony_ci } 4819e5b75505Sopenharmony_ci 4820e5b75505Sopenharmony_ci if (reassoc) 4821e5b75505Sopenharmony_ci status = le_to_host16(mgmt->u.reassoc_resp.status_code); 4822e5b75505Sopenharmony_ci else 4823e5b75505Sopenharmony_ci status = le_to_host16(mgmt->u.assoc_resp.status_code); 4824e5b75505Sopenharmony_ci 4825e5b75505Sopenharmony_ci if (!ok) { 4826e5b75505Sopenharmony_ci hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, 4827e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 4828e5b75505Sopenharmony_ci "did not acknowledge association response"); 4829e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_ASSOC_REQ_OK; 4830e5b75505Sopenharmony_ci /* The STA is added only in case of SUCCESS */ 4831e5b75505Sopenharmony_ci if (status == WLAN_STATUS_SUCCESS) 4832e5b75505Sopenharmony_ci hostapd_drv_sta_remove(hapd, sta->addr); 4833e5b75505Sopenharmony_ci 4834e5b75505Sopenharmony_ci return; 4835e5b75505Sopenharmony_ci } 4836e5b75505Sopenharmony_ci 4837e5b75505Sopenharmony_ci if (status != WLAN_STATUS_SUCCESS) 4838e5b75505Sopenharmony_ci return; 4839e5b75505Sopenharmony_ci 4840e5b75505Sopenharmony_ci /* Stop previous accounting session, if one is started, and allocate 4841e5b75505Sopenharmony_ci * new session id for the new session. */ 4842e5b75505Sopenharmony_ci accounting_sta_stop(hapd, sta); 4843e5b75505Sopenharmony_ci 4844e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4845e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 4846e5b75505Sopenharmony_ci "associated (aid %d)", 4847e5b75505Sopenharmony_ci sta->aid); 4848e5b75505Sopenharmony_ci 4849e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_ASSOC) 4850e5b75505Sopenharmony_ci new_assoc = 0; 4851e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_ASSOC; 4852e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 4853e5b75505Sopenharmony_ci if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && 4854e5b75505Sopenharmony_ci !hapd->conf->osen) || 4855e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK || 4856e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4857e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK || 4858e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FT) { 4859e5b75505Sopenharmony_ci /* 4860e5b75505Sopenharmony_ci * Open, static WEP, FT protocol, or FILS; no separate 4861e5b75505Sopenharmony_ci * authorization step. 4862e5b75505Sopenharmony_ci */ 4863e5b75505Sopenharmony_ci ap_sta_set_authorized(hapd, sta, 1); 4864e5b75505Sopenharmony_ci } 4865e5b75505Sopenharmony_ci 4866e5b75505Sopenharmony_ci if (reassoc) 4867e5b75505Sopenharmony_ci mlme_reassociate_indication(hapd, sta); 4868e5b75505Sopenharmony_ci else 4869e5b75505Sopenharmony_ci mlme_associate_indication(hapd, sta); 4870e5b75505Sopenharmony_ci 4871e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 4872e5b75505Sopenharmony_ci sta->sa_query_timed_out = 0; 4873e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 4874e5b75505Sopenharmony_ci 4875e5b75505Sopenharmony_ci if (sta->eapol_sm == NULL) { 4876e5b75505Sopenharmony_ci /* 4877e5b75505Sopenharmony_ci * This STA does not use RADIUS server for EAP authentication, 4878e5b75505Sopenharmony_ci * so bind it to the selected VLAN interface now, since the 4879e5b75505Sopenharmony_ci * interface selection is not going to change anymore. 4880e5b75505Sopenharmony_ci */ 4881e5b75505Sopenharmony_ci if (ap_sta_bind_vlan(hapd, sta) < 0) 4882e5b75505Sopenharmony_ci return; 4883e5b75505Sopenharmony_ci } else if (sta->vlan_id) { 4884e5b75505Sopenharmony_ci /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ 4885e5b75505Sopenharmony_ci if (ap_sta_bind_vlan(hapd, sta) < 0) 4886e5b75505Sopenharmony_ci return; 4887e5b75505Sopenharmony_ci } 4888e5b75505Sopenharmony_ci 4889e5b75505Sopenharmony_ci hostapd_set_sta_flags(hapd, sta); 4890e5b75505Sopenharmony_ci 4891e5b75505Sopenharmony_ci if (!(sta->flags & WLAN_STA_WDS) && sta->pending_wds_enable) { 4892e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for STA " 4893e5b75505Sopenharmony_ci MACSTR " based on pending request", 4894e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 4895e5b75505Sopenharmony_ci sta->pending_wds_enable = 0; 4896e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_WDS; 4897e5b75505Sopenharmony_ci } 4898e5b75505Sopenharmony_ci 4899e5b75505Sopenharmony_ci if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) { 4900e5b75505Sopenharmony_ci int ret; 4901e5b75505Sopenharmony_ci char ifname_wds[IFNAMSIZ + 1]; 4902e5b75505Sopenharmony_ci 4903e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Reenable 4-address WDS mode for STA " 4904e5b75505Sopenharmony_ci MACSTR " (aid %u)", 4905e5b75505Sopenharmony_ci MAC2STR(sta->addr), sta->aid); 4906e5b75505Sopenharmony_ci ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr, 4907e5b75505Sopenharmony_ci sta->aid, 1); 4908e5b75505Sopenharmony_ci if (!ret) 4909e5b75505Sopenharmony_ci hostapd_set_wds_encryption(hapd, sta, ifname_wds); 4910e5b75505Sopenharmony_ci } 4911e5b75505Sopenharmony_ci 4912e5b75505Sopenharmony_ci if (sta->auth_alg == WLAN_AUTH_FT) 4913e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 4914e5b75505Sopenharmony_ci else 4915e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 4916e5b75505Sopenharmony_ci hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); 4917e5b75505Sopenharmony_ci ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 4918e5b75505Sopenharmony_ci 4919e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 4920e5b75505Sopenharmony_ci if ((sta->auth_alg == WLAN_AUTH_FILS_SK || 4921e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 4922e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK) && 4923e5b75505Sopenharmony_ci fils_set_tk(sta->wpa_sm) < 0) { 4924e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "FILS: TK configuration failed"); 4925e5b75505Sopenharmony_ci ap_sta_disconnect(hapd, sta, sta->addr, 4926e5b75505Sopenharmony_ci WLAN_REASON_UNSPECIFIED); 4927e5b75505Sopenharmony_ci return; 4928e5b75505Sopenharmony_ci } 4929e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 4930e5b75505Sopenharmony_ci 4931e5b75505Sopenharmony_ci if (sta->pending_eapol_rx) { 4932e5b75505Sopenharmony_ci struct os_reltime now, age; 4933e5b75505Sopenharmony_ci 4934e5b75505Sopenharmony_ci os_get_reltime(&now); 4935e5b75505Sopenharmony_ci os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age); 4936e5b75505Sopenharmony_ci if (age.sec == 0 && age.usec < 200000) { 4937e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 4938e5b75505Sopenharmony_ci "Process pending EAPOL frame that was received from " MACSTR " just before association notification", 4939e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 4940e5b75505Sopenharmony_ci ieee802_1x_receive( 4941e5b75505Sopenharmony_ci hapd, mgmt->da, 4942e5b75505Sopenharmony_ci wpabuf_head(sta->pending_eapol_rx->buf), 4943e5b75505Sopenharmony_ci wpabuf_len(sta->pending_eapol_rx->buf)); 4944e5b75505Sopenharmony_ci } 4945e5b75505Sopenharmony_ci wpabuf_free(sta->pending_eapol_rx->buf); 4946e5b75505Sopenharmony_ci os_free(sta->pending_eapol_rx); 4947e5b75505Sopenharmony_ci sta->pending_eapol_rx = NULL; 4948e5b75505Sopenharmony_ci } 4949e5b75505Sopenharmony_ci} 4950e5b75505Sopenharmony_ci 4951e5b75505Sopenharmony_ci 4952e5b75505Sopenharmony_cistatic void handle_deauth_cb(struct hostapd_data *hapd, 4953e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, 4954e5b75505Sopenharmony_ci size_t len, int ok) 4955e5b75505Sopenharmony_ci{ 4956e5b75505Sopenharmony_ci struct sta_info *sta; 4957e5b75505Sopenharmony_ci if (is_multicast_ether_addr(mgmt->da)) 4958e5b75505Sopenharmony_ci return; 4959e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->da); 4960e5b75505Sopenharmony_ci if (!sta) { 4961e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR 4962e5b75505Sopenharmony_ci " not found", MAC2STR(mgmt->da)); 4963e5b75505Sopenharmony_ci return; 4964e5b75505Sopenharmony_ci } 4965e5b75505Sopenharmony_ci if (ok) 4966e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth", 4967e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 4968e5b75505Sopenharmony_ci else 4969e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " 4970e5b75505Sopenharmony_ci "deauth", MAC2STR(sta->addr)); 4971e5b75505Sopenharmony_ci 4972e5b75505Sopenharmony_ci ap_sta_deauth_cb(hapd, sta); 4973e5b75505Sopenharmony_ci} 4974e5b75505Sopenharmony_ci 4975e5b75505Sopenharmony_ci 4976e5b75505Sopenharmony_cistatic void handle_disassoc_cb(struct hostapd_data *hapd, 4977e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, 4978e5b75505Sopenharmony_ci size_t len, int ok) 4979e5b75505Sopenharmony_ci{ 4980e5b75505Sopenharmony_ci struct sta_info *sta; 4981e5b75505Sopenharmony_ci if (is_multicast_ether_addr(mgmt->da)) 4982e5b75505Sopenharmony_ci return; 4983e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->da); 4984e5b75505Sopenharmony_ci if (!sta) { 4985e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR 4986e5b75505Sopenharmony_ci " not found", MAC2STR(mgmt->da)); 4987e5b75505Sopenharmony_ci return; 4988e5b75505Sopenharmony_ci } 4989e5b75505Sopenharmony_ci if (ok) 4990e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc", 4991e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 4992e5b75505Sopenharmony_ci else 4993e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge " 4994e5b75505Sopenharmony_ci "disassoc", MAC2STR(sta->addr)); 4995e5b75505Sopenharmony_ci 4996e5b75505Sopenharmony_ci ap_sta_disassoc_cb(hapd, sta); 4997e5b75505Sopenharmony_ci} 4998e5b75505Sopenharmony_ci 4999e5b75505Sopenharmony_ci 5000e5b75505Sopenharmony_cistatic void handle_action_cb(struct hostapd_data *hapd, 5001e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt, 5002e5b75505Sopenharmony_ci size_t len, int ok) 5003e5b75505Sopenharmony_ci{ 5004e5b75505Sopenharmony_ci struct sta_info *sta; 5005e5b75505Sopenharmony_ci const struct rrm_measurement_report_element *report; 5006e5b75505Sopenharmony_ci 5007e5b75505Sopenharmony_ci if (is_multicast_ether_addr(mgmt->da)) 5008e5b75505Sopenharmony_ci return; 5009e5b75505Sopenharmony_ci#ifdef CONFIG_DPP 5010e5b75505Sopenharmony_ci if (len >= IEEE80211_HDRLEN + 6 && 5011e5b75505Sopenharmony_ci mgmt->u.action.category == WLAN_ACTION_PUBLIC && 5012e5b75505Sopenharmony_ci mgmt->u.action.u.vs_public_action.action == 5013e5b75505Sopenharmony_ci WLAN_PA_VENDOR_SPECIFIC && 5014e5b75505Sopenharmony_ci WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 5015e5b75505Sopenharmony_ci OUI_WFA && 5016e5b75505Sopenharmony_ci mgmt->u.action.u.vs_public_action.variable[0] == 5017e5b75505Sopenharmony_ci DPP_OUI_TYPE) { 5018e5b75505Sopenharmony_ci const u8 *pos, *end; 5019e5b75505Sopenharmony_ci 5020e5b75505Sopenharmony_ci pos = &mgmt->u.action.u.vs_public_action.variable[1]; 5021e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 5022e5b75505Sopenharmony_ci hostapd_dpp_tx_status(hapd, mgmt->da, pos, end - pos, ok); 5023e5b75505Sopenharmony_ci return; 5024e5b75505Sopenharmony_ci } 5025e5b75505Sopenharmony_ci if (len >= IEEE80211_HDRLEN + 2 && 5026e5b75505Sopenharmony_ci mgmt->u.action.category == WLAN_ACTION_PUBLIC && 5027e5b75505Sopenharmony_ci (mgmt->u.action.u.public_action.action == 5028e5b75505Sopenharmony_ci WLAN_PA_GAS_INITIAL_REQ || 5029e5b75505Sopenharmony_ci mgmt->u.action.u.public_action.action == 5030e5b75505Sopenharmony_ci WLAN_PA_GAS_COMEBACK_REQ)) { 5031e5b75505Sopenharmony_ci const u8 *pos, *end; 5032e5b75505Sopenharmony_ci 5033e5b75505Sopenharmony_ci pos = mgmt->u.action.u.public_action.variable; 5034e5b75505Sopenharmony_ci end = ((const u8 *) mgmt) + len; 5035e5b75505Sopenharmony_ci gas_query_ap_tx_status(hapd->gas, mgmt->da, pos, end - pos, ok); 5036e5b75505Sopenharmony_ci return; 5037e5b75505Sopenharmony_ci } 5038e5b75505Sopenharmony_ci#endif /* CONFIG_DPP */ 5039e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, mgmt->da); 5040e5b75505Sopenharmony_ci if (!sta) { 5041e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR 5042e5b75505Sopenharmony_ci " not found", MAC2STR(mgmt->da)); 5043e5b75505Sopenharmony_ci return; 5044e5b75505Sopenharmony_ci } 5045e5b75505Sopenharmony_ci 5046e5b75505Sopenharmony_ci if (len < 24 + 5 + sizeof(*report)) 5047e5b75505Sopenharmony_ci return; 5048e5b75505Sopenharmony_ci report = (const struct rrm_measurement_report_element *) 5049e5b75505Sopenharmony_ci &mgmt->u.action.u.rrm.variable[2]; 5050e5b75505Sopenharmony_ci if (mgmt->u.action.category == WLAN_ACTION_RADIO_MEASUREMENT && 5051e5b75505Sopenharmony_ci mgmt->u.action.u.rrm.action == WLAN_RRM_RADIO_MEASUREMENT_REQUEST && 5052e5b75505Sopenharmony_ci report->eid == WLAN_EID_MEASURE_REQUEST && 5053e5b75505Sopenharmony_ci report->len >= 3 && 5054e5b75505Sopenharmony_ci report->type == MEASURE_TYPE_BEACON) 5055e5b75505Sopenharmony_ci hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok); 5056e5b75505Sopenharmony_ci} 5057e5b75505Sopenharmony_ci 5058e5b75505Sopenharmony_ci 5059e5b75505Sopenharmony_ci/** 5060e5b75505Sopenharmony_ci * ieee802_11_mgmt_cb - Process management frame TX status callback 5061e5b75505Sopenharmony_ci * @hapd: hostapd BSS data structure (the BSS from which the management frame 5062e5b75505Sopenharmony_ci * was sent from) 5063e5b75505Sopenharmony_ci * @buf: management frame data (starting from IEEE 802.11 header) 5064e5b75505Sopenharmony_ci * @len: length of frame data in octets 5065e5b75505Sopenharmony_ci * @stype: management frame subtype from frame control field 5066e5b75505Sopenharmony_ci * @ok: Whether the frame was ACK'ed 5067e5b75505Sopenharmony_ci */ 5068e5b75505Sopenharmony_civoid ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, 5069e5b75505Sopenharmony_ci u16 stype, int ok) 5070e5b75505Sopenharmony_ci{ 5071e5b75505Sopenharmony_ci const struct ieee80211_mgmt *mgmt; 5072e5b75505Sopenharmony_ci mgmt = (const struct ieee80211_mgmt *) buf; 5073e5b75505Sopenharmony_ci 5074e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 5075e5b75505Sopenharmony_ci if (hapd->ext_mgmt_frame_handling) { 5076e5b75505Sopenharmony_ci size_t hex_len = 2 * len + 1; 5077e5b75505Sopenharmony_ci char *hex = os_malloc(hex_len); 5078e5b75505Sopenharmony_ci 5079e5b75505Sopenharmony_ci if (hex) { 5080e5b75505Sopenharmony_ci wpa_snprintf_hex(hex, hex_len, buf, len); 5081e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_INFO, 5082e5b75505Sopenharmony_ci "MGMT-TX-STATUS stype=%u ok=%d buf=%s", 5083e5b75505Sopenharmony_ci stype, ok, hex); 5084e5b75505Sopenharmony_ci os_free(hex); 5085e5b75505Sopenharmony_ci } 5086e5b75505Sopenharmony_ci return; 5087e5b75505Sopenharmony_ci } 5088e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 5089e5b75505Sopenharmony_ci 5090e5b75505Sopenharmony_ci switch (stype) { 5091e5b75505Sopenharmony_ci case WLAN_FC_STYPE_AUTH: 5092e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::auth cb"); 5093e5b75505Sopenharmony_ci handle_auth_cb(hapd, mgmt, len, ok); 5094e5b75505Sopenharmony_ci break; 5095e5b75505Sopenharmony_ci case WLAN_FC_STYPE_ASSOC_RESP: 5096e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb"); 5097e5b75505Sopenharmony_ci handle_assoc_cb(hapd, mgmt, len, 0, ok); 5098e5b75505Sopenharmony_ci break; 5099e5b75505Sopenharmony_ci case WLAN_FC_STYPE_REASSOC_RESP: 5100e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb"); 5101e5b75505Sopenharmony_ci handle_assoc_cb(hapd, mgmt, len, 1, ok); 5102e5b75505Sopenharmony_ci break; 5103e5b75505Sopenharmony_ci case WLAN_FC_STYPE_PROBE_RESP: 5104e5b75505Sopenharmony_ci wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb ok=%d", ok); 5105e5b75505Sopenharmony_ci break; 5106e5b75505Sopenharmony_ci case WLAN_FC_STYPE_DEAUTH: 5107e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::deauth cb"); 5108e5b75505Sopenharmony_ci handle_deauth_cb(hapd, mgmt, len, ok); 5109e5b75505Sopenharmony_ci break; 5110e5b75505Sopenharmony_ci case WLAN_FC_STYPE_DISASSOC: 5111e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::disassoc cb"); 5112e5b75505Sopenharmony_ci handle_disassoc_cb(hapd, mgmt, len, ok); 5113e5b75505Sopenharmony_ci break; 5114e5b75505Sopenharmony_ci case WLAN_FC_STYPE_ACTION: 5115e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "mgmt::action cb ok=%d", ok); 5116e5b75505Sopenharmony_ci handle_action_cb(hapd, mgmt, len, ok); 5117e5b75505Sopenharmony_ci break; 5118e5b75505Sopenharmony_ci default: 5119e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "unknown mgmt cb frame subtype %d", stype); 5120e5b75505Sopenharmony_ci break; 5121e5b75505Sopenharmony_ci } 5122e5b75505Sopenharmony_ci} 5123e5b75505Sopenharmony_ci 5124e5b75505Sopenharmony_ci 5125e5b75505Sopenharmony_ciint ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 5126e5b75505Sopenharmony_ci{ 5127e5b75505Sopenharmony_ci /* TODO */ 5128e5b75505Sopenharmony_ci return 0; 5129e5b75505Sopenharmony_ci} 5130e5b75505Sopenharmony_ci 5131e5b75505Sopenharmony_ci 5132e5b75505Sopenharmony_ciint ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 5133e5b75505Sopenharmony_ci char *buf, size_t buflen) 5134e5b75505Sopenharmony_ci{ 5135e5b75505Sopenharmony_ci /* TODO */ 5136e5b75505Sopenharmony_ci return 0; 5137e5b75505Sopenharmony_ci} 5138e5b75505Sopenharmony_ci 5139e5b75505Sopenharmony_ci 5140e5b75505Sopenharmony_civoid hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, 5141e5b75505Sopenharmony_ci const u8 *buf, size_t len, int ack) 5142e5b75505Sopenharmony_ci{ 5143e5b75505Sopenharmony_ci struct sta_info *sta; 5144e5b75505Sopenharmony_ci struct hostapd_iface *iface = hapd->iface; 5145e5b75505Sopenharmony_ci 5146e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, addr); 5147e5b75505Sopenharmony_ci if (sta == NULL && iface->num_bss > 1) { 5148e5b75505Sopenharmony_ci size_t j; 5149e5b75505Sopenharmony_ci for (j = 0; j < iface->num_bss; j++) { 5150e5b75505Sopenharmony_ci hapd = iface->bss[j]; 5151e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, addr); 5152e5b75505Sopenharmony_ci if (sta) 5153e5b75505Sopenharmony_ci break; 5154e5b75505Sopenharmony_ci } 5155e5b75505Sopenharmony_ci } 5156e5b75505Sopenharmony_ci if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) 5157e5b75505Sopenharmony_ci return; 5158e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_PENDING_POLL) { 5159e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " 5160e5b75505Sopenharmony_ci "activity poll", MAC2STR(sta->addr), 5161e5b75505Sopenharmony_ci ack ? "ACKed" : "did not ACK"); 5162e5b75505Sopenharmony_ci if (ack) 5163e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_PENDING_POLL; 5164e5b75505Sopenharmony_ci } 5165e5b75505Sopenharmony_ci 5166e5b75505Sopenharmony_ci ieee802_1x_tx_status(hapd, sta, buf, len, ack); 5167e5b75505Sopenharmony_ci} 5168e5b75505Sopenharmony_ci 5169e5b75505Sopenharmony_ci 5170e5b75505Sopenharmony_civoid hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, 5171e5b75505Sopenharmony_ci const u8 *data, size_t len, int ack) 5172e5b75505Sopenharmony_ci{ 5173e5b75505Sopenharmony_ci struct sta_info *sta; 5174e5b75505Sopenharmony_ci struct hostapd_iface *iface = hapd->iface; 5175e5b75505Sopenharmony_ci 5176e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, dst); 5177e5b75505Sopenharmony_ci if (sta == NULL && iface->num_bss > 1) { 5178e5b75505Sopenharmony_ci size_t j; 5179e5b75505Sopenharmony_ci for (j = 0; j < iface->num_bss; j++) { 5180e5b75505Sopenharmony_ci hapd = iface->bss[j]; 5181e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, dst); 5182e5b75505Sopenharmony_ci if (sta) 5183e5b75505Sopenharmony_ci break; 5184e5b75505Sopenharmony_ci } 5185e5b75505Sopenharmony_ci } 5186e5b75505Sopenharmony_ci if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { 5187e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA " 5188e5b75505Sopenharmony_ci MACSTR " that is not currently associated", 5189e5b75505Sopenharmony_ci MAC2STR(dst)); 5190e5b75505Sopenharmony_ci return; 5191e5b75505Sopenharmony_ci } 5192e5b75505Sopenharmony_ci 5193e5b75505Sopenharmony_ci ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); 5194e5b75505Sopenharmony_ci} 5195e5b75505Sopenharmony_ci 5196e5b75505Sopenharmony_ci 5197e5b75505Sopenharmony_civoid hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr) 5198e5b75505Sopenharmony_ci{ 5199e5b75505Sopenharmony_ci struct sta_info *sta; 5200e5b75505Sopenharmony_ci struct hostapd_iface *iface = hapd->iface; 5201e5b75505Sopenharmony_ci 5202e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, addr); 5203e5b75505Sopenharmony_ci if (sta == NULL && iface->num_bss > 1) { 5204e5b75505Sopenharmony_ci size_t j; 5205e5b75505Sopenharmony_ci for (j = 0; j < iface->num_bss; j++) { 5206e5b75505Sopenharmony_ci hapd = iface->bss[j]; 5207e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, addr); 5208e5b75505Sopenharmony_ci if (sta) 5209e5b75505Sopenharmony_ci break; 5210e5b75505Sopenharmony_ci } 5211e5b75505Sopenharmony_ci } 5212e5b75505Sopenharmony_ci if (sta == NULL) 5213e5b75505Sopenharmony_ci return; 5214e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POLL_OK MACSTR, 5215e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 5216e5b75505Sopenharmony_ci if (!(sta->flags & WLAN_STA_PENDING_POLL)) 5217e5b75505Sopenharmony_ci return; 5218e5b75505Sopenharmony_ci 5219e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending " 5220e5b75505Sopenharmony_ci "activity poll", MAC2STR(sta->addr)); 5221e5b75505Sopenharmony_ci sta->flags &= ~WLAN_STA_PENDING_POLL; 5222e5b75505Sopenharmony_ci} 5223e5b75505Sopenharmony_ci 5224e5b75505Sopenharmony_ci 5225e5b75505Sopenharmony_civoid ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, 5226e5b75505Sopenharmony_ci int wds) 5227e5b75505Sopenharmony_ci{ 5228e5b75505Sopenharmony_ci struct sta_info *sta; 5229e5b75505Sopenharmony_ci 5230e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, src); 5231e5b75505Sopenharmony_ci if (sta && 5232e5b75505Sopenharmony_ci ((sta->flags & WLAN_STA_ASSOC) || 5233e5b75505Sopenharmony_ci ((sta->flags & WLAN_STA_ASSOC_REQ_OK) && wds))) { 5234e5b75505Sopenharmony_ci if (!hapd->conf->wds_sta) 5235e5b75505Sopenharmony_ci return; 5236e5b75505Sopenharmony_ci 5237e5b75505Sopenharmony_ci if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK)) == 5238e5b75505Sopenharmony_ci WLAN_STA_ASSOC_REQ_OK) { 5239e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 5240e5b75505Sopenharmony_ci "Postpone 4-address WDS mode enabling for STA " 5241e5b75505Sopenharmony_ci MACSTR " since TX status for AssocResp is not yet known", 5242e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 5243e5b75505Sopenharmony_ci sta->pending_wds_enable = 1; 5244e5b75505Sopenharmony_ci return; 5245e5b75505Sopenharmony_ci } 5246e5b75505Sopenharmony_ci 5247e5b75505Sopenharmony_ci if (wds && !(sta->flags & WLAN_STA_WDS)) { 5248e5b75505Sopenharmony_ci int ret; 5249e5b75505Sopenharmony_ci char ifname_wds[IFNAMSIZ + 1]; 5250e5b75505Sopenharmony_ci 5251e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " 5252e5b75505Sopenharmony_ci "STA " MACSTR " (aid %u)", 5253e5b75505Sopenharmony_ci MAC2STR(sta->addr), sta->aid); 5254e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_WDS; 5255e5b75505Sopenharmony_ci ret = hostapd_set_wds_sta(hapd, ifname_wds, 5256e5b75505Sopenharmony_ci sta->addr, sta->aid, 1); 5257e5b75505Sopenharmony_ci if (!ret) 5258e5b75505Sopenharmony_ci hostapd_set_wds_encryption(hapd, sta, 5259e5b75505Sopenharmony_ci ifname_wds); 5260e5b75505Sopenharmony_ci } 5261e5b75505Sopenharmony_ci return; 5262e5b75505Sopenharmony_ci } 5263e5b75505Sopenharmony_ci 5264e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " 5265e5b75505Sopenharmony_ci MACSTR, MAC2STR(src)); 5266e5b75505Sopenharmony_ci if (is_multicast_ether_addr(src)) { 5267e5b75505Sopenharmony_ci /* Broadcast bit set in SA?! Ignore the frame silently. */ 5268e5b75505Sopenharmony_ci return; 5269e5b75505Sopenharmony_ci } 5270e5b75505Sopenharmony_ci 5271e5b75505Sopenharmony_ci if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) { 5272e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Association Response to the STA has " 5273e5b75505Sopenharmony_ci "already been sent, but no TX status yet known - " 5274e5b75505Sopenharmony_ci "ignore Class 3 frame issue with " MACSTR, 5275e5b75505Sopenharmony_ci MAC2STR(src)); 5276e5b75505Sopenharmony_ci return; 5277e5b75505Sopenharmony_ci } 5278e5b75505Sopenharmony_ci 5279e5b75505Sopenharmony_ci if (sta && (sta->flags & WLAN_STA_AUTH)) 5280e5b75505Sopenharmony_ci hostapd_drv_sta_disassoc( 5281e5b75505Sopenharmony_ci hapd, src, 5282e5b75505Sopenharmony_ci WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); 5283e5b75505Sopenharmony_ci else 5284e5b75505Sopenharmony_ci hostapd_drv_sta_deauth( 5285e5b75505Sopenharmony_ci hapd, src, 5286e5b75505Sopenharmony_ci WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); 5287e5b75505Sopenharmony_ci} 5288e5b75505Sopenharmony_ci 5289e5b75505Sopenharmony_ci 5290e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */ 5291