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" 19*c1d255d3SCy Schubert #include "common/sae.h" 20*c1d255d3SCy Schubert #include "common/hw_features_common.h" 21f05cddf9SRui Paulo #include "crypto/random.h" 22f05cddf9SRui Paulo #include "p2p/p2p.h" 23f05cddf9SRui Paulo #include "wps/wps.h" 24325151a3SRui Paulo #include "fst/fst.h" 25f05cddf9SRui Paulo #include "wnm_ap.h" 26e28a4053SRui Paulo #include "hostapd.h" 27e28a4053SRui Paulo #include "ieee802_11.h" 28780fb4a2SCy Schubert #include "ieee802_11_auth.h" 29e28a4053SRui Paulo #include "sta_info.h" 30e28a4053SRui Paulo #include "accounting.h" 31e28a4053SRui Paulo #include "tkip_countermeasures.h" 32e28a4053SRui Paulo #include "ieee802_1x.h" 33e28a4053SRui Paulo #include "wpa_auth.h" 34e28a4053SRui Paulo #include "wps_hostapd.h" 35f05cddf9SRui Paulo #include "ap_drv_ops.h" 36e28a4053SRui Paulo #include "ap_config.h" 3785732ac8SCy Schubert #include "ap_mlme.h" 38f05cddf9SRui Paulo #include "hw_features.h" 395b9c547cSRui Paulo #include "dfs.h" 405b9c547cSRui Paulo #include "beacon.h" 41780fb4a2SCy Schubert #include "mbo_ap.h" 4285732ac8SCy Schubert #include "dpp_hostapd.h" 4385732ac8SCy Schubert #include "fils_hlp.h" 444bc52338SCy Schubert #include "neighbor_db.h" 4585732ac8SCy Schubert 4685732ac8SCy Schubert 4785732ac8SCy Schubert #ifdef CONFIG_FILS 4885732ac8SCy Schubert void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, 4985732ac8SCy Schubert struct sta_info *sta) 5085732ac8SCy Schubert { 5185732ac8SCy Schubert u16 reply_res = WLAN_STATUS_SUCCESS; 5285732ac8SCy Schubert struct ieee802_11_elems elems; 5385732ac8SCy Schubert u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf; 5485732ac8SCy Schubert int new_assoc; 5585732ac8SCy Schubert 5685732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR, 5785732ac8SCy Schubert __func__, MAC2STR(sta->addr)); 5885732ac8SCy Schubert eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 5985732ac8SCy Schubert if (!sta->fils_pending_assoc_req) 6085732ac8SCy Schubert return; 6185732ac8SCy Schubert 6285732ac8SCy Schubert ieee802_11_parse_elems(sta->fils_pending_assoc_req, 6385732ac8SCy Schubert sta->fils_pending_assoc_req_len, &elems, 0); 6485732ac8SCy Schubert if (!elems.fils_session) { 6585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element", 6685732ac8SCy Schubert __func__); 6785732ac8SCy Schubert return; 6885732ac8SCy Schubert } 6985732ac8SCy Schubert 7085732ac8SCy Schubert p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, 7185732ac8SCy Schubert elems.fils_session, 7285732ac8SCy Schubert sta->fils_hlp_resp); 7385732ac8SCy Schubert 7485732ac8SCy Schubert reply_res = hostapd_sta_assoc(hapd, sta->addr, 7585732ac8SCy Schubert sta->fils_pending_assoc_is_reassoc, 7685732ac8SCy Schubert WLAN_STATUS_SUCCESS, 7785732ac8SCy Schubert buf, p - buf); 7885732ac8SCy Schubert ap_sta_set_authorized(hapd, sta, 1); 7985732ac8SCy Schubert new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 8085732ac8SCy Schubert sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 8185732ac8SCy Schubert sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 8285732ac8SCy Schubert hostapd_set_sta_flags(hapd, sta); 8385732ac8SCy Schubert wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); 8485732ac8SCy Schubert ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 8585732ac8SCy Schubert hostapd_new_assoc_sta(hapd, sta, !new_assoc); 8685732ac8SCy Schubert os_free(sta->fils_pending_assoc_req); 8785732ac8SCy Schubert sta->fils_pending_assoc_req = NULL; 8885732ac8SCy Schubert sta->fils_pending_assoc_req_len = 0; 8985732ac8SCy Schubert wpabuf_free(sta->fils_hlp_resp); 9085732ac8SCy Schubert sta->fils_hlp_resp = NULL; 9185732ac8SCy Schubert wpabuf_free(sta->hlp_dhcp_discover); 9285732ac8SCy Schubert sta->hlp_dhcp_discover = NULL; 9385732ac8SCy Schubert fils_hlp_deinit(hapd); 9485732ac8SCy Schubert 9585732ac8SCy Schubert /* 9685732ac8SCy Schubert * Remove the station in case transmission of a success response fails 9785732ac8SCy Schubert * (the STA was added associated to the driver) or if the station was 9885732ac8SCy Schubert * previously added unassociated. 9985732ac8SCy Schubert */ 10085732ac8SCy Schubert if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) { 10185732ac8SCy Schubert hostapd_drv_sta_remove(hapd, sta->addr); 10285732ac8SCy Schubert sta->added_unassoc = 0; 10385732ac8SCy Schubert } 10485732ac8SCy Schubert } 10585732ac8SCy Schubert #endif /* CONFIG_FILS */ 106e28a4053SRui Paulo 107e28a4053SRui Paulo 108*c1d255d3SCy Schubert static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta) 109*c1d255d3SCy Schubert { 110*c1d255d3SCy Schubert if ((sta->flags & 111*c1d255d3SCy Schubert (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) != 112*c1d255d3SCy Schubert (WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) 113*c1d255d3SCy Schubert return false; 114*c1d255d3SCy Schubert 115*c1d255d3SCy Schubert if (!sta->sa_query_timed_out && sta->sa_query_count > 0) 116*c1d255d3SCy Schubert ap_check_sa_query_timeout(hapd, sta); 117*c1d255d3SCy Schubert 118*c1d255d3SCy Schubert if (!sta->sa_query_timed_out && (sta->auth_alg != WLAN_AUTH_FT)) { 119*c1d255d3SCy Schubert /* 120*c1d255d3SCy Schubert * STA has already been associated with MFP and SA Query timeout 121*c1d255d3SCy Schubert * has not been reached. Reject the association attempt 122*c1d255d3SCy Schubert * temporarily and start SA Query, if one is not pending. 123*c1d255d3SCy Schubert */ 124*c1d255d3SCy Schubert if (sta->sa_query_count == 0) 125*c1d255d3SCy Schubert ap_sta_start_sa_query(hapd, sta); 126*c1d255d3SCy Schubert 127*c1d255d3SCy Schubert return true; 128*c1d255d3SCy Schubert } 129*c1d255d3SCy Schubert 130*c1d255d3SCy Schubert return false; 131*c1d255d3SCy Schubert } 132*c1d255d3SCy Schubert 133*c1d255d3SCy Schubert 134e28a4053SRui Paulo int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, 135f05cddf9SRui Paulo const u8 *req_ies, size_t req_ies_len, int reassoc) 136e28a4053SRui Paulo { 137e28a4053SRui Paulo struct sta_info *sta; 138*c1d255d3SCy Schubert int new_assoc; 139*c1d255d3SCy Schubert enum wpa_validate_result res; 140e28a4053SRui Paulo struct ieee802_11_elems elems; 141f05cddf9SRui Paulo const u8 *ie; 142f05cddf9SRui Paulo size_t ielen; 143f05cddf9SRui Paulo u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; 144f05cddf9SRui Paulo u8 *p = buf; 145f05cddf9SRui Paulo u16 reason = WLAN_REASON_UNSPECIFIED; 146*c1d255d3SCy Schubert int status = WLAN_STATUS_SUCCESS; 1475b9c547cSRui Paulo const u8 *p2p_dev_addr = NULL; 148e28a4053SRui Paulo 149e28a4053SRui Paulo if (addr == NULL) { 150e28a4053SRui Paulo /* 151e28a4053SRui Paulo * This could potentially happen with unexpected event from the 152e28a4053SRui Paulo * driver wrapper. This was seen at least in one case where the 153e28a4053SRui Paulo * driver ended up being set to station mode while hostapd was 154e28a4053SRui Paulo * running, so better make sure we stop processing such an 155e28a4053SRui Paulo * event here. 156e28a4053SRui Paulo */ 157325151a3SRui Paulo wpa_printf(MSG_DEBUG, 158325151a3SRui Paulo "hostapd_notif_assoc: Skip event with no address"); 159e28a4053SRui Paulo return -1; 160e28a4053SRui Paulo } 161*c1d255d3SCy Schubert 162*c1d255d3SCy Schubert if (is_multicast_ether_addr(addr) || 163*c1d255d3SCy Schubert is_zero_ether_addr(addr) || 164*c1d255d3SCy Schubert os_memcmp(addr, hapd->own_addr, ETH_ALEN) == 0) { 165*c1d255d3SCy Schubert /* Do not process any frames with unexpected/invalid SA so that 166*c1d255d3SCy Schubert * we do not add any state for unexpected STA addresses or end 167*c1d255d3SCy Schubert * up sending out frames to unexpected destination. */ 168*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "%s: Invalid SA=" MACSTR 169*c1d255d3SCy Schubert " in received indication - ignore this indication silently", 170*c1d255d3SCy Schubert __func__, MAC2STR(addr)); 171*c1d255d3SCy Schubert return 0; 172*c1d255d3SCy Schubert } 173*c1d255d3SCy Schubert 174f05cddf9SRui Paulo random_add_randomness(addr, ETH_ALEN); 175e28a4053SRui Paulo 176e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 177e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "associated"); 178e28a4053SRui Paulo 179f05cddf9SRui Paulo ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); 180e28a4053SRui Paulo if (elems.wps_ie) { 181e28a4053SRui Paulo ie = elems.wps_ie - 2; 182e28a4053SRui Paulo ielen = elems.wps_ie_len + 2; 183e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); 184e28a4053SRui Paulo } else if (elems.rsn_ie) { 185e28a4053SRui Paulo ie = elems.rsn_ie - 2; 186e28a4053SRui Paulo ielen = elems.rsn_ie_len + 2; 187e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); 188e28a4053SRui Paulo } else if (elems.wpa_ie) { 189e28a4053SRui Paulo ie = elems.wpa_ie - 2; 190e28a4053SRui Paulo ielen = elems.wpa_ie_len + 2; 191e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); 1925b9c547cSRui Paulo #ifdef CONFIG_HS20 1935b9c547cSRui Paulo } else if (elems.osen) { 1945b9c547cSRui Paulo ie = elems.osen - 2; 1955b9c547cSRui Paulo ielen = elems.osen_len + 2; 1965b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq"); 1975b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 198e28a4053SRui Paulo } else { 199e28a4053SRui Paulo ie = NULL; 200e28a4053SRui Paulo ielen = 0; 201325151a3SRui Paulo wpa_printf(MSG_DEBUG, 202325151a3SRui Paulo "STA did not include WPS/RSN/WPA IE in (Re)AssocReq"); 203e28a4053SRui Paulo } 204e28a4053SRui Paulo 205e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 206e28a4053SRui Paulo if (sta) { 2075b9c547cSRui Paulo ap_sta_no_session_timeout(hapd, sta); 208e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 209f05cddf9SRui Paulo 210f05cddf9SRui Paulo /* 211f05cddf9SRui Paulo * Make sure that the previously registered inactivity timer 212f05cddf9SRui Paulo * will not remove the STA immediately. 213f05cddf9SRui Paulo */ 214f05cddf9SRui Paulo sta->timeout_next = STA_NULLFUNC; 215e28a4053SRui Paulo } else { 216e28a4053SRui Paulo sta = ap_sta_add(hapd, addr); 217f05cddf9SRui Paulo if (sta == NULL) { 218f05cddf9SRui Paulo hostapd_drv_sta_disassoc(hapd, addr, 219f05cddf9SRui Paulo WLAN_REASON_DISASSOC_AP_BUSY); 220e28a4053SRui Paulo return -1; 221e28a4053SRui Paulo } 222f05cddf9SRui Paulo } 223f05cddf9SRui Paulo sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 224f05cddf9SRui Paulo 225780fb4a2SCy Schubert /* 226780fb4a2SCy Schubert * ACL configurations to the drivers (implementing AP SME and ACL 227780fb4a2SCy Schubert * offload) without hostapd's knowledge, can result in a disconnection 228780fb4a2SCy Schubert * though the driver accepts the connection. Skip the hostapd check for 229780fb4a2SCy Schubert * ACL if the driver supports ACL offload to avoid potentially 230780fb4a2SCy Schubert * conflicting ACL rules. 231780fb4a2SCy Schubert */ 232780fb4a2SCy Schubert if (hapd->iface->drv_max_acl_mac_addrs == 0 && 233780fb4a2SCy Schubert hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) { 234780fb4a2SCy Schubert wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect", 235780fb4a2SCy Schubert MAC2STR(addr)); 236780fb4a2SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 237780fb4a2SCy Schubert goto fail; 238780fb4a2SCy Schubert } 239780fb4a2SCy Schubert 240f05cddf9SRui Paulo #ifdef CONFIG_P2P 241f05cddf9SRui Paulo if (elems.p2p) { 242f05cddf9SRui Paulo wpabuf_free(sta->p2p_ie); 243f05cddf9SRui Paulo sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 244f05cddf9SRui Paulo P2P_IE_VENDOR_TYPE); 2455b9c547cSRui Paulo if (sta->p2p_ie) 2465b9c547cSRui Paulo p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 247f05cddf9SRui Paulo } 248f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 249f05cddf9SRui Paulo 2505b9c547cSRui Paulo #ifdef NEED_AP_MLME 2515b9c547cSRui Paulo if (elems.ht_capabilities && 2525b9c547cSRui Paulo (hapd->iface->conf->ht_capab & 2535b9c547cSRui Paulo HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 2545b9c547cSRui Paulo struct ieee80211_ht_capabilities *ht_cap = 2555b9c547cSRui Paulo (struct ieee80211_ht_capabilities *) 2565b9c547cSRui Paulo elems.ht_capabilities; 2575b9c547cSRui Paulo 2585b9c547cSRui Paulo if (le_to_host16(ht_cap->ht_capabilities_info) & 2595b9c547cSRui Paulo HT_CAP_INFO_40MHZ_INTOLERANT) 2605b9c547cSRui Paulo ht40_intolerant_add(hapd->iface, sta); 2615b9c547cSRui Paulo } 2625b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 2635b9c547cSRui Paulo 2645b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING 2655b9c547cSRui Paulo if (elems.ext_capab && elems.ext_capab_len > 4) { 2665b9c547cSRui Paulo if (elems.ext_capab[4] & 0x01) 2675b9c547cSRui Paulo sta->qos_map_enabled = 1; 2685b9c547cSRui Paulo } 2695b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */ 2705b9c547cSRui Paulo 271f05cddf9SRui Paulo #ifdef CONFIG_HS20 272f05cddf9SRui Paulo wpabuf_free(sta->hs20_ie); 273f05cddf9SRui Paulo if (elems.hs20 && elems.hs20_len > 4) { 274f05cddf9SRui Paulo sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, 275f05cddf9SRui Paulo elems.hs20_len - 4); 276f05cddf9SRui Paulo } else 277f05cddf9SRui Paulo sta->hs20_ie = NULL; 27885732ac8SCy Schubert 27985732ac8SCy Schubert wpabuf_free(sta->roaming_consortium); 28085732ac8SCy Schubert if (elems.roaming_cons_sel) 28185732ac8SCy Schubert sta->roaming_consortium = wpabuf_alloc_copy( 28285732ac8SCy Schubert elems.roaming_cons_sel + 4, 28385732ac8SCy Schubert elems.roaming_cons_sel_len - 4); 28485732ac8SCy Schubert else 28585732ac8SCy Schubert sta->roaming_consortium = NULL; 286f05cddf9SRui Paulo #endif /* CONFIG_HS20 */ 287e28a4053SRui Paulo 288325151a3SRui Paulo #ifdef CONFIG_FST 289325151a3SRui Paulo wpabuf_free(sta->mb_ies); 290325151a3SRui Paulo if (hapd->iface->fst) 291325151a3SRui Paulo sta->mb_ies = mb_ies_by_info(&elems.mb_ies); 292325151a3SRui Paulo else 293325151a3SRui Paulo sta->mb_ies = NULL; 294325151a3SRui Paulo #endif /* CONFIG_FST */ 295325151a3SRui Paulo 296780fb4a2SCy Schubert mbo_ap_check_sta_assoc(hapd, sta, &elems); 297780fb4a2SCy Schubert 298780fb4a2SCy Schubert ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes, 299780fb4a2SCy Schubert elems.supp_op_classes_len); 300780fb4a2SCy Schubert 301e28a4053SRui Paulo if (hapd->conf->wpa) { 302e28a4053SRui Paulo if (ie == NULL || ielen == 0) { 303f05cddf9SRui Paulo #ifdef CONFIG_WPS 304e28a4053SRui Paulo if (hapd->conf->wps_state) { 305325151a3SRui Paulo wpa_printf(MSG_DEBUG, 306325151a3SRui Paulo "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use"); 307e28a4053SRui Paulo sta->flags |= WLAN_STA_MAYBE_WPS; 308e28a4053SRui Paulo goto skip_wpa_check; 309e28a4053SRui Paulo } 310f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 311e28a4053SRui Paulo 312e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); 31385732ac8SCy Schubert reason = WLAN_REASON_INVALID_IE; 31485732ac8SCy Schubert status = WLAN_STATUS_INVALID_IE; 31585732ac8SCy Schubert goto fail; 316e28a4053SRui Paulo } 317f05cddf9SRui Paulo #ifdef CONFIG_WPS 318e28a4053SRui Paulo if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && 319e28a4053SRui Paulo os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { 320f05cddf9SRui Paulo struct wpabuf *wps; 321325151a3SRui Paulo 322*c1d255d3SCy Schubert if (check_sa_query_need(hapd, sta)) { 323*c1d255d3SCy Schubert status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 324*c1d255d3SCy Schubert 325*c1d255d3SCy Schubert p = hostapd_eid_assoc_comeback_time(hapd, sta, 326*c1d255d3SCy Schubert p); 327*c1d255d3SCy Schubert 328*c1d255d3SCy Schubert hostapd_sta_assoc(hapd, addr, reassoc, status, 329*c1d255d3SCy Schubert buf, p - buf); 330*c1d255d3SCy Schubert return 0; 331*c1d255d3SCy Schubert } 332*c1d255d3SCy Schubert 333e28a4053SRui Paulo sta->flags |= WLAN_STA_WPS; 334f05cddf9SRui Paulo wps = ieee802_11_vendor_ie_concat(ie, ielen, 335f05cddf9SRui Paulo WPS_IE_VENDOR_TYPE); 336f05cddf9SRui Paulo if (wps) { 337f05cddf9SRui Paulo if (wps_is_20(wps)) { 338325151a3SRui Paulo wpa_printf(MSG_DEBUG, 339325151a3SRui Paulo "WPS: STA supports WPS 2.0"); 340f05cddf9SRui Paulo sta->flags |= WLAN_STA_WPS2; 341f05cddf9SRui Paulo } 342f05cddf9SRui Paulo wpabuf_free(wps); 343f05cddf9SRui Paulo } 344e28a4053SRui Paulo goto skip_wpa_check; 345e28a4053SRui Paulo } 346f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 347e28a4053SRui Paulo 348e28a4053SRui Paulo if (sta->wpa_sm == NULL) 349e28a4053SRui Paulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 3505b9c547cSRui Paulo sta->addr, 3515b9c547cSRui Paulo p2p_dev_addr); 352e28a4053SRui Paulo if (sta->wpa_sm == NULL) { 353325151a3SRui Paulo wpa_printf(MSG_ERROR, 354325151a3SRui Paulo "Failed to initialize WPA state machine"); 355e28a4053SRui Paulo return -1; 356e28a4053SRui Paulo } 357e28a4053SRui Paulo res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 3584bc52338SCy Schubert hapd->iface->freq, 359f05cddf9SRui Paulo ie, ielen, 360*c1d255d3SCy Schubert elems.rsnxe ? elems.rsnxe - 2 : NULL, 361*c1d255d3SCy Schubert elems.rsnxe ? elems.rsnxe_len + 2 : 0, 36285732ac8SCy Schubert elems.mdie, elems.mdie_len, 36385732ac8SCy Schubert elems.owe_dh, elems.owe_dh_len); 364*c1d255d3SCy Schubert reason = WLAN_REASON_INVALID_IE; 365*c1d255d3SCy Schubert status = WLAN_STATUS_INVALID_IE; 366*c1d255d3SCy Schubert switch (res) { 367*c1d255d3SCy Schubert case WPA_IE_OK: 368*c1d255d3SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 369*c1d255d3SCy Schubert status = WLAN_STATUS_SUCCESS; 370*c1d255d3SCy Schubert break; 371*c1d255d3SCy Schubert case WPA_INVALID_IE: 372*c1d255d3SCy Schubert reason = WLAN_REASON_INVALID_IE; 373*c1d255d3SCy Schubert status = WLAN_STATUS_INVALID_IE; 374*c1d255d3SCy Schubert break; 375*c1d255d3SCy Schubert case WPA_INVALID_GROUP: 376*c1d255d3SCy Schubert reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; 377*c1d255d3SCy Schubert status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 378*c1d255d3SCy Schubert break; 379*c1d255d3SCy Schubert case WPA_INVALID_PAIRWISE: 380*c1d255d3SCy Schubert reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; 381*c1d255d3SCy Schubert status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 382*c1d255d3SCy Schubert break; 383*c1d255d3SCy Schubert case WPA_INVALID_AKMP: 384*c1d255d3SCy Schubert reason = WLAN_REASON_AKMP_NOT_VALID; 385*c1d255d3SCy Schubert status = WLAN_STATUS_AKMP_NOT_VALID; 386*c1d255d3SCy Schubert break; 387*c1d255d3SCy Schubert case WPA_NOT_ENABLED: 388*c1d255d3SCy Schubert reason = WLAN_REASON_INVALID_IE; 389*c1d255d3SCy Schubert status = WLAN_STATUS_INVALID_IE; 390*c1d255d3SCy Schubert break; 391*c1d255d3SCy Schubert case WPA_ALLOC_FAIL: 392*c1d255d3SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 393*c1d255d3SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE; 394*c1d255d3SCy Schubert break; 395*c1d255d3SCy Schubert case WPA_MGMT_FRAME_PROTECTION_VIOLATION: 396*c1d255d3SCy Schubert reason = WLAN_REASON_INVALID_IE; 397*c1d255d3SCy Schubert status = WLAN_STATUS_INVALID_IE; 398*c1d255d3SCy Schubert break; 399*c1d255d3SCy Schubert case WPA_INVALID_MGMT_GROUP_CIPHER: 400*c1d255d3SCy Schubert reason = WLAN_REASON_CIPHER_SUITE_REJECTED; 401*c1d255d3SCy Schubert status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 402*c1d255d3SCy Schubert break; 403*c1d255d3SCy Schubert case WPA_INVALID_MDIE: 404*c1d255d3SCy Schubert reason = WLAN_REASON_INVALID_MDE; 405*c1d255d3SCy Schubert status = WLAN_STATUS_INVALID_MDIE; 406*c1d255d3SCy Schubert break; 407*c1d255d3SCy Schubert case WPA_INVALID_PROTO: 408*c1d255d3SCy Schubert reason = WLAN_REASON_INVALID_IE; 409*c1d255d3SCy Schubert status = WLAN_STATUS_INVALID_IE; 410*c1d255d3SCy Schubert break; 411*c1d255d3SCy Schubert case WPA_INVALID_PMKID: 412*c1d255d3SCy Schubert reason = WLAN_REASON_INVALID_PMKID; 413*c1d255d3SCy Schubert status = WLAN_STATUS_INVALID_PMKID; 414*c1d255d3SCy Schubert break; 415*c1d255d3SCy Schubert case WPA_DENIED_OTHER_REASON: 416*c1d255d3SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 417*c1d255d3SCy Schubert status = WLAN_STATUS_ASSOC_DENIED_UNSPEC; 418*c1d255d3SCy Schubert break; 419*c1d255d3SCy Schubert } 420*c1d255d3SCy Schubert if (status != WLAN_STATUS_SUCCESS) { 421325151a3SRui Paulo wpa_printf(MSG_DEBUG, 422325151a3SRui Paulo "WPA/RSN information element rejected? (res %u)", 423325151a3SRui Paulo res); 424e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); 425f05cddf9SRui Paulo goto fail; 426f05cddf9SRui Paulo } 427f05cddf9SRui Paulo 428*c1d255d3SCy Schubert if (check_sa_query_need(hapd, sta)) { 429f05cddf9SRui Paulo status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 430f05cddf9SRui Paulo 431f05cddf9SRui Paulo p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 432f05cddf9SRui Paulo 433f05cddf9SRui Paulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, 434f05cddf9SRui Paulo p - buf); 435f05cddf9SRui Paulo return 0; 436f05cddf9SRui Paulo } 437f05cddf9SRui Paulo 438f05cddf9SRui Paulo if (wpa_auth_uses_mfp(sta->wpa_sm)) 439f05cddf9SRui Paulo sta->flags |= WLAN_STA_MFP; 440f05cddf9SRui Paulo else 441f05cddf9SRui Paulo sta->flags &= ~WLAN_STA_MFP; 442f05cddf9SRui Paulo 44385732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 444f05cddf9SRui Paulo if (sta->auth_alg == WLAN_AUTH_FT) { 445f05cddf9SRui Paulo status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, 446f05cddf9SRui Paulo req_ies_len); 447f05cddf9SRui Paulo if (status != WLAN_STATUS_SUCCESS) { 448f05cddf9SRui Paulo if (status == WLAN_STATUS_INVALID_PMKID) 449f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 450f05cddf9SRui Paulo if (status == WLAN_STATUS_INVALID_MDIE) 451f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 452f05cddf9SRui Paulo if (status == WLAN_STATUS_INVALID_FTIE) 453f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 454f05cddf9SRui Paulo goto fail; 455f05cddf9SRui Paulo } 456f05cddf9SRui Paulo } 45785732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 458*c1d255d3SCy Schubert #ifdef CONFIG_SAE 459*c1d255d3SCy Schubert if (hapd->conf->sae_pwe == 2 && 460*c1d255d3SCy Schubert sta->auth_alg == WLAN_AUTH_SAE && 461*c1d255d3SCy Schubert sta->sae && !sta->sae->h2e && 462*c1d255d3SCy Schubert ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, 463*c1d255d3SCy Schubert WLAN_RSNX_CAPAB_SAE_H2E)) { 464*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "SAE: " MACSTR 465*c1d255d3SCy Schubert " indicates support for SAE H2E, but did not use it", 466*c1d255d3SCy Schubert MAC2STR(sta->addr)); 467*c1d255d3SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE; 468*c1d255d3SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 469*c1d255d3SCy Schubert goto fail; 470*c1d255d3SCy Schubert } 471*c1d255d3SCy Schubert #endif /* CONFIG_SAE */ 472e28a4053SRui Paulo } else if (hapd->conf->wps_state) { 473f05cddf9SRui Paulo #ifdef CONFIG_WPS 474f05cddf9SRui Paulo struct wpabuf *wps; 475325151a3SRui Paulo 476f05cddf9SRui Paulo if (req_ies) 477f05cddf9SRui Paulo wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 478f05cddf9SRui Paulo WPS_IE_VENDOR_TYPE); 479f05cddf9SRui Paulo else 480f05cddf9SRui Paulo wps = NULL; 481f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT 482f05cddf9SRui Paulo if (wps && wps_validate_assoc_req(wps) < 0) { 483f05cddf9SRui Paulo reason = WLAN_REASON_INVALID_IE; 484f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_IE; 485f05cddf9SRui Paulo wpabuf_free(wps); 486f05cddf9SRui Paulo goto fail; 487f05cddf9SRui Paulo } 488f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */ 489f05cddf9SRui Paulo if (wps) { 490e28a4053SRui Paulo sta->flags |= WLAN_STA_WPS; 491f05cddf9SRui Paulo if (wps_is_20(wps)) { 492325151a3SRui Paulo wpa_printf(MSG_DEBUG, 493325151a3SRui Paulo "WPS: STA supports WPS 2.0"); 494f05cddf9SRui Paulo sta->flags |= WLAN_STA_WPS2; 495f05cddf9SRui Paulo } 496e28a4053SRui Paulo } else 497e28a4053SRui Paulo sta->flags |= WLAN_STA_MAYBE_WPS; 498f05cddf9SRui Paulo wpabuf_free(wps); 499f05cddf9SRui Paulo #endif /* CONFIG_WPS */ 5005b9c547cSRui Paulo #ifdef CONFIG_HS20 5015b9c547cSRui Paulo } else if (hapd->conf->osen) { 5025b9c547cSRui Paulo if (elems.osen == NULL) { 5035b9c547cSRui Paulo hostapd_logger( 5045b9c547cSRui Paulo hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 5055b9c547cSRui Paulo HOSTAPD_LEVEL_INFO, 5065b9c547cSRui Paulo "No HS 2.0 OSEN element in association request"); 5075b9c547cSRui Paulo return WLAN_STATUS_INVALID_IE; 5085b9c547cSRui Paulo } 5095b9c547cSRui Paulo 5105b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); 5115b9c547cSRui Paulo if (sta->wpa_sm == NULL) 5125b9c547cSRui Paulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 5135b9c547cSRui Paulo sta->addr, NULL); 5145b9c547cSRui Paulo if (sta->wpa_sm == NULL) { 515325151a3SRui Paulo wpa_printf(MSG_WARNING, 516325151a3SRui Paulo "Failed to initialize WPA state machine"); 5175b9c547cSRui Paulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 5185b9c547cSRui Paulo } 5195b9c547cSRui Paulo if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, 5205b9c547cSRui Paulo elems.osen - 2, elems.osen_len + 2) < 0) 5215b9c547cSRui Paulo return WLAN_STATUS_INVALID_IE; 5225b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 523e28a4053SRui Paulo } 524*c1d255d3SCy Schubert #ifdef CONFIG_WPS 525*c1d255d3SCy Schubert skip_wpa_check: 526*c1d255d3SCy Schubert #endif /* CONFIG_WPS */ 527780fb4a2SCy Schubert 528780fb4a2SCy Schubert #ifdef CONFIG_MBO 529780fb4a2SCy Schubert if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && 530780fb4a2SCy Schubert elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && 531780fb4a2SCy Schubert hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 532780fb4a2SCy Schubert wpa_printf(MSG_INFO, 533780fb4a2SCy Schubert "MBO: Reject WPA2 association without PMF"); 534780fb4a2SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 535780fb4a2SCy Schubert } 536780fb4a2SCy Schubert #endif /* CONFIG_MBO */ 537780fb4a2SCy Schubert 53885732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 539f05cddf9SRui Paulo p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), 540*c1d255d3SCy Schubert sta->auth_alg, req_ies, req_ies_len, 541*c1d255d3SCy Schubert !elems.rsnxe); 54285732ac8SCy Schubert if (!p) { 54385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs"); 54485732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 54585732ac8SCy Schubert } 54685732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 547f05cddf9SRui Paulo 54885732ac8SCy Schubert #ifdef CONFIG_FILS 54985732ac8SCy Schubert if (sta->auth_alg == WLAN_AUTH_FILS_SK || 55085732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 55185732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) { 55285732ac8SCy Schubert int delay_assoc = 0; 55385732ac8SCy Schubert 55485732ac8SCy Schubert if (!req_ies) 55585732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 55685732ac8SCy Schubert 55785732ac8SCy Schubert if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies, 55885732ac8SCy Schubert req_ies_len, 55985732ac8SCy Schubert sta->fils_session)) { 56085732ac8SCy Schubert wpa_printf(MSG_DEBUG, 56185732ac8SCy Schubert "FILS: Session validation failed"); 56285732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 56385732ac8SCy Schubert } 56485732ac8SCy Schubert 56585732ac8SCy Schubert res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies, 56685732ac8SCy Schubert req_ies_len); 56785732ac8SCy Schubert if (res < 0) { 56885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 56985732ac8SCy Schubert "FILS: Key Confirm validation failed"); 57085732ac8SCy Schubert return WLAN_STATUS_UNSPECIFIED_FAILURE; 57185732ac8SCy Schubert } 57285732ac8SCy Schubert 57385732ac8SCy Schubert if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) { 57485732ac8SCy Schubert wpa_printf(MSG_DEBUG, 57585732ac8SCy Schubert "FILS: Delaying Assoc Response (HLP)"); 57685732ac8SCy Schubert delay_assoc = 1; 57785732ac8SCy Schubert } else { 57885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 57985732ac8SCy Schubert "FILS: Going ahead with Assoc Response (no HLP)"); 58085732ac8SCy Schubert } 58185732ac8SCy Schubert 58285732ac8SCy Schubert if (sta) { 58385732ac8SCy Schubert wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup"); 58485732ac8SCy Schubert eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 58585732ac8SCy Schubert os_free(sta->fils_pending_assoc_req); 58685732ac8SCy Schubert sta->fils_pending_assoc_req = NULL; 58785732ac8SCy Schubert sta->fils_pending_assoc_req_len = 0; 58885732ac8SCy Schubert wpabuf_free(sta->fils_hlp_resp); 58985732ac8SCy Schubert sta->fils_hlp_resp = NULL; 59085732ac8SCy Schubert sta->fils_drv_assoc_finish = 0; 59185732ac8SCy Schubert } 59285732ac8SCy Schubert 59385732ac8SCy Schubert if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) { 59485732ac8SCy Schubert u8 *req_tmp; 59585732ac8SCy Schubert 59685732ac8SCy Schubert req_tmp = os_malloc(req_ies_len); 59785732ac8SCy Schubert if (!req_tmp) { 59885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 59985732ac8SCy Schubert "FILS: buffer allocation failed for assoc req"); 60085732ac8SCy Schubert goto fail; 60185732ac8SCy Schubert } 60285732ac8SCy Schubert os_memcpy(req_tmp, req_ies, req_ies_len); 60385732ac8SCy Schubert sta->fils_pending_assoc_req = req_tmp; 60485732ac8SCy Schubert sta->fils_pending_assoc_req_len = req_ies_len; 60585732ac8SCy Schubert sta->fils_pending_assoc_is_reassoc = reassoc; 60685732ac8SCy Schubert sta->fils_drv_assoc_finish = 1; 60785732ac8SCy Schubert wpa_printf(MSG_DEBUG, 60885732ac8SCy Schubert "FILS: Waiting for HLP processing before sending (Re)Association Response frame to " 60985732ac8SCy Schubert MACSTR, MAC2STR(sta->addr)); 61085732ac8SCy Schubert eloop_register_timeout( 61185732ac8SCy Schubert 0, hapd->conf->fils_hlp_wait_time * 1024, 61285732ac8SCy Schubert fils_hlp_timeout, hapd, sta); 61385732ac8SCy Schubert return 0; 61485732ac8SCy Schubert } 61585732ac8SCy Schubert p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, 61685732ac8SCy Schubert elems.fils_session, 61785732ac8SCy Schubert sta->fils_hlp_resp); 61885732ac8SCy Schubert wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)", 61985732ac8SCy Schubert buf, p - buf); 62085732ac8SCy Schubert } 62185732ac8SCy Schubert #endif /* CONFIG_FILS */ 62285732ac8SCy Schubert 62385732ac8SCy Schubert #ifdef CONFIG_OWE 62485732ac8SCy Schubert if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 62585732ac8SCy Schubert wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && 62685732ac8SCy Schubert elems.owe_dh) { 62785732ac8SCy Schubert u8 *npos; 628*c1d255d3SCy Schubert u16 ret_status; 62985732ac8SCy Schubert 63085732ac8SCy Schubert npos = owe_assoc_req_process(hapd, sta, 63185732ac8SCy Schubert elems.owe_dh, elems.owe_dh_len, 63285732ac8SCy Schubert p, sizeof(buf) - (p - buf), 633*c1d255d3SCy Schubert &ret_status); 634*c1d255d3SCy Schubert status = ret_status; 63585732ac8SCy Schubert if (npos) 63685732ac8SCy Schubert p = npos; 637*c1d255d3SCy Schubert 63885732ac8SCy Schubert if (!npos && 639*c1d255d3SCy Schubert status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { 640*c1d255d3SCy Schubert hostapd_sta_assoc(hapd, addr, reassoc, ret_status, buf, 64185732ac8SCy Schubert p - buf); 64285732ac8SCy Schubert return 0; 64385732ac8SCy Schubert } 64485732ac8SCy Schubert 645*c1d255d3SCy Schubert if (!npos || status != WLAN_STATUS_SUCCESS) 64685732ac8SCy Schubert goto fail; 64785732ac8SCy Schubert } 64885732ac8SCy Schubert #endif /* CONFIG_OWE */ 64985732ac8SCy Schubert 6504bc52338SCy Schubert #ifdef CONFIG_DPP2 6514bc52338SCy Schubert dpp_pfs_free(sta->dpp_pfs); 6524bc52338SCy Schubert sta->dpp_pfs = NULL; 6534bc52338SCy Schubert 6544bc52338SCy Schubert if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && 6554bc52338SCy Schubert hapd->conf->dpp_netaccesskey && sta->wpa_sm && 6564bc52338SCy Schubert wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && 6574bc52338SCy Schubert elems.owe_dh) { 6584bc52338SCy Schubert sta->dpp_pfs = dpp_pfs_init( 6594bc52338SCy Schubert wpabuf_head(hapd->conf->dpp_netaccesskey), 6604bc52338SCy Schubert wpabuf_len(hapd->conf->dpp_netaccesskey)); 6614bc52338SCy Schubert if (!sta->dpp_pfs) { 6624bc52338SCy Schubert wpa_printf(MSG_DEBUG, 6634bc52338SCy Schubert "DPP: Could not initialize PFS"); 6644bc52338SCy Schubert /* Try to continue without PFS */ 6654bc52338SCy Schubert goto pfs_fail; 6664bc52338SCy Schubert } 6674bc52338SCy Schubert 6684bc52338SCy Schubert if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, 6694bc52338SCy Schubert elems.owe_dh_len) < 0) { 6704bc52338SCy Schubert dpp_pfs_free(sta->dpp_pfs); 6714bc52338SCy Schubert sta->dpp_pfs = NULL; 6724bc52338SCy Schubert reason = WLAN_REASON_UNSPECIFIED; 6734bc52338SCy Schubert goto fail; 6744bc52338SCy Schubert } 6754bc52338SCy Schubert } 6764bc52338SCy Schubert 6774bc52338SCy Schubert wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? 6784bc52338SCy Schubert sta->dpp_pfs->secret : NULL); 6794bc52338SCy Schubert pfs_fail: 6804bc52338SCy Schubert #endif /* CONFIG_DPP2 */ 6814bc52338SCy Schubert 682*c1d255d3SCy Schubert if (elems.rrm_enabled && 683*c1d255d3SCy Schubert elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa)) 684*c1d255d3SCy Schubert os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled, 685*c1d255d3SCy Schubert sizeof(sta->rrm_enabled_capa)); 686*c1d255d3SCy Schubert 68785732ac8SCy Schubert #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE) 688f05cddf9SRui Paulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 6895b9c547cSRui Paulo 69085732ac8SCy Schubert if (sta->auth_alg == WLAN_AUTH_FT || 69185732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK || 69285732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 69385732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) 6945b9c547cSRui Paulo ap_sta_set_authorized(hapd, sta, 1); 69585732ac8SCy Schubert #else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ 696f05cddf9SRui Paulo /* Keep compiler silent about unused variables */ 697f05cddf9SRui Paulo if (status) { 698f05cddf9SRui Paulo } 69985732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ 700e28a4053SRui Paulo 701e28a4053SRui Paulo new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 702e28a4053SRui Paulo sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 7035b9c547cSRui Paulo sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 7045b9c547cSRui Paulo 7055b9c547cSRui Paulo hostapd_set_sta_flags(hapd, sta); 706f05cddf9SRui Paulo 707f05cddf9SRui Paulo if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) 708f05cddf9SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 70985732ac8SCy Schubert #ifdef CONFIG_FILS 71085732ac8SCy Schubert else if (sta->auth_alg == WLAN_AUTH_FILS_SK || 71185732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 71285732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) 71385732ac8SCy Schubert wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); 71485732ac8SCy Schubert #endif /* CONFIG_FILS */ 715f05cddf9SRui Paulo else 716e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 717e28a4053SRui Paulo 718e28a4053SRui Paulo hostapd_new_assoc_sta(hapd, sta, !new_assoc); 719e28a4053SRui Paulo 720e28a4053SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 721e28a4053SRui Paulo 722f05cddf9SRui Paulo #ifdef CONFIG_P2P 723f05cddf9SRui Paulo if (req_ies) { 724f05cddf9SRui Paulo p2p_group_notif_assoc(hapd->p2p_group, sta->addr, 725f05cddf9SRui Paulo req_ies, req_ies_len); 726f05cddf9SRui Paulo } 727f05cddf9SRui Paulo #endif /* CONFIG_P2P */ 728f05cddf9SRui Paulo 729e28a4053SRui Paulo return 0; 730f05cddf9SRui Paulo 731f05cddf9SRui Paulo fail: 73285732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 733*c1d255d3SCy Schubert if (status >= 0) 734f05cddf9SRui Paulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 73585732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 736f05cddf9SRui Paulo hostapd_drv_sta_disassoc(hapd, sta->addr, reason); 737f05cddf9SRui Paulo ap_free_sta(hapd, sta); 738f05cddf9SRui Paulo return -1; 739e28a4053SRui Paulo } 740e28a4053SRui Paulo 741e28a4053SRui Paulo 742e28a4053SRui Paulo void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) 743e28a4053SRui Paulo { 744e28a4053SRui Paulo struct sta_info *sta; 745e28a4053SRui Paulo 746f05cddf9SRui Paulo if (addr == NULL) { 747f05cddf9SRui Paulo /* 748f05cddf9SRui Paulo * This could potentially happen with unexpected event from the 749f05cddf9SRui Paulo * driver wrapper. This was seen at least in one case where the 750f05cddf9SRui Paulo * driver ended up reporting a station mode event while hostapd 751f05cddf9SRui Paulo * was running, so better make sure we stop processing such an 752f05cddf9SRui Paulo * event here. 753f05cddf9SRui Paulo */ 754325151a3SRui Paulo wpa_printf(MSG_DEBUG, 755325151a3SRui Paulo "hostapd_notif_disassoc: Skip event with no address"); 756f05cddf9SRui Paulo return; 757f05cddf9SRui Paulo } 758f05cddf9SRui Paulo 759e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 760e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, "disassociated"); 761e28a4053SRui Paulo 762e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 763e28a4053SRui Paulo if (sta == NULL) { 764325151a3SRui Paulo wpa_printf(MSG_DEBUG, 765325151a3SRui Paulo "Disassociation notification for unknown STA " 766325151a3SRui Paulo MACSTR, MAC2STR(addr)); 767e28a4053SRui Paulo return; 768e28a4053SRui Paulo } 769e28a4053SRui Paulo 770f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 771e28a4053SRui Paulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 772*c1d255d3SCy Schubert hostapd_set_sta_flags(hapd, sta); 773e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 774e28a4053SRui Paulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 775e28a4053SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 776e28a4053SRui Paulo ap_free_sta(hapd, sta); 777e28a4053SRui Paulo } 778e28a4053SRui Paulo 779e28a4053SRui Paulo 780f05cddf9SRui Paulo void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) 781f05cddf9SRui Paulo { 782f05cddf9SRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 783f05cddf9SRui Paulo 78485732ac8SCy Schubert if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer) 785f05cddf9SRui Paulo return; 786f05cddf9SRui Paulo 787f05cddf9SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 788325151a3SRui Paulo HOSTAPD_LEVEL_INFO, 789325151a3SRui Paulo "disconnected due to excessive missing ACKs"); 790f05cddf9SRui Paulo hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); 791f05cddf9SRui Paulo ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); 792f05cddf9SRui Paulo } 793f05cddf9SRui Paulo 794f05cddf9SRui Paulo 79585732ac8SCy Schubert void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, 79685732ac8SCy Schubert enum smps_mode smps_mode, 79785732ac8SCy Schubert enum chan_width chan_width, u8 rx_nss) 79885732ac8SCy Schubert { 79985732ac8SCy Schubert struct sta_info *sta = ap_get_sta(hapd, addr); 80085732ac8SCy Schubert const char *txt; 80185732ac8SCy Schubert 80285732ac8SCy Schubert if (!sta) 80385732ac8SCy Schubert return; 80485732ac8SCy Schubert 80585732ac8SCy Schubert switch (smps_mode) { 80685732ac8SCy Schubert case SMPS_AUTOMATIC: 80785732ac8SCy Schubert txt = "automatic"; 80885732ac8SCy Schubert break; 80985732ac8SCy Schubert case SMPS_OFF: 81085732ac8SCy Schubert txt = "off"; 81185732ac8SCy Schubert break; 81285732ac8SCy Schubert case SMPS_DYNAMIC: 81385732ac8SCy Schubert txt = "dynamic"; 81485732ac8SCy Schubert break; 81585732ac8SCy Schubert case SMPS_STATIC: 81685732ac8SCy Schubert txt = "static"; 81785732ac8SCy Schubert break; 81885732ac8SCy Schubert default: 81985732ac8SCy Schubert txt = NULL; 82085732ac8SCy Schubert break; 82185732ac8SCy Schubert } 82285732ac8SCy Schubert if (txt) { 82385732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED 82485732ac8SCy Schubert MACSTR " %s", MAC2STR(addr), txt); 82585732ac8SCy Schubert } 82685732ac8SCy Schubert 82785732ac8SCy Schubert switch (chan_width) { 82885732ac8SCy Schubert case CHAN_WIDTH_20_NOHT: 82985732ac8SCy Schubert txt = "20(no-HT)"; 83085732ac8SCy Schubert break; 83185732ac8SCy Schubert case CHAN_WIDTH_20: 83285732ac8SCy Schubert txt = "20"; 83385732ac8SCy Schubert break; 83485732ac8SCy Schubert case CHAN_WIDTH_40: 83585732ac8SCy Schubert txt = "40"; 83685732ac8SCy Schubert break; 83785732ac8SCy Schubert case CHAN_WIDTH_80: 83885732ac8SCy Schubert txt = "80"; 83985732ac8SCy Schubert break; 84085732ac8SCy Schubert case CHAN_WIDTH_80P80: 84185732ac8SCy Schubert txt = "80+80"; 84285732ac8SCy Schubert break; 84385732ac8SCy Schubert case CHAN_WIDTH_160: 84485732ac8SCy Schubert txt = "160"; 84585732ac8SCy Schubert break; 84685732ac8SCy Schubert default: 84785732ac8SCy Schubert txt = NULL; 84885732ac8SCy Schubert break; 84985732ac8SCy Schubert } 85085732ac8SCy Schubert if (txt) { 85185732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED 85285732ac8SCy Schubert MACSTR " %s", MAC2STR(addr), txt); 85385732ac8SCy Schubert } 85485732ac8SCy Schubert 85585732ac8SCy Schubert if (rx_nss != 0xff) { 85685732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED 85785732ac8SCy Schubert MACSTR " %d", MAC2STR(addr), rx_nss); 85885732ac8SCy Schubert } 85985732ac8SCy Schubert } 86085732ac8SCy Schubert 86185732ac8SCy Schubert 862f05cddf9SRui Paulo void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, 863206b73d0SCy Schubert int offset, int width, int cf1, int cf2, 864206b73d0SCy Schubert int finished) 865f05cddf9SRui Paulo { 866f05cddf9SRui Paulo #ifdef NEED_AP_MLME 867780fb4a2SCy Schubert int channel, chwidth, is_dfs; 868780fb4a2SCy Schubert u8 seg0_idx = 0, seg1_idx = 0; 8694bc52338SCy Schubert size_t i; 870f05cddf9SRui Paulo 871f05cddf9SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 8725b9c547cSRui Paulo HOSTAPD_LEVEL_INFO, 873*c1d255d3SCy Schubert "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", 874206b73d0SCy Schubert finished ? "had" : "starting", 875*c1d255d3SCy Schubert freq, ht, hapd->iconf->ch_switch_vht_config, 876*c1d255d3SCy Schubert hapd->iconf->ch_switch_he_config, offset, 87785732ac8SCy Schubert width, channel_width_to_string(width), cf1, cf2); 878f05cddf9SRui Paulo 879206b73d0SCy Schubert if (!hapd->iface->current_mode) { 880206b73d0SCy Schubert hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 881206b73d0SCy Schubert HOSTAPD_LEVEL_WARNING, 882206b73d0SCy Schubert "ignore channel switch since the interface is not yet ready"); 883206b73d0SCy Schubert return; 884206b73d0SCy Schubert } 885206b73d0SCy Schubert 886f05cddf9SRui Paulo hapd->iface->freq = freq; 887f05cddf9SRui Paulo 888f05cddf9SRui Paulo channel = hostapd_hw_get_channel(hapd, freq); 889f05cddf9SRui Paulo if (!channel) { 890f05cddf9SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 891325151a3SRui Paulo HOSTAPD_LEVEL_WARNING, 892325151a3SRui Paulo "driver switched to bad channel!"); 893f05cddf9SRui Paulo return; 894f05cddf9SRui Paulo } 895f05cddf9SRui Paulo 8965b9c547cSRui Paulo switch (width) { 8975b9c547cSRui Paulo case CHAN_WIDTH_80: 898206b73d0SCy Schubert chwidth = CHANWIDTH_80MHZ; 8995b9c547cSRui Paulo break; 9005b9c547cSRui Paulo case CHAN_WIDTH_80P80: 901206b73d0SCy Schubert chwidth = CHANWIDTH_80P80MHZ; 9025b9c547cSRui Paulo break; 9035b9c547cSRui Paulo case CHAN_WIDTH_160: 904206b73d0SCy Schubert chwidth = CHANWIDTH_160MHZ; 9055b9c547cSRui Paulo break; 9065b9c547cSRui Paulo case CHAN_WIDTH_20_NOHT: 9075b9c547cSRui Paulo case CHAN_WIDTH_20: 9085b9c547cSRui Paulo case CHAN_WIDTH_40: 9095b9c547cSRui Paulo default: 910206b73d0SCy Schubert chwidth = CHANWIDTH_USE_HT; 9115b9c547cSRui Paulo break; 9125b9c547cSRui Paulo } 9135b9c547cSRui Paulo 9145b9c547cSRui Paulo switch (hapd->iface->current_mode->mode) { 9155b9c547cSRui Paulo case HOSTAPD_MODE_IEEE80211A: 916*c1d255d3SCy Schubert if (cf1 == 5935) 917*c1d255d3SCy Schubert seg0_idx = (cf1 - 5925) / 5; 918*c1d255d3SCy Schubert else if (cf1 > 5950) 919*c1d255d3SCy Schubert seg0_idx = (cf1 - 5950) / 5; 920*c1d255d3SCy Schubert else if (cf1 > 5000) 9215b9c547cSRui Paulo seg0_idx = (cf1 - 5000) / 5; 922*c1d255d3SCy Schubert 923*c1d255d3SCy Schubert if (cf2 == 5935) 924*c1d255d3SCy Schubert seg1_idx = (cf2 - 5925) / 5; 925*c1d255d3SCy Schubert else if (cf2 > 5950) 926*c1d255d3SCy Schubert seg1_idx = (cf2 - 5950) / 5; 927*c1d255d3SCy Schubert else if (cf2 > 5000) 9285b9c547cSRui Paulo seg1_idx = (cf2 - 5000) / 5; 9295b9c547cSRui Paulo break; 9305b9c547cSRui Paulo default: 931780fb4a2SCy Schubert ieee80211_freq_to_chan(cf1, &seg0_idx); 932780fb4a2SCy Schubert ieee80211_freq_to_chan(cf2, &seg1_idx); 9335b9c547cSRui Paulo break; 9345b9c547cSRui Paulo } 9355b9c547cSRui Paulo 936f05cddf9SRui Paulo hapd->iconf->channel = channel; 937f05cddf9SRui Paulo hapd->iconf->ieee80211n = ht; 93885732ac8SCy Schubert if (!ht) { 9395b9c547cSRui Paulo hapd->iconf->ieee80211ac = 0; 94085732ac8SCy Schubert } else if (hapd->iconf->ch_switch_vht_config) { 94185732ac8SCy Schubert /* CHAN_SWITCH VHT config */ 94285732ac8SCy Schubert if (hapd->iconf->ch_switch_vht_config & 94385732ac8SCy Schubert CH_SWITCH_VHT_ENABLED) 94485732ac8SCy Schubert hapd->iconf->ieee80211ac = 1; 94585732ac8SCy Schubert else if (hapd->iconf->ch_switch_vht_config & 94685732ac8SCy Schubert CH_SWITCH_VHT_DISABLED) 94785732ac8SCy Schubert hapd->iconf->ieee80211ac = 0; 948*c1d255d3SCy Schubert } else if (hapd->iconf->ch_switch_he_config) { 949*c1d255d3SCy Schubert /* CHAN_SWITCH HE config */ 950*c1d255d3SCy Schubert if (hapd->iconf->ch_switch_he_config & 951*c1d255d3SCy Schubert CH_SWITCH_HE_ENABLED) 952*c1d255d3SCy Schubert hapd->iconf->ieee80211ax = 1; 953*c1d255d3SCy Schubert else if (hapd->iconf->ch_switch_he_config & 954*c1d255d3SCy Schubert CH_SWITCH_HE_DISABLED) 955*c1d255d3SCy Schubert hapd->iconf->ieee80211ax = 0; 95685732ac8SCy Schubert } 95785732ac8SCy Schubert hapd->iconf->ch_switch_vht_config = 0; 958*c1d255d3SCy Schubert hapd->iconf->ch_switch_he_config = 0; 95985732ac8SCy Schubert 960f05cddf9SRui Paulo hapd->iconf->secondary_channel = offset; 961206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, chwidth); 962206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx); 963206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx); 964*c1d255d3SCy Schubert if (hapd->iconf->ieee80211ac) { 965*c1d255d3SCy Schubert hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK; 966*c1d255d3SCy Schubert if (chwidth == CHANWIDTH_160MHZ) 967*c1d255d3SCy Schubert hapd->iconf->vht_capab |= 968*c1d255d3SCy Schubert VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; 969*c1d255d3SCy Schubert else if (chwidth == CHANWIDTH_80P80MHZ) 970*c1d255d3SCy Schubert hapd->iconf->vht_capab |= 971*c1d255d3SCy Schubert VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; 972*c1d255d3SCy Schubert } 9735b9c547cSRui Paulo 97485732ac8SCy Schubert is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features, 97585732ac8SCy Schubert hapd->iface->num_hw_features); 9765b9c547cSRui Paulo 977206b73d0SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, 978206b73d0SCy Schubert "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d", 979206b73d0SCy Schubert finished ? WPA_EVENT_CHANNEL_SWITCH : 980206b73d0SCy Schubert WPA_EVENT_CHANNEL_SWITCH_STARTED, 981206b73d0SCy Schubert freq, ht, offset, channel_width_to_string(width), 982206b73d0SCy Schubert cf1, cf2, is_dfs); 983206b73d0SCy Schubert if (!finished) 984206b73d0SCy Schubert return; 985206b73d0SCy Schubert 9865b9c547cSRui Paulo if (hapd->csa_in_progress && 9875b9c547cSRui Paulo freq == hapd->cs_freq_params.freq) { 9885b9c547cSRui Paulo hostapd_cleanup_cs_params(hapd); 9895b9c547cSRui Paulo ieee802_11_set_beacon(hapd); 9905b9c547cSRui Paulo 9915b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 9925b9c547cSRui Paulo "freq=%d dfs=%d", freq, is_dfs); 9935b9c547cSRui Paulo } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { 9945b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 9955b9c547cSRui Paulo "freq=%d dfs=%d", freq, is_dfs); 996*c1d255d3SCy Schubert } else if (is_dfs && 997*c1d255d3SCy Schubert hostapd_is_dfs_required(hapd->iface) && 998*c1d255d3SCy Schubert !hostapd_is_dfs_chan_available(hapd->iface) && 999*c1d255d3SCy Schubert !hapd->iface->cac_started) { 1000*c1d255d3SCy Schubert hostapd_disable_iface(hapd->iface); 1001*c1d255d3SCy Schubert hostapd_enable_iface(hapd->iface); 10025b9c547cSRui Paulo } 10034bc52338SCy Schubert 10044bc52338SCy Schubert for (i = 0; i < hapd->iface->num_bss; i++) 10054bc52338SCy Schubert hostapd_neighbor_set_own_report(hapd->iface->bss[i]); 1006*c1d255d3SCy Schubert 1007*c1d255d3SCy Schubert #ifdef CONFIG_OCV 1008*c1d255d3SCy Schubert if (hapd->conf->ocv) { 1009*c1d255d3SCy Schubert struct sta_info *sta; 1010*c1d255d3SCy Schubert bool check_sa_query = false; 1011*c1d255d3SCy Schubert 1012*c1d255d3SCy Schubert for (sta = hapd->sta_list; sta; sta = sta->next) { 1013*c1d255d3SCy Schubert if (wpa_auth_uses_ocv(sta->wpa_sm) && 1014*c1d255d3SCy Schubert !(sta->flags & WLAN_STA_WNM_SLEEP_MODE)) { 1015*c1d255d3SCy Schubert sta->post_csa_sa_query = 1; 1016*c1d255d3SCy Schubert check_sa_query = true; 1017*c1d255d3SCy Schubert } 1018*c1d255d3SCy Schubert } 1019*c1d255d3SCy Schubert 1020*c1d255d3SCy Schubert if (check_sa_query) { 1021*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1022*c1d255d3SCy Schubert "OCV: Check post-CSA SA Query initiation in 15 seconds"); 1023*c1d255d3SCy Schubert eloop_register_timeout(15, 0, 1024*c1d255d3SCy Schubert hostapd_ocv_check_csa_sa_query, 1025*c1d255d3SCy Schubert hapd, NULL); 1026*c1d255d3SCy Schubert } 1027*c1d255d3SCy Schubert } 1028*c1d255d3SCy Schubert #endif /* CONFIG_OCV */ 1029f05cddf9SRui Paulo #endif /* NEED_AP_MLME */ 1030f05cddf9SRui Paulo } 1031f05cddf9SRui Paulo 1032f05cddf9SRui Paulo 10335b9c547cSRui Paulo void hostapd_event_connect_failed_reason(struct hostapd_data *hapd, 10345b9c547cSRui Paulo const u8 *addr, int reason_code) 10355b9c547cSRui Paulo { 10365b9c547cSRui Paulo switch (reason_code) { 10375b9c547cSRui Paulo case MAX_CLIENT_REACHED: 10385b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR, 10395b9c547cSRui Paulo MAC2STR(addr)); 10405b9c547cSRui Paulo break; 10415b9c547cSRui Paulo case BLOCKED_CLIENT: 10425b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR, 10435b9c547cSRui Paulo MAC2STR(addr)); 10445b9c547cSRui Paulo break; 10455b9c547cSRui Paulo } 10465b9c547cSRui Paulo } 10475b9c547cSRui Paulo 10485b9c547cSRui Paulo 10495b9c547cSRui Paulo #ifdef CONFIG_ACS 1050780fb4a2SCy Schubert void hostapd_acs_channel_selected(struct hostapd_data *hapd, 1051325151a3SRui Paulo struct acs_selected_channels *acs_res) 10525b9c547cSRui Paulo { 1053325151a3SRui Paulo int ret, i; 1054780fb4a2SCy Schubert int err = 0; 1055*c1d255d3SCy Schubert struct hostapd_channel_data *pri_chan; 10565b9c547cSRui Paulo 10575b9c547cSRui Paulo if (hapd->iconf->channel) { 10585b9c547cSRui Paulo wpa_printf(MSG_INFO, "ACS: Channel was already set to %d", 10595b9c547cSRui Paulo hapd->iconf->channel); 10605b9c547cSRui Paulo return; 10615b9c547cSRui Paulo } 10625b9c547cSRui Paulo 1063*c1d255d3SCy Schubert hapd->iface->freq = acs_res->pri_freq; 1064*c1d255d3SCy Schubert 1065325151a3SRui Paulo if (!hapd->iface->current_mode) { 1066325151a3SRui Paulo for (i = 0; i < hapd->iface->num_hw_features; i++) { 1067325151a3SRui Paulo struct hostapd_hw_modes *mode = 1068325151a3SRui Paulo &hapd->iface->hw_features[i]; 10695b9c547cSRui Paulo 1070325151a3SRui Paulo if (mode->mode == acs_res->hw_mode) { 1071*c1d255d3SCy Schubert if (hapd->iface->freq > 0 && 1072*c1d255d3SCy Schubert !hw_get_chan(mode->mode, 1073*c1d255d3SCy Schubert hapd->iface->freq, 1074*c1d255d3SCy Schubert hapd->iface->hw_features, 1075*c1d255d3SCy Schubert hapd->iface->num_hw_features)) 1076*c1d255d3SCy Schubert continue; 1077325151a3SRui Paulo hapd->iface->current_mode = mode; 1078325151a3SRui Paulo break; 1079325151a3SRui Paulo } 1080325151a3SRui Paulo } 1081325151a3SRui Paulo if (!hapd->iface->current_mode) { 1082325151a3SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 1083325151a3SRui Paulo HOSTAPD_LEVEL_WARNING, 1084325151a3SRui Paulo "driver selected to bad hw_mode"); 1085780fb4a2SCy Schubert err = 1; 1086780fb4a2SCy Schubert goto out; 1087325151a3SRui Paulo } 1088325151a3SRui Paulo } 1089325151a3SRui Paulo 1090*c1d255d3SCy Schubert if (!acs_res->pri_freq) { 10915b9c547cSRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 10925b9c547cSRui Paulo HOSTAPD_LEVEL_WARNING, 10935b9c547cSRui Paulo "driver switched to bad channel"); 1094780fb4a2SCy Schubert err = 1; 1095780fb4a2SCy Schubert goto out; 10965b9c547cSRui Paulo } 1097*c1d255d3SCy Schubert pri_chan = hw_get_channel_freq(hapd->iface->current_mode->mode, 1098*c1d255d3SCy Schubert acs_res->pri_freq, NULL, 1099*c1d255d3SCy Schubert hapd->iface->hw_features, 1100*c1d255d3SCy Schubert hapd->iface->num_hw_features); 1101*c1d255d3SCy Schubert if (!pri_chan) { 1102*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, 1103*c1d255d3SCy Schubert "ACS: Could not determine primary channel number from pri_freq %u", 1104*c1d255d3SCy Schubert acs_res->pri_freq); 1105*c1d255d3SCy Schubert err = 1; 1106*c1d255d3SCy Schubert goto out; 1107*c1d255d3SCy Schubert } 11085b9c547cSRui Paulo 1109*c1d255d3SCy Schubert hapd->iconf->channel = pri_chan->chan; 1110325151a3SRui Paulo hapd->iconf->acs = 1; 11115b9c547cSRui Paulo 1112*c1d255d3SCy Schubert if (acs_res->sec_freq == 0) 11135b9c547cSRui Paulo hapd->iconf->secondary_channel = 0; 1114*c1d255d3SCy Schubert else if (acs_res->sec_freq < acs_res->pri_freq) 11155b9c547cSRui Paulo hapd->iconf->secondary_channel = -1; 1116*c1d255d3SCy Schubert else if (acs_res->sec_freq > acs_res->pri_freq) 11175b9c547cSRui Paulo hapd->iconf->secondary_channel = 1; 11185b9c547cSRui Paulo else { 11195b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Invalid secondary channel!"); 1120780fb4a2SCy Schubert err = 1; 1121780fb4a2SCy Schubert goto out; 11225b9c547cSRui Paulo } 11235b9c547cSRui Paulo 1124*c1d255d3SCy Schubert hapd->iconf->edmg_channel = acs_res->edmg_channel; 1125*c1d255d3SCy Schubert 1126206b73d0SCy Schubert if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) { 1127325151a3SRui Paulo /* set defaults for backwards compatibility */ 1128206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); 1129206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0); 1130206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT); 1131*c1d255d3SCy Schubert if (acs_res->ch_width == 40) { 1132*c1d255d3SCy Schubert if (is_6ghz_freq(acs_res->pri_freq)) 1133*c1d255d3SCy Schubert hostapd_set_oper_centr_freq_seg0_idx( 1134*c1d255d3SCy Schubert hapd->iconf, 1135*c1d255d3SCy Schubert acs_res->vht_seg0_center_ch); 1136*c1d255d3SCy Schubert } else if (acs_res->ch_width == 80) { 1137206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg0_idx( 1138206b73d0SCy Schubert hapd->iconf, acs_res->vht_seg0_center_ch); 1139325151a3SRui Paulo if (acs_res->vht_seg1_center_ch == 0) { 1140206b73d0SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, 1141*c1d255d3SCy Schubert CHANWIDTH_80MHZ); 1142325151a3SRui Paulo } else { 1143*c1d255d3SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, 1144*c1d255d3SCy Schubert CHANWIDTH_80P80MHZ); 1145206b73d0SCy Schubert hostapd_set_oper_centr_freq_seg1_idx( 1146206b73d0SCy Schubert hapd->iconf, 1147206b73d0SCy Schubert acs_res->vht_seg1_center_ch); 1148325151a3SRui Paulo } 1149*c1d255d3SCy Schubert } else if (acs_res->ch_width == 160) { 1150*c1d255d3SCy Schubert hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ); 1151*c1d255d3SCy Schubert hostapd_set_oper_centr_freq_seg0_idx( 1152*c1d255d3SCy Schubert hapd->iconf, acs_res->vht_seg1_center_ch); 1153325151a3SRui Paulo } 1154325151a3SRui Paulo } 1155325151a3SRui Paulo 1156780fb4a2SCy Schubert out: 1157780fb4a2SCy Schubert ret = hostapd_acs_completed(hapd->iface, err); 11585b9c547cSRui Paulo if (ret) { 11595b9c547cSRui Paulo wpa_printf(MSG_ERROR, 11605b9c547cSRui Paulo "ACS: Possibly channel configuration is invalid"); 11615b9c547cSRui Paulo } 11625b9c547cSRui Paulo } 11635b9c547cSRui Paulo #endif /* CONFIG_ACS */ 11645b9c547cSRui Paulo 11655b9c547cSRui Paulo 1166f05cddf9SRui Paulo int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, 1167f05cddf9SRui Paulo const u8 *bssid, const u8 *ie, size_t ie_len, 1168f05cddf9SRui Paulo int ssi_signal) 1169f05cddf9SRui Paulo { 1170f05cddf9SRui Paulo size_t i; 1171f05cddf9SRui Paulo int ret = 0; 1172f05cddf9SRui Paulo 1173f05cddf9SRui Paulo if (sa == NULL || ie == NULL) 1174f05cddf9SRui Paulo return -1; 1175f05cddf9SRui Paulo 1176f05cddf9SRui Paulo random_add_randomness(sa, ETH_ALEN); 1177f05cddf9SRui Paulo for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { 1178f05cddf9SRui Paulo if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 1179f05cddf9SRui Paulo sa, da, bssid, ie, ie_len, 1180f05cddf9SRui Paulo ssi_signal) > 0) { 1181f05cddf9SRui Paulo ret = 1; 1182f05cddf9SRui Paulo break; 1183f05cddf9SRui Paulo } 1184f05cddf9SRui Paulo } 1185f05cddf9SRui Paulo return ret; 1186f05cddf9SRui Paulo } 1187f05cddf9SRui Paulo 1188f05cddf9SRui Paulo 1189e28a4053SRui Paulo #ifdef HOSTAPD 1190e28a4053SRui Paulo 119185732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1192f05cddf9SRui Paulo static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, 1193f05cddf9SRui Paulo const u8 *bssid, 1194f05cddf9SRui Paulo u16 auth_transaction, u16 status, 1195f05cddf9SRui Paulo const u8 *ies, size_t ies_len) 1196e28a4053SRui Paulo { 1197f05cddf9SRui Paulo struct hostapd_data *hapd = ctx; 1198f05cddf9SRui Paulo struct sta_info *sta; 1199e28a4053SRui Paulo 1200f05cddf9SRui Paulo sta = ap_get_sta(hapd, dst); 1201f05cddf9SRui Paulo if (sta == NULL) 1202f05cddf9SRui Paulo return; 1203e28a4053SRui Paulo 1204f05cddf9SRui Paulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 1205f05cddf9SRui Paulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 1206f05cddf9SRui Paulo sta->flags |= WLAN_STA_AUTH; 1207e28a4053SRui Paulo 1208f05cddf9SRui Paulo hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len); 1209e28a4053SRui Paulo } 121085732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 121185732ac8SCy Schubert 121285732ac8SCy Schubert 121385732ac8SCy Schubert #ifdef CONFIG_FILS 121485732ac8SCy Schubert static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd, 121585732ac8SCy Schubert struct sta_info *sta, u16 resp, 121685732ac8SCy Schubert struct wpabuf *data, int pub) 121785732ac8SCy Schubert { 121885732ac8SCy Schubert if (resp == WLAN_STATUS_SUCCESS) { 121985732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 122085732ac8SCy Schubert HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)"); 122185732ac8SCy Schubert sta->flags |= WLAN_STA_AUTH; 122285732ac8SCy Schubert wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 122385732ac8SCy Schubert sta->auth_alg = WLAN_AUTH_FILS_SK; 122485732ac8SCy Schubert mlme_authenticate_indication(hapd, sta); 122585732ac8SCy Schubert } else { 122685732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 122785732ac8SCy Schubert HOSTAPD_LEVEL_DEBUG, 122885732ac8SCy Schubert "authentication failed (FILS)"); 122985732ac8SCy Schubert } 123085732ac8SCy Schubert 123185732ac8SCy Schubert hostapd_sta_auth(hapd, sta->addr, 2, resp, 123285732ac8SCy Schubert data ? wpabuf_head(data) : NULL, 123385732ac8SCy Schubert data ? wpabuf_len(data) : 0); 123485732ac8SCy Schubert wpabuf_free(data); 123585732ac8SCy Schubert } 123685732ac8SCy Schubert #endif /* CONFIG_FILS */ 1237f05cddf9SRui Paulo 1238f05cddf9SRui Paulo 1239f05cddf9SRui Paulo static void hostapd_notif_auth(struct hostapd_data *hapd, 1240f05cddf9SRui Paulo struct auth_info *rx_auth) 1241f05cddf9SRui Paulo { 1242f05cddf9SRui Paulo struct sta_info *sta; 1243f05cddf9SRui Paulo u16 status = WLAN_STATUS_SUCCESS; 1244f05cddf9SRui Paulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 1245f05cddf9SRui Paulo size_t resp_ies_len = 0; 1246f05cddf9SRui Paulo 1247f05cddf9SRui Paulo sta = ap_get_sta(hapd, rx_auth->peer); 1248f05cddf9SRui Paulo if (!sta) { 1249f05cddf9SRui Paulo sta = ap_sta_add(hapd, rx_auth->peer); 1250f05cddf9SRui Paulo if (sta == NULL) { 12515b9c547cSRui Paulo status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 1252f05cddf9SRui Paulo goto fail; 1253e28a4053SRui Paulo } 1254e28a4053SRui Paulo } 1255f05cddf9SRui Paulo sta->flags &= ~WLAN_STA_PREAUTH; 1256f05cddf9SRui Paulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 125785732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1258f05cddf9SRui Paulo if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { 1259f05cddf9SRui Paulo sta->auth_alg = WLAN_AUTH_FT; 1260f05cddf9SRui Paulo if (sta->wpa_sm == NULL) 1261f05cddf9SRui Paulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 12625b9c547cSRui Paulo sta->addr, NULL); 1263f05cddf9SRui Paulo if (sta->wpa_sm == NULL) { 1264325151a3SRui Paulo wpa_printf(MSG_DEBUG, 1265325151a3SRui Paulo "FT: Failed to initialize WPA state machine"); 1266f05cddf9SRui Paulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1267f05cddf9SRui Paulo goto fail; 1268f05cddf9SRui Paulo } 1269f05cddf9SRui Paulo wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, 1270f05cddf9SRui Paulo rx_auth->auth_transaction, rx_auth->ies, 1271f05cddf9SRui Paulo rx_auth->ies_len, 1272f05cddf9SRui Paulo hostapd_notify_auth_ft_finish, hapd); 1273f05cddf9SRui Paulo return; 1274f05cddf9SRui Paulo } 127585732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 127685732ac8SCy Schubert 127785732ac8SCy Schubert #ifdef CONFIG_FILS 127885732ac8SCy Schubert if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) { 127985732ac8SCy Schubert sta->auth_alg = WLAN_AUTH_FILS_SK; 128085732ac8SCy Schubert handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len, 128185732ac8SCy Schubert rx_auth->auth_type, rx_auth->auth_transaction, 128285732ac8SCy Schubert rx_auth->status_code, 128385732ac8SCy Schubert hostapd_notify_auth_fils_finish); 128485732ac8SCy Schubert return; 128585732ac8SCy Schubert } 128685732ac8SCy Schubert #endif /* CONFIG_FILS */ 128785732ac8SCy Schubert 1288f05cddf9SRui Paulo fail: 1289f05cddf9SRui Paulo hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, 1290f05cddf9SRui Paulo status, resp_ies, resp_ies_len); 1291f05cddf9SRui Paulo } 1292e28a4053SRui Paulo 1293e28a4053SRui Paulo 12944bc52338SCy Schubert #ifndef NEED_AP_MLME 1295f05cddf9SRui Paulo static void hostapd_action_rx(struct hostapd_data *hapd, 12965b9c547cSRui Paulo struct rx_mgmt *drv_mgmt) 1297f05cddf9SRui Paulo { 12985b9c547cSRui Paulo struct ieee80211_mgmt *mgmt; 1299f05cddf9SRui Paulo struct sta_info *sta; 13005b9c547cSRui Paulo size_t plen __maybe_unused; 13015b9c547cSRui Paulo u16 fc; 130285732ac8SCy Schubert u8 *action __maybe_unused; 13035b9c547cSRui Paulo 130485732ac8SCy Schubert if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1) 13055b9c547cSRui Paulo return; 13065b9c547cSRui Paulo 13074bc52338SCy Schubert plen = drv_mgmt->frame_len - IEEE80211_HDRLEN; 13085b9c547cSRui Paulo 13095b9c547cSRui Paulo mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; 13105b9c547cSRui Paulo fc = le_to_host16(mgmt->frame_control); 13115b9c547cSRui Paulo if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) 13125b9c547cSRui Paulo return; /* handled by the driver */ 1313f05cddf9SRui Paulo 131485732ac8SCy Schubert action = (u8 *) &mgmt->u.action.u; 131585732ac8SCy Schubert wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR 131685732ac8SCy Schubert " da " MACSTR " plen %d", 131785732ac8SCy Schubert mgmt->u.action.category, *action, 131885732ac8SCy Schubert MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen); 1319f05cddf9SRui Paulo 13205b9c547cSRui Paulo sta = ap_get_sta(hapd, mgmt->sa); 1321f05cddf9SRui Paulo if (sta == NULL) { 1322f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 1323f05cddf9SRui Paulo return; 1324f05cddf9SRui Paulo } 132585732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 13265b9c547cSRui Paulo if (mgmt->u.action.category == WLAN_ACTION_FT) { 13274bc52338SCy Schubert wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen); 13284bc52338SCy Schubert return; 1329f05cddf9SRui Paulo } 133085732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 13314bc52338SCy Schubert if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) { 13324bc52338SCy Schubert ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len); 13334bc52338SCy Schubert return; 1334f05cddf9SRui Paulo } 133585732ac8SCy Schubert #ifdef CONFIG_WNM_AP 13365b9c547cSRui Paulo if (mgmt->u.action.category == WLAN_ACTION_WNM) { 13375b9c547cSRui Paulo ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); 13384bc52338SCy Schubert return; 1339f05cddf9SRui Paulo } 134085732ac8SCy Schubert #endif /* CONFIG_WNM_AP */ 1341325151a3SRui Paulo #ifdef CONFIG_FST 1342325151a3SRui Paulo if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) { 1343325151a3SRui Paulo fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len); 1344325151a3SRui Paulo return; 1345325151a3SRui Paulo } 1346325151a3SRui Paulo #endif /* CONFIG_FST */ 134785732ac8SCy Schubert #ifdef CONFIG_DPP 13484bc52338SCy Schubert if (plen >= 2 + 4 && 134985732ac8SCy Schubert mgmt->u.action.u.vs_public_action.action == 135085732ac8SCy Schubert WLAN_PA_VENDOR_SPECIFIC && 135185732ac8SCy Schubert WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 135285732ac8SCy Schubert OUI_WFA && 135385732ac8SCy Schubert mgmt->u.action.u.vs_public_action.variable[0] == 135485732ac8SCy Schubert DPP_OUI_TYPE) { 135585732ac8SCy Schubert const u8 *pos, *end; 1356325151a3SRui Paulo 135785732ac8SCy Schubert pos = mgmt->u.action.u.vs_public_action.oui; 135885732ac8SCy Schubert end = drv_mgmt->frame + drv_mgmt->frame_len; 135985732ac8SCy Schubert hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos, 136085732ac8SCy Schubert drv_mgmt->freq); 136185732ac8SCy Schubert return; 136285732ac8SCy Schubert } 136385732ac8SCy Schubert #endif /* CONFIG_DPP */ 1364f05cddf9SRui Paulo } 13654bc52338SCy Schubert #endif /* NEED_AP_MLME */ 1366f05cddf9SRui Paulo 1367f05cddf9SRui Paulo 1368f05cddf9SRui Paulo #ifdef NEED_AP_MLME 1369f05cddf9SRui Paulo 1370e28a4053SRui Paulo #define HAPD_BROADCAST ((struct hostapd_data *) -1) 1371e28a4053SRui Paulo 1372e28a4053SRui Paulo static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, 1373e28a4053SRui Paulo const u8 *bssid) 1374e28a4053SRui Paulo { 1375e28a4053SRui Paulo size_t i; 1376e28a4053SRui Paulo 1377e28a4053SRui Paulo if (bssid == NULL) 1378e28a4053SRui Paulo return NULL; 1379e28a4053SRui Paulo if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && 1380e28a4053SRui Paulo bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) 1381e28a4053SRui Paulo return HAPD_BROADCAST; 1382e28a4053SRui Paulo 1383e28a4053SRui Paulo for (i = 0; i < iface->num_bss; i++) { 1384e28a4053SRui Paulo if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) 1385e28a4053SRui Paulo return iface->bss[i]; 1386e28a4053SRui Paulo } 1387e28a4053SRui Paulo 1388e28a4053SRui Paulo return NULL; 1389e28a4053SRui Paulo } 1390e28a4053SRui Paulo 1391e28a4053SRui Paulo 1392e28a4053SRui Paulo static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, 1393f05cddf9SRui Paulo const u8 *bssid, const u8 *addr, 1394f05cddf9SRui Paulo int wds) 1395e28a4053SRui Paulo { 1396f05cddf9SRui Paulo hapd = get_hapd_bssid(hapd->iface, bssid); 1397e28a4053SRui Paulo if (hapd == NULL || hapd == HAPD_BROADCAST) 1398e28a4053SRui Paulo return; 1399e28a4053SRui Paulo 1400f05cddf9SRui Paulo ieee802_11_rx_from_unknown(hapd, addr, wds); 1401e28a4053SRui Paulo } 1402e28a4053SRui Paulo 1403e28a4053SRui Paulo 14045b9c547cSRui Paulo static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) 1405e28a4053SRui Paulo { 1406e28a4053SRui Paulo struct hostapd_iface *iface = hapd->iface; 1407e28a4053SRui Paulo const struct ieee80211_hdr *hdr; 1408e28a4053SRui Paulo const u8 *bssid; 1409e28a4053SRui Paulo struct hostapd_frame_info fi; 14105b9c547cSRui Paulo int ret; 14115b9c547cSRui Paulo 14125b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 14135b9c547cSRui Paulo if (hapd->ext_mgmt_frame_handling) { 14145b9c547cSRui Paulo size_t hex_len = 2 * rx_mgmt->frame_len + 1; 14155b9c547cSRui Paulo char *hex = os_malloc(hex_len); 1416325151a3SRui Paulo 14175b9c547cSRui Paulo if (hex) { 14185b9c547cSRui Paulo wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame, 14195b9c547cSRui Paulo rx_mgmt->frame_len); 14205b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); 14215b9c547cSRui Paulo os_free(hex); 14225b9c547cSRui Paulo } 14235b9c547cSRui Paulo return 1; 14245b9c547cSRui Paulo } 14255b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 1426e28a4053SRui Paulo 1427e28a4053SRui Paulo hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; 1428e28a4053SRui Paulo bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); 1429e28a4053SRui Paulo if (bssid == NULL) 14305b9c547cSRui Paulo return 0; 1431e28a4053SRui Paulo 1432e28a4053SRui Paulo hapd = get_hapd_bssid(iface, bssid); 1433e28a4053SRui Paulo if (hapd == NULL) { 1434325151a3SRui Paulo u16 fc = le_to_host16(hdr->frame_control); 1435e28a4053SRui Paulo 1436e28a4053SRui Paulo /* 1437e28a4053SRui Paulo * Drop frames to unknown BSSIDs except for Beacon frames which 1438e28a4053SRui Paulo * could be used to update neighbor information. 1439e28a4053SRui Paulo */ 1440e28a4053SRui Paulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1441e28a4053SRui Paulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1442e28a4053SRui Paulo hapd = iface->bss[0]; 1443e28a4053SRui Paulo else 14445b9c547cSRui Paulo return 0; 1445e28a4053SRui Paulo } 1446e28a4053SRui Paulo 1447e28a4053SRui Paulo os_memset(&fi, 0, sizeof(fi)); 144885732ac8SCy Schubert fi.freq = rx_mgmt->freq; 1449e28a4053SRui Paulo fi.datarate = rx_mgmt->datarate; 1450e28a4053SRui Paulo fi.ssi_signal = rx_mgmt->ssi_signal; 1451e28a4053SRui Paulo 1452e28a4053SRui Paulo if (hapd == HAPD_BROADCAST) { 1453e28a4053SRui Paulo size_t i; 1454325151a3SRui Paulo 14555b9c547cSRui Paulo ret = 0; 14565b9c547cSRui Paulo for (i = 0; i < iface->num_bss; i++) { 14575b9c547cSRui Paulo /* if bss is set, driver will call this function for 14585b9c547cSRui Paulo * each bss individually. */ 14595b9c547cSRui Paulo if (rx_mgmt->drv_priv && 14605b9c547cSRui Paulo (iface->bss[i]->drv_priv != rx_mgmt->drv_priv)) 14615b9c547cSRui Paulo continue; 14625b9c547cSRui Paulo 14635b9c547cSRui Paulo if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, 14645b9c547cSRui Paulo rx_mgmt->frame_len, &fi) > 0) 14655b9c547cSRui Paulo ret = 1; 14665b9c547cSRui Paulo } 1467e28a4053SRui Paulo } else 14685b9c547cSRui Paulo ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, 14695b9c547cSRui Paulo &fi); 1470f05cddf9SRui Paulo 1471f05cddf9SRui Paulo random_add_randomness(&fi, sizeof(fi)); 1472f05cddf9SRui Paulo 14735b9c547cSRui Paulo return ret; 1474e28a4053SRui Paulo } 1475e28a4053SRui Paulo 1476e28a4053SRui Paulo 1477e28a4053SRui Paulo static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, 1478e28a4053SRui Paulo size_t len, u16 stype, int ok) 1479e28a4053SRui Paulo { 1480e28a4053SRui Paulo struct ieee80211_hdr *hdr; 1481780fb4a2SCy Schubert struct hostapd_data *orig_hapd = hapd; 1482325151a3SRui Paulo 1483e28a4053SRui Paulo hdr = (struct ieee80211_hdr *) buf; 1484e28a4053SRui Paulo hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); 1485780fb4a2SCy Schubert if (!hapd) 1486e28a4053SRui Paulo return; 1487780fb4a2SCy Schubert if (hapd == HAPD_BROADCAST) { 1488780fb4a2SCy Schubert if (stype != WLAN_FC_STYPE_ACTION || len <= 25 || 1489780fb4a2SCy Schubert buf[24] != WLAN_ACTION_PUBLIC) 1490780fb4a2SCy Schubert return; 1491780fb4a2SCy Schubert hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2); 1492780fb4a2SCy Schubert if (!hapd || hapd == HAPD_BROADCAST) 1493780fb4a2SCy Schubert return; 1494780fb4a2SCy Schubert /* 1495780fb4a2SCy Schubert * Allow processing of TX status for a Public Action frame that 1496780fb4a2SCy Schubert * used wildcard BBSID. 1497780fb4a2SCy Schubert */ 1498780fb4a2SCy Schubert } 1499e28a4053SRui Paulo ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); 1500e28a4053SRui Paulo } 1501e28a4053SRui Paulo 1502e28a4053SRui Paulo #endif /* NEED_AP_MLME */ 1503e28a4053SRui Paulo 1504e28a4053SRui Paulo 1505e28a4053SRui Paulo static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) 1506e28a4053SRui Paulo { 1507e28a4053SRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 1508325151a3SRui Paulo 1509e28a4053SRui Paulo if (sta) 1510e28a4053SRui Paulo return 0; 1511e28a4053SRui Paulo 1512e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR 1513e28a4053SRui Paulo " - adding a new STA", MAC2STR(addr)); 1514e28a4053SRui Paulo sta = ap_sta_add(hapd, addr); 1515e28a4053SRui Paulo if (sta) { 1516e28a4053SRui Paulo hostapd_new_assoc_sta(hapd, sta, 0); 1517e28a4053SRui Paulo } else { 1518e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, 1519e28a4053SRui Paulo MAC2STR(addr)); 1520e28a4053SRui Paulo return -1; 1521e28a4053SRui Paulo } 1522e28a4053SRui Paulo 1523e28a4053SRui Paulo return 0; 1524e28a4053SRui Paulo } 1525e28a4053SRui Paulo 1526e28a4053SRui Paulo 1527e28a4053SRui Paulo static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, 1528e28a4053SRui Paulo const u8 *data, size_t data_len) 1529e28a4053SRui Paulo { 1530e28a4053SRui Paulo struct hostapd_iface *iface = hapd->iface; 1531f05cddf9SRui Paulo struct sta_info *sta; 1532e28a4053SRui Paulo size_t j; 1533e28a4053SRui Paulo 1534e28a4053SRui Paulo for (j = 0; j < iface->num_bss; j++) { 1535325151a3SRui Paulo sta = ap_get_sta(iface->bss[j], src); 1536325151a3SRui Paulo if (sta && sta->flags & WLAN_STA_ASSOC) { 1537e28a4053SRui Paulo hapd = iface->bss[j]; 1538e28a4053SRui Paulo break; 1539e28a4053SRui Paulo } 1540e28a4053SRui Paulo } 1541e28a4053SRui Paulo 1542e28a4053SRui Paulo ieee802_1x_receive(hapd, src, data, data_len); 1543e28a4053SRui Paulo } 1544e28a4053SRui Paulo 1545780fb4a2SCy Schubert #endif /* HOSTAPD */ 1546780fb4a2SCy Schubert 1547e28a4053SRui Paulo 1548*c1d255d3SCy Schubert static struct hostapd_channel_data * 1549*c1d255d3SCy Schubert hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq) 1550*c1d255d3SCy Schubert { 1551*c1d255d3SCy Schubert int i; 1552*c1d255d3SCy Schubert struct hostapd_channel_data *chan; 1553*c1d255d3SCy Schubert 1554*c1d255d3SCy Schubert for (i = 0; i < mode->num_channels; i++) { 1555*c1d255d3SCy Schubert chan = &mode->channels[i]; 1556*c1d255d3SCy Schubert if ((unsigned int) chan->freq == freq) 1557*c1d255d3SCy Schubert return chan; 1558*c1d255d3SCy Schubert } 1559*c1d255d3SCy Schubert 1560*c1d255d3SCy Schubert return NULL; 1561*c1d255d3SCy Schubert } 1562*c1d255d3SCy Schubert 1563*c1d255d3SCy Schubert 15645b9c547cSRui Paulo static struct hostapd_channel_data * hostapd_get_mode_channel( 15655b9c547cSRui Paulo struct hostapd_iface *iface, unsigned int freq) 15665b9c547cSRui Paulo { 15675b9c547cSRui Paulo int i; 15685b9c547cSRui Paulo struct hostapd_channel_data *chan; 15695b9c547cSRui Paulo 1570*c1d255d3SCy Schubert for (i = 0; i < iface->num_hw_features; i++) { 1571*c1d255d3SCy Schubert if (hostapd_hw_skip_mode(iface, &iface->hw_features[i])) 1572*c1d255d3SCy Schubert continue; 1573*c1d255d3SCy Schubert chan = hostapd_get_mode_chan(&iface->hw_features[i], freq); 1574*c1d255d3SCy Schubert if (chan) 15755b9c547cSRui Paulo return chan; 15765b9c547cSRui Paulo } 15775b9c547cSRui Paulo 15785b9c547cSRui Paulo return NULL; 15795b9c547cSRui Paulo } 15805b9c547cSRui Paulo 15815b9c547cSRui Paulo 15825b9c547cSRui Paulo static void hostapd_update_nf(struct hostapd_iface *iface, 15835b9c547cSRui Paulo struct hostapd_channel_data *chan, 15845b9c547cSRui Paulo struct freq_survey *survey) 15855b9c547cSRui Paulo { 15865b9c547cSRui Paulo if (!iface->chans_surveyed) { 15875b9c547cSRui Paulo chan->min_nf = survey->nf; 15885b9c547cSRui Paulo iface->lowest_nf = survey->nf; 15895b9c547cSRui Paulo } else { 15905b9c547cSRui Paulo if (dl_list_empty(&chan->survey_list)) 15915b9c547cSRui Paulo chan->min_nf = survey->nf; 15925b9c547cSRui Paulo else if (survey->nf < chan->min_nf) 15935b9c547cSRui Paulo chan->min_nf = survey->nf; 15945b9c547cSRui Paulo if (survey->nf < iface->lowest_nf) 15955b9c547cSRui Paulo iface->lowest_nf = survey->nf; 15965b9c547cSRui Paulo } 15975b9c547cSRui Paulo } 15985b9c547cSRui Paulo 15995b9c547cSRui Paulo 16005b9c547cSRui Paulo static void hostapd_single_channel_get_survey(struct hostapd_iface *iface, 16015b9c547cSRui Paulo struct survey_results *survey_res) 16025b9c547cSRui Paulo { 16035b9c547cSRui Paulo struct hostapd_channel_data *chan; 16045b9c547cSRui Paulo struct freq_survey *survey; 16055b9c547cSRui Paulo u64 divisor, dividend; 16065b9c547cSRui Paulo 16075b9c547cSRui Paulo survey = dl_list_first(&survey_res->survey_list, struct freq_survey, 16085b9c547cSRui Paulo list); 16095b9c547cSRui Paulo if (!survey || !survey->freq) 16105b9c547cSRui Paulo return; 16115b9c547cSRui Paulo 16125b9c547cSRui Paulo chan = hostapd_get_mode_channel(iface, survey->freq); 16135b9c547cSRui Paulo if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED) 16145b9c547cSRui Paulo return; 16155b9c547cSRui Paulo 1616325151a3SRui Paulo wpa_printf(MSG_DEBUG, 1617325151a3SRui Paulo "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", 16185b9c547cSRui Paulo survey->freq, 16195b9c547cSRui Paulo (unsigned long int) survey->channel_time, 16205b9c547cSRui Paulo (unsigned long int) survey->channel_time_busy); 16215b9c547cSRui Paulo 16225b9c547cSRui Paulo if (survey->channel_time > iface->last_channel_time && 16235b9c547cSRui Paulo survey->channel_time > survey->channel_time_busy) { 16245b9c547cSRui Paulo dividend = survey->channel_time_busy - 16255b9c547cSRui Paulo iface->last_channel_time_busy; 16265b9c547cSRui Paulo divisor = survey->channel_time - iface->last_channel_time; 16275b9c547cSRui Paulo 16285b9c547cSRui Paulo iface->channel_utilization = dividend * 255 / divisor; 16295b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Channel Utilization: %d", 16305b9c547cSRui Paulo iface->channel_utilization); 16315b9c547cSRui Paulo } 16325b9c547cSRui Paulo iface->last_channel_time = survey->channel_time; 16335b9c547cSRui Paulo iface->last_channel_time_busy = survey->channel_time_busy; 16345b9c547cSRui Paulo } 16355b9c547cSRui Paulo 16365b9c547cSRui Paulo 1637780fb4a2SCy Schubert void hostapd_event_get_survey(struct hostapd_iface *iface, 16385b9c547cSRui Paulo struct survey_results *survey_results) 16395b9c547cSRui Paulo { 16405b9c547cSRui Paulo struct freq_survey *survey, *tmp; 16415b9c547cSRui Paulo struct hostapd_channel_data *chan; 16425b9c547cSRui Paulo 16435b9c547cSRui Paulo if (dl_list_empty(&survey_results->survey_list)) { 16445b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "No survey data received"); 16455b9c547cSRui Paulo return; 16465b9c547cSRui Paulo } 16475b9c547cSRui Paulo 16485b9c547cSRui Paulo if (survey_results->freq_filter) { 16495b9c547cSRui Paulo hostapd_single_channel_get_survey(iface, survey_results); 16505b9c547cSRui Paulo return; 16515b9c547cSRui Paulo } 16525b9c547cSRui Paulo 16535b9c547cSRui Paulo dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, 16545b9c547cSRui Paulo struct freq_survey, list) { 16555b9c547cSRui Paulo chan = hostapd_get_mode_channel(iface, survey->freq); 16565b9c547cSRui Paulo if (!chan) 16575b9c547cSRui Paulo continue; 16585b9c547cSRui Paulo if (chan->flag & HOSTAPD_CHAN_DISABLED) 16595b9c547cSRui Paulo continue; 16605b9c547cSRui Paulo 16615b9c547cSRui Paulo dl_list_del(&survey->list); 16625b9c547cSRui Paulo dl_list_add_tail(&chan->survey_list, &survey->list); 16635b9c547cSRui Paulo 16645b9c547cSRui Paulo hostapd_update_nf(iface, chan, survey); 16655b9c547cSRui Paulo 16665b9c547cSRui Paulo iface->chans_surveyed++; 16675b9c547cSRui Paulo } 16685b9c547cSRui Paulo } 16695b9c547cSRui Paulo 16705b9c547cSRui Paulo 1671780fb4a2SCy Schubert #ifdef HOSTAPD 16725b9c547cSRui Paulo #ifdef NEED_AP_MLME 16735b9c547cSRui Paulo 16745b9c547cSRui Paulo static void hostapd_event_iface_unavailable(struct hostapd_data *hapd) 16755b9c547cSRui Paulo { 16765b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped", 16775b9c547cSRui Paulo hapd->conf->iface); 16785b9c547cSRui Paulo 16795b9c547cSRui Paulo if (hapd->csa_in_progress) { 16805b9c547cSRui Paulo wpa_printf(MSG_INFO, "CSA failed (%s was stopped)", 16815b9c547cSRui Paulo hapd->conf->iface); 16825b9c547cSRui Paulo hostapd_switch_channel_fallback(hapd->iface, 16835b9c547cSRui Paulo &hapd->cs_freq_params); 16845b9c547cSRui Paulo } 16855b9c547cSRui Paulo } 16865b9c547cSRui Paulo 16875b9c547cSRui Paulo 16885b9c547cSRui Paulo static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd, 16895b9c547cSRui Paulo struct dfs_event *radar) 16905b9c547cSRui Paulo { 16915b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq); 16925b9c547cSRui Paulo hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled, 16935b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 16945b9c547cSRui Paulo radar->cf1, radar->cf2); 16955b9c547cSRui Paulo } 16965b9c547cSRui Paulo 16975b9c547cSRui Paulo 169885732ac8SCy Schubert static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd, 169985732ac8SCy Schubert struct dfs_event *radar) 170085732ac8SCy Schubert { 170185732ac8SCy Schubert wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq); 170285732ac8SCy Schubert hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled, 170385732ac8SCy Schubert radar->chan_offset, radar->chan_width, 170485732ac8SCy Schubert radar->cf1, radar->cf2); 170585732ac8SCy Schubert } 170685732ac8SCy Schubert 170785732ac8SCy Schubert 17085b9c547cSRui Paulo static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd, 17095b9c547cSRui Paulo struct dfs_event *radar) 17105b9c547cSRui Paulo { 17115b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq); 17125b9c547cSRui Paulo hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled, 17135b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 17145b9c547cSRui Paulo radar->cf1, radar->cf2); 17155b9c547cSRui Paulo } 17165b9c547cSRui Paulo 17175b9c547cSRui Paulo 17185b9c547cSRui Paulo static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd, 17195b9c547cSRui Paulo struct dfs_event *radar) 17205b9c547cSRui Paulo { 17215b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq); 17225b9c547cSRui Paulo hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled, 17235b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 17245b9c547cSRui Paulo radar->cf1, radar->cf2); 17255b9c547cSRui Paulo } 17265b9c547cSRui Paulo 17275b9c547cSRui Paulo 17285b9c547cSRui Paulo static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd, 17295b9c547cSRui Paulo struct dfs_event *radar) 17305b9c547cSRui Paulo { 17315b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq); 17325b9c547cSRui Paulo hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled, 17335b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 17345b9c547cSRui Paulo radar->cf1, radar->cf2); 17355b9c547cSRui Paulo } 17365b9c547cSRui Paulo 17375b9c547cSRui Paulo 17385b9c547cSRui Paulo static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd, 17395b9c547cSRui Paulo struct dfs_event *radar) 17405b9c547cSRui Paulo { 17415b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq); 17425b9c547cSRui Paulo hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled, 17435b9c547cSRui Paulo radar->chan_offset, radar->chan_width, 17445b9c547cSRui Paulo radar->cf1, radar->cf2); 17455b9c547cSRui Paulo } 17465b9c547cSRui Paulo 17475b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 17485b9c547cSRui Paulo 17495b9c547cSRui Paulo 175085732ac8SCy Schubert static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd, 175185732ac8SCy Schubert int istatus, 175285732ac8SCy Schubert const char *ifname, 175385732ac8SCy Schubert const u8 *addr) 175485732ac8SCy Schubert { 175585732ac8SCy Schubert struct sta_info *sta = ap_get_sta(hapd, addr); 175685732ac8SCy Schubert 175785732ac8SCy Schubert if (sta) { 175885732ac8SCy Schubert os_free(sta->ifname_wds); 175985732ac8SCy Schubert if (istatus == INTERFACE_ADDED) 176085732ac8SCy Schubert sta->ifname_wds = os_strdup(ifname); 176185732ac8SCy Schubert else 176285732ac8SCy Schubert sta->ifname_wds = NULL; 176385732ac8SCy Schubert } 176485732ac8SCy Schubert 176585732ac8SCy Schubert wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR, 176685732ac8SCy Schubert istatus == INTERFACE_ADDED ? 176785732ac8SCy Schubert WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED, 176885732ac8SCy Schubert ifname, MAC2STR(addr)); 176985732ac8SCy Schubert } 177085732ac8SCy Schubert 177185732ac8SCy Schubert 1772206b73d0SCy Schubert #ifdef CONFIG_OWE 1773206b73d0SCy Schubert static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, 1774206b73d0SCy Schubert const u8 *peer, const u8 *ie, 1775206b73d0SCy Schubert size_t ie_len) 1776206b73d0SCy Schubert { 1777206b73d0SCy Schubert u16 status; 1778206b73d0SCy Schubert struct sta_info *sta; 1779206b73d0SCy Schubert struct ieee802_11_elems elems; 1780206b73d0SCy Schubert 1781206b73d0SCy Schubert if (!hapd || !hapd->wpa_auth) { 1782206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context"); 1783206b73d0SCy Schubert return -1; 1784206b73d0SCy Schubert } 1785206b73d0SCy Schubert if (!peer) { 1786206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: Peer unknown"); 1787206b73d0SCy Schubert return -1; 1788206b73d0SCy Schubert } 1789206b73d0SCy Schubert if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) { 1790206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured"); 1791206b73d0SCy Schubert status = WLAN_STATUS_AKMP_NOT_VALID; 1792206b73d0SCy Schubert goto err; 1793206b73d0SCy Schubert } 1794206b73d0SCy Schubert if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) { 1795206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for " 1796206b73d0SCy Schubert MACSTR, MAC2STR(peer)); 1797206b73d0SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1798206b73d0SCy Schubert goto err; 1799206b73d0SCy Schubert } 1800206b73d0SCy Schubert status = owe_validate_request(hapd, peer, elems.rsn_ie, 1801206b73d0SCy Schubert elems.rsn_ie_len, 1802206b73d0SCy Schubert elems.owe_dh, elems.owe_dh_len); 1803206b73d0SCy Schubert if (status != WLAN_STATUS_SUCCESS) 1804206b73d0SCy Schubert goto err; 1805206b73d0SCy Schubert 1806206b73d0SCy Schubert sta = ap_get_sta(hapd, peer); 1807206b73d0SCy Schubert if (sta) { 1808206b73d0SCy Schubert ap_sta_no_session_timeout(hapd, sta); 1809206b73d0SCy Schubert accounting_sta_stop(hapd, sta); 1810206b73d0SCy Schubert 1811206b73d0SCy Schubert /* 1812206b73d0SCy Schubert * Make sure that the previously registered inactivity timer 1813206b73d0SCy Schubert * will not remove the STA immediately. 1814206b73d0SCy Schubert */ 1815206b73d0SCy Schubert sta->timeout_next = STA_NULLFUNC; 1816206b73d0SCy Schubert } else { 1817206b73d0SCy Schubert sta = ap_sta_add(hapd, peer); 1818206b73d0SCy Schubert if (!sta) { 1819206b73d0SCy Schubert status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1820206b73d0SCy Schubert goto err; 1821206b73d0SCy Schubert } 1822206b73d0SCy Schubert } 1823206b73d0SCy Schubert sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 1824206b73d0SCy Schubert 1825206b73d0SCy Schubert status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, 1826206b73d0SCy Schubert elems.rsn_ie_len, elems.owe_dh, 1827206b73d0SCy Schubert elems.owe_dh_len); 1828206b73d0SCy Schubert if (status != WLAN_STATUS_SUCCESS) 1829206b73d0SCy Schubert ap_free_sta(hapd, sta); 1830206b73d0SCy Schubert 1831206b73d0SCy Schubert return 0; 1832206b73d0SCy Schubert err: 1833206b73d0SCy Schubert hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0); 1834206b73d0SCy Schubert return 0; 1835206b73d0SCy Schubert } 1836206b73d0SCy Schubert #endif /* CONFIG_OWE */ 1837206b73d0SCy Schubert 1838206b73d0SCy Schubert 1839e28a4053SRui Paulo void wpa_supplicant_event(void *ctx, enum wpa_event_type event, 1840e28a4053SRui Paulo union wpa_event_data *data) 1841e28a4053SRui Paulo { 1842e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 1843f05cddf9SRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG 1844f05cddf9SRui Paulo int level = MSG_DEBUG; 1845f05cddf9SRui Paulo 1846f05cddf9SRui Paulo if (event == EVENT_RX_MGMT && data->rx_mgmt.frame && 1847f05cddf9SRui Paulo data->rx_mgmt.frame_len >= 24) { 1848f05cddf9SRui Paulo const struct ieee80211_hdr *hdr; 1849f05cddf9SRui Paulo u16 fc; 1850325151a3SRui Paulo 1851f05cddf9SRui Paulo hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; 1852f05cddf9SRui Paulo fc = le_to_host16(hdr->frame_control); 1853f05cddf9SRui Paulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1854f05cddf9SRui Paulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1855f05cddf9SRui Paulo level = MSG_EXCESSIVE; 18565b9c547cSRui Paulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 18575b9c547cSRui Paulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) 18585b9c547cSRui Paulo level = MSG_EXCESSIVE; 1859f05cddf9SRui Paulo } 1860f05cddf9SRui Paulo 1861f05cddf9SRui Paulo wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", 1862f05cddf9SRui Paulo event_to_string(event), event); 1863f05cddf9SRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */ 1864e28a4053SRui Paulo 1865e28a4053SRui Paulo switch (event) { 1866e28a4053SRui Paulo case EVENT_MICHAEL_MIC_FAILURE: 1867e28a4053SRui Paulo michael_mic_failure(hapd, data->michael_mic_failure.src, 1); 1868e28a4053SRui Paulo break; 1869e28a4053SRui Paulo case EVENT_SCAN_RESULTS: 1870e28a4053SRui Paulo if (hapd->iface->scan_cb) 1871e28a4053SRui Paulo hapd->iface->scan_cb(hapd->iface); 1872e28a4053SRui Paulo break; 1873e28a4053SRui Paulo case EVENT_WPS_BUTTON_PUSHED: 1874f05cddf9SRui Paulo hostapd_wps_button_pushed(hapd, NULL); 1875e28a4053SRui Paulo break; 1876e28a4053SRui Paulo #ifdef NEED_AP_MLME 1877e28a4053SRui Paulo case EVENT_TX_STATUS: 1878e28a4053SRui Paulo switch (data->tx_status.type) { 1879e28a4053SRui Paulo case WLAN_FC_TYPE_MGMT: 1880e28a4053SRui Paulo hostapd_mgmt_tx_cb(hapd, data->tx_status.data, 1881e28a4053SRui Paulo data->tx_status.data_len, 1882e28a4053SRui Paulo data->tx_status.stype, 1883e28a4053SRui Paulo data->tx_status.ack); 1884e28a4053SRui Paulo break; 1885e28a4053SRui Paulo case WLAN_FC_TYPE_DATA: 1886e28a4053SRui Paulo hostapd_tx_status(hapd, data->tx_status.dst, 1887e28a4053SRui Paulo data->tx_status.data, 1888e28a4053SRui Paulo data->tx_status.data_len, 1889e28a4053SRui Paulo data->tx_status.ack); 1890e28a4053SRui Paulo break; 1891e28a4053SRui Paulo } 1892e28a4053SRui Paulo break; 1893f05cddf9SRui Paulo case EVENT_EAPOL_TX_STATUS: 1894f05cddf9SRui Paulo hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, 1895f05cddf9SRui Paulo data->eapol_tx_status.data, 1896f05cddf9SRui Paulo data->eapol_tx_status.data_len, 1897f05cddf9SRui Paulo data->eapol_tx_status.ack); 1898f05cddf9SRui Paulo break; 1899f05cddf9SRui Paulo case EVENT_DRIVER_CLIENT_POLL_OK: 1900f05cddf9SRui Paulo hostapd_client_poll_ok(hapd, data->client_poll.addr); 1901f05cddf9SRui Paulo break; 1902e28a4053SRui Paulo case EVENT_RX_FROM_UNKNOWN: 1903f05cddf9SRui Paulo hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, 1904f05cddf9SRui Paulo data->rx_from_unknown.addr, 1905f05cddf9SRui Paulo data->rx_from_unknown.wds); 1906e28a4053SRui Paulo break; 19075b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 1908e28a4053SRui Paulo case EVENT_RX_MGMT: 19095b9c547cSRui Paulo if (!data->rx_mgmt.frame) 19105b9c547cSRui Paulo break; 19115b9c547cSRui Paulo #ifdef NEED_AP_MLME 19124bc52338SCy Schubert hostapd_mgmt_rx(hapd, &data->rx_mgmt); 19134bc52338SCy Schubert #else /* NEED_AP_MLME */ 19145b9c547cSRui Paulo hostapd_action_rx(hapd, &data->rx_mgmt); 19154bc52338SCy Schubert #endif /* NEED_AP_MLME */ 19165b9c547cSRui Paulo break; 1917e28a4053SRui Paulo case EVENT_RX_PROBE_REQ: 1918f05cddf9SRui Paulo if (data->rx_probe_req.sa == NULL || 1919f05cddf9SRui Paulo data->rx_probe_req.ie == NULL) 1920f05cddf9SRui Paulo break; 1921e28a4053SRui Paulo hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, 1922f05cddf9SRui Paulo data->rx_probe_req.da, 1923f05cddf9SRui Paulo data->rx_probe_req.bssid, 1924e28a4053SRui Paulo data->rx_probe_req.ie, 1925f05cddf9SRui Paulo data->rx_probe_req.ie_len, 1926f05cddf9SRui Paulo data->rx_probe_req.ssi_signal); 1927e28a4053SRui Paulo break; 1928e28a4053SRui Paulo case EVENT_NEW_STA: 1929e28a4053SRui Paulo hostapd_event_new_sta(hapd, data->new_sta.addr); 1930e28a4053SRui Paulo break; 1931e28a4053SRui Paulo case EVENT_EAPOL_RX: 1932e28a4053SRui Paulo hostapd_event_eapol_rx(hapd, data->eapol_rx.src, 1933e28a4053SRui Paulo data->eapol_rx.data, 1934e28a4053SRui Paulo data->eapol_rx.data_len); 1935e28a4053SRui Paulo break; 1936e28a4053SRui Paulo case EVENT_ASSOC: 19375b9c547cSRui Paulo if (!data) 19385b9c547cSRui Paulo return; 1939e28a4053SRui Paulo hostapd_notif_assoc(hapd, data->assoc_info.addr, 1940e28a4053SRui Paulo data->assoc_info.req_ies, 1941f05cddf9SRui Paulo data->assoc_info.req_ies_len, 1942f05cddf9SRui Paulo data->assoc_info.reassoc); 1943e28a4053SRui Paulo break; 1944206b73d0SCy Schubert #ifdef CONFIG_OWE 1945206b73d0SCy Schubert case EVENT_UPDATE_DH: 1946206b73d0SCy Schubert if (!data) 1947206b73d0SCy Schubert return; 1948206b73d0SCy Schubert hostapd_notif_update_dh_ie(hapd, data->update_dh.peer, 1949206b73d0SCy Schubert data->update_dh.ie, 1950206b73d0SCy Schubert data->update_dh.ie_len); 1951206b73d0SCy Schubert break; 1952206b73d0SCy Schubert #endif /* CONFIG_OWE */ 1953e28a4053SRui Paulo case EVENT_DISASSOC: 1954e28a4053SRui Paulo if (data) 1955e28a4053SRui Paulo hostapd_notif_disassoc(hapd, data->disassoc_info.addr); 1956e28a4053SRui Paulo break; 1957e28a4053SRui Paulo case EVENT_DEAUTH: 1958e28a4053SRui Paulo if (data) 1959e28a4053SRui Paulo hostapd_notif_disassoc(hapd, data->deauth_info.addr); 1960e28a4053SRui Paulo break; 1961f05cddf9SRui Paulo case EVENT_STATION_LOW_ACK: 1962f05cddf9SRui Paulo if (!data) 1963f05cddf9SRui Paulo break; 1964f05cddf9SRui Paulo hostapd_event_sta_low_ack(hapd, data->low_ack.addr); 1965f05cddf9SRui Paulo break; 1966f05cddf9SRui Paulo case EVENT_AUTH: 1967f05cddf9SRui Paulo hostapd_notif_auth(hapd, &data->auth); 1968f05cddf9SRui Paulo break; 1969206b73d0SCy Schubert case EVENT_CH_SWITCH_STARTED: 1970f05cddf9SRui Paulo case EVENT_CH_SWITCH: 1971f05cddf9SRui Paulo if (!data) 1972f05cddf9SRui Paulo break; 1973f05cddf9SRui Paulo hostapd_event_ch_switch(hapd, data->ch_switch.freq, 1974f05cddf9SRui Paulo data->ch_switch.ht_enabled, 19755b9c547cSRui Paulo data->ch_switch.ch_offset, 19765b9c547cSRui Paulo data->ch_switch.ch_width, 19775b9c547cSRui Paulo data->ch_switch.cf1, 1978206b73d0SCy Schubert data->ch_switch.cf2, 1979206b73d0SCy Schubert event == EVENT_CH_SWITCH); 1980f05cddf9SRui Paulo break; 19815b9c547cSRui Paulo case EVENT_CONNECT_FAILED_REASON: 19825b9c547cSRui Paulo if (!data) 19835b9c547cSRui Paulo break; 19845b9c547cSRui Paulo hostapd_event_connect_failed_reason( 19855b9c547cSRui Paulo hapd, data->connect_failed_reason.addr, 19865b9c547cSRui Paulo data->connect_failed_reason.code); 19875b9c547cSRui Paulo break; 19885b9c547cSRui Paulo case EVENT_SURVEY: 1989780fb4a2SCy Schubert hostapd_event_get_survey(hapd->iface, &data->survey_results); 19905b9c547cSRui Paulo break; 19915b9c547cSRui Paulo #ifdef NEED_AP_MLME 19925b9c547cSRui Paulo case EVENT_INTERFACE_UNAVAILABLE: 19935b9c547cSRui Paulo hostapd_event_iface_unavailable(hapd); 19945b9c547cSRui Paulo break; 19955b9c547cSRui Paulo case EVENT_DFS_RADAR_DETECTED: 19965b9c547cSRui Paulo if (!data) 19975b9c547cSRui Paulo break; 19985b9c547cSRui Paulo hostapd_event_dfs_radar_detected(hapd, &data->dfs_event); 19995b9c547cSRui Paulo break; 200085732ac8SCy Schubert case EVENT_DFS_PRE_CAC_EXPIRED: 200185732ac8SCy Schubert if (!data) 200285732ac8SCy Schubert break; 200385732ac8SCy Schubert hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event); 200485732ac8SCy Schubert break; 20055b9c547cSRui Paulo case EVENT_DFS_CAC_FINISHED: 20065b9c547cSRui Paulo if (!data) 20075b9c547cSRui Paulo break; 20085b9c547cSRui Paulo hostapd_event_dfs_cac_finished(hapd, &data->dfs_event); 20095b9c547cSRui Paulo break; 20105b9c547cSRui Paulo case EVENT_DFS_CAC_ABORTED: 20115b9c547cSRui Paulo if (!data) 20125b9c547cSRui Paulo break; 20135b9c547cSRui Paulo hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event); 20145b9c547cSRui Paulo break; 20155b9c547cSRui Paulo case EVENT_DFS_NOP_FINISHED: 20165b9c547cSRui Paulo if (!data) 20175b9c547cSRui Paulo break; 20185b9c547cSRui Paulo hostapd_event_dfs_nop_finished(hapd, &data->dfs_event); 20195b9c547cSRui Paulo break; 20205b9c547cSRui Paulo case EVENT_CHANNEL_LIST_CHANGED: 20215b9c547cSRui Paulo /* channel list changed (regulatory?), update channel list */ 20225b9c547cSRui Paulo /* TODO: check this. hostapd_get_hw_features() initializes 20235b9c547cSRui Paulo * too much stuff. */ 20245b9c547cSRui Paulo /* hostapd_get_hw_features(hapd->iface); */ 20255b9c547cSRui Paulo hostapd_channel_list_updated( 20265b9c547cSRui Paulo hapd->iface, data->channel_list_changed.initiator); 20275b9c547cSRui Paulo break; 20285b9c547cSRui Paulo case EVENT_DFS_CAC_STARTED: 20295b9c547cSRui Paulo if (!data) 20305b9c547cSRui Paulo break; 20315b9c547cSRui Paulo hostapd_event_dfs_cac_started(hapd, &data->dfs_event); 20325b9c547cSRui Paulo break; 20335b9c547cSRui Paulo #endif /* NEED_AP_MLME */ 20345b9c547cSRui Paulo case EVENT_INTERFACE_ENABLED: 20355b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED); 20365b9c547cSRui Paulo if (hapd->disabled && hapd->started) { 20375b9c547cSRui Paulo hapd->disabled = 0; 20385b9c547cSRui Paulo /* 20395b9c547cSRui Paulo * Try to re-enable interface if the driver stopped it 20405b9c547cSRui Paulo * when the interface got disabled. 20415b9c547cSRui Paulo */ 204285732ac8SCy Schubert if (hapd->wpa_auth) 20435b9c547cSRui Paulo wpa_auth_reconfig_group_keys(hapd->wpa_auth); 204485732ac8SCy Schubert else 204585732ac8SCy Schubert hostapd_reconfig_encryption(hapd); 20465b9c547cSRui Paulo hapd->reenable_beacon = 1; 20475b9c547cSRui Paulo ieee802_11_set_beacon(hapd); 20484bc52338SCy Schubert #ifdef NEED_AP_MLME 20494bc52338SCy Schubert } else if (hapd->disabled && hapd->iface->cac_started) { 20504bc52338SCy Schubert wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC"); 20514bc52338SCy Schubert hostapd_handle_dfs(hapd->iface); 20524bc52338SCy Schubert #endif /* NEED_AP_MLME */ 20535b9c547cSRui Paulo } 20545b9c547cSRui Paulo break; 20555b9c547cSRui Paulo case EVENT_INTERFACE_DISABLED: 20565b9c547cSRui Paulo hostapd_free_stas(hapd); 20575b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED); 20585b9c547cSRui Paulo hapd->disabled = 1; 20595b9c547cSRui Paulo break; 20605b9c547cSRui Paulo #ifdef CONFIG_ACS 20615b9c547cSRui Paulo case EVENT_ACS_CHANNEL_SELECTED: 2062325151a3SRui Paulo hostapd_acs_channel_selected(hapd, 2063325151a3SRui Paulo &data->acs_selected_channels); 20645b9c547cSRui Paulo break; 20655b9c547cSRui Paulo #endif /* CONFIG_ACS */ 206685732ac8SCy Schubert case EVENT_STATION_OPMODE_CHANGED: 206785732ac8SCy Schubert hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr, 206885732ac8SCy Schubert data->sta_opmode.smps_mode, 206985732ac8SCy Schubert data->sta_opmode.chan_width, 207085732ac8SCy Schubert data->sta_opmode.rx_nss); 207185732ac8SCy Schubert break; 207285732ac8SCy Schubert case EVENT_WDS_STA_INTERFACE_STATUS: 207385732ac8SCy Schubert hostapd_event_wds_sta_interface_status( 207485732ac8SCy Schubert hapd, data->wds_sta_interface.istatus, 207585732ac8SCy Schubert data->wds_sta_interface.ifname, 207685732ac8SCy Schubert data->wds_sta_interface.sta_addr); 207785732ac8SCy Schubert break; 2078e28a4053SRui Paulo default: 2079e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Unknown event %d", event); 2080e28a4053SRui Paulo break; 2081e28a4053SRui Paulo } 2082e28a4053SRui Paulo } 2083e28a4053SRui Paulo 2084780fb4a2SCy Schubert 2085780fb4a2SCy Schubert void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, 2086780fb4a2SCy Schubert union wpa_event_data *data) 2087780fb4a2SCy Schubert { 2088780fb4a2SCy Schubert struct hapd_interfaces *interfaces = ctx; 2089780fb4a2SCy Schubert struct hostapd_data *hapd; 2090780fb4a2SCy Schubert 2091780fb4a2SCy Schubert if (event != EVENT_INTERFACE_STATUS) 2092780fb4a2SCy Schubert return; 2093780fb4a2SCy Schubert 2094780fb4a2SCy Schubert hapd = hostapd_get_iface(interfaces, data->interface_status.ifname); 2095780fb4a2SCy Schubert if (hapd && hapd->driver && hapd->driver->get_ifindex && 2096780fb4a2SCy Schubert hapd->drv_priv) { 2097780fb4a2SCy Schubert unsigned int ifindex; 2098780fb4a2SCy Schubert 2099780fb4a2SCy Schubert ifindex = hapd->driver->get_ifindex(hapd->drv_priv); 2100780fb4a2SCy Schubert if (ifindex != data->interface_status.ifindex) { 2101780fb4a2SCy Schubert wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 2102780fb4a2SCy Schubert "interface status ifindex %d mismatch (%d)", 2103780fb4a2SCy Schubert ifindex, data->interface_status.ifindex); 2104780fb4a2SCy Schubert return; 2105780fb4a2SCy Schubert } 2106780fb4a2SCy Schubert } 2107780fb4a2SCy Schubert if (hapd) 2108780fb4a2SCy Schubert wpa_supplicant_event(hapd, event, data); 2109780fb4a2SCy Schubert } 2110780fb4a2SCy Schubert 2111e28a4053SRui Paulo #endif /* HOSTAPD */ 2112