1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * hostapd / Callback functions for driver wrappers 35b9c547cSRui Paulo * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "utils/includes.h" 10e28a4053SRui Paulo 11e28a4053SRui Paulo #include "utils/common.h" 125b9c547cSRui Paulo #include "utils/eloop.h" 13e28a4053SRui Paulo #include "radius/radius.h" 14e28a4053SRui Paulo #include "drivers/driver.h" 15e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 16e28a4053SRui Paulo #include "common/ieee802_11_common.h" 175b9c547cSRui Paulo #include "common/wpa_ctrl.h" 184bc52338SCy Schubert #include "common/dpp.h" 19f05cddf9SRui Paulo #include "crypto/random.h" 20f05cddf9SRui Paulo #include "p2p/p2p.h" 21f05cddf9SRui Paulo #include "wps/wps.h" 22325151a3SRui Paulo #include "fst/fst.h" 23f05cddf9SRui Paulo #include "wnm_ap.h" 24e28a4053SRui Paulo #include "hostapd.h" 25e28a4053SRui Paulo #include "ieee802_11.h" 26780fb4a2SCy Schubert #include "ieee802_11_auth.h" 27e28a4053SRui Paulo #include "sta_info.h" 28e28a4053SRui Paulo #include "accounting.h" 29e28a4053SRui Paulo #include "tkip_countermeasures.h" 30e28a4053SRui Paulo #include "ieee802_1x.h" 31e28a4053SRui Paulo #include "wpa_auth.h" 32e28a4053SRui Paulo #include "wps_hostapd.h" 33f05cddf9SRui Paulo #include "ap_drv_ops.h" 34e28a4053SRui Paulo #include "ap_config.h" 3585732ac8SCy Schubert #include "ap_mlme.h" 36f05cddf9SRui Paulo #include "hw_features.h" 375b9c547cSRui Paulo #include "dfs.h" 385b9c547cSRui Paulo #include "beacon.h" 39780fb4a2SCy Schubert #include "mbo_ap.h" 4085732ac8SCy Schubert #include "dpp_hostapd.h" 4185732ac8SCy Schubert #include "fils_hlp.h" 424bc52338SCy Schubert #include "neighbor_db.h" 4385732ac8SCy Schubert 4485732ac8SCy Schubert 4585732ac8SCy Schubert #ifdef CONFIG_FILS 4685732ac8SCy Schubert void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, 4785732ac8SCy Schubert struct sta_info *sta) 4885732ac8SCy Schubert { 4985732ac8SCy Schubert u16 reply_res = WLAN_STATUS_SUCCESS; 5085732ac8SCy Schubert struct ieee802_11_elems elems; 5185732ac8SCy Schubert u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf; 5285732ac8SCy Schubert int new_assoc; 5385732ac8SCy Schubert 5485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR, 5585732ac8SCy Schubert __func__, MAC2STR(sta->addr)); 5685732ac8SCy Schubert eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 5785732ac8SCy Schubert if (!sta->fils_pending_assoc_req) 5885732ac8SCy Schubert return; 5985732ac8SCy Schubert 6085732ac8SCy Schubert ieee802_11_parse_elems(sta->fils_pending_assoc_req, 6185732ac8SCy Schubert sta->fils_pending_assoc_req_len, &elems, 0); 6285732ac8SCy Schubert if (!elems.fils_session) { 6385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element", 6485732ac8SCy Schubert __func__); 6585732ac8SCy Schubert return; 6685732ac8SCy Schubert } 6785732ac8SCy Schubert 6885732ac8SCy Schubert p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, 6985732ac8SCy Schubert elems.fils_session, 7085732ac8SCy Schubert sta->fils_hlp_resp); 7185732ac8SCy Schubert 7285732ac8SCy Schubert reply_res = hostapd_sta_assoc(hapd, sta->addr, 7385732ac8SCy Schubert sta->fils_pending_assoc_is_reassoc, 7485732ac8SCy Schubert WLAN_STATUS_SUCCESS, 7585732ac8SCy Schubert buf, p - buf); 7685732ac8SCy Schubert ap_sta_set_authorized(hapd, sta, 1); 7785732ac8SCy Schubert new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 7885732ac8SCy Schubert sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 7985732ac8SCy Schubert sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 8085732ac8SCy Schubert hostapd_set_sta_flags(hapd, sta); 8185732ac8SCy Schubert wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); 8285732ac8SCy Schubert ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 8385732ac8SCy Schubert hostapd_new_assoc_sta(hapd, sta, !new_assoc); 8485732ac8SCy Schubert os_free(sta->fils_pending_assoc_req); 8585732ac8SCy Schubert sta->fils_pending_assoc_req = NULL; 8685732ac8SCy Schubert sta->fils_pending_assoc_req_len = 0; 8785732ac8SCy Schubert wpabuf_free(sta->fils_hlp_resp); 8885732ac8SCy Schubert sta->fils_hlp_resp = NULL; 8985732ac8SCy Schubert wpabuf_free(sta->hlp_dhcp_discover); 9085732ac8SCy Schubert sta->hlp_dhcp_discover = NULL; 9185732ac8SCy Schubert fils_hlp_deinit(hapd); 9285732ac8SCy Schubert 9385732ac8SCy Schubert /* 9485732ac8SCy Schubert * Remove the station in case transmission of a success response fails 9585732ac8SCy Schubert * (the STA was added associated to the driver) or if the station was 9685732ac8SCy Schubert * previously added unassociated. 9785732ac8SCy Schubert */ 9885732ac8SCy Schubert if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) { 9985732ac8SCy Schubert hostapd_drv_sta_remove(hapd, sta->addr); 10085732ac8SCy Schubert sta->added_unassoc = 0; 10185732ac8SCy Schubert } 10285732ac8SCy Schubert } 10385732ac8SCy Schubert #endif /* CONFIG_FILS */ 104e28a4053SRui Paulo 105e28a4053SRui Paulo 106e28a4053SRui Paulo int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, 107f05cddf9SRui Paulo const u8 *req_ies, size_t req_ies_len, int reassoc) 108e28a4053SRui Paulo { 109e28a4053SRui Paulo struct sta_info *sta; 110e28a4053SRui Paulo int new_assoc, res; 111e28a4053SRui Paulo struct ieee802_11_elems elems; 112f05cddf9SRui Paulo const u8 *ie; 113f05cddf9SRui Paulo size_t ielen; 11485732ac8SCy Schubert #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE) 115f05cddf9SRui Paulo u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; 116f05cddf9SRui Paulo u8 *p = buf; 11785732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */ 118f05cddf9SRui Paulo u16 reason = WLAN_REASON_UNSPECIFIED; 119f05cddf9SRui Paulo u16 status = WLAN_STATUS_SUCCESS; 1205b9c547cSRui Paulo const u8 *p2p_dev_addr = NULL; 121e28a4053SRui Paulo 122e28a4053SRui Paulo if (addr == NULL) { 123e28a4053SRui Paulo /* 124e28a4053SRui Paulo * This could potentially happen with unexpected event from the 125e28a4053SRui Paulo * driver wrapper. This was seen at least in one case where the 126e28a4053SRui Paulo * driver ended up being set to station mode while hostapd was 127e28a4053SRui Paulo * running, so better make sure we stop processing such an 128e28a4053SRui Paulo * event here. 129e28a4053SRui Paulo */ 130325151a3SRui Paulo wpa_printf(MSG_DEBUG, 131325151a3SRui Paulo "hostapd_notif_assoc: Skip event with no address"); 132e28a4053SRui Paulo return -1; 133e28a4053SRui Paulo } 134f05cddf9SRui Paulo random_add_randomness(addr, ETH_ALEN); 135e28a4053SRui Paulo 136e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 137e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "associated"); 138e28a4053SRui Paulo 139f05cddf9SRui Paulo ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); 140e28a4053SRui Paulo if (elems.wps_ie) { 141e28a4053SRui Paulo ie = elems.wps_ie - 2; 142e28a4053SRui Paulo ielen = elems.wps_ie_len + 2; 143e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); 144e28a4053SRui Paulo } else if (elems.rsn_ie) { 145e28a4053SRui Paulo ie = elems.rsn_ie - 2; 146e28a4053SRui Paulo ielen = elems.rsn_ie_len + 2; 147e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); 148e28a4053SRui Paulo } else if (elems.wpa_ie) { 149e28a4053SRui Paulo ie = elems.wpa_ie - 2; 150e28a4053SRui Paulo ielen = elems.wpa_ie_len + 2; 151e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); 1525b9c547cSRui Paulo #ifdef CONFIG_HS20 1535b9c547cSRui Paulo } else if (elems.osen) { 1545b9c547cSRui Paulo ie = elems.osen - 2; 1555b9c547cSRui Paulo ielen = elems.osen_len + 2; 1565b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq"); 1575b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 158e28a4053SRui Paulo } else { 159e28a4053SRui Paulo ie = NULL; 160e28a4053SRui Paulo ielen = 0; 161325151a3SRui Paulo wpa_printf(MSG_DEBUG, 162325151a3SRui Paulo "STA did not include WPS/RSN/WPA IE in (Re)AssocReq"); 163e28a4053SRui Paulo } 164e28a4053SRui Paulo 165e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 166e28a4053SRui Paulo if (sta) { 1675b9c547cSRui Paulo ap_sta_no_session_timeout(hapd, sta); 168e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 169f05cddf9SRui Paulo 170f05cddf9SRui Paulo /* 171f05cddf9SRui Paulo * Make sure that the previously registered inactivity timer 172f05cddf9SRui Paulo * will not remove the STA immediately. 173f05cddf9SRui Paulo */ 174f05cddf9SRui Paulo sta->timeout_next = STA_NULLFUNC; 175e28a4053SRui Paulo } else { 176e28a4053SRui Paulo sta = ap_sta_add(hapd, addr); 177f05cddf9SRui Paulo if (sta == NULL) { 178f05cddf9SRui Paulo hostapd_drv_sta_disassoc(hapd, addr, 179f05cddf9SRui Paulo WLAN_REASON_DISASSOC_AP_BUSY); 180e28a4053SRui Paulo return -1; 181e28a4053SRui Paulo } 182f05cddf9SRui Paulo } 183f05cddf9SRui Paulo sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 184f05cddf9SRui Paulo 185780fb4a2SCy Schubert /* 186780fb4a2SCy Schubert * ACL configurations to the drivers (implementing AP SME and ACL 187780fb4a2SCy Schubert * offload) without hostapd's knowledge, can result in a disconnection 188780fb4a2SCy Schubert * though the driver accepts the connection. Skip the hostapd check for 189780fb4a2SCy Schubert * ACL if the driver supports ACL offload to avoid potentially 190780fb4a2SCy Schubert * conflicting ACL rules. 191780fb4a2SCy Schubert */ 192780fb4a2SCy Schubert if (hapd->iface->drv_max_acl_mac_addrs == 0 && 193780fb4a2SCy Schubert hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) { 194780fb4a2SCy Schubert wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect", 195780fb4a2SCy Schubert MAC2STR(addr)); 196780fb4a2SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 197780fb4a2SCy Schubert goto fail; 198780fb4a2SCy Schubert } 199780fb4a2SCy Schubert 200f05cddf9SRui Paulo #ifdef CONFIG_P2P 201f05cddf9SRui Paulo if (elems.p2p) { 202f05cddf9SRui Paulo wpabuf_free(sta->p2p_ie); 203f05cddf9SRui Paulo sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 204f05cddf9SRui Paulo P2P_IE_VENDOR_TYPE); 2055b9c547cSRui Paulo if (sta->p2p_ie) 2065b9c547cSRui Paulo p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 207f05cddf9SRui Paulo } 208f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 209f05cddf9SRui Paulo 2105b9c547cSRui Paulo #ifdef CONFIG_IEEE80211N 2115b9c547cSRui Paulo #ifdef NEED_AP_MLME 2125b9c547cSRui Paulo if (elems.ht_capabilities && 2135b9c547cSRui Paulo (hapd->iface->conf->ht_capab & 2145b9c547cSRui Paulo HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 2155b9c547cSRui Paulo struct ieee80211_ht_capabilities *ht_cap = 2165b9c547cSRui Paulo (struct ieee80211_ht_capabilities *) 2175b9c547cSRui Paulo elems.ht_capabilities; 2185b9c547cSRui Paulo 2195b9c547cSRui Paulo if (le_to_host16(ht_cap->ht_capabilities_info) & 2205b9c547cSRui Paulo HT_CAP_INFO_40MHZ_INTOLERANT) 2215b9c547cSRui Paulo ht40_intolerant_add(hapd->iface, sta); 2225b9c547cSRui Paulo } 2235b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 2245b9c547cSRui Paulo #endif /* CONFIG_IEEE80211N */ 2255b9c547cSRui Paulo 2265b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING 2275b9c547cSRui Paulo if (elems.ext_capab && elems.ext_capab_len > 4) { 2285b9c547cSRui Paulo if (elems.ext_capab[4] & 0x01) 2295b9c547cSRui Paulo sta->qos_map_enabled = 1; 2305b9c547cSRui Paulo } 2315b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */ 2325b9c547cSRui Paulo 233f05cddf9SRui Paulo #ifdef CONFIG_HS20 234f05cddf9SRui Paulo wpabuf_free(sta->hs20_ie); 235f05cddf9SRui Paulo if (elems.hs20 && elems.hs20_len > 4) { 236f05cddf9SRui Paulo sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, 237f05cddf9SRui Paulo elems.hs20_len - 4); 238f05cddf9SRui Paulo } else 239f05cddf9SRui Paulo sta->hs20_ie = NULL; 24085732ac8SCy Schubert 24185732ac8SCy Schubert wpabuf_free(sta->roaming_consortium); 24285732ac8SCy Schubert if (elems.roaming_cons_sel) 24385732ac8SCy Schubert sta->roaming_consortium = wpabuf_alloc_copy( 24485732ac8SCy Schubert elems.roaming_cons_sel + 4, 24585732ac8SCy Schubert elems.roaming_cons_sel_len - 4); 24685732ac8SCy Schubert else 24785732ac8SCy Schubert sta->roaming_consortium = NULL; 248f05cddf9SRui Paulo #endif /* CONFIG_HS20 */ 249e28a4053SRui Paulo 250325151a3SRui Paulo #ifdef CONFIG_FST 251325151a3SRui Paulo wpabuf_free(sta->mb_ies); 252325151a3SRui Paulo if (hapd->iface->fst) 253325151a3SRui Paulo sta->mb_ies = mb_ies_by_info(&elems.mb_ies); 254325151a3SRui Paulo else 255325151a3SRui Paulo sta->mb_ies = NULL; 256325151a3SRui Paulo #endif /* CONFIG_FST */ 257325151a3SRui Paulo 258780fb4a2SCy Schubert mbo_ap_check_sta_assoc(hapd, sta, &elems); 259780fb4a2SCy Schubert 260780fb4a2SCy Schubert ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes, 261780fb4a2SCy Schubert elems.supp_op_classes_len); 262780fb4a2SCy Schubert 263e28a4053SRui Paulo if (hapd->conf->wpa) { 264e28a4053SRui Paulo if (ie == NULL || ielen == 0) { 265f05cddf9SRui Paulo #ifdef CONFIG_WPS 266e28a4053SRui Paulo if (hapd->conf->wps_state) { 267325151a3SRui Paulo wpa_printf(MSG_DEBUG, 268325151a3SRui Paulo "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use"); 269e28a4053SRui Paulo sta->flags |= WLAN_STA_MAYBE_WPS; 270e28a4053SRui Paulo goto skip_wpa_check; 271e28a4053SRui Paulo } 272f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 273e28a4053SRui Paulo 274e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); 27585732ac8SCy Schubert reason = WLAN_REASON_INVALID_IE; 27685732ac8SCy Schubert status = WLAN_STATUS_INVALID_IE; 27785732ac8SCy Schubert goto fail; 278e28a4053SRui Paulo } 279f05cddf9SRui Paulo #ifdef CONFIG_WPS 280e28a4053SRui Paulo if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && 281e28a4053SRui Paulo os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { 282f05cddf9SRui Paulo struct wpabuf *wps; 283325151a3SRui Paulo 284e28a4053SRui Paulo sta->flags |= WLAN_STA_WPS; 285f05cddf9SRui Paulo wps = ieee802_11_vendor_ie_concat(ie, ielen, 286f05cddf9SRui Paulo WPS_IE_VENDOR_TYPE); 287f05cddf9SRui Paulo if (wps) { 288f05cddf9SRui Paulo if (wps_is_20(wps)) { 289325151a3SRui Paulo wpa_printf(MSG_DEBUG, 290325151a3SRui Paulo "WPS: STA supports WPS 2.0"); 291f05cddf9SRui Paulo sta->flags |= WLAN_STA_WPS2; 292f05cddf9SRui Paulo } 293f05cddf9SRui Paulo wpabuf_free(wps); 294f05cddf9SRui Paulo } 295e28a4053SRui Paulo goto skip_wpa_check; 296e28a4053SRui Paulo } 297f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 298e28a4053SRui Paulo 299e28a4053SRui Paulo if (sta->wpa_sm == NULL) 300e28a4053SRui Paulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 3015b9c547cSRui Paulo sta->addr, 3025b9c547cSRui Paulo p2p_dev_addr); 303e28a4053SRui Paulo if (sta->wpa_sm == NULL) { 304325151a3SRui Paulo wpa_printf(MSG_ERROR, 305325151a3SRui Paulo "Failed to initialize WPA state machine"); 306e28a4053SRui Paulo return -1; 307e28a4053SRui Paulo } 308e28a4053SRui Paulo res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 3094bc52338SCy Schubert hapd->iface->freq, 310f05cddf9SRui Paulo ie, ielen, 31185732ac8SCy Schubert elems.mdie, elems.mdie_len, 31285732ac8SCy Schubert elems.owe_dh, elems.owe_dh_len); 313e28a4053SRui Paulo if (res != WPA_IE_OK) { 314325151a3SRui Paulo wpa_printf(MSG_DEBUG, 315325151a3SRui Paulo "WPA/RSN information element rejected? (res %u)", 316325151a3SRui Paulo res); 317e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); 318f05cddf9SRui Paulo if (res == WPA_INVALID_GROUP) { 319f05cddf9SRui Paulo reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; 320f05cddf9SRui Paulo status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 321f05cddf9SRui Paulo } else if (res == WPA_INVALID_PAIRWISE) { 322f05cddf9SRui Paulo reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; 323f05cddf9SRui Paulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 324f05cddf9SRui Paulo } else if (res == WPA_INVALID_AKMP) { 325f05cddf9SRui Paulo reason = WLAN_REASON_AKMP_NOT_VALID; 326f05cddf9SRui Paulo status = WLAN_STATUS_AKMP_NOT_VALID; 327e28a4053SRui Paulo } 328f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W 329f05cddf9SRui Paulo else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { 330f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 331f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_IE; 332f05cddf9SRui Paulo } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { 33385732ac8SCy Schubert reason = WLAN_REASON_CIPHER_SUITE_REJECTED; 33485732ac8SCy Schubert status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 335f05cddf9SRui Paulo } 336f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */ 337f05cddf9SRui Paulo else { 338f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 339f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_IE; 340f05cddf9SRui Paulo } 341f05cddf9SRui Paulo goto fail; 342f05cddf9SRui Paulo } 343f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W 34485732ac8SCy Schubert if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 34585732ac8SCy Schubert (WLAN_STA_ASSOC | WLAN_STA_MFP) && 34685732ac8SCy Schubert !sta->sa_query_timed_out && 347f05cddf9SRui Paulo sta->sa_query_count > 0) 348f05cddf9SRui Paulo ap_check_sa_query_timeout(hapd, sta); 34985732ac8SCy Schubert if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 35085732ac8SCy Schubert (WLAN_STA_ASSOC | WLAN_STA_MFP) && 35185732ac8SCy Schubert !sta->sa_query_timed_out && 352f05cddf9SRui Paulo (sta->auth_alg != WLAN_AUTH_FT)) { 353f05cddf9SRui Paulo /* 354f05cddf9SRui Paulo * STA has already been associated with MFP and SA 355f05cddf9SRui Paulo * Query timeout has not been reached. Reject the 356f05cddf9SRui Paulo * association attempt temporarily and start SA Query, 357f05cddf9SRui Paulo * if one is not pending. 358f05cddf9SRui Paulo */ 359f05cddf9SRui Paulo 360f05cddf9SRui Paulo if (sta->sa_query_count == 0) 361f05cddf9SRui Paulo ap_sta_start_sa_query(hapd, sta); 362f05cddf9SRui Paulo 363f05cddf9SRui Paulo status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 364f05cddf9SRui Paulo 365f05cddf9SRui Paulo p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 366f05cddf9SRui Paulo 367f05cddf9SRui Paulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, 368f05cddf9SRui Paulo p - buf); 369f05cddf9SRui Paulo return 0; 370f05cddf9SRui Paulo } 371f05cddf9SRui Paulo 372f05cddf9SRui Paulo if (wpa_auth_uses_mfp(sta->wpa_sm)) 373f05cddf9SRui Paulo sta->flags |= WLAN_STA_MFP; 374f05cddf9SRui Paulo else 375f05cddf9SRui Paulo sta->flags &= ~WLAN_STA_MFP; 376f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */ 377f05cddf9SRui Paulo 37885732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 379f05cddf9SRui Paulo if (sta->auth_alg == WLAN_AUTH_FT) { 380f05cddf9SRui Paulo status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, 381f05cddf9SRui Paulo req_ies_len); 382f05cddf9SRui Paulo if (status != WLAN_STATUS_SUCCESS) { 383f05cddf9SRui Paulo if (status == WLAN_STATUS_INVALID_PMKID) 384f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 385f05cddf9SRui Paulo if (status == WLAN_STATUS_INVALID_MDIE) 386f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 387f05cddf9SRui Paulo if (status == WLAN_STATUS_INVALID_FTIE) 388f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 389f05cddf9SRui Paulo goto fail; 390f05cddf9SRui Paulo } 391f05cddf9SRui Paulo } 39285732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 393e28a4053SRui Paulo } else if (hapd->conf->wps_state) { 394f05cddf9SRui Paulo #ifdef CONFIG_WPS 395f05cddf9SRui Paulo struct wpabuf *wps; 396325151a3SRui Paulo 397f05cddf9SRui Paulo if (req_ies) 398f05cddf9SRui Paulo wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 399f05cddf9SRui Paulo WPS_IE_VENDOR_TYPE); 400f05cddf9SRui Paulo else 401f05cddf9SRui Paulo wps = NULL; 402f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT 403f05cddf9SRui Paulo if (wps && wps_validate_assoc_req(wps) < 0) { 404f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 405f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_IE; 406f05cddf9SRui Paulo wpabuf_free(wps); 407f05cddf9SRui Paulo goto fail; 408f05cddf9SRui Paulo } 409f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */ 410f05cddf9SRui Paulo if (wps) { 411e28a4053SRui Paulo sta->flags |= WLAN_STA_WPS; 412f05cddf9SRui Paulo if (wps_is_20(wps)) { 413325151a3SRui Paulo wpa_printf(MSG_DEBUG, 414325151a3SRui Paulo "WPS: STA supports WPS 2.0"); 415f05cddf9SRui Paulo sta->flags |= WLAN_STA_WPS2; 416f05cddf9SRui Paulo } 417e28a4053SRui Paulo } else 418e28a4053SRui Paulo sta->flags |= WLAN_STA_MAYBE_WPS; 419f05cddf9SRui Paulo wpabuf_free(wps); 420f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 4215b9c547cSRui Paulo #ifdef CONFIG_HS20 4225b9c547cSRui Paulo } else if (hapd->conf->osen) { 4235b9c547cSRui Paulo if (elems.osen == NULL) { 4245b9c547cSRui Paulo hostapd_logger( 4255b9c547cSRui Paulo hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 4265b9c547cSRui Paulo HOSTAPD_LEVEL_INFO, 4275b9c547cSRui Paulo "No HS 2.0 OSEN element in association request"); 4285b9c547cSRui Paulo return WLAN_STATUS_INVALID_IE; 4295b9c547cSRui Paulo } 4305b9c547cSRui Paulo 4315b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); 4325b9c547cSRui Paulo if (sta->wpa_sm == NULL) 4335b9c547cSRui Paulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 4345b9c547cSRui Paulo sta->addr, NULL); 4355b9c547cSRui Paulo if (sta->wpa_sm == NULL) { 436325151a3SRui Paulo wpa_printf(MSG_WARNING, 437325151a3SRui Paulo "Failed to initialize WPA state machine"); 4385b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 4395b9c547cSRui Paulo } 4405b9c547cSRui Paulo if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, 4415b9c547cSRui Paulo elems.osen - 2, elems.osen_len + 2) < 0) 4425b9c547cSRui Paulo return WLAN_STATUS_INVALID_IE; 4435b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 444e28a4053SRui Paulo } 445780fb4a2SCy Schubert 446780fb4a2SCy Schubert #ifdef CONFIG_MBO 447780fb4a2SCy Schubert if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && 448780fb4a2SCy Schubert elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && 449780fb4a2SCy Schubert hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 450780fb4a2SCy Schubert wpa_printf(MSG_INFO, 451780fb4a2SCy Schubert "MBO: Reject WPA2 association without PMF"); 452780fb4a2SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 453780fb4a2SCy Schubert } 454780fb4a2SCy Schubert #endif /* CONFIG_MBO */ 455780fb4a2SCy Schubert 456f05cddf9SRui Paulo #ifdef CONFIG_WPS 457e28a4053SRui Paulo skip_wpa_check: 458f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 459f05cddf9SRui Paulo 46085732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 461f05cddf9SRui Paulo p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), 462f05cddf9SRui Paulo sta->auth_alg, req_ies, req_ies_len); 46385732ac8SCy Schubert if (!p) { 46485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs"); 46585732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 46685732ac8SCy Schubert } 46785732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 468f05cddf9SRui Paulo 46985732ac8SCy Schubert #ifdef CONFIG_FILS 47085732ac8SCy Schubert if (sta->auth_alg == WLAN_AUTH_FILS_SK || 47185732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 47285732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) { 47385732ac8SCy Schubert int delay_assoc = 0; 47485732ac8SCy Schubert 47585732ac8SCy Schubert if (!req_ies) 47685732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 47785732ac8SCy Schubert 47885732ac8SCy Schubert if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies, 47985732ac8SCy Schubert req_ies_len, 48085732ac8SCy Schubert sta->fils_session)) { 48185732ac8SCy Schubert wpa_printf(MSG_DEBUG, 48285732ac8SCy Schubert "FILS: Session validation failed"); 48385732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 48485732ac8SCy Schubert } 48585732ac8SCy Schubert 48685732ac8SCy Schubert res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies, 48785732ac8SCy Schubert req_ies_len); 48885732ac8SCy Schubert if (res < 0) { 48985732ac8SCy Schubert wpa_printf(MSG_DEBUG, 49085732ac8SCy Schubert "FILS: Key Confirm validation failed"); 49185732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 49285732ac8SCy Schubert } 49385732ac8SCy Schubert 49485732ac8SCy Schubert if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) { 49585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 49685732ac8SCy Schubert "FILS: Delaying Assoc Response (HLP)"); 49785732ac8SCy Schubert delay_assoc = 1; 49885732ac8SCy Schubert } else { 49985732ac8SCy Schubert wpa_printf(MSG_DEBUG, 50085732ac8SCy Schubert "FILS: Going ahead with Assoc Response (no HLP)"); 50185732ac8SCy Schubert } 50285732ac8SCy Schubert 50385732ac8SCy Schubert if (sta) { 50485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup"); 50585732ac8SCy Schubert eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 50685732ac8SCy Schubert os_free(sta->fils_pending_assoc_req); 50785732ac8SCy Schubert sta->fils_pending_assoc_req = NULL; 50885732ac8SCy Schubert sta->fils_pending_assoc_req_len = 0; 50985732ac8SCy Schubert wpabuf_free(sta->fils_hlp_resp); 51085732ac8SCy Schubert sta->fils_hlp_resp = NULL; 51185732ac8SCy Schubert sta->fils_drv_assoc_finish = 0; 51285732ac8SCy Schubert } 51385732ac8SCy Schubert 51485732ac8SCy Schubert if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) { 51585732ac8SCy Schubert u8 *req_tmp; 51685732ac8SCy Schubert 51785732ac8SCy Schubert req_tmp = os_malloc(req_ies_len); 51885732ac8SCy Schubert if (!req_tmp) { 51985732ac8SCy Schubert wpa_printf(MSG_DEBUG, 52085732ac8SCy Schubert "FILS: buffer allocation failed for assoc req"); 52185732ac8SCy Schubert goto fail; 52285732ac8SCy Schubert } 52385732ac8SCy Schubert os_memcpy(req_tmp, req_ies, req_ies_len); 52485732ac8SCy Schubert sta->fils_pending_assoc_req = req_tmp; 52585732ac8SCy Schubert sta->fils_pending_assoc_req_len = req_ies_len; 52685732ac8SCy Schubert sta->fils_pending_assoc_is_reassoc = reassoc; 52785732ac8SCy Schubert sta->fils_drv_assoc_finish = 1; 52885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 52985732ac8SCy Schubert "FILS: Waiting for HLP processing before sending (Re)Association Response frame to " 53085732ac8SCy Schubert MACSTR, MAC2STR(sta->addr)); 53185732ac8SCy Schubert eloop_register_timeout( 53285732ac8SCy Schubert 0, hapd->conf->fils_hlp_wait_time * 1024, 53385732ac8SCy Schubert fils_hlp_timeout, hapd, sta); 53485732ac8SCy Schubert return 0; 53585732ac8SCy Schubert } 53685732ac8SCy Schubert p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, 53785732ac8SCy Schubert elems.fils_session, 53885732ac8SCy Schubert sta->fils_hlp_resp); 53985732ac8SCy Schubert wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)", 54085732ac8SCy Schubert buf, p - buf); 54185732ac8SCy Schubert } 54285732ac8SCy Schubert #endif /* CONFIG_FILS */ 54385732ac8SCy Schubert 54485732ac8SCy Schubert #ifdef CONFIG_OWE 54585732ac8SCy Schubert if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 54685732ac8SCy Schubert wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && 54785732ac8SCy Schubert elems.owe_dh) { 54885732ac8SCy Schubert u8 *npos; 54985732ac8SCy Schubert 55085732ac8SCy Schubert npos = owe_assoc_req_process(hapd, sta, 55185732ac8SCy Schubert elems.owe_dh, elems.owe_dh_len, 55285732ac8SCy Schubert p, sizeof(buf) - (p - buf), 55385732ac8SCy Schubert &reason); 55485732ac8SCy Schubert if (npos) 55585732ac8SCy Schubert p = npos; 55685732ac8SCy Schubert if (!npos && 55785732ac8SCy Schubert reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { 55885732ac8SCy Schubert status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 55985732ac8SCy Schubert hostapd_sta_assoc(hapd, addr, reassoc, status, buf, 56085732ac8SCy Schubert p - buf); 56185732ac8SCy Schubert return 0; 56285732ac8SCy Schubert } 56385732ac8SCy Schubert 56485732ac8SCy Schubert if (!npos || reason != WLAN_STATUS_SUCCESS) 56585732ac8SCy Schubert goto fail; 56685732ac8SCy Schubert } 56785732ac8SCy Schubert #endif /* CONFIG_OWE */ 56885732ac8SCy Schubert 5694bc52338SCy Schubert #ifdef CONFIG_DPP2 5704bc52338SCy Schubert dpp_pfs_free(sta->dpp_pfs); 5714bc52338SCy Schubert sta->dpp_pfs = NULL; 5724bc52338SCy Schubert 5734bc52338SCy Schubert if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && 5744bc52338SCy Schubert hapd->conf->dpp_netaccesskey && sta->wpa_sm && 5754bc52338SCy Schubert wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && 5764bc52338SCy Schubert elems.owe_dh) { 5774bc52338SCy Schubert sta->dpp_pfs = dpp_pfs_init( 5784bc52338SCy Schubert wpabuf_head(hapd->conf->dpp_netaccesskey), 5794bc52338SCy Schubert wpabuf_len(hapd->conf->dpp_netaccesskey)); 5804bc52338SCy Schubert if (!sta->dpp_pfs) { 5814bc52338SCy Schubert wpa_printf(MSG_DEBUG, 5824bc52338SCy Schubert "DPP: Could not initialize PFS"); 5834bc52338SCy Schubert /* Try to continue without PFS */ 5844bc52338SCy Schubert goto pfs_fail; 5854bc52338SCy Schubert } 5864bc52338SCy Schubert 5874bc52338SCy Schubert if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, 5884bc52338SCy Schubert elems.owe_dh_len) < 0) { 5894bc52338SCy Schubert dpp_pfs_free(sta->dpp_pfs); 5904bc52338SCy Schubert sta->dpp_pfs = NULL; 5914bc52338SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 5924bc52338SCy Schubert goto fail; 5934bc52338SCy Schubert } 5944bc52338SCy Schubert } 5954bc52338SCy Schubert 5964bc52338SCy Schubert wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? 5974bc52338SCy Schubert sta->dpp_pfs->secret : NULL); 5984bc52338SCy Schubert pfs_fail: 5994bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 6004bc52338SCy Schubert 60185732ac8SCy Schubert #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE) 602f05cddf9SRui Paulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 6035b9c547cSRui Paulo 60485732ac8SCy Schubert if (sta->auth_alg == WLAN_AUTH_FT || 60585732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK || 60685732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 60785732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) 6085b9c547cSRui Paulo ap_sta_set_authorized(hapd, sta, 1); 60985732ac8SCy Schubert #else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ 610f05cddf9SRui Paulo /* Keep compiler silent about unused variables */ 611f05cddf9SRui Paulo if (status) { 612f05cddf9SRui Paulo } 61385732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ 614e28a4053SRui Paulo 615e28a4053SRui Paulo new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 616e28a4053SRui Paulo sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 6175b9c547cSRui Paulo sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 6185b9c547cSRui Paulo 6195b9c547cSRui Paulo hostapd_set_sta_flags(hapd, sta); 620f05cddf9SRui Paulo 621f05cddf9SRui Paulo if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) 622f05cddf9SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 62385732ac8SCy Schubert #ifdef CONFIG_FILS 62485732ac8SCy Schubert else if (sta->auth_alg == WLAN_AUTH_FILS_SK || 62585732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 62685732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) 62785732ac8SCy Schubert wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); 62885732ac8SCy Schubert #endif /* CONFIG_FILS */ 629f05cddf9SRui Paulo else 630e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 631e28a4053SRui Paulo 632e28a4053SRui Paulo hostapd_new_assoc_sta(hapd, sta, !new_assoc); 633e28a4053SRui Paulo 634e28a4053SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 635e28a4053SRui Paulo 636f05cddf9SRui Paulo #ifdef CONFIG_P2P 637f05cddf9SRui Paulo if (req_ies) { 638f05cddf9SRui Paulo p2p_group_notif_assoc(hapd->p2p_group, sta->addr, 639f05cddf9SRui Paulo req_ies, req_ies_len); 640f05cddf9SRui Paulo } 641f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 642f05cddf9SRui Paulo 643e28a4053SRui Paulo return 0; 644f05cddf9SRui Paulo 645f05cddf9SRui Paulo fail: 64685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 647f05cddf9SRui Paulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 64885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 649f05cddf9SRui Paulo hostapd_drv_sta_disassoc(hapd, sta->addr, reason); 650f05cddf9SRui Paulo ap_free_sta(hapd, sta); 651f05cddf9SRui Paulo return -1; 652e28a4053SRui Paulo } 653e28a4053SRui Paulo 654e28a4053SRui Paulo 655e28a4053SRui Paulo void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) 656e28a4053SRui Paulo { 657e28a4053SRui Paulo struct sta_info *sta; 658e28a4053SRui Paulo 659f05cddf9SRui Paulo if (addr == NULL) { 660f05cddf9SRui Paulo /* 661f05cddf9SRui Paulo * This could potentially happen with unexpected event from the 662f05cddf9SRui Paulo * driver wrapper. This was seen at least in one case where the 663f05cddf9SRui Paulo * driver ended up reporting a station mode event while hostapd 664f05cddf9SRui Paulo * was running, so better make sure we stop processing such an 665f05cddf9SRui Paulo * event here. 666f05cddf9SRui Paulo */ 667325151a3SRui Paulo wpa_printf(MSG_DEBUG, 668325151a3SRui Paulo "hostapd_notif_disassoc: Skip event with no address"); 669f05cddf9SRui Paulo return; 670f05cddf9SRui Paulo } 671f05cddf9SRui Paulo 672e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 673e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "disassociated"); 674e28a4053SRui Paulo 675e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 676e28a4053SRui Paulo if (sta == NULL) { 677325151a3SRui Paulo wpa_printf(MSG_DEBUG, 678325151a3SRui Paulo "Disassociation notification for unknown STA " 679325151a3SRui Paulo MACSTR, MAC2STR(addr)); 680e28a4053SRui Paulo return; 681e28a4053SRui Paulo } 682e28a4053SRui Paulo 683f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 684e28a4053SRui Paulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 685e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 686e28a4053SRui Paulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 687e28a4053SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 688e28a4053SRui Paulo ap_free_sta(hapd, sta); 689e28a4053SRui Paulo } 690e28a4053SRui Paulo 691e28a4053SRui Paulo 692f05cddf9SRui Paulo void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) 693f05cddf9SRui Paulo { 694f05cddf9SRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 695f05cddf9SRui Paulo 69685732ac8SCy Schubert if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer) 697f05cddf9SRui Paulo return; 698f05cddf9SRui Paulo 699f05cddf9SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 700325151a3SRui Paulo HOSTAPD_LEVEL_INFO, 701325151a3SRui Paulo "disconnected due to excessive missing ACKs"); 702f05cddf9SRui Paulo hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); 703f05cddf9SRui Paulo ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); 704f05cddf9SRui Paulo } 705f05cddf9SRui Paulo 706f05cddf9SRui Paulo 70785732ac8SCy Schubert void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, 70885732ac8SCy Schubert enum smps_mode smps_mode, 70985732ac8SCy Schubert enum chan_width chan_width, u8 rx_nss) 71085732ac8SCy Schubert { 71185732ac8SCy Schubert struct sta_info *sta = ap_get_sta(hapd, addr); 71285732ac8SCy Schubert const char *txt; 71385732ac8SCy Schubert 71485732ac8SCy Schubert if (!sta) 71585732ac8SCy Schubert return; 71685732ac8SCy Schubert 71785732ac8SCy Schubert switch (smps_mode) { 71885732ac8SCy Schubert case SMPS_AUTOMATIC: 71985732ac8SCy Schubert txt = "automatic"; 72085732ac8SCy Schubert break; 72185732ac8SCy Schubert case SMPS_OFF: 72285732ac8SCy Schubert txt = "off"; 72385732ac8SCy Schubert break; 72485732ac8SCy Schubert case SMPS_DYNAMIC: 72585732ac8SCy Schubert txt = "dynamic"; 72685732ac8SCy Schubert break; 72785732ac8SCy Schubert case SMPS_STATIC: 72885732ac8SCy Schubert txt = "static"; 72985732ac8SCy Schubert break; 73085732ac8SCy Schubert default: 73185732ac8SCy Schubert txt = NULL; 73285732ac8SCy Schubert break; 73385732ac8SCy Schubert } 73485732ac8SCy Schubert if (txt) { 73585732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED 73685732ac8SCy Schubert MACSTR " %s", MAC2STR(addr), txt); 73785732ac8SCy Schubert } 73885732ac8SCy Schubert 73985732ac8SCy Schubert switch (chan_width) { 74085732ac8SCy Schubert case CHAN_WIDTH_20_NOHT: 74185732ac8SCy Schubert txt = "20(no-HT)"; 74285732ac8SCy Schubert break; 74385732ac8SCy Schubert case CHAN_WIDTH_20: 74485732ac8SCy Schubert txt = "20"; 74585732ac8SCy Schubert break; 74685732ac8SCy Schubert case CHAN_WIDTH_40: 74785732ac8SCy Schubert txt = "40"; 74885732ac8SCy Schubert break; 74985732ac8SCy Schubert case CHAN_WIDTH_80: 75085732ac8SCy Schubert txt = "80"; 75185732ac8SCy Schubert break; 75285732ac8SCy Schubert case CHAN_WIDTH_80P80: 75385732ac8SCy Schubert txt = "80+80"; 75485732ac8SCy Schubert break; 75585732ac8SCy Schubert case CHAN_WIDTH_160: 75685732ac8SCy Schubert txt = "160"; 75785732ac8SCy Schubert break; 75885732ac8SCy Schubert default: 75985732ac8SCy Schubert txt = NULL; 76085732ac8SCy Schubert break; 76185732ac8SCy Schubert } 76285732ac8SCy Schubert if (txt) { 76385732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED 76485732ac8SCy Schubert MACSTR " %s", MAC2STR(addr), txt); 76585732ac8SCy Schubert } 76685732ac8SCy Schubert 76785732ac8SCy Schubert if (rx_nss != 0xff) { 76885732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED 76985732ac8SCy Schubert MACSTR " %d", MAC2STR(addr), rx_nss); 77085732ac8SCy Schubert } 77185732ac8SCy Schubert } 77285732ac8SCy Schubert 77385732ac8SCy Schubert 774f05cddf9SRui Paulo void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, 775*206b73d0SCy Schubert int offset, int width, int cf1, int cf2, 776*206b73d0SCy Schubert int finished) 777f05cddf9SRui Paulo { 7784bc52338SCy Schubert /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */ 7794bc52338SCy Schubert 780f05cddf9SRui Paulo #ifdef NEED_AP_MLME 781780fb4a2SCy Schubert int channel, chwidth, is_dfs; 782780fb4a2SCy Schubert u8 seg0_idx = 0, seg1_idx = 0; 7834bc52338SCy Schubert size_t i; 784f05cddf9SRui Paulo 785f05cddf9SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 7865b9c547cSRui Paulo HOSTAPD_LEVEL_INFO, 787*206b73d0SCy Schubert "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", 788*206b73d0SCy Schubert finished ? "had" : "starting", 78985732ac8SCy Schubert freq, ht, hapd->iconf->ch_switch_vht_config, offset, 79085732ac8SCy Schubert width, channel_width_to_string(width), cf1, cf2); 791f05cddf9SRui Paulo 792*206b73d0SCy Schubert if (!hapd->iface->current_mode) { 793*206b73d0SCy Schubert hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 794*206b73d0SCy Schubert HOSTAPD_LEVEL_WARNING, 795*206b73d0SCy Schubert "ignore channel switch since the interface is not yet ready"); 796*206b73d0SCy Schubert return; 797*206b73d0SCy Schubert } 798*206b73d0SCy Schubert 799f05cddf9SRui Paulo hapd->iface->freq = freq; 800f05cddf9SRui Paulo 801f05cddf9SRui Paulo channel = hostapd_hw_get_channel(hapd, freq); 802f05cddf9SRui Paulo if (!channel) { 803f05cddf9SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 804325151a3SRui Paulo HOSTAPD_LEVEL_WARNING, 805325151a3SRui Paulo "driver switched to bad channel!"); 806f05cddf9SRui Paulo return; 807f05cddf9SRui Paulo } 808f05cddf9SRui Paulo 8095b9c547cSRui Paulo switch (width) { 8105b9c547cSRui Paulo case CHAN_WIDTH_80: 811*206b73d0SCy Schubert chwidth = CHANWIDTH_80MHZ; 8125b9c547cSRui Paulo break; 8135b9c547cSRui Paulo case CHAN_WIDTH_80P80: 814*206b73d0SCy Schubert chwidth = CHANWIDTH_80P80MHZ; 8155b9c547cSRui Paulo break; 8165b9c547cSRui Paulo case CHAN_WIDTH_160: 817*206b73d0SCy Schubert chwidth = CHANWIDTH_160MHZ; 8185b9c547cSRui Paulo break; 8195b9c547cSRui Paulo case CHAN_WIDTH_20_NOHT: 8205b9c547cSRui Paulo case CHAN_WIDTH_20: 8215b9c547cSRui Paulo case CHAN_WIDTH_40: 8225b9c547cSRui Paulo default: 823*206b73d0SCy Schubert chwidth = CHANWIDTH_USE_HT; 8245b9c547cSRui Paulo break; 8255b9c547cSRui Paulo } 8265b9c547cSRui Paulo 8275b9c547cSRui Paulo switch (hapd->iface->current_mode->mode) { 8285b9c547cSRui Paulo case HOSTAPD_MODE_IEEE80211A: 8295b9c547cSRui Paulo if (cf1 > 5000) 8305b9c547cSRui Paulo seg0_idx = (cf1 - 5000) / 5; 8315b9c547cSRui Paulo if (cf2 > 5000) 8325b9c547cSRui Paulo seg1_idx = (cf2 - 5000) / 5; 8335b9c547cSRui Paulo break; 8345b9c547cSRui Paulo default: 835780fb4a2SCy Schubert ieee80211_freq_to_chan(cf1, &seg0_idx); 836780fb4a2SCy Schubert ieee80211_freq_to_chan(cf2, &seg1_idx); 8375b9c547cSRui Paulo break; 8385b9c547cSRui Paulo } 8395b9c547cSRui Paulo 840f05cddf9SRui Paulo hapd->iconf->channel = channel; 841f05cddf9SRui Paulo hapd->iconf->ieee80211n = ht; 84285732ac8SCy Schubert if (!ht) { 8435b9c547cSRui Paulo hapd->iconf->ieee80211ac = 0; 84485732ac8SCy Schubert } else if (hapd->iconf->ch_switch_vht_config) { 84585732ac8SCy Schubert /* CHAN_SWITCH VHT config */ 84685732ac8SCy Schubert if (hapd->iconf->ch_switch_vht_config & 84785732ac8SCy Schubert CH_SWITCH_VHT_ENABLED) 84885732ac8SCy Schubert hapd->iconf->ieee80211ac = 1; 84985732ac8SCy Schubert else if (hapd->iconf->ch_switch_vht_config & 85085732ac8SCy Schubert CH_SWITCH_VHT_DISABLED) 85185732ac8SCy Schubert hapd->iconf->ieee80211ac = 0; 85285732ac8SCy Schubert } 85385732ac8SCy Schubert hapd->iconf->ch_switch_vht_config = 0; 85485732ac8SCy Schubert 855f05cddf9SRui Paulo hapd->iconf->secondary_channel = offset; 856*206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, chwidth); 857*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx); 858*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx); 8595b9c547cSRui Paulo 86085732ac8SCy Schubert is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features, 86185732ac8SCy Schubert hapd->iface->num_hw_features); 8625b9c547cSRui Paulo 863*206b73d0SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, 864*206b73d0SCy Schubert "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d", 865*206b73d0SCy Schubert finished ? WPA_EVENT_CHANNEL_SWITCH : 866*206b73d0SCy Schubert WPA_EVENT_CHANNEL_SWITCH_STARTED, 867*206b73d0SCy Schubert freq, ht, offset, channel_width_to_string(width), 868*206b73d0SCy Schubert cf1, cf2, is_dfs); 869*206b73d0SCy Schubert if (!finished) 870*206b73d0SCy Schubert return; 871*206b73d0SCy Schubert 8725b9c547cSRui Paulo if (hapd->csa_in_progress && 8735b9c547cSRui Paulo freq == hapd->cs_freq_params.freq) { 8745b9c547cSRui Paulo hostapd_cleanup_cs_params(hapd); 8755b9c547cSRui Paulo ieee802_11_set_beacon(hapd); 8765b9c547cSRui Paulo 8775b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 8785b9c547cSRui Paulo "freq=%d dfs=%d", freq, is_dfs); 8795b9c547cSRui Paulo } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { 8805b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 8815b9c547cSRui Paulo "freq=%d dfs=%d", freq, is_dfs); 8825b9c547cSRui Paulo } 8834bc52338SCy Schubert 8844bc52338SCy Schubert for (i = 0; i < hapd->iface->num_bss; i++) 8854bc52338SCy Schubert hostapd_neighbor_set_own_report(hapd->iface->bss[i]); 886f05cddf9SRui Paulo #endif /* NEED_AP_MLME */ 887f05cddf9SRui Paulo } 888f05cddf9SRui Paulo 889f05cddf9SRui Paulo 8905b9c547cSRui Paulo void hostapd_event_connect_failed_reason(struct hostapd_data *hapd, 8915b9c547cSRui Paulo const u8 *addr, int reason_code) 8925b9c547cSRui Paulo { 8935b9c547cSRui Paulo switch (reason_code) { 8945b9c547cSRui Paulo case MAX_CLIENT_REACHED: 8955b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR, 8965b9c547cSRui Paulo MAC2STR(addr)); 8975b9c547cSRui Paulo break; 8985b9c547cSRui Paulo case BLOCKED_CLIENT: 8995b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR, 9005b9c547cSRui Paulo MAC2STR(addr)); 9015b9c547cSRui Paulo break; 9025b9c547cSRui Paulo } 9035b9c547cSRui Paulo } 9045b9c547cSRui Paulo 9055b9c547cSRui Paulo 9065b9c547cSRui Paulo #ifdef CONFIG_ACS 907780fb4a2SCy Schubert void hostapd_acs_channel_selected(struct hostapd_data *hapd, 908325151a3SRui Paulo struct acs_selected_channels *acs_res) 9095b9c547cSRui Paulo { 910325151a3SRui Paulo int ret, i; 911780fb4a2SCy Schubert int err = 0; 9125b9c547cSRui Paulo 9135b9c547cSRui Paulo if (hapd->iconf->channel) { 9145b9c547cSRui Paulo wpa_printf(MSG_INFO, "ACS: Channel was already set to %d", 9155b9c547cSRui Paulo hapd->iconf->channel); 9165b9c547cSRui Paulo return; 9175b9c547cSRui Paulo } 9185b9c547cSRui Paulo 919325151a3SRui Paulo if (!hapd->iface->current_mode) { 920325151a3SRui Paulo for (i = 0; i < hapd->iface->num_hw_features; i++) { 921325151a3SRui Paulo struct hostapd_hw_modes *mode = 922325151a3SRui Paulo &hapd->iface->hw_features[i]; 9235b9c547cSRui Paulo 924325151a3SRui Paulo if (mode->mode == acs_res->hw_mode) { 925325151a3SRui Paulo hapd->iface->current_mode = mode; 926325151a3SRui Paulo break; 927325151a3SRui Paulo } 928325151a3SRui Paulo } 929325151a3SRui Paulo if (!hapd->iface->current_mode) { 930325151a3SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 931325151a3SRui Paulo HOSTAPD_LEVEL_WARNING, 932325151a3SRui Paulo "driver selected to bad hw_mode"); 933780fb4a2SCy Schubert err = 1; 934780fb4a2SCy Schubert goto out; 935325151a3SRui Paulo } 936325151a3SRui Paulo } 937325151a3SRui Paulo 938325151a3SRui Paulo hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel); 939325151a3SRui Paulo 940325151a3SRui Paulo if (!acs_res->pri_channel) { 9415b9c547cSRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 9425b9c547cSRui Paulo HOSTAPD_LEVEL_WARNING, 9435b9c547cSRui Paulo "driver switched to bad channel"); 944780fb4a2SCy Schubert err = 1; 945780fb4a2SCy Schubert goto out; 9465b9c547cSRui Paulo } 9475b9c547cSRui Paulo 948325151a3SRui Paulo hapd->iconf->channel = acs_res->pri_channel; 949325151a3SRui Paulo hapd->iconf->acs = 1; 9505b9c547cSRui Paulo 951325151a3SRui Paulo if (acs_res->sec_channel == 0) 9525b9c547cSRui Paulo hapd->iconf->secondary_channel = 0; 953325151a3SRui Paulo else if (acs_res->sec_channel < acs_res->pri_channel) 9545b9c547cSRui Paulo hapd->iconf->secondary_channel = -1; 955325151a3SRui Paulo else if (acs_res->sec_channel > acs_res->pri_channel) 9565b9c547cSRui Paulo hapd->iconf->secondary_channel = 1; 9575b9c547cSRui Paulo else { 9585b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Invalid secondary channel!"); 959780fb4a2SCy Schubert err = 1; 960780fb4a2SCy Schubert goto out; 9615b9c547cSRui Paulo } 9625b9c547cSRui Paulo 963*206b73d0SCy Schubert if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) { 964325151a3SRui Paulo /* set defaults for backwards compatibility */ 965*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); 966*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0); 967*206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT); 968325151a3SRui Paulo if (acs_res->ch_width == 80) { 969*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx( 970*206b73d0SCy Schubert hapd->iconf, acs_res->vht_seg0_center_ch); 971*206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ); 972325151a3SRui Paulo } else if (acs_res->ch_width == 160) { 973325151a3SRui Paulo if (acs_res->vht_seg1_center_ch == 0) { 974*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx( 975*206b73d0SCy Schubert hapd->iconf, 976*206b73d0SCy Schubert acs_res->vht_seg0_center_ch); 977*206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, 978*206b73d0SCy Schubert CHANWIDTH_160MHZ); 979325151a3SRui Paulo } else { 980*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx( 981*206b73d0SCy Schubert hapd->iconf, 982*206b73d0SCy Schubert acs_res->vht_seg0_center_ch); 983*206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg1_idx( 984*206b73d0SCy Schubert hapd->iconf, 985*206b73d0SCy Schubert acs_res->vht_seg1_center_ch); 986*206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, 987*206b73d0SCy Schubert CHANWIDTH_80P80MHZ); 988325151a3SRui Paulo } 989325151a3SRui Paulo } 990325151a3SRui Paulo } 991325151a3SRui Paulo 992780fb4a2SCy Schubert out: 993780fb4a2SCy Schubert ret = hostapd_acs_completed(hapd->iface, err); 9945b9c547cSRui Paulo if (ret) { 9955b9c547cSRui Paulo wpa_printf(MSG_ERROR, 9965b9c547cSRui Paulo "ACS: Possibly channel configuration is invalid"); 9975b9c547cSRui Paulo } 9985b9c547cSRui Paulo } 9995b9c547cSRui Paulo #endif /* CONFIG_ACS */ 10005b9c547cSRui Paulo 10015b9c547cSRui Paulo 1002f05cddf9SRui Paulo int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, 1003f05cddf9SRui Paulo const u8 *bssid, const u8 *ie, size_t ie_len, 1004f05cddf9SRui Paulo int ssi_signal) 1005f05cddf9SRui Paulo { 1006f05cddf9SRui Paulo size_t i; 1007f05cddf9SRui Paulo int ret = 0; 1008f05cddf9SRui Paulo 1009f05cddf9SRui Paulo if (sa == NULL || ie == NULL) 1010f05cddf9SRui Paulo return -1; 1011f05cddf9SRui Paulo 1012f05cddf9SRui Paulo random_add_randomness(sa, ETH_ALEN); 1013f05cddf9SRui Paulo for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { 1014f05cddf9SRui Paulo if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 1015f05cddf9SRui Paulo sa, da, bssid, ie, ie_len, 1016f05cddf9SRui Paulo ssi_signal) > 0) { 1017f05cddf9SRui Paulo ret = 1; 1018f05cddf9SRui Paulo break; 1019f05cddf9SRui Paulo } 1020f05cddf9SRui Paulo } 1021f05cddf9SRui Paulo return ret; 1022f05cddf9SRui Paulo } 1023f05cddf9SRui Paulo 1024f05cddf9SRui Paulo 1025e28a4053SRui Paulo #ifdef HOSTAPD 1026e28a4053SRui Paulo 102785732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1028f05cddf9SRui Paulo static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, 1029f05cddf9SRui Paulo const u8 *bssid, 1030f05cddf9SRui Paulo u16 auth_transaction, u16 status, 1031f05cddf9SRui Paulo const u8 *ies, size_t ies_len) 1032e28a4053SRui Paulo { 1033f05cddf9SRui Paulo struct hostapd_data *hapd = ctx; 1034f05cddf9SRui Paulo struct sta_info *sta; 1035e28a4053SRui Paulo 1036f05cddf9SRui Paulo sta = ap_get_sta(hapd, dst); 1037f05cddf9SRui Paulo if (sta == NULL) 1038f05cddf9SRui Paulo return; 1039e28a4053SRui Paulo 1040f05cddf9SRui Paulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 1041f05cddf9SRui Paulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 1042f05cddf9SRui Paulo sta->flags |= WLAN_STA_AUTH; 1043e28a4053SRui Paulo 1044f05cddf9SRui Paulo hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len); 1045e28a4053SRui Paulo } 104685732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 104785732ac8SCy Schubert 104885732ac8SCy Schubert 104985732ac8SCy Schubert #ifdef CONFIG_FILS 105085732ac8SCy Schubert static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd, 105185732ac8SCy Schubert struct sta_info *sta, u16 resp, 105285732ac8SCy Schubert struct wpabuf *data, int pub) 105385732ac8SCy Schubert { 105485732ac8SCy Schubert if (resp == WLAN_STATUS_SUCCESS) { 105585732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 105685732ac8SCy Schubert HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)"); 105785732ac8SCy Schubert sta->flags |= WLAN_STA_AUTH; 105885732ac8SCy Schubert wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 105985732ac8SCy Schubert sta->auth_alg = WLAN_AUTH_FILS_SK; 106085732ac8SCy Schubert mlme_authenticate_indication(hapd, sta); 106185732ac8SCy Schubert } else { 106285732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 106385732ac8SCy Schubert HOSTAPD_LEVEL_DEBUG, 106485732ac8SCy Schubert "authentication failed (FILS)"); 106585732ac8SCy Schubert } 106685732ac8SCy Schubert 106785732ac8SCy Schubert hostapd_sta_auth(hapd, sta->addr, 2, resp, 106885732ac8SCy Schubert data ? wpabuf_head(data) : NULL, 106985732ac8SCy Schubert data ? wpabuf_len(data) : 0); 107085732ac8SCy Schubert wpabuf_free(data); 107185732ac8SCy Schubert } 107285732ac8SCy Schubert #endif /* CONFIG_FILS */ 1073f05cddf9SRui Paulo 1074f05cddf9SRui Paulo 1075f05cddf9SRui Paulo static void hostapd_notif_auth(struct hostapd_data *hapd, 1076f05cddf9SRui Paulo struct auth_info *rx_auth) 1077f05cddf9SRui Paulo { 1078f05cddf9SRui Paulo struct sta_info *sta; 1079f05cddf9SRui Paulo u16 status = WLAN_STATUS_SUCCESS; 1080f05cddf9SRui Paulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 1081f05cddf9SRui Paulo size_t resp_ies_len = 0; 1082f05cddf9SRui Paulo 1083f05cddf9SRui Paulo sta = ap_get_sta(hapd, rx_auth->peer); 1084f05cddf9SRui Paulo if (!sta) { 1085f05cddf9SRui Paulo sta = ap_sta_add(hapd, rx_auth->peer); 1086f05cddf9SRui Paulo if (sta == NULL) { 10875b9c547cSRui Paulo status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 1088f05cddf9SRui Paulo goto fail; 1089e28a4053SRui Paulo } 1090e28a4053SRui Paulo } 1091f05cddf9SRui Paulo sta->flags &= ~WLAN_STA_PREAUTH; 1092f05cddf9SRui Paulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 109385732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1094f05cddf9SRui Paulo if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { 1095f05cddf9SRui Paulo sta->auth_alg = WLAN_AUTH_FT; 1096f05cddf9SRui Paulo if (sta->wpa_sm == NULL) 1097f05cddf9SRui Paulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 10985b9c547cSRui Paulo sta->addr, NULL); 1099f05cddf9SRui Paulo if (sta->wpa_sm == NULL) { 1100325151a3SRui Paulo wpa_printf(MSG_DEBUG, 1101325151a3SRui Paulo "FT: Failed to initialize WPA state machine"); 1102f05cddf9SRui Paulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1103f05cddf9SRui Paulo goto fail; 1104f05cddf9SRui Paulo } 1105f05cddf9SRui Paulo wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, 1106f05cddf9SRui Paulo rx_auth->auth_transaction, rx_auth->ies, 1107f05cddf9SRui Paulo rx_auth->ies_len, 1108f05cddf9SRui Paulo hostapd_notify_auth_ft_finish, hapd); 1109f05cddf9SRui Paulo return; 1110f05cddf9SRui Paulo } 111185732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 111285732ac8SCy Schubert 111385732ac8SCy Schubert #ifdef CONFIG_FILS 111485732ac8SCy Schubert if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) { 111585732ac8SCy Schubert sta->auth_alg = WLAN_AUTH_FILS_SK; 111685732ac8SCy Schubert handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len, 111785732ac8SCy Schubert rx_auth->auth_type, rx_auth->auth_transaction, 111885732ac8SCy Schubert rx_auth->status_code, 111985732ac8SCy Schubert hostapd_notify_auth_fils_finish); 112085732ac8SCy Schubert return; 112185732ac8SCy Schubert } 112285732ac8SCy Schubert #endif /* CONFIG_FILS */ 112385732ac8SCy Schubert 1124f05cddf9SRui Paulo fail: 1125f05cddf9SRui Paulo hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, 1126f05cddf9SRui Paulo status, resp_ies, resp_ies_len); 1127f05cddf9SRui Paulo } 1128e28a4053SRui Paulo 1129e28a4053SRui Paulo 11304bc52338SCy Schubert #ifndef NEED_AP_MLME 1131f05cddf9SRui Paulo static void hostapd_action_rx(struct hostapd_data *hapd, 11325b9c547cSRui Paulo struct rx_mgmt *drv_mgmt) 1133f05cddf9SRui Paulo { 11345b9c547cSRui Paulo struct ieee80211_mgmt *mgmt; 1135f05cddf9SRui Paulo struct sta_info *sta; 11365b9c547cSRui Paulo size_t plen __maybe_unused; 11375b9c547cSRui Paulo u16 fc; 113885732ac8SCy Schubert u8 *action __maybe_unused; 11395b9c547cSRui Paulo 114085732ac8SCy Schubert if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1) 11415b9c547cSRui Paulo return; 11425b9c547cSRui Paulo 11434bc52338SCy Schubert plen = drv_mgmt->frame_len - IEEE80211_HDRLEN; 11445b9c547cSRui Paulo 11455b9c547cSRui Paulo mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; 11465b9c547cSRui Paulo fc = le_to_host16(mgmt->frame_control); 11475b9c547cSRui Paulo if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) 11485b9c547cSRui Paulo return; /* handled by the driver */ 1149f05cddf9SRui Paulo 115085732ac8SCy Schubert action = (u8 *) &mgmt->u.action.u; 115185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR 115285732ac8SCy Schubert " da " MACSTR " plen %d", 115385732ac8SCy Schubert mgmt->u.action.category, *action, 115485732ac8SCy Schubert MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen); 1155f05cddf9SRui Paulo 11565b9c547cSRui Paulo sta = ap_get_sta(hapd, mgmt->sa); 1157f05cddf9SRui Paulo if (sta == NULL) { 1158f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 1159f05cddf9SRui Paulo return; 1160f05cddf9SRui Paulo } 116185732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 11625b9c547cSRui Paulo if (mgmt->u.action.category == WLAN_ACTION_FT) { 11634bc52338SCy Schubert wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen); 11644bc52338SCy Schubert return; 1165f05cddf9SRui Paulo } 116685732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 1167f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W 11684bc52338SCy Schubert if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) { 11694bc52338SCy Schubert ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len); 11704bc52338SCy Schubert return; 1171f05cddf9SRui Paulo } 1172f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */ 117385732ac8SCy Schubert #ifdef CONFIG_WNM_AP 11745b9c547cSRui Paulo if (mgmt->u.action.category == WLAN_ACTION_WNM) { 11755b9c547cSRui Paulo ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); 11764bc52338SCy Schubert return; 1177f05cddf9SRui Paulo } 117885732ac8SCy Schubert #endif /* CONFIG_WNM_AP */ 1179325151a3SRui Paulo #ifdef CONFIG_FST 1180325151a3SRui Paulo if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) { 1181325151a3SRui Paulo fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len); 1182325151a3SRui Paulo return; 1183325151a3SRui Paulo } 1184325151a3SRui Paulo #endif /* CONFIG_FST */ 118585732ac8SCy Schubert #ifdef CONFIG_DPP 11864bc52338SCy Schubert if (plen >= 2 + 4 && 118785732ac8SCy Schubert mgmt->u.action.u.vs_public_action.action == 118885732ac8SCy Schubert WLAN_PA_VENDOR_SPECIFIC && 118985732ac8SCy Schubert WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 119085732ac8SCy Schubert OUI_WFA && 119185732ac8SCy Schubert mgmt->u.action.u.vs_public_action.variable[0] == 119285732ac8SCy Schubert DPP_OUI_TYPE) { 119385732ac8SCy Schubert const u8 *pos, *end; 1194325151a3SRui Paulo 119585732ac8SCy Schubert pos = mgmt->u.action.u.vs_public_action.oui; 119685732ac8SCy Schubert end = drv_mgmt->frame + drv_mgmt->frame_len; 119785732ac8SCy Schubert hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos, 119885732ac8SCy Schubert drv_mgmt->freq); 119985732ac8SCy Schubert return; 120085732ac8SCy Schubert } 120185732ac8SCy Schubert #endif /* CONFIG_DPP */ 1202f05cddf9SRui Paulo } 12034bc52338SCy Schubert #endif /* NEED_AP_MLME */ 1204f05cddf9SRui Paulo 1205f05cddf9SRui Paulo 1206f05cddf9SRui Paulo #ifdef NEED_AP_MLME 1207f05cddf9SRui Paulo 1208e28a4053SRui Paulo #define HAPD_BROADCAST ((struct hostapd_data *) -1) 1209e28a4053SRui Paulo 1210e28a4053SRui Paulo static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, 1211e28a4053SRui Paulo const u8 *bssid) 1212e28a4053SRui Paulo { 1213e28a4053SRui Paulo size_t i; 1214e28a4053SRui Paulo 1215e28a4053SRui Paulo if (bssid == NULL) 1216e28a4053SRui Paulo return NULL; 1217e28a4053SRui Paulo if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && 1218e28a4053SRui Paulo bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) 1219e28a4053SRui Paulo return HAPD_BROADCAST; 1220e28a4053SRui Paulo 1221e28a4053SRui Paulo for (i = 0; i < iface->num_bss; i++) { 1222e28a4053SRui Paulo if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) 1223e28a4053SRui Paulo return iface->bss[i]; 1224e28a4053SRui Paulo } 1225e28a4053SRui Paulo 1226e28a4053SRui Paulo return NULL; 1227e28a4053SRui Paulo } 1228e28a4053SRui Paulo 1229e28a4053SRui Paulo 1230e28a4053SRui Paulo static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, 1231f05cddf9SRui Paulo const u8 *bssid, const u8 *addr, 1232f05cddf9SRui Paulo int wds) 1233e28a4053SRui Paulo { 1234f05cddf9SRui Paulo hapd = get_hapd_bssid(hapd->iface, bssid); 1235e28a4053SRui Paulo if (hapd == NULL || hapd == HAPD_BROADCAST) 1236e28a4053SRui Paulo return; 1237e28a4053SRui Paulo 1238f05cddf9SRui Paulo ieee802_11_rx_from_unknown(hapd, addr, wds); 1239e28a4053SRui Paulo } 1240e28a4053SRui Paulo 1241e28a4053SRui Paulo 12425b9c547cSRui Paulo static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) 1243e28a4053SRui Paulo { 1244e28a4053SRui Paulo struct hostapd_iface *iface = hapd->iface; 1245e28a4053SRui Paulo const struct ieee80211_hdr *hdr; 1246e28a4053SRui Paulo const u8 *bssid; 1247e28a4053SRui Paulo struct hostapd_frame_info fi; 12485b9c547cSRui Paulo int ret; 12495b9c547cSRui Paulo 12505b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 12515b9c547cSRui Paulo if (hapd->ext_mgmt_frame_handling) { 12525b9c547cSRui Paulo size_t hex_len = 2 * rx_mgmt->frame_len + 1; 12535b9c547cSRui Paulo char *hex = os_malloc(hex_len); 1254325151a3SRui Paulo 12555b9c547cSRui Paulo if (hex) { 12565b9c547cSRui Paulo wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame, 12575b9c547cSRui Paulo rx_mgmt->frame_len); 12585b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); 12595b9c547cSRui Paulo os_free(hex); 12605b9c547cSRui Paulo } 12615b9c547cSRui Paulo return 1; 12625b9c547cSRui Paulo } 12635b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 1264e28a4053SRui Paulo 1265e28a4053SRui Paulo hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; 1266e28a4053SRui Paulo bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); 1267e28a4053SRui Paulo if (bssid == NULL) 12685b9c547cSRui Paulo return 0; 1269e28a4053SRui Paulo 1270e28a4053SRui Paulo hapd = get_hapd_bssid(iface, bssid); 1271e28a4053SRui Paulo if (hapd == NULL) { 1272325151a3SRui Paulo u16 fc = le_to_host16(hdr->frame_control); 1273e28a4053SRui Paulo 1274e28a4053SRui Paulo /* 1275e28a4053SRui Paulo * Drop frames to unknown BSSIDs except for Beacon frames which 1276e28a4053SRui Paulo * could be used to update neighbor information. 1277e28a4053SRui Paulo */ 1278e28a4053SRui Paulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1279e28a4053SRui Paulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1280e28a4053SRui Paulo hapd = iface->bss[0]; 1281e28a4053SRui Paulo else 12825b9c547cSRui Paulo return 0; 1283e28a4053SRui Paulo } 1284e28a4053SRui Paulo 1285e28a4053SRui Paulo os_memset(&fi, 0, sizeof(fi)); 128685732ac8SCy Schubert fi.freq = rx_mgmt->freq; 1287e28a4053SRui Paulo fi.datarate = rx_mgmt->datarate; 1288e28a4053SRui Paulo fi.ssi_signal = rx_mgmt->ssi_signal; 1289e28a4053SRui Paulo 1290e28a4053SRui Paulo if (hapd == HAPD_BROADCAST) { 1291e28a4053SRui Paulo size_t i; 1292325151a3SRui Paulo 12935b9c547cSRui Paulo ret = 0; 12945b9c547cSRui Paulo for (i = 0; i < iface->num_bss; i++) { 12955b9c547cSRui Paulo /* if bss is set, driver will call this function for 12965b9c547cSRui Paulo * each bss individually. */ 12975b9c547cSRui Paulo if (rx_mgmt->drv_priv && 12985b9c547cSRui Paulo (iface->bss[i]->drv_priv != rx_mgmt->drv_priv)) 12995b9c547cSRui Paulo continue; 13005b9c547cSRui Paulo 13015b9c547cSRui Paulo if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, 13025b9c547cSRui Paulo rx_mgmt->frame_len, &fi) > 0) 13035b9c547cSRui Paulo ret = 1; 13045b9c547cSRui Paulo } 1305e28a4053SRui Paulo } else 13065b9c547cSRui Paulo ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, 13075b9c547cSRui Paulo &fi); 1308f05cddf9SRui Paulo 1309f05cddf9SRui Paulo random_add_randomness(&fi, sizeof(fi)); 1310f05cddf9SRui Paulo 13115b9c547cSRui Paulo return ret; 1312e28a4053SRui Paulo } 1313e28a4053SRui Paulo 1314e28a4053SRui Paulo 1315e28a4053SRui Paulo static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, 1316e28a4053SRui Paulo size_t len, u16 stype, int ok) 1317e28a4053SRui Paulo { 1318e28a4053SRui Paulo struct ieee80211_hdr *hdr; 1319780fb4a2SCy Schubert struct hostapd_data *orig_hapd = hapd; 1320325151a3SRui Paulo 1321e28a4053SRui Paulo hdr = (struct ieee80211_hdr *) buf; 1322e28a4053SRui Paulo hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); 1323780fb4a2SCy Schubert if (!hapd) 1324e28a4053SRui Paulo return; 1325780fb4a2SCy Schubert if (hapd == HAPD_BROADCAST) { 1326780fb4a2SCy Schubert if (stype != WLAN_FC_STYPE_ACTION || len <= 25 || 1327780fb4a2SCy Schubert buf[24] != WLAN_ACTION_PUBLIC) 1328780fb4a2SCy Schubert return; 1329780fb4a2SCy Schubert hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2); 1330780fb4a2SCy Schubert if (!hapd || hapd == HAPD_BROADCAST) 1331780fb4a2SCy Schubert return; 1332780fb4a2SCy Schubert /* 1333780fb4a2SCy Schubert * Allow processing of TX status for a Public Action frame that 1334780fb4a2SCy Schubert * used wildcard BBSID. 1335780fb4a2SCy Schubert */ 1336780fb4a2SCy Schubert } 1337e28a4053SRui Paulo ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); 1338e28a4053SRui Paulo } 1339e28a4053SRui Paulo 1340e28a4053SRui Paulo #endif /* NEED_AP_MLME */ 1341e28a4053SRui Paulo 1342e28a4053SRui Paulo 1343e28a4053SRui Paulo static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) 1344e28a4053SRui Paulo { 1345e28a4053SRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 1346325151a3SRui Paulo 1347e28a4053SRui Paulo if (sta) 1348e28a4053SRui Paulo return 0; 1349e28a4053SRui Paulo 1350e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR 1351e28a4053SRui Paulo " - adding a new STA", MAC2STR(addr)); 1352e28a4053SRui Paulo sta = ap_sta_add(hapd, addr); 1353e28a4053SRui Paulo if (sta) { 1354e28a4053SRui Paulo hostapd_new_assoc_sta(hapd, sta, 0); 1355e28a4053SRui Paulo } else { 1356e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, 1357e28a4053SRui Paulo MAC2STR(addr)); 1358e28a4053SRui Paulo return -1; 1359e28a4053SRui Paulo } 1360e28a4053SRui Paulo 1361e28a4053SRui Paulo return 0; 1362e28a4053SRui Paulo } 1363e28a4053SRui Paulo 1364e28a4053SRui Paulo 1365e28a4053SRui Paulo static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, 1366e28a4053SRui Paulo const u8 *data, size_t data_len) 1367e28a4053SRui Paulo { 1368e28a4053SRui Paulo struct hostapd_iface *iface = hapd->iface; 1369f05cddf9SRui Paulo struct sta_info *sta; 1370e28a4053SRui Paulo size_t j; 1371e28a4053SRui Paulo 1372e28a4053SRui Paulo for (j = 0; j < iface->num_bss; j++) { 1373325151a3SRui Paulo sta = ap_get_sta(iface->bss[j], src); 1374325151a3SRui Paulo if (sta && sta->flags & WLAN_STA_ASSOC) { 1375e28a4053SRui Paulo hapd = iface->bss[j]; 1376e28a4053SRui Paulo break; 1377e28a4053SRui Paulo } 1378e28a4053SRui Paulo } 1379e28a4053SRui Paulo 1380e28a4053SRui Paulo ieee802_1x_receive(hapd, src, data, data_len); 1381e28a4053SRui Paulo } 1382e28a4053SRui Paulo 1383780fb4a2SCy Schubert #endif /* HOSTAPD */ 1384780fb4a2SCy Schubert 1385e28a4053SRui Paulo 13865b9c547cSRui Paulo static struct hostapd_channel_data * hostapd_get_mode_channel( 13875b9c547cSRui Paulo struct hostapd_iface *iface, unsigned int freq) 13885b9c547cSRui Paulo { 13895b9c547cSRui Paulo int i; 13905b9c547cSRui Paulo struct hostapd_channel_data *chan; 13915b9c547cSRui Paulo 13925b9c547cSRui Paulo for (i = 0; i < iface->current_mode->num_channels; i++) { 13935b9c547cSRui Paulo chan = &iface->current_mode->channels[i]; 13945b9c547cSRui Paulo if ((unsigned int) chan->freq == freq) 13955b9c547cSRui Paulo return chan; 13965b9c547cSRui Paulo } 13975b9c547cSRui Paulo 13985b9c547cSRui Paulo return NULL; 13995b9c547cSRui Paulo } 14005b9c547cSRui Paulo 14015b9c547cSRui Paulo 14025b9c547cSRui Paulo static void hostapd_update_nf(struct hostapd_iface *iface, 14035b9c547cSRui Paulo struct hostapd_channel_data *chan, 14045b9c547cSRui Paulo struct freq_survey *survey) 14055b9c547cSRui Paulo { 14065b9c547cSRui Paulo if (!iface->chans_surveyed) { 14075b9c547cSRui Paulo chan->min_nf = survey->nf; 14085b9c547cSRui Paulo iface->lowest_nf = survey->nf; 14095b9c547cSRui Paulo } else { 14105b9c547cSRui Paulo if (dl_list_empty(&chan->survey_list)) 14115b9c547cSRui Paulo chan->min_nf = survey->nf; 14125b9c547cSRui Paulo else if (survey->nf < chan->min_nf) 14135b9c547cSRui Paulo chan->min_nf = survey->nf; 14145b9c547cSRui Paulo if (survey->nf < iface->lowest_nf) 14155b9c547cSRui Paulo iface->lowest_nf = survey->nf; 14165b9c547cSRui Paulo } 14175b9c547cSRui Paulo } 14185b9c547cSRui Paulo 14195b9c547cSRui Paulo 14205b9c547cSRui Paulo static void hostapd_single_channel_get_survey(struct hostapd_iface *iface, 14215b9c547cSRui Paulo struct survey_results *survey_res) 14225b9c547cSRui Paulo { 14235b9c547cSRui Paulo struct hostapd_channel_data *chan; 14245b9c547cSRui Paulo struct freq_survey *survey; 14255b9c547cSRui Paulo u64 divisor, dividend; 14265b9c547cSRui Paulo 14275b9c547cSRui Paulo survey = dl_list_first(&survey_res->survey_list, struct freq_survey, 14285b9c547cSRui Paulo list); 14295b9c547cSRui Paulo if (!survey || !survey->freq) 14305b9c547cSRui Paulo return; 14315b9c547cSRui Paulo 14325b9c547cSRui Paulo chan = hostapd_get_mode_channel(iface, survey->freq); 14335b9c547cSRui Paulo if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED) 14345b9c547cSRui Paulo return; 14355b9c547cSRui Paulo 1436325151a3SRui Paulo wpa_printf(MSG_DEBUG, 1437325151a3SRui Paulo "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", 14385b9c547cSRui Paulo survey->freq, 14395b9c547cSRui Paulo (unsigned long int) survey->channel_time, 14405b9c547cSRui Paulo (unsigned long int) survey->channel_time_busy); 14415b9c547cSRui Paulo 14425b9c547cSRui Paulo if (survey->channel_time > iface->last_channel_time && 14435b9c547cSRui Paulo survey->channel_time > survey->channel_time_busy) { 14445b9c547cSRui Paulo dividend = survey->channel_time_busy - 14455b9c547cSRui Paulo iface->last_channel_time_busy; 14465b9c547cSRui Paulo divisor = survey->channel_time - iface->last_channel_time; 14475b9c547cSRui Paulo 14485b9c547cSRui Paulo iface->channel_utilization = dividend * 255 / divisor; 14495b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Channel Utilization: %d", 14505b9c547cSRui Paulo iface->channel_utilization); 14515b9c547cSRui Paulo } 14525b9c547cSRui Paulo iface->last_channel_time = survey->channel_time; 14535b9c547cSRui Paulo iface->last_channel_time_busy = survey->channel_time_busy; 14545b9c547cSRui Paulo } 14555b9c547cSRui Paulo 14565b9c547cSRui Paulo 1457780fb4a2SCy Schubert void hostapd_event_get_survey(struct hostapd_iface *iface, 14585b9c547cSRui Paulo struct survey_results *survey_results) 14595b9c547cSRui Paulo { 14605b9c547cSRui Paulo struct freq_survey *survey, *tmp; 14615b9c547cSRui Paulo struct hostapd_channel_data *chan; 14625b9c547cSRui Paulo 14635b9c547cSRui Paulo if (dl_list_empty(&survey_results->survey_list)) { 14645b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "No survey data received"); 14655b9c547cSRui Paulo return; 14665b9c547cSRui Paulo } 14675b9c547cSRui Paulo 14685b9c547cSRui Paulo if (survey_results->freq_filter) { 14695b9c547cSRui Paulo hostapd_single_channel_get_survey(iface, survey_results); 14705b9c547cSRui Paulo return; 14715b9c547cSRui Paulo } 14725b9c547cSRui Paulo 14735b9c547cSRui Paulo dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, 14745b9c547cSRui Paulo struct freq_survey, list) { 14755b9c547cSRui Paulo chan = hostapd_get_mode_channel(iface, survey->freq); 14765b9c547cSRui Paulo if (!chan) 14775b9c547cSRui Paulo continue; 14785b9c547cSRui Paulo if (chan->flag & HOSTAPD_CHAN_DISABLED) 14795b9c547cSRui Paulo continue; 14805b9c547cSRui Paulo 14815b9c547cSRui Paulo dl_list_del(&survey->list); 14825b9c547cSRui Paulo dl_list_add_tail(&chan->survey_list, &survey->list); 14835b9c547cSRui Paulo 14845b9c547cSRui Paulo hostapd_update_nf(iface, chan, survey); 14855b9c547cSRui Paulo 14865b9c547cSRui Paulo iface->chans_surveyed++; 14875b9c547cSRui Paulo } 14885b9c547cSRui Paulo } 14895b9c547cSRui Paulo 14905b9c547cSRui Paulo 1491780fb4a2SCy Schubert #ifdef HOSTAPD 14925b9c547cSRui Paulo #ifdef NEED_AP_MLME 14935b9c547cSRui Paulo 14945b9c547cSRui Paulo static void hostapd_event_iface_unavailable(struct hostapd_data *hapd) 14955b9c547cSRui Paulo { 14965b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped", 14975b9c547cSRui Paulo hapd->conf->iface); 14985b9c547cSRui Paulo 14995b9c547cSRui Paulo if (hapd->csa_in_progress) { 15005b9c547cSRui Paulo wpa_printf(MSG_INFO, "CSA failed (%s was stopped)", 15015b9c547cSRui Paulo hapd->conf->iface); 15025b9c547cSRui Paulo hostapd_switch_channel_fallback(hapd->iface, 15035b9c547cSRui Paulo &hapd->cs_freq_params); 15045b9c547cSRui Paulo } 15055b9c547cSRui Paulo } 15065b9c547cSRui Paulo 15075b9c547cSRui Paulo 15085b9c547cSRui Paulo static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd, 15095b9c547cSRui Paulo struct dfs_event *radar) 15105b9c547cSRui Paulo { 15115b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq); 15125b9c547cSRui Paulo hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled, 15135b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 15145b9c547cSRui Paulo radar->cf1, radar->cf2); 15155b9c547cSRui Paulo } 15165b9c547cSRui Paulo 15175b9c547cSRui Paulo 151885732ac8SCy Schubert static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd, 151985732ac8SCy Schubert struct dfs_event *radar) 152085732ac8SCy Schubert { 152185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq); 152285732ac8SCy Schubert hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled, 152385732ac8SCy Schubert radar->chan_offset, radar->chan_width, 152485732ac8SCy Schubert radar->cf1, radar->cf2); 152585732ac8SCy Schubert } 152685732ac8SCy Schubert 152785732ac8SCy Schubert 15285b9c547cSRui Paulo static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd, 15295b9c547cSRui Paulo struct dfs_event *radar) 15305b9c547cSRui Paulo { 15315b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq); 15325b9c547cSRui Paulo hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled, 15335b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 15345b9c547cSRui Paulo radar->cf1, radar->cf2); 15355b9c547cSRui Paulo } 15365b9c547cSRui Paulo 15375b9c547cSRui Paulo 15385b9c547cSRui Paulo static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd, 15395b9c547cSRui Paulo struct dfs_event *radar) 15405b9c547cSRui Paulo { 15415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq); 15425b9c547cSRui Paulo hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled, 15435b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 15445b9c547cSRui Paulo radar->cf1, radar->cf2); 15455b9c547cSRui Paulo } 15465b9c547cSRui Paulo 15475b9c547cSRui Paulo 15485b9c547cSRui Paulo static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd, 15495b9c547cSRui Paulo struct dfs_event *radar) 15505b9c547cSRui Paulo { 15515b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq); 15525b9c547cSRui Paulo hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled, 15535b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 15545b9c547cSRui Paulo radar->cf1, radar->cf2); 15555b9c547cSRui Paulo } 15565b9c547cSRui Paulo 15575b9c547cSRui Paulo 15585b9c547cSRui Paulo static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd, 15595b9c547cSRui Paulo struct dfs_event *radar) 15605b9c547cSRui Paulo { 15615b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq); 15625b9c547cSRui Paulo hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled, 15635b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 15645b9c547cSRui Paulo radar->cf1, radar->cf2); 15655b9c547cSRui Paulo } 15665b9c547cSRui Paulo 15675b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 15685b9c547cSRui Paulo 15695b9c547cSRui Paulo 157085732ac8SCy Schubert static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd, 157185732ac8SCy Schubert int istatus, 157285732ac8SCy Schubert const char *ifname, 157385732ac8SCy Schubert const u8 *addr) 157485732ac8SCy Schubert { 157585732ac8SCy Schubert struct sta_info *sta = ap_get_sta(hapd, addr); 157685732ac8SCy Schubert 157785732ac8SCy Schubert if (sta) { 157885732ac8SCy Schubert os_free(sta->ifname_wds); 157985732ac8SCy Schubert if (istatus == INTERFACE_ADDED) 158085732ac8SCy Schubert sta->ifname_wds = os_strdup(ifname); 158185732ac8SCy Schubert else 158285732ac8SCy Schubert sta->ifname_wds = NULL; 158385732ac8SCy Schubert } 158485732ac8SCy Schubert 158585732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR, 158685732ac8SCy Schubert istatus == INTERFACE_ADDED ? 158785732ac8SCy Schubert WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED, 158885732ac8SCy Schubert ifname, MAC2STR(addr)); 158985732ac8SCy Schubert } 159085732ac8SCy Schubert 159185732ac8SCy Schubert 1592*206b73d0SCy Schubert #ifdef CONFIG_OWE 1593*206b73d0SCy Schubert static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, 1594*206b73d0SCy Schubert const u8 *peer, const u8 *ie, 1595*206b73d0SCy Schubert size_t ie_len) 1596*206b73d0SCy Schubert { 1597*206b73d0SCy Schubert u16 status; 1598*206b73d0SCy Schubert struct sta_info *sta; 1599*206b73d0SCy Schubert struct ieee802_11_elems elems; 1600*206b73d0SCy Schubert 1601*206b73d0SCy Schubert if (!hapd || !hapd->wpa_auth) { 1602*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context"); 1603*206b73d0SCy Schubert return -1; 1604*206b73d0SCy Schubert } 1605*206b73d0SCy Schubert if (!peer) { 1606*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: Peer unknown"); 1607*206b73d0SCy Schubert return -1; 1608*206b73d0SCy Schubert } 1609*206b73d0SCy Schubert if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) { 1610*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured"); 1611*206b73d0SCy Schubert status = WLAN_STATUS_AKMP_NOT_VALID; 1612*206b73d0SCy Schubert goto err; 1613*206b73d0SCy Schubert } 1614*206b73d0SCy Schubert if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) { 1615*206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for " 1616*206b73d0SCy Schubert MACSTR, MAC2STR(peer)); 1617*206b73d0SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1618*206b73d0SCy Schubert goto err; 1619*206b73d0SCy Schubert } 1620*206b73d0SCy Schubert status = owe_validate_request(hapd, peer, elems.rsn_ie, 1621*206b73d0SCy Schubert elems.rsn_ie_len, 1622*206b73d0SCy Schubert elems.owe_dh, elems.owe_dh_len); 1623*206b73d0SCy Schubert if (status != WLAN_STATUS_SUCCESS) 1624*206b73d0SCy Schubert goto err; 1625*206b73d0SCy Schubert 1626*206b73d0SCy Schubert sta = ap_get_sta(hapd, peer); 1627*206b73d0SCy Schubert if (sta) { 1628*206b73d0SCy Schubert ap_sta_no_session_timeout(hapd, sta); 1629*206b73d0SCy Schubert accounting_sta_stop(hapd, sta); 1630*206b73d0SCy Schubert 1631*206b73d0SCy Schubert /* 1632*206b73d0SCy Schubert * Make sure that the previously registered inactivity timer 1633*206b73d0SCy Schubert * will not remove the STA immediately. 1634*206b73d0SCy Schubert */ 1635*206b73d0SCy Schubert sta->timeout_next = STA_NULLFUNC; 1636*206b73d0SCy Schubert } else { 1637*206b73d0SCy Schubert sta = ap_sta_add(hapd, peer); 1638*206b73d0SCy Schubert if (!sta) { 1639*206b73d0SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1640*206b73d0SCy Schubert goto err; 1641*206b73d0SCy Schubert } 1642*206b73d0SCy Schubert } 1643*206b73d0SCy Schubert sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 1644*206b73d0SCy Schubert 1645*206b73d0SCy Schubert status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, 1646*206b73d0SCy Schubert elems.rsn_ie_len, elems.owe_dh, 1647*206b73d0SCy Schubert elems.owe_dh_len); 1648*206b73d0SCy Schubert if (status != WLAN_STATUS_SUCCESS) 1649*206b73d0SCy Schubert ap_free_sta(hapd, sta); 1650*206b73d0SCy Schubert 1651*206b73d0SCy Schubert return 0; 1652*206b73d0SCy Schubert err: 1653*206b73d0SCy Schubert hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0); 1654*206b73d0SCy Schubert return 0; 1655*206b73d0SCy Schubert } 1656*206b73d0SCy Schubert #endif /* CONFIG_OWE */ 1657*206b73d0SCy Schubert 1658*206b73d0SCy Schubert 1659e28a4053SRui Paulo void wpa_supplicant_event(void *ctx, enum wpa_event_type event, 1660e28a4053SRui Paulo union wpa_event_data *data) 1661e28a4053SRui Paulo { 1662e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 1663f05cddf9SRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG 1664f05cddf9SRui Paulo int level = MSG_DEBUG; 1665f05cddf9SRui Paulo 1666f05cddf9SRui Paulo if (event == EVENT_RX_MGMT && data->rx_mgmt.frame && 1667f05cddf9SRui Paulo data->rx_mgmt.frame_len >= 24) { 1668f05cddf9SRui Paulo const struct ieee80211_hdr *hdr; 1669f05cddf9SRui Paulo u16 fc; 1670325151a3SRui Paulo 1671f05cddf9SRui Paulo hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; 1672f05cddf9SRui Paulo fc = le_to_host16(hdr->frame_control); 1673f05cddf9SRui Paulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1674f05cddf9SRui Paulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1675f05cddf9SRui Paulo level = MSG_EXCESSIVE; 16765b9c547cSRui Paulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 16775b9c547cSRui Paulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) 16785b9c547cSRui Paulo level = MSG_EXCESSIVE; 1679f05cddf9SRui Paulo } 1680f05cddf9SRui Paulo 1681f05cddf9SRui Paulo wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", 1682f05cddf9SRui Paulo event_to_string(event), event); 1683f05cddf9SRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */ 1684e28a4053SRui Paulo 1685e28a4053SRui Paulo switch (event) { 1686e28a4053SRui Paulo case EVENT_MICHAEL_MIC_FAILURE: 1687e28a4053SRui Paulo michael_mic_failure(hapd, data->michael_mic_failure.src, 1); 1688e28a4053SRui Paulo break; 1689e28a4053SRui Paulo case EVENT_SCAN_RESULTS: 1690e28a4053SRui Paulo if (hapd->iface->scan_cb) 1691e28a4053SRui Paulo hapd->iface->scan_cb(hapd->iface); 1692e28a4053SRui Paulo break; 1693e28a4053SRui Paulo case EVENT_WPS_BUTTON_PUSHED: 1694f05cddf9SRui Paulo hostapd_wps_button_pushed(hapd, NULL); 1695e28a4053SRui Paulo break; 1696e28a4053SRui Paulo #ifdef NEED_AP_MLME 1697e28a4053SRui Paulo case EVENT_TX_STATUS: 1698e28a4053SRui Paulo switch (data->tx_status.type) { 1699e28a4053SRui Paulo case WLAN_FC_TYPE_MGMT: 1700e28a4053SRui Paulo hostapd_mgmt_tx_cb(hapd, data->tx_status.data, 1701e28a4053SRui Paulo data->tx_status.data_len, 1702e28a4053SRui Paulo data->tx_status.stype, 1703e28a4053SRui Paulo data->tx_status.ack); 1704e28a4053SRui Paulo break; 1705e28a4053SRui Paulo case WLAN_FC_TYPE_DATA: 1706e28a4053SRui Paulo hostapd_tx_status(hapd, data->tx_status.dst, 1707e28a4053SRui Paulo data->tx_status.data, 1708e28a4053SRui Paulo data->tx_status.data_len, 1709e28a4053SRui Paulo data->tx_status.ack); 1710e28a4053SRui Paulo break; 1711e28a4053SRui Paulo } 1712e28a4053SRui Paulo break; 1713f05cddf9SRui Paulo case EVENT_EAPOL_TX_STATUS: 1714f05cddf9SRui Paulo hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, 1715f05cddf9SRui Paulo data->eapol_tx_status.data, 1716f05cddf9SRui Paulo data->eapol_tx_status.data_len, 1717f05cddf9SRui Paulo data->eapol_tx_status.ack); 1718f05cddf9SRui Paulo break; 1719f05cddf9SRui Paulo case EVENT_DRIVER_CLIENT_POLL_OK: 1720f05cddf9SRui Paulo hostapd_client_poll_ok(hapd, data->client_poll.addr); 1721f05cddf9SRui Paulo break; 1722e28a4053SRui Paulo case EVENT_RX_FROM_UNKNOWN: 1723f05cddf9SRui Paulo hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, 1724f05cddf9SRui Paulo data->rx_from_unknown.addr, 1725f05cddf9SRui Paulo data->rx_from_unknown.wds); 1726e28a4053SRui Paulo break; 17275b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 1728e28a4053SRui Paulo case EVENT_RX_MGMT: 17295b9c547cSRui Paulo if (!data->rx_mgmt.frame) 17305b9c547cSRui Paulo break; 17315b9c547cSRui Paulo #ifdef NEED_AP_MLME 17324bc52338SCy Schubert hostapd_mgmt_rx(hapd, &data->rx_mgmt); 17334bc52338SCy Schubert #else /* NEED_AP_MLME */ 17345b9c547cSRui Paulo hostapd_action_rx(hapd, &data->rx_mgmt); 17354bc52338SCy Schubert #endif /* NEED_AP_MLME */ 17365b9c547cSRui Paulo break; 1737e28a4053SRui Paulo case EVENT_RX_PROBE_REQ: 1738f05cddf9SRui Paulo if (data->rx_probe_req.sa == NULL || 1739f05cddf9SRui Paulo data->rx_probe_req.ie == NULL) 1740f05cddf9SRui Paulo break; 1741e28a4053SRui Paulo hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, 1742f05cddf9SRui Paulo data->rx_probe_req.da, 1743f05cddf9SRui Paulo data->rx_probe_req.bssid, 1744e28a4053SRui Paulo data->rx_probe_req.ie, 1745f05cddf9SRui Paulo data->rx_probe_req.ie_len, 1746f05cddf9SRui Paulo data->rx_probe_req.ssi_signal); 1747e28a4053SRui Paulo break; 1748e28a4053SRui Paulo case EVENT_NEW_STA: 1749e28a4053SRui Paulo hostapd_event_new_sta(hapd, data->new_sta.addr); 1750e28a4053SRui Paulo break; 1751e28a4053SRui Paulo case EVENT_EAPOL_RX: 1752e28a4053SRui Paulo hostapd_event_eapol_rx(hapd, data->eapol_rx.src, 1753e28a4053SRui Paulo data->eapol_rx.data, 1754e28a4053SRui Paulo data->eapol_rx.data_len); 1755e28a4053SRui Paulo break; 1756e28a4053SRui Paulo case EVENT_ASSOC: 17575b9c547cSRui Paulo if (!data) 17585b9c547cSRui Paulo return; 1759e28a4053SRui Paulo hostapd_notif_assoc(hapd, data->assoc_info.addr, 1760e28a4053SRui Paulo data->assoc_info.req_ies, 1761f05cddf9SRui Paulo data->assoc_info.req_ies_len, 1762f05cddf9SRui Paulo data->assoc_info.reassoc); 1763e28a4053SRui Paulo break; 1764*206b73d0SCy Schubert #ifdef CONFIG_OWE 1765*206b73d0SCy Schubert case EVENT_UPDATE_DH: 1766*206b73d0SCy Schubert if (!data) 1767*206b73d0SCy Schubert return; 1768*206b73d0SCy Schubert hostapd_notif_update_dh_ie(hapd, data->update_dh.peer, 1769*206b73d0SCy Schubert data->update_dh.ie, 1770*206b73d0SCy Schubert data->update_dh.ie_len); 1771*206b73d0SCy Schubert break; 1772*206b73d0SCy Schubert #endif /* CONFIG_OWE */ 1773e28a4053SRui Paulo case EVENT_DISASSOC: 1774e28a4053SRui Paulo if (data) 1775e28a4053SRui Paulo hostapd_notif_disassoc(hapd, data->disassoc_info.addr); 1776e28a4053SRui Paulo break; 1777e28a4053SRui Paulo case EVENT_DEAUTH: 1778e28a4053SRui Paulo if (data) 1779e28a4053SRui Paulo hostapd_notif_disassoc(hapd, data->deauth_info.addr); 1780e28a4053SRui Paulo break; 1781f05cddf9SRui Paulo case EVENT_STATION_LOW_ACK: 1782f05cddf9SRui Paulo if (!data) 1783f05cddf9SRui Paulo break; 1784f05cddf9SRui Paulo hostapd_event_sta_low_ack(hapd, data->low_ack.addr); 1785f05cddf9SRui Paulo break; 1786f05cddf9SRui Paulo case EVENT_AUTH: 1787f05cddf9SRui Paulo hostapd_notif_auth(hapd, &data->auth); 1788f05cddf9SRui Paulo break; 1789*206b73d0SCy Schubert case EVENT_CH_SWITCH_STARTED: 1790f05cddf9SRui Paulo case EVENT_CH_SWITCH: 1791f05cddf9SRui Paulo if (!data) 1792f05cddf9SRui Paulo break; 1793f05cddf9SRui Paulo hostapd_event_ch_switch(hapd, data->ch_switch.freq, 1794f05cddf9SRui Paulo data->ch_switch.ht_enabled, 17955b9c547cSRui Paulo data->ch_switch.ch_offset, 17965b9c547cSRui Paulo data->ch_switch.ch_width, 17975b9c547cSRui Paulo data->ch_switch.cf1, 1798*206b73d0SCy Schubert data->ch_switch.cf2, 1799*206b73d0SCy Schubert event == EVENT_CH_SWITCH); 1800f05cddf9SRui Paulo break; 18015b9c547cSRui Paulo case EVENT_CONNECT_FAILED_REASON: 18025b9c547cSRui Paulo if (!data) 18035b9c547cSRui Paulo break; 18045b9c547cSRui Paulo hostapd_event_connect_failed_reason( 18055b9c547cSRui Paulo hapd, data->connect_failed_reason.addr, 18065b9c547cSRui Paulo data->connect_failed_reason.code); 18075b9c547cSRui Paulo break; 18085b9c547cSRui Paulo case EVENT_SURVEY: 1809780fb4a2SCy Schubert hostapd_event_get_survey(hapd->iface, &data->survey_results); 18105b9c547cSRui Paulo break; 18115b9c547cSRui Paulo #ifdef NEED_AP_MLME 18125b9c547cSRui Paulo case EVENT_INTERFACE_UNAVAILABLE: 18135b9c547cSRui Paulo hostapd_event_iface_unavailable(hapd); 18145b9c547cSRui Paulo break; 18155b9c547cSRui Paulo case EVENT_DFS_RADAR_DETECTED: 18165b9c547cSRui Paulo if (!data) 18175b9c547cSRui Paulo break; 18185b9c547cSRui Paulo hostapd_event_dfs_radar_detected(hapd, &data->dfs_event); 18195b9c547cSRui Paulo break; 182085732ac8SCy Schubert case EVENT_DFS_PRE_CAC_EXPIRED: 182185732ac8SCy Schubert if (!data) 182285732ac8SCy Schubert break; 182385732ac8SCy Schubert hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event); 182485732ac8SCy Schubert break; 18255b9c547cSRui Paulo case EVENT_DFS_CAC_FINISHED: 18265b9c547cSRui Paulo if (!data) 18275b9c547cSRui Paulo break; 18285b9c547cSRui Paulo hostapd_event_dfs_cac_finished(hapd, &data->dfs_event); 18295b9c547cSRui Paulo break; 18305b9c547cSRui Paulo case EVENT_DFS_CAC_ABORTED: 18315b9c547cSRui Paulo if (!data) 18325b9c547cSRui Paulo break; 18335b9c547cSRui Paulo hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event); 18345b9c547cSRui Paulo break; 18355b9c547cSRui Paulo case EVENT_DFS_NOP_FINISHED: 18365b9c547cSRui Paulo if (!data) 18375b9c547cSRui Paulo break; 18385b9c547cSRui Paulo hostapd_event_dfs_nop_finished(hapd, &data->dfs_event); 18395b9c547cSRui Paulo break; 18405b9c547cSRui Paulo case EVENT_CHANNEL_LIST_CHANGED: 18415b9c547cSRui Paulo /* channel list changed (regulatory?), update channel list */ 18425b9c547cSRui Paulo /* TODO: check this. hostapd_get_hw_features() initializes 18435b9c547cSRui Paulo * too much stuff. */ 18445b9c547cSRui Paulo /* hostapd_get_hw_features(hapd->iface); */ 18455b9c547cSRui Paulo hostapd_channel_list_updated( 18465b9c547cSRui Paulo hapd->iface, data->channel_list_changed.initiator); 18475b9c547cSRui Paulo break; 18485b9c547cSRui Paulo case EVENT_DFS_CAC_STARTED: 18495b9c547cSRui Paulo if (!data) 18505b9c547cSRui Paulo break; 18515b9c547cSRui Paulo hostapd_event_dfs_cac_started(hapd, &data->dfs_event); 18525b9c547cSRui Paulo break; 18535b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 18545b9c547cSRui Paulo case EVENT_INTERFACE_ENABLED: 18555b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED); 18565b9c547cSRui Paulo if (hapd->disabled && hapd->started) { 18575b9c547cSRui Paulo hapd->disabled = 0; 18585b9c547cSRui Paulo /* 18595b9c547cSRui Paulo * Try to re-enable interface if the driver stopped it 18605b9c547cSRui Paulo * when the interface got disabled. 18615b9c547cSRui Paulo */ 186285732ac8SCy Schubert if (hapd->wpa_auth) 18635b9c547cSRui Paulo wpa_auth_reconfig_group_keys(hapd->wpa_auth); 186485732ac8SCy Schubert else 186585732ac8SCy Schubert hostapd_reconfig_encryption(hapd); 18665b9c547cSRui Paulo hapd->reenable_beacon = 1; 18675b9c547cSRui Paulo ieee802_11_set_beacon(hapd); 18684bc52338SCy Schubert #ifdef NEED_AP_MLME 18694bc52338SCy Schubert } else if (hapd->disabled && hapd->iface->cac_started) { 18704bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC"); 18714bc52338SCy Schubert hostapd_handle_dfs(hapd->iface); 18724bc52338SCy Schubert #endif /* NEED_AP_MLME */ 18735b9c547cSRui Paulo } 18745b9c547cSRui Paulo break; 18755b9c547cSRui Paulo case EVENT_INTERFACE_DISABLED: 18765b9c547cSRui Paulo hostapd_free_stas(hapd); 18775b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED); 18785b9c547cSRui Paulo hapd->disabled = 1; 18795b9c547cSRui Paulo break; 18805b9c547cSRui Paulo #ifdef CONFIG_ACS 18815b9c547cSRui Paulo case EVENT_ACS_CHANNEL_SELECTED: 1882325151a3SRui Paulo hostapd_acs_channel_selected(hapd, 1883325151a3SRui Paulo &data->acs_selected_channels); 18845b9c547cSRui Paulo break; 18855b9c547cSRui Paulo #endif /* CONFIG_ACS */ 188685732ac8SCy Schubert case EVENT_STATION_OPMODE_CHANGED: 188785732ac8SCy Schubert hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr, 188885732ac8SCy Schubert data->sta_opmode.smps_mode, 188985732ac8SCy Schubert data->sta_opmode.chan_width, 189085732ac8SCy Schubert data->sta_opmode.rx_nss); 189185732ac8SCy Schubert break; 189285732ac8SCy Schubert case EVENT_WDS_STA_INTERFACE_STATUS: 189385732ac8SCy Schubert hostapd_event_wds_sta_interface_status( 189485732ac8SCy Schubert hapd, data->wds_sta_interface.istatus, 189585732ac8SCy Schubert data->wds_sta_interface.ifname, 189685732ac8SCy Schubert data->wds_sta_interface.sta_addr); 189785732ac8SCy Schubert break; 1898e28a4053SRui Paulo default: 1899e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Unknown event %d", event); 1900e28a4053SRui Paulo break; 1901e28a4053SRui Paulo } 1902e28a4053SRui Paulo } 1903e28a4053SRui Paulo 1904780fb4a2SCy Schubert 1905780fb4a2SCy Schubert void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, 1906780fb4a2SCy Schubert union wpa_event_data *data) 1907780fb4a2SCy Schubert { 1908780fb4a2SCy Schubert struct hapd_interfaces *interfaces = ctx; 1909780fb4a2SCy Schubert struct hostapd_data *hapd; 1910780fb4a2SCy Schubert 1911780fb4a2SCy Schubert if (event != EVENT_INTERFACE_STATUS) 1912780fb4a2SCy Schubert return; 1913780fb4a2SCy Schubert 1914780fb4a2SCy Schubert hapd = hostapd_get_iface(interfaces, data->interface_status.ifname); 1915780fb4a2SCy Schubert if (hapd && hapd->driver && hapd->driver->get_ifindex && 1916780fb4a2SCy Schubert hapd->drv_priv) { 1917780fb4a2SCy Schubert unsigned int ifindex; 1918780fb4a2SCy Schubert 1919780fb4a2SCy Schubert ifindex = hapd->driver->get_ifindex(hapd->drv_priv); 1920780fb4a2SCy Schubert if (ifindex != data->interface_status.ifindex) { 1921780fb4a2SCy Schubert wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 1922780fb4a2SCy Schubert "interface status ifindex %d mismatch (%d)", 1923780fb4a2SCy Schubert ifindex, data->interface_status.ifindex); 1924780fb4a2SCy Schubert return; 1925780fb4a2SCy Schubert } 1926780fb4a2SCy Schubert } 1927780fb4a2SCy Schubert if (hapd) 1928780fb4a2SCy Schubert wpa_supplicant_event(hapd, event, data); 1929780fb4a2SCy Schubert } 1930780fb4a2SCy Schubert 1931e28a4053SRui Paulo #endif /* HOSTAPD */ 1932