1214501Srpaulo/* 2214501Srpaulo * hostapd / Callback functions for driver wrappers 3281806Srpaulo * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12281806Srpaulo#include "utils/eloop.h" 13214501Srpaulo#include "radius/radius.h" 14214501Srpaulo#include "drivers/driver.h" 15214501Srpaulo#include "common/ieee802_11_defs.h" 16214501Srpaulo#include "common/ieee802_11_common.h" 17281806Srpaulo#include "common/wpa_ctrl.h" 18346981Scy#include "common/dpp.h" 19252726Srpaulo#include "crypto/random.h" 20252726Srpaulo#include "p2p/p2p.h" 21252726Srpaulo#include "wps/wps.h" 22289549Srpaulo#include "fst/fst.h" 23252726Srpaulo#include "wnm_ap.h" 24214501Srpaulo#include "hostapd.h" 25214501Srpaulo#include "ieee802_11.h" 26337817Scy#include "ieee802_11_auth.h" 27214501Srpaulo#include "sta_info.h" 28214501Srpaulo#include "accounting.h" 29214501Srpaulo#include "tkip_countermeasures.h" 30214501Srpaulo#include "ieee802_1x.h" 31214501Srpaulo#include "wpa_auth.h" 32214501Srpaulo#include "wps_hostapd.h" 33252726Srpaulo#include "ap_drv_ops.h" 34214501Srpaulo#include "ap_config.h" 35346981Scy#include "ap_mlme.h" 36252726Srpaulo#include "hw_features.h" 37281806Srpaulo#include "dfs.h" 38281806Srpaulo#include "beacon.h" 39337817Scy#include "mbo_ap.h" 40346981Scy#include "dpp_hostapd.h" 41346981Scy#include "fils_hlp.h" 42346981Scy#include "neighbor_db.h" 43214501Srpaulo 44214501Srpaulo 45346981Scy#ifdef CONFIG_FILS 46346981Scyvoid hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, 47346981Scy struct sta_info *sta) 48346981Scy{ 49346981Scy u16 reply_res = WLAN_STATUS_SUCCESS; 50346981Scy struct ieee802_11_elems elems; 51346981Scy u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf; 52346981Scy int new_assoc; 53346981Scy 54346981Scy wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR, 55346981Scy __func__, MAC2STR(sta->addr)); 56346981Scy eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 57346981Scy if (!sta->fils_pending_assoc_req) 58346981Scy return; 59346981Scy 60346981Scy ieee802_11_parse_elems(sta->fils_pending_assoc_req, 61346981Scy sta->fils_pending_assoc_req_len, &elems, 0); 62346981Scy if (!elems.fils_session) { 63346981Scy wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element", 64346981Scy __func__); 65346981Scy return; 66346981Scy } 67346981Scy 68346981Scy p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, 69346981Scy elems.fils_session, 70346981Scy sta->fils_hlp_resp); 71346981Scy 72346981Scy reply_res = hostapd_sta_assoc(hapd, sta->addr, 73346981Scy sta->fils_pending_assoc_is_reassoc, 74346981Scy WLAN_STATUS_SUCCESS, 75346981Scy buf, p - buf); 76346981Scy ap_sta_set_authorized(hapd, sta, 1); 77346981Scy new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 78346981Scy sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 79346981Scy sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 80346981Scy hostapd_set_sta_flags(hapd, sta); 81346981Scy wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); 82346981Scy ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 83346981Scy hostapd_new_assoc_sta(hapd, sta, !new_assoc); 84346981Scy os_free(sta->fils_pending_assoc_req); 85346981Scy sta->fils_pending_assoc_req = NULL; 86346981Scy sta->fils_pending_assoc_req_len = 0; 87346981Scy wpabuf_free(sta->fils_hlp_resp); 88346981Scy sta->fils_hlp_resp = NULL; 89346981Scy wpabuf_free(sta->hlp_dhcp_discover); 90346981Scy sta->hlp_dhcp_discover = NULL; 91346981Scy fils_hlp_deinit(hapd); 92346981Scy 93346981Scy /* 94346981Scy * Remove the station in case transmission of a success response fails 95346981Scy * (the STA was added associated to the driver) or if the station was 96346981Scy * previously added unassociated. 97346981Scy */ 98346981Scy if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) { 99346981Scy hostapd_drv_sta_remove(hapd, sta->addr); 100346981Scy sta->added_unassoc = 0; 101346981Scy } 102346981Scy} 103346981Scy#endif /* CONFIG_FILS */ 104346981Scy 105346981Scy 106214501Srpauloint hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, 107252726Srpaulo const u8 *req_ies, size_t req_ies_len, int reassoc) 108214501Srpaulo{ 109214501Srpaulo struct sta_info *sta; 110214501Srpaulo int new_assoc, res; 111214501Srpaulo struct ieee802_11_elems elems; 112252726Srpaulo const u8 *ie; 113252726Srpaulo size_t ielen; 114346981Scy#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE) 115252726Srpaulo u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; 116252726Srpaulo u8 *p = buf; 117346981Scy#endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */ 118252726Srpaulo u16 reason = WLAN_REASON_UNSPECIFIED; 119252726Srpaulo u16 status = WLAN_STATUS_SUCCESS; 120281806Srpaulo const u8 *p2p_dev_addr = NULL; 121214501Srpaulo 122214501Srpaulo if (addr == NULL) { 123214501Srpaulo /* 124214501Srpaulo * This could potentially happen with unexpected event from the 125214501Srpaulo * driver wrapper. This was seen at least in one case where the 126214501Srpaulo * driver ended up being set to station mode while hostapd was 127214501Srpaulo * running, so better make sure we stop processing such an 128214501Srpaulo * event here. 129214501Srpaulo */ 130289549Srpaulo wpa_printf(MSG_DEBUG, 131289549Srpaulo "hostapd_notif_assoc: Skip event with no address"); 132214501Srpaulo return -1; 133214501Srpaulo } 134252726Srpaulo random_add_randomness(addr, ETH_ALEN); 135214501Srpaulo 136214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 137214501Srpaulo HOSTAPD_LEVEL_INFO, "associated"); 138214501Srpaulo 139252726Srpaulo ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); 140214501Srpaulo if (elems.wps_ie) { 141214501Srpaulo ie = elems.wps_ie - 2; 142214501Srpaulo ielen = elems.wps_ie_len + 2; 143214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); 144214501Srpaulo } else if (elems.rsn_ie) { 145214501Srpaulo ie = elems.rsn_ie - 2; 146214501Srpaulo ielen = elems.rsn_ie_len + 2; 147214501Srpaulo wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); 148214501Srpaulo } else if (elems.wpa_ie) { 149214501Srpaulo ie = elems.wpa_ie - 2; 150214501Srpaulo ielen = elems.wpa_ie_len + 2; 151214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); 152281806Srpaulo#ifdef CONFIG_HS20 153281806Srpaulo } else if (elems.osen) { 154281806Srpaulo ie = elems.osen - 2; 155281806Srpaulo ielen = elems.osen_len + 2; 156281806Srpaulo wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq"); 157281806Srpaulo#endif /* CONFIG_HS20 */ 158214501Srpaulo } else { 159214501Srpaulo ie = NULL; 160214501Srpaulo ielen = 0; 161289549Srpaulo wpa_printf(MSG_DEBUG, 162289549Srpaulo "STA did not include WPS/RSN/WPA IE in (Re)AssocReq"); 163214501Srpaulo } 164214501Srpaulo 165214501Srpaulo sta = ap_get_sta(hapd, addr); 166214501Srpaulo if (sta) { 167281806Srpaulo ap_sta_no_session_timeout(hapd, sta); 168214501Srpaulo accounting_sta_stop(hapd, sta); 169252726Srpaulo 170252726Srpaulo /* 171252726Srpaulo * Make sure that the previously registered inactivity timer 172252726Srpaulo * will not remove the STA immediately. 173252726Srpaulo */ 174252726Srpaulo sta->timeout_next = STA_NULLFUNC; 175214501Srpaulo } else { 176214501Srpaulo sta = ap_sta_add(hapd, addr); 177252726Srpaulo if (sta == NULL) { 178252726Srpaulo hostapd_drv_sta_disassoc(hapd, addr, 179252726Srpaulo WLAN_REASON_DISASSOC_AP_BUSY); 180214501Srpaulo return -1; 181252726Srpaulo } 182214501Srpaulo } 183252726Srpaulo sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 184214501Srpaulo 185337817Scy /* 186337817Scy * ACL configurations to the drivers (implementing AP SME and ACL 187337817Scy * offload) without hostapd's knowledge, can result in a disconnection 188337817Scy * though the driver accepts the connection. Skip the hostapd check for 189337817Scy * ACL if the driver supports ACL offload to avoid potentially 190337817Scy * conflicting ACL rules. 191337817Scy */ 192337817Scy if (hapd->iface->drv_max_acl_mac_addrs == 0 && 193337817Scy hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) { 194337817Scy wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect", 195337817Scy MAC2STR(addr)); 196337817Scy reason = WLAN_REASON_UNSPECIFIED; 197337817Scy goto fail; 198337817Scy } 199337817Scy 200252726Srpaulo#ifdef CONFIG_P2P 201252726Srpaulo if (elems.p2p) { 202252726Srpaulo wpabuf_free(sta->p2p_ie); 203252726Srpaulo sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 204252726Srpaulo P2P_IE_VENDOR_TYPE); 205281806Srpaulo if (sta->p2p_ie) 206281806Srpaulo p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 207252726Srpaulo } 208252726Srpaulo#endif /* CONFIG_P2P */ 209252726Srpaulo 210281806Srpaulo#ifdef CONFIG_IEEE80211N 211281806Srpaulo#ifdef NEED_AP_MLME 212281806Srpaulo if (elems.ht_capabilities && 213281806Srpaulo (hapd->iface->conf->ht_capab & 214281806Srpaulo HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 215281806Srpaulo struct ieee80211_ht_capabilities *ht_cap = 216281806Srpaulo (struct ieee80211_ht_capabilities *) 217281806Srpaulo elems.ht_capabilities; 218281806Srpaulo 219281806Srpaulo if (le_to_host16(ht_cap->ht_capabilities_info) & 220281806Srpaulo HT_CAP_INFO_40MHZ_INTOLERANT) 221281806Srpaulo ht40_intolerant_add(hapd->iface, sta); 222281806Srpaulo } 223281806Srpaulo#endif /* NEED_AP_MLME */ 224281806Srpaulo#endif /* CONFIG_IEEE80211N */ 225281806Srpaulo 226281806Srpaulo#ifdef CONFIG_INTERWORKING 227281806Srpaulo if (elems.ext_capab && elems.ext_capab_len > 4) { 228281806Srpaulo if (elems.ext_capab[4] & 0x01) 229281806Srpaulo sta->qos_map_enabled = 1; 230281806Srpaulo } 231281806Srpaulo#endif /* CONFIG_INTERWORKING */ 232281806Srpaulo 233252726Srpaulo#ifdef CONFIG_HS20 234252726Srpaulo wpabuf_free(sta->hs20_ie); 235252726Srpaulo if (elems.hs20 && elems.hs20_len > 4) { 236252726Srpaulo sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, 237252726Srpaulo elems.hs20_len - 4); 238252726Srpaulo } else 239252726Srpaulo sta->hs20_ie = NULL; 240346981Scy 241346981Scy wpabuf_free(sta->roaming_consortium); 242346981Scy if (elems.roaming_cons_sel) 243346981Scy sta->roaming_consortium = wpabuf_alloc_copy( 244346981Scy elems.roaming_cons_sel + 4, 245346981Scy elems.roaming_cons_sel_len - 4); 246346981Scy else 247346981Scy sta->roaming_consortium = NULL; 248252726Srpaulo#endif /* CONFIG_HS20 */ 249252726Srpaulo 250289549Srpaulo#ifdef CONFIG_FST 251289549Srpaulo wpabuf_free(sta->mb_ies); 252289549Srpaulo if (hapd->iface->fst) 253289549Srpaulo sta->mb_ies = mb_ies_by_info(&elems.mb_ies); 254289549Srpaulo else 255289549Srpaulo sta->mb_ies = NULL; 256289549Srpaulo#endif /* CONFIG_FST */ 257289549Srpaulo 258337817Scy mbo_ap_check_sta_assoc(hapd, sta, &elems); 259337817Scy 260337817Scy ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes, 261337817Scy elems.supp_op_classes_len); 262337817Scy 263214501Srpaulo if (hapd->conf->wpa) { 264214501Srpaulo if (ie == NULL || ielen == 0) { 265252726Srpaulo#ifdef CONFIG_WPS 266214501Srpaulo if (hapd->conf->wps_state) { 267289549Srpaulo wpa_printf(MSG_DEBUG, 268289549Srpaulo "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use"); 269214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 270214501Srpaulo goto skip_wpa_check; 271214501Srpaulo } 272252726Srpaulo#endif /* CONFIG_WPS */ 273214501Srpaulo 274214501Srpaulo wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); 275346981Scy reason = WLAN_REASON_INVALID_IE; 276346981Scy status = WLAN_STATUS_INVALID_IE; 277346981Scy goto fail; 278214501Srpaulo } 279252726Srpaulo#ifdef CONFIG_WPS 280214501Srpaulo if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && 281214501Srpaulo os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { 282252726Srpaulo struct wpabuf *wps; 283289549Srpaulo 284214501Srpaulo sta->flags |= WLAN_STA_WPS; 285252726Srpaulo wps = ieee802_11_vendor_ie_concat(ie, ielen, 286252726Srpaulo WPS_IE_VENDOR_TYPE); 287252726Srpaulo if (wps) { 288252726Srpaulo if (wps_is_20(wps)) { 289289549Srpaulo wpa_printf(MSG_DEBUG, 290289549Srpaulo "WPS: STA supports WPS 2.0"); 291252726Srpaulo sta->flags |= WLAN_STA_WPS2; 292252726Srpaulo } 293252726Srpaulo wpabuf_free(wps); 294252726Srpaulo } 295214501Srpaulo goto skip_wpa_check; 296214501Srpaulo } 297252726Srpaulo#endif /* CONFIG_WPS */ 298214501Srpaulo 299214501Srpaulo if (sta->wpa_sm == NULL) 300214501Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 301281806Srpaulo sta->addr, 302281806Srpaulo p2p_dev_addr); 303214501Srpaulo if (sta->wpa_sm == NULL) { 304289549Srpaulo wpa_printf(MSG_ERROR, 305289549Srpaulo "Failed to initialize WPA state machine"); 306214501Srpaulo return -1; 307214501Srpaulo } 308214501Srpaulo res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 309346981Scy hapd->iface->freq, 310252726Srpaulo ie, ielen, 311346981Scy elems.mdie, elems.mdie_len, 312346981Scy elems.owe_dh, elems.owe_dh_len); 313214501Srpaulo if (res != WPA_IE_OK) { 314289549Srpaulo wpa_printf(MSG_DEBUG, 315289549Srpaulo "WPA/RSN information element rejected? (res %u)", 316289549Srpaulo res); 317214501Srpaulo wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); 318252726Srpaulo if (res == WPA_INVALID_GROUP) { 319252726Srpaulo reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; 320252726Srpaulo status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 321252726Srpaulo } else if (res == WPA_INVALID_PAIRWISE) { 322252726Srpaulo reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; 323252726Srpaulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 324252726Srpaulo } else if (res == WPA_INVALID_AKMP) { 325252726Srpaulo reason = WLAN_REASON_AKMP_NOT_VALID; 326252726Srpaulo status = WLAN_STATUS_AKMP_NOT_VALID; 327252726Srpaulo } 328214501Srpaulo#ifdef CONFIG_IEEE80211W 329252726Srpaulo else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { 330252726Srpaulo reason = WLAN_REASON_INVALID_IE; 331252726Srpaulo status = WLAN_STATUS_INVALID_IE; 332252726Srpaulo } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { 333346981Scy reason = WLAN_REASON_CIPHER_SUITE_REJECTED; 334346981Scy status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 335252726Srpaulo } 336214501Srpaulo#endif /* CONFIG_IEEE80211W */ 337252726Srpaulo else { 338252726Srpaulo reason = WLAN_REASON_INVALID_IE; 339252726Srpaulo status = WLAN_STATUS_INVALID_IE; 340252726Srpaulo } 341252726Srpaulo goto fail; 342214501Srpaulo } 343252726Srpaulo#ifdef CONFIG_IEEE80211W 344346981Scy if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 345346981Scy (WLAN_STA_ASSOC | WLAN_STA_MFP) && 346346981Scy !sta->sa_query_timed_out && 347252726Srpaulo sta->sa_query_count > 0) 348252726Srpaulo ap_check_sa_query_timeout(hapd, sta); 349346981Scy if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) == 350346981Scy (WLAN_STA_ASSOC | WLAN_STA_MFP) && 351346981Scy !sta->sa_query_timed_out && 352252726Srpaulo (sta->auth_alg != WLAN_AUTH_FT)) { 353252726Srpaulo /* 354252726Srpaulo * STA has already been associated with MFP and SA 355252726Srpaulo * Query timeout has not been reached. Reject the 356252726Srpaulo * association attempt temporarily and start SA Query, 357252726Srpaulo * if one is not pending. 358252726Srpaulo */ 359252726Srpaulo 360252726Srpaulo if (sta->sa_query_count == 0) 361252726Srpaulo ap_sta_start_sa_query(hapd, sta); 362252726Srpaulo 363252726Srpaulo status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 364252726Srpaulo 365252726Srpaulo p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 366252726Srpaulo 367252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, 368252726Srpaulo p - buf); 369252726Srpaulo return 0; 370252726Srpaulo } 371252726Srpaulo 372252726Srpaulo if (wpa_auth_uses_mfp(sta->wpa_sm)) 373252726Srpaulo sta->flags |= WLAN_STA_MFP; 374252726Srpaulo else 375252726Srpaulo sta->flags &= ~WLAN_STA_MFP; 376252726Srpaulo#endif /* CONFIG_IEEE80211W */ 377252726Srpaulo 378346981Scy#ifdef CONFIG_IEEE80211R_AP 379252726Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) { 380252726Srpaulo status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, 381252726Srpaulo req_ies_len); 382252726Srpaulo if (status != WLAN_STATUS_SUCCESS) { 383252726Srpaulo if (status == WLAN_STATUS_INVALID_PMKID) 384252726Srpaulo reason = WLAN_REASON_INVALID_IE; 385252726Srpaulo if (status == WLAN_STATUS_INVALID_MDIE) 386252726Srpaulo reason = WLAN_REASON_INVALID_IE; 387252726Srpaulo if (status == WLAN_STATUS_INVALID_FTIE) 388252726Srpaulo reason = WLAN_REASON_INVALID_IE; 389252726Srpaulo goto fail; 390252726Srpaulo } 391252726Srpaulo } 392346981Scy#endif /* CONFIG_IEEE80211R_AP */ 393214501Srpaulo } else if (hapd->conf->wps_state) { 394252726Srpaulo#ifdef CONFIG_WPS 395252726Srpaulo struct wpabuf *wps; 396289549Srpaulo 397252726Srpaulo if (req_ies) 398252726Srpaulo wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 399252726Srpaulo WPS_IE_VENDOR_TYPE); 400252726Srpaulo else 401252726Srpaulo wps = NULL; 402252726Srpaulo#ifdef CONFIG_WPS_STRICT 403252726Srpaulo if (wps && wps_validate_assoc_req(wps) < 0) { 404252726Srpaulo reason = WLAN_REASON_INVALID_IE; 405252726Srpaulo status = WLAN_STATUS_INVALID_IE; 406252726Srpaulo wpabuf_free(wps); 407252726Srpaulo goto fail; 408252726Srpaulo } 409252726Srpaulo#endif /* CONFIG_WPS_STRICT */ 410252726Srpaulo if (wps) { 411214501Srpaulo sta->flags |= WLAN_STA_WPS; 412252726Srpaulo if (wps_is_20(wps)) { 413289549Srpaulo wpa_printf(MSG_DEBUG, 414289549Srpaulo "WPS: STA supports WPS 2.0"); 415252726Srpaulo sta->flags |= WLAN_STA_WPS2; 416252726Srpaulo } 417214501Srpaulo } else 418214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 419252726Srpaulo wpabuf_free(wps); 420252726Srpaulo#endif /* CONFIG_WPS */ 421281806Srpaulo#ifdef CONFIG_HS20 422281806Srpaulo } else if (hapd->conf->osen) { 423281806Srpaulo if (elems.osen == NULL) { 424281806Srpaulo hostapd_logger( 425281806Srpaulo hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 426281806Srpaulo HOSTAPD_LEVEL_INFO, 427281806Srpaulo "No HS 2.0 OSEN element in association request"); 428281806Srpaulo return WLAN_STATUS_INVALID_IE; 429281806Srpaulo } 430281806Srpaulo 431281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); 432281806Srpaulo if (sta->wpa_sm == NULL) 433281806Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 434281806Srpaulo sta->addr, NULL); 435281806Srpaulo if (sta->wpa_sm == NULL) { 436289549Srpaulo wpa_printf(MSG_WARNING, 437289549Srpaulo "Failed to initialize WPA state machine"); 438281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 439281806Srpaulo } 440281806Srpaulo if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, 441281806Srpaulo elems.osen - 2, elems.osen_len + 2) < 0) 442281806Srpaulo return WLAN_STATUS_INVALID_IE; 443281806Srpaulo#endif /* CONFIG_HS20 */ 444214501Srpaulo } 445337817Scy 446337817Scy#ifdef CONFIG_MBO 447337817Scy if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && 448337817Scy elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && 449337817Scy hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 450337817Scy wpa_printf(MSG_INFO, 451337817Scy "MBO: Reject WPA2 association without PMF"); 452337817Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 453337817Scy } 454337817Scy#endif /* CONFIG_MBO */ 455337817Scy 456252726Srpaulo#ifdef CONFIG_WPS 457214501Srpauloskip_wpa_check: 458252726Srpaulo#endif /* CONFIG_WPS */ 459214501Srpaulo 460346981Scy#ifdef CONFIG_IEEE80211R_AP 461252726Srpaulo p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), 462252726Srpaulo sta->auth_alg, req_ies, req_ies_len); 463346981Scy if (!p) { 464346981Scy wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs"); 465346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 466346981Scy } 467346981Scy#endif /* CONFIG_IEEE80211R_AP */ 468252726Srpaulo 469346981Scy#ifdef CONFIG_FILS 470346981Scy if (sta->auth_alg == WLAN_AUTH_FILS_SK || 471346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 472346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) { 473346981Scy int delay_assoc = 0; 474346981Scy 475346981Scy if (!req_ies) 476346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 477346981Scy 478346981Scy if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies, 479346981Scy req_ies_len, 480346981Scy sta->fils_session)) { 481346981Scy wpa_printf(MSG_DEBUG, 482346981Scy "FILS: Session validation failed"); 483346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 484346981Scy } 485346981Scy 486346981Scy res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies, 487346981Scy req_ies_len); 488346981Scy if (res < 0) { 489346981Scy wpa_printf(MSG_DEBUG, 490346981Scy "FILS: Key Confirm validation failed"); 491346981Scy return WLAN_STATUS_UNSPECIFIED_FAILURE; 492346981Scy } 493346981Scy 494346981Scy if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) { 495346981Scy wpa_printf(MSG_DEBUG, 496346981Scy "FILS: Delaying Assoc Response (HLP)"); 497346981Scy delay_assoc = 1; 498346981Scy } else { 499346981Scy wpa_printf(MSG_DEBUG, 500346981Scy "FILS: Going ahead with Assoc Response (no HLP)"); 501346981Scy } 502346981Scy 503346981Scy if (sta) { 504346981Scy wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup"); 505346981Scy eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); 506346981Scy os_free(sta->fils_pending_assoc_req); 507346981Scy sta->fils_pending_assoc_req = NULL; 508346981Scy sta->fils_pending_assoc_req_len = 0; 509346981Scy wpabuf_free(sta->fils_hlp_resp); 510346981Scy sta->fils_hlp_resp = NULL; 511346981Scy sta->fils_drv_assoc_finish = 0; 512346981Scy } 513346981Scy 514346981Scy if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) { 515346981Scy u8 *req_tmp; 516346981Scy 517346981Scy req_tmp = os_malloc(req_ies_len); 518346981Scy if (!req_tmp) { 519346981Scy wpa_printf(MSG_DEBUG, 520346981Scy "FILS: buffer allocation failed for assoc req"); 521346981Scy goto fail; 522346981Scy } 523346981Scy os_memcpy(req_tmp, req_ies, req_ies_len); 524346981Scy sta->fils_pending_assoc_req = req_tmp; 525346981Scy sta->fils_pending_assoc_req_len = req_ies_len; 526346981Scy sta->fils_pending_assoc_is_reassoc = reassoc; 527346981Scy sta->fils_drv_assoc_finish = 1; 528346981Scy wpa_printf(MSG_DEBUG, 529346981Scy "FILS: Waiting for HLP processing before sending (Re)Association Response frame to " 530346981Scy MACSTR, MAC2STR(sta->addr)); 531346981Scy eloop_register_timeout( 532346981Scy 0, hapd->conf->fils_hlp_wait_time * 1024, 533346981Scy fils_hlp_timeout, hapd, sta); 534346981Scy return 0; 535346981Scy } 536346981Scy p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p, 537346981Scy elems.fils_session, 538346981Scy sta->fils_hlp_resp); 539346981Scy wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)", 540346981Scy buf, p - buf); 541346981Scy } 542346981Scy#endif /* CONFIG_FILS */ 543346981Scy 544346981Scy#ifdef CONFIG_OWE 545346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 546346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && 547346981Scy elems.owe_dh) { 548346981Scy u8 *npos; 549346981Scy 550346981Scy npos = owe_assoc_req_process(hapd, sta, 551346981Scy elems.owe_dh, elems.owe_dh_len, 552346981Scy p, sizeof(buf) - (p - buf), 553346981Scy &reason); 554346981Scy if (npos) 555346981Scy p = npos; 556346981Scy if (!npos && 557346981Scy reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { 558346981Scy status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; 559346981Scy hostapd_sta_assoc(hapd, addr, reassoc, status, buf, 560346981Scy p - buf); 561346981Scy return 0; 562346981Scy } 563346981Scy 564346981Scy if (!npos || reason != WLAN_STATUS_SUCCESS) 565346981Scy goto fail; 566346981Scy } 567346981Scy#endif /* CONFIG_OWE */ 568346981Scy 569346981Scy#ifdef CONFIG_DPP2 570346981Scy dpp_pfs_free(sta->dpp_pfs); 571346981Scy sta->dpp_pfs = NULL; 572346981Scy 573346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && 574346981Scy hapd->conf->dpp_netaccesskey && sta->wpa_sm && 575346981Scy wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && 576346981Scy elems.owe_dh) { 577346981Scy sta->dpp_pfs = dpp_pfs_init( 578346981Scy wpabuf_head(hapd->conf->dpp_netaccesskey), 579346981Scy wpabuf_len(hapd->conf->dpp_netaccesskey)); 580346981Scy if (!sta->dpp_pfs) { 581346981Scy wpa_printf(MSG_DEBUG, 582346981Scy "DPP: Could not initialize PFS"); 583346981Scy /* Try to continue without PFS */ 584346981Scy goto pfs_fail; 585346981Scy } 586346981Scy 587346981Scy if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, 588346981Scy elems.owe_dh_len) < 0) { 589346981Scy dpp_pfs_free(sta->dpp_pfs); 590346981Scy sta->dpp_pfs = NULL; 591346981Scy reason = WLAN_REASON_UNSPECIFIED; 592346981Scy goto fail; 593346981Scy } 594346981Scy } 595346981Scy 596346981Scy wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ? 597346981Scy sta->dpp_pfs->secret : NULL); 598346981Scy pfs_fail: 599346981Scy#endif /* CONFIG_DPP2 */ 600346981Scy 601346981Scy#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE) 602252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 603281806Srpaulo 604346981Scy if (sta->auth_alg == WLAN_AUTH_FT || 605346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK || 606346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 607346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) 608281806Srpaulo ap_sta_set_authorized(hapd, sta, 1); 609346981Scy#else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ 610252726Srpaulo /* Keep compiler silent about unused variables */ 611252726Srpaulo if (status) { 612252726Srpaulo } 613346981Scy#endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ 614252726Srpaulo 615214501Srpaulo new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 616214501Srpaulo sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 617281806Srpaulo sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 618214501Srpaulo 619281806Srpaulo hostapd_set_sta_flags(hapd, sta); 620281806Srpaulo 621252726Srpaulo if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) 622252726Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 623346981Scy#ifdef CONFIG_FILS 624346981Scy else if (sta->auth_alg == WLAN_AUTH_FILS_SK || 625346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 626346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) 627346981Scy wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); 628346981Scy#endif /* CONFIG_FILS */ 629252726Srpaulo else 630252726Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 631252726Srpaulo 632214501Srpaulo hostapd_new_assoc_sta(hapd, sta, !new_assoc); 633214501Srpaulo 634214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 635214501Srpaulo 636252726Srpaulo#ifdef CONFIG_P2P 637252726Srpaulo if (req_ies) { 638252726Srpaulo p2p_group_notif_assoc(hapd->p2p_group, sta->addr, 639252726Srpaulo req_ies, req_ies_len); 640252726Srpaulo } 641252726Srpaulo#endif /* CONFIG_P2P */ 642252726Srpaulo 643214501Srpaulo return 0; 644252726Srpaulo 645252726Srpaulofail: 646346981Scy#ifdef CONFIG_IEEE80211R_AP 647252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 648346981Scy#endif /* CONFIG_IEEE80211R_AP */ 649252726Srpaulo hostapd_drv_sta_disassoc(hapd, sta->addr, reason); 650252726Srpaulo ap_free_sta(hapd, sta); 651252726Srpaulo return -1; 652214501Srpaulo} 653214501Srpaulo 654214501Srpaulo 655214501Srpaulovoid hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) 656214501Srpaulo{ 657214501Srpaulo struct sta_info *sta; 658214501Srpaulo 659252726Srpaulo if (addr == NULL) { 660252726Srpaulo /* 661252726Srpaulo * This could potentially happen with unexpected event from the 662252726Srpaulo * driver wrapper. This was seen at least in one case where the 663252726Srpaulo * driver ended up reporting a station mode event while hostapd 664252726Srpaulo * was running, so better make sure we stop processing such an 665252726Srpaulo * event here. 666252726Srpaulo */ 667289549Srpaulo wpa_printf(MSG_DEBUG, 668289549Srpaulo "hostapd_notif_disassoc: Skip event with no address"); 669252726Srpaulo return; 670252726Srpaulo } 671252726Srpaulo 672214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 673214501Srpaulo HOSTAPD_LEVEL_INFO, "disassociated"); 674214501Srpaulo 675214501Srpaulo sta = ap_get_sta(hapd, addr); 676214501Srpaulo if (sta == NULL) { 677289549Srpaulo wpa_printf(MSG_DEBUG, 678289549Srpaulo "Disassociation notification for unknown STA " 679289549Srpaulo MACSTR, MAC2STR(addr)); 680214501Srpaulo return; 681214501Srpaulo } 682214501Srpaulo 683252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 684214501Srpaulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 685214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 686214501Srpaulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 687214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 688214501Srpaulo ap_free_sta(hapd, sta); 689214501Srpaulo} 690214501Srpaulo 691214501Srpaulo 692252726Srpaulovoid hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) 693252726Srpaulo{ 694252726Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 695214501Srpaulo 696346981Scy if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer) 697252726Srpaulo return; 698252726Srpaulo 699252726Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 700289549Srpaulo HOSTAPD_LEVEL_INFO, 701289549Srpaulo "disconnected due to excessive missing ACKs"); 702252726Srpaulo hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); 703346981Scy ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); 704252726Srpaulo} 705252726Srpaulo 706252726Srpaulo 707346981Scyvoid hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, 708346981Scy enum smps_mode smps_mode, 709346981Scy enum chan_width chan_width, u8 rx_nss) 710346981Scy{ 711346981Scy struct sta_info *sta = ap_get_sta(hapd, addr); 712346981Scy const char *txt; 713346981Scy 714346981Scy if (!sta) 715346981Scy return; 716346981Scy 717346981Scy switch (smps_mode) { 718346981Scy case SMPS_AUTOMATIC: 719346981Scy txt = "automatic"; 720346981Scy break; 721346981Scy case SMPS_OFF: 722346981Scy txt = "off"; 723346981Scy break; 724346981Scy case SMPS_DYNAMIC: 725346981Scy txt = "dynamic"; 726346981Scy break; 727346981Scy case SMPS_STATIC: 728346981Scy txt = "static"; 729346981Scy break; 730346981Scy default: 731346981Scy txt = NULL; 732346981Scy break; 733346981Scy } 734346981Scy if (txt) { 735346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED 736346981Scy MACSTR " %s", MAC2STR(addr), txt); 737346981Scy } 738346981Scy 739346981Scy switch (chan_width) { 740346981Scy case CHAN_WIDTH_20_NOHT: 741346981Scy txt = "20(no-HT)"; 742346981Scy break; 743346981Scy case CHAN_WIDTH_20: 744346981Scy txt = "20"; 745346981Scy break; 746346981Scy case CHAN_WIDTH_40: 747346981Scy txt = "40"; 748346981Scy break; 749346981Scy case CHAN_WIDTH_80: 750346981Scy txt = "80"; 751346981Scy break; 752346981Scy case CHAN_WIDTH_80P80: 753346981Scy txt = "80+80"; 754346981Scy break; 755346981Scy case CHAN_WIDTH_160: 756346981Scy txt = "160"; 757346981Scy break; 758346981Scy default: 759346981Scy txt = NULL; 760346981Scy break; 761346981Scy } 762346981Scy if (txt) { 763346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED 764346981Scy MACSTR " %s", MAC2STR(addr), txt); 765346981Scy } 766346981Scy 767346981Scy if (rx_nss != 0xff) { 768346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED 769346981Scy MACSTR " %d", MAC2STR(addr), rx_nss); 770346981Scy } 771346981Scy} 772346981Scy 773346981Scy 774252726Srpaulovoid hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, 775351611Scy int offset, int width, int cf1, int cf2, 776351611Scy int finished) 777252726Srpaulo{ 778346981Scy /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */ 779346981Scy 780214501Srpaulo#ifdef NEED_AP_MLME 781337817Scy int channel, chwidth, is_dfs; 782337817Scy u8 seg0_idx = 0, seg1_idx = 0; 783346981Scy size_t i; 784214501Srpaulo 785252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 786281806Srpaulo HOSTAPD_LEVEL_INFO, 787351611Scy "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", 788351611Scy finished ? "had" : "starting", 789346981Scy freq, ht, hapd->iconf->ch_switch_vht_config, offset, 790346981Scy width, channel_width_to_string(width), cf1, cf2); 791252726Srpaulo 792351611Scy if (!hapd->iface->current_mode) { 793351611Scy hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 794351611Scy HOSTAPD_LEVEL_WARNING, 795351611Scy "ignore channel switch since the interface is not yet ready"); 796351611Scy return; 797351611Scy } 798351611Scy 799252726Srpaulo hapd->iface->freq = freq; 800252726Srpaulo 801252726Srpaulo channel = hostapd_hw_get_channel(hapd, freq); 802252726Srpaulo if (!channel) { 803252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 804289549Srpaulo HOSTAPD_LEVEL_WARNING, 805289549Srpaulo "driver switched to bad channel!"); 806252726Srpaulo return; 807252726Srpaulo } 808252726Srpaulo 809281806Srpaulo switch (width) { 810281806Srpaulo case CHAN_WIDTH_80: 811351611Scy chwidth = CHANWIDTH_80MHZ; 812281806Srpaulo break; 813281806Srpaulo case CHAN_WIDTH_80P80: 814351611Scy chwidth = CHANWIDTH_80P80MHZ; 815281806Srpaulo break; 816281806Srpaulo case CHAN_WIDTH_160: 817351611Scy chwidth = CHANWIDTH_160MHZ; 818281806Srpaulo break; 819281806Srpaulo case CHAN_WIDTH_20_NOHT: 820281806Srpaulo case CHAN_WIDTH_20: 821281806Srpaulo case CHAN_WIDTH_40: 822281806Srpaulo default: 823351611Scy chwidth = CHANWIDTH_USE_HT; 824281806Srpaulo break; 825281806Srpaulo } 826281806Srpaulo 827281806Srpaulo switch (hapd->iface->current_mode->mode) { 828281806Srpaulo case HOSTAPD_MODE_IEEE80211A: 829281806Srpaulo if (cf1 > 5000) 830281806Srpaulo seg0_idx = (cf1 - 5000) / 5; 831281806Srpaulo if (cf2 > 5000) 832281806Srpaulo seg1_idx = (cf2 - 5000) / 5; 833281806Srpaulo break; 834281806Srpaulo default: 835337817Scy ieee80211_freq_to_chan(cf1, &seg0_idx); 836337817Scy ieee80211_freq_to_chan(cf2, &seg1_idx); 837281806Srpaulo break; 838281806Srpaulo } 839281806Srpaulo 840252726Srpaulo hapd->iconf->channel = channel; 841252726Srpaulo hapd->iconf->ieee80211n = ht; 842346981Scy if (!ht) { 843281806Srpaulo hapd->iconf->ieee80211ac = 0; 844346981Scy } else if (hapd->iconf->ch_switch_vht_config) { 845346981Scy /* CHAN_SWITCH VHT config */ 846346981Scy if (hapd->iconf->ch_switch_vht_config & 847346981Scy CH_SWITCH_VHT_ENABLED) 848346981Scy hapd->iconf->ieee80211ac = 1; 849346981Scy else if (hapd->iconf->ch_switch_vht_config & 850346981Scy CH_SWITCH_VHT_DISABLED) 851346981Scy hapd->iconf->ieee80211ac = 0; 852346981Scy } 853346981Scy hapd->iconf->ch_switch_vht_config = 0; 854346981Scy 855252726Srpaulo hapd->iconf->secondary_channel = offset; 856351611Scy hostapd_set_oper_chwidth(hapd->iconf, chwidth); 857351611Scy hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx); 858351611Scy hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx); 859281806Srpaulo 860346981Scy is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features, 861346981Scy hapd->iface->num_hw_features); 862281806Srpaulo 863351611Scy wpa_msg(hapd->msg_ctx, MSG_INFO, 864351611Scy "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d", 865351611Scy finished ? WPA_EVENT_CHANNEL_SWITCH : 866351611Scy WPA_EVENT_CHANNEL_SWITCH_STARTED, 867351611Scy freq, ht, offset, channel_width_to_string(width), 868351611Scy cf1, cf2, is_dfs); 869351611Scy if (!finished) 870351611Scy return; 871351611Scy 872281806Srpaulo if (hapd->csa_in_progress && 873281806Srpaulo freq == hapd->cs_freq_params.freq) { 874281806Srpaulo hostapd_cleanup_cs_params(hapd); 875281806Srpaulo ieee802_11_set_beacon(hapd); 876281806Srpaulo 877281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 878281806Srpaulo "freq=%d dfs=%d", freq, is_dfs); 879281806Srpaulo } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { 880281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 881281806Srpaulo "freq=%d dfs=%d", freq, is_dfs); 882281806Srpaulo } 883346981Scy 884346981Scy for (i = 0; i < hapd->iface->num_bss; i++) 885346981Scy hostapd_neighbor_set_own_report(hapd->iface->bss[i]); 886252726Srpaulo#endif /* NEED_AP_MLME */ 887252726Srpaulo} 888252726Srpaulo 889252726Srpaulo 890281806Srpaulovoid hostapd_event_connect_failed_reason(struct hostapd_data *hapd, 891281806Srpaulo const u8 *addr, int reason_code) 892281806Srpaulo{ 893281806Srpaulo switch (reason_code) { 894281806Srpaulo case MAX_CLIENT_REACHED: 895281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR, 896281806Srpaulo MAC2STR(addr)); 897281806Srpaulo break; 898281806Srpaulo case BLOCKED_CLIENT: 899281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR, 900281806Srpaulo MAC2STR(addr)); 901281806Srpaulo break; 902281806Srpaulo } 903281806Srpaulo} 904281806Srpaulo 905281806Srpaulo 906281806Srpaulo#ifdef CONFIG_ACS 907337817Scyvoid hostapd_acs_channel_selected(struct hostapd_data *hapd, 908337817Scy struct acs_selected_channels *acs_res) 909281806Srpaulo{ 910289549Srpaulo int ret, i; 911337817Scy int err = 0; 912281806Srpaulo 913281806Srpaulo if (hapd->iconf->channel) { 914281806Srpaulo wpa_printf(MSG_INFO, "ACS: Channel was already set to %d", 915281806Srpaulo hapd->iconf->channel); 916281806Srpaulo return; 917281806Srpaulo } 918281806Srpaulo 919289549Srpaulo if (!hapd->iface->current_mode) { 920289549Srpaulo for (i = 0; i < hapd->iface->num_hw_features; i++) { 921289549Srpaulo struct hostapd_hw_modes *mode = 922289549Srpaulo &hapd->iface->hw_features[i]; 923281806Srpaulo 924289549Srpaulo if (mode->mode == acs_res->hw_mode) { 925289549Srpaulo hapd->iface->current_mode = mode; 926289549Srpaulo break; 927289549Srpaulo } 928289549Srpaulo } 929289549Srpaulo if (!hapd->iface->current_mode) { 930289549Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 931289549Srpaulo HOSTAPD_LEVEL_WARNING, 932289549Srpaulo "driver selected to bad hw_mode"); 933337817Scy err = 1; 934337817Scy goto out; 935289549Srpaulo } 936289549Srpaulo } 937289549Srpaulo 938289549Srpaulo hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel); 939289549Srpaulo 940289549Srpaulo if (!acs_res->pri_channel) { 941281806Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 942281806Srpaulo HOSTAPD_LEVEL_WARNING, 943281806Srpaulo "driver switched to bad channel"); 944337817Scy err = 1; 945337817Scy goto out; 946281806Srpaulo } 947281806Srpaulo 948289549Srpaulo hapd->iconf->channel = acs_res->pri_channel; 949289549Srpaulo hapd->iconf->acs = 1; 950281806Srpaulo 951289549Srpaulo if (acs_res->sec_channel == 0) 952281806Srpaulo hapd->iconf->secondary_channel = 0; 953289549Srpaulo else if (acs_res->sec_channel < acs_res->pri_channel) 954281806Srpaulo hapd->iconf->secondary_channel = -1; 955289549Srpaulo else if (acs_res->sec_channel > acs_res->pri_channel) 956281806Srpaulo hapd->iconf->secondary_channel = 1; 957281806Srpaulo else { 958281806Srpaulo wpa_printf(MSG_ERROR, "Invalid secondary channel!"); 959337817Scy err = 1; 960337817Scy goto out; 961281806Srpaulo } 962281806Srpaulo 963351611Scy if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) { 964289549Srpaulo /* set defaults for backwards compatibility */ 965351611Scy hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); 966351611Scy hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0); 967351611Scy hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT); 968289549Srpaulo if (acs_res->ch_width == 80) { 969351611Scy hostapd_set_oper_centr_freq_seg0_idx( 970351611Scy hapd->iconf, acs_res->vht_seg0_center_ch); 971351611Scy hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ); 972289549Srpaulo } else if (acs_res->ch_width == 160) { 973289549Srpaulo if (acs_res->vht_seg1_center_ch == 0) { 974351611Scy hostapd_set_oper_centr_freq_seg0_idx( 975351611Scy hapd->iconf, 976351611Scy acs_res->vht_seg0_center_ch); 977351611Scy hostapd_set_oper_chwidth(hapd->iconf, 978351611Scy CHANWIDTH_160MHZ); 979289549Srpaulo } else { 980351611Scy hostapd_set_oper_centr_freq_seg0_idx( 981351611Scy hapd->iconf, 982351611Scy acs_res->vht_seg0_center_ch); 983351611Scy hostapd_set_oper_centr_freq_seg1_idx( 984351611Scy hapd->iconf, 985351611Scy acs_res->vht_seg1_center_ch); 986351611Scy hostapd_set_oper_chwidth(hapd->iconf, 987351611Scy CHANWIDTH_80P80MHZ); 988289549Srpaulo } 989289549Srpaulo } 990289549Srpaulo } 991289549Srpaulo 992337817Scyout: 993337817Scy ret = hostapd_acs_completed(hapd->iface, err); 994281806Srpaulo if (ret) { 995281806Srpaulo wpa_printf(MSG_ERROR, 996281806Srpaulo "ACS: Possibly channel configuration is invalid"); 997281806Srpaulo } 998281806Srpaulo} 999281806Srpaulo#endif /* CONFIG_ACS */ 1000281806Srpaulo 1001281806Srpaulo 1002252726Srpauloint hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, 1003252726Srpaulo const u8 *bssid, const u8 *ie, size_t ie_len, 1004252726Srpaulo int ssi_signal) 1005214501Srpaulo{ 1006252726Srpaulo size_t i; 1007252726Srpaulo int ret = 0; 1008214501Srpaulo 1009252726Srpaulo if (sa == NULL || ie == NULL) 1010252726Srpaulo return -1; 1011214501Srpaulo 1012252726Srpaulo random_add_randomness(sa, ETH_ALEN); 1013252726Srpaulo for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { 1014252726Srpaulo if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 1015252726Srpaulo sa, da, bssid, ie, ie_len, 1016252726Srpaulo ssi_signal) > 0) { 1017252726Srpaulo ret = 1; 1018252726Srpaulo break; 1019252726Srpaulo } 1020252726Srpaulo } 1021252726Srpaulo return ret; 1022252726Srpaulo} 1023214501Srpaulo 1024252726Srpaulo 1025252726Srpaulo#ifdef HOSTAPD 1026252726Srpaulo 1027346981Scy#ifdef CONFIG_IEEE80211R_AP 1028252726Srpaulostatic void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, 1029252726Srpaulo const u8 *bssid, 1030252726Srpaulo u16 auth_transaction, u16 status, 1031252726Srpaulo const u8 *ies, size_t ies_len) 1032252726Srpaulo{ 1033252726Srpaulo struct hostapd_data *hapd = ctx; 1034252726Srpaulo struct sta_info *sta; 1035252726Srpaulo 1036252726Srpaulo sta = ap_get_sta(hapd, dst); 1037252726Srpaulo if (sta == NULL) 1038252726Srpaulo return; 1039252726Srpaulo 1040252726Srpaulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 1041252726Srpaulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 1042252726Srpaulo sta->flags |= WLAN_STA_AUTH; 1043252726Srpaulo 1044252726Srpaulo hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len); 1045252726Srpaulo} 1046346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1047252726Srpaulo 1048252726Srpaulo 1049346981Scy#ifdef CONFIG_FILS 1050346981Scystatic void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd, 1051346981Scy struct sta_info *sta, u16 resp, 1052346981Scy struct wpabuf *data, int pub) 1053346981Scy{ 1054346981Scy if (resp == WLAN_STATUS_SUCCESS) { 1055346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1056346981Scy HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)"); 1057346981Scy sta->flags |= WLAN_STA_AUTH; 1058346981Scy wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 1059346981Scy sta->auth_alg = WLAN_AUTH_FILS_SK; 1060346981Scy mlme_authenticate_indication(hapd, sta); 1061346981Scy } else { 1062346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1063346981Scy HOSTAPD_LEVEL_DEBUG, 1064346981Scy "authentication failed (FILS)"); 1065346981Scy } 1066346981Scy 1067346981Scy hostapd_sta_auth(hapd, sta->addr, 2, resp, 1068346981Scy data ? wpabuf_head(data) : NULL, 1069346981Scy data ? wpabuf_len(data) : 0); 1070346981Scy wpabuf_free(data); 1071346981Scy} 1072346981Scy#endif /* CONFIG_FILS */ 1073346981Scy 1074346981Scy 1075252726Srpaulostatic void hostapd_notif_auth(struct hostapd_data *hapd, 1076252726Srpaulo struct auth_info *rx_auth) 1077252726Srpaulo{ 1078252726Srpaulo struct sta_info *sta; 1079252726Srpaulo u16 status = WLAN_STATUS_SUCCESS; 1080252726Srpaulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 1081252726Srpaulo size_t resp_ies_len = 0; 1082252726Srpaulo 1083252726Srpaulo sta = ap_get_sta(hapd, rx_auth->peer); 1084252726Srpaulo if (!sta) { 1085252726Srpaulo sta = ap_sta_add(hapd, rx_auth->peer); 1086252726Srpaulo if (sta == NULL) { 1087281806Srpaulo status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 1088252726Srpaulo goto fail; 1089214501Srpaulo } 1090214501Srpaulo } 1091252726Srpaulo sta->flags &= ~WLAN_STA_PREAUTH; 1092252726Srpaulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 1093346981Scy#ifdef CONFIG_IEEE80211R_AP 1094252726Srpaulo if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { 1095252726Srpaulo sta->auth_alg = WLAN_AUTH_FT; 1096252726Srpaulo if (sta->wpa_sm == NULL) 1097252726Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 1098281806Srpaulo sta->addr, NULL); 1099252726Srpaulo if (sta->wpa_sm == NULL) { 1100289549Srpaulo wpa_printf(MSG_DEBUG, 1101289549Srpaulo "FT: Failed to initialize WPA state machine"); 1102252726Srpaulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1103252726Srpaulo goto fail; 1104252726Srpaulo } 1105252726Srpaulo wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, 1106252726Srpaulo rx_auth->auth_transaction, rx_auth->ies, 1107252726Srpaulo rx_auth->ies_len, 1108252726Srpaulo hostapd_notify_auth_ft_finish, hapd); 1109252726Srpaulo return; 1110252726Srpaulo } 1111346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1112346981Scy 1113346981Scy#ifdef CONFIG_FILS 1114346981Scy if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) { 1115346981Scy sta->auth_alg = WLAN_AUTH_FILS_SK; 1116346981Scy handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len, 1117346981Scy rx_auth->auth_type, rx_auth->auth_transaction, 1118346981Scy rx_auth->status_code, 1119346981Scy hostapd_notify_auth_fils_finish); 1120346981Scy return; 1121346981Scy } 1122346981Scy#endif /* CONFIG_FILS */ 1123346981Scy 1124252726Srpaulofail: 1125252726Srpaulo hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, 1126252726Srpaulo status, resp_ies, resp_ies_len); 1127214501Srpaulo} 1128214501Srpaulo 1129214501Srpaulo 1130346981Scy#ifndef NEED_AP_MLME 1131252726Srpaulostatic void hostapd_action_rx(struct hostapd_data *hapd, 1132281806Srpaulo struct rx_mgmt *drv_mgmt) 1133252726Srpaulo{ 1134281806Srpaulo struct ieee80211_mgmt *mgmt; 1135252726Srpaulo struct sta_info *sta; 1136281806Srpaulo size_t plen __maybe_unused; 1137281806Srpaulo u16 fc; 1138346981Scy u8 *action __maybe_unused; 1139252726Srpaulo 1140346981Scy if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1) 1141281806Srpaulo return; 1142281806Srpaulo 1143346981Scy plen = drv_mgmt->frame_len - IEEE80211_HDRLEN; 1144281806Srpaulo 1145281806Srpaulo mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; 1146281806Srpaulo fc = le_to_host16(mgmt->frame_control); 1147281806Srpaulo if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) 1148281806Srpaulo return; /* handled by the driver */ 1149281806Srpaulo 1150346981Scy action = (u8 *) &mgmt->u.action.u; 1151346981Scy wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR 1152346981Scy " da " MACSTR " plen %d", 1153346981Scy mgmt->u.action.category, *action, 1154346981Scy MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen); 1155252726Srpaulo 1156281806Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 1157252726Srpaulo if (sta == NULL) { 1158252726Srpaulo wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 1159252726Srpaulo return; 1160252726Srpaulo } 1161346981Scy#ifdef CONFIG_IEEE80211R_AP 1162281806Srpaulo if (mgmt->u.action.category == WLAN_ACTION_FT) { 1163346981Scy wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen); 1164346981Scy return; 1165252726Srpaulo } 1166346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1167252726Srpaulo#ifdef CONFIG_IEEE80211W 1168346981Scy if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) { 1169346981Scy ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len); 1170346981Scy return; 1171252726Srpaulo } 1172252726Srpaulo#endif /* CONFIG_IEEE80211W */ 1173346981Scy#ifdef CONFIG_WNM_AP 1174281806Srpaulo if (mgmt->u.action.category == WLAN_ACTION_WNM) { 1175281806Srpaulo ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); 1176346981Scy return; 1177252726Srpaulo } 1178346981Scy#endif /* CONFIG_WNM_AP */ 1179289549Srpaulo#ifdef CONFIG_FST 1180289549Srpaulo if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) { 1181289549Srpaulo fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len); 1182289549Srpaulo return; 1183289549Srpaulo } 1184289549Srpaulo#endif /* CONFIG_FST */ 1185346981Scy#ifdef CONFIG_DPP 1186346981Scy if (plen >= 2 + 4 && 1187346981Scy mgmt->u.action.u.vs_public_action.action == 1188346981Scy WLAN_PA_VENDOR_SPECIFIC && 1189346981Scy WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 1190346981Scy OUI_WFA && 1191346981Scy mgmt->u.action.u.vs_public_action.variable[0] == 1192346981Scy DPP_OUI_TYPE) { 1193346981Scy const u8 *pos, *end; 1194289549Srpaulo 1195346981Scy pos = mgmt->u.action.u.vs_public_action.oui; 1196346981Scy end = drv_mgmt->frame + drv_mgmt->frame_len; 1197346981Scy hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos, 1198346981Scy drv_mgmt->freq); 1199346981Scy return; 1200346981Scy } 1201346981Scy#endif /* CONFIG_DPP */ 1202252726Srpaulo} 1203346981Scy#endif /* NEED_AP_MLME */ 1204252726Srpaulo 1205252726Srpaulo 1206252726Srpaulo#ifdef NEED_AP_MLME 1207252726Srpaulo 1208214501Srpaulo#define HAPD_BROADCAST ((struct hostapd_data *) -1) 1209214501Srpaulo 1210214501Srpaulostatic struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, 1211214501Srpaulo const u8 *bssid) 1212214501Srpaulo{ 1213214501Srpaulo size_t i; 1214214501Srpaulo 1215214501Srpaulo if (bssid == NULL) 1216214501Srpaulo return NULL; 1217214501Srpaulo if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && 1218214501Srpaulo bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) 1219214501Srpaulo return HAPD_BROADCAST; 1220214501Srpaulo 1221214501Srpaulo for (i = 0; i < iface->num_bss; i++) { 1222214501Srpaulo if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) 1223214501Srpaulo return iface->bss[i]; 1224214501Srpaulo } 1225214501Srpaulo 1226214501Srpaulo return NULL; 1227214501Srpaulo} 1228214501Srpaulo 1229214501Srpaulo 1230214501Srpaulostatic void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, 1231252726Srpaulo const u8 *bssid, const u8 *addr, 1232252726Srpaulo int wds) 1233214501Srpaulo{ 1234252726Srpaulo hapd = get_hapd_bssid(hapd->iface, bssid); 1235214501Srpaulo if (hapd == NULL || hapd == HAPD_BROADCAST) 1236214501Srpaulo return; 1237214501Srpaulo 1238252726Srpaulo ieee802_11_rx_from_unknown(hapd, addr, wds); 1239214501Srpaulo} 1240214501Srpaulo 1241214501Srpaulo 1242281806Srpaulostatic int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) 1243214501Srpaulo{ 1244214501Srpaulo struct hostapd_iface *iface = hapd->iface; 1245214501Srpaulo const struct ieee80211_hdr *hdr; 1246214501Srpaulo const u8 *bssid; 1247214501Srpaulo struct hostapd_frame_info fi; 1248281806Srpaulo int ret; 1249214501Srpaulo 1250281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 1251281806Srpaulo if (hapd->ext_mgmt_frame_handling) { 1252281806Srpaulo size_t hex_len = 2 * rx_mgmt->frame_len + 1; 1253281806Srpaulo char *hex = os_malloc(hex_len); 1254289549Srpaulo 1255281806Srpaulo if (hex) { 1256281806Srpaulo wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame, 1257281806Srpaulo rx_mgmt->frame_len); 1258281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); 1259281806Srpaulo os_free(hex); 1260281806Srpaulo } 1261281806Srpaulo return 1; 1262281806Srpaulo } 1263281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 1264281806Srpaulo 1265214501Srpaulo hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; 1266214501Srpaulo bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); 1267214501Srpaulo if (bssid == NULL) 1268281806Srpaulo return 0; 1269214501Srpaulo 1270214501Srpaulo hapd = get_hapd_bssid(iface, bssid); 1271214501Srpaulo if (hapd == NULL) { 1272289549Srpaulo u16 fc = le_to_host16(hdr->frame_control); 1273214501Srpaulo 1274214501Srpaulo /* 1275214501Srpaulo * Drop frames to unknown BSSIDs except for Beacon frames which 1276214501Srpaulo * could be used to update neighbor information. 1277214501Srpaulo */ 1278214501Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1279214501Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1280214501Srpaulo hapd = iface->bss[0]; 1281214501Srpaulo else 1282281806Srpaulo return 0; 1283214501Srpaulo } 1284214501Srpaulo 1285214501Srpaulo os_memset(&fi, 0, sizeof(fi)); 1286346981Scy fi.freq = rx_mgmt->freq; 1287214501Srpaulo fi.datarate = rx_mgmt->datarate; 1288214501Srpaulo fi.ssi_signal = rx_mgmt->ssi_signal; 1289214501Srpaulo 1290214501Srpaulo if (hapd == HAPD_BROADCAST) { 1291214501Srpaulo size_t i; 1292289549Srpaulo 1293281806Srpaulo ret = 0; 1294281806Srpaulo for (i = 0; i < iface->num_bss; i++) { 1295281806Srpaulo /* if bss is set, driver will call this function for 1296281806Srpaulo * each bss individually. */ 1297281806Srpaulo if (rx_mgmt->drv_priv && 1298281806Srpaulo (iface->bss[i]->drv_priv != rx_mgmt->drv_priv)) 1299281806Srpaulo continue; 1300281806Srpaulo 1301281806Srpaulo if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, 1302281806Srpaulo rx_mgmt->frame_len, &fi) > 0) 1303281806Srpaulo ret = 1; 1304281806Srpaulo } 1305214501Srpaulo } else 1306281806Srpaulo ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, 1307281806Srpaulo &fi); 1308252726Srpaulo 1309252726Srpaulo random_add_randomness(&fi, sizeof(fi)); 1310214501Srpaulo 1311281806Srpaulo return ret; 1312252726Srpaulo} 1313252726Srpaulo 1314252726Srpaulo 1315214501Srpaulostatic void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, 1316214501Srpaulo size_t len, u16 stype, int ok) 1317214501Srpaulo{ 1318214501Srpaulo struct ieee80211_hdr *hdr; 1319337817Scy struct hostapd_data *orig_hapd = hapd; 1320289549Srpaulo 1321214501Srpaulo hdr = (struct ieee80211_hdr *) buf; 1322214501Srpaulo hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); 1323337817Scy if (!hapd) 1324214501Srpaulo return; 1325337817Scy if (hapd == HAPD_BROADCAST) { 1326337817Scy if (stype != WLAN_FC_STYPE_ACTION || len <= 25 || 1327337817Scy buf[24] != WLAN_ACTION_PUBLIC) 1328337817Scy return; 1329337817Scy hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2); 1330337817Scy if (!hapd || hapd == HAPD_BROADCAST) 1331337817Scy return; 1332337817Scy /* 1333337817Scy * Allow processing of TX status for a Public Action frame that 1334337817Scy * used wildcard BBSID. 1335337817Scy */ 1336337817Scy } 1337214501Srpaulo ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); 1338214501Srpaulo} 1339214501Srpaulo 1340214501Srpaulo#endif /* NEED_AP_MLME */ 1341214501Srpaulo 1342214501Srpaulo 1343214501Srpaulostatic int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) 1344214501Srpaulo{ 1345214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 1346289549Srpaulo 1347214501Srpaulo if (sta) 1348214501Srpaulo return 0; 1349214501Srpaulo 1350214501Srpaulo wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR 1351214501Srpaulo " - adding a new STA", MAC2STR(addr)); 1352214501Srpaulo sta = ap_sta_add(hapd, addr); 1353214501Srpaulo if (sta) { 1354214501Srpaulo hostapd_new_assoc_sta(hapd, sta, 0); 1355214501Srpaulo } else { 1356214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, 1357214501Srpaulo MAC2STR(addr)); 1358214501Srpaulo return -1; 1359214501Srpaulo } 1360214501Srpaulo 1361214501Srpaulo return 0; 1362214501Srpaulo} 1363214501Srpaulo 1364214501Srpaulo 1365214501Srpaulostatic void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, 1366214501Srpaulo const u8 *data, size_t data_len) 1367214501Srpaulo{ 1368214501Srpaulo struct hostapd_iface *iface = hapd->iface; 1369252726Srpaulo struct sta_info *sta; 1370214501Srpaulo size_t j; 1371214501Srpaulo 1372214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 1373289549Srpaulo sta = ap_get_sta(iface->bss[j], src); 1374289549Srpaulo if (sta && sta->flags & WLAN_STA_ASSOC) { 1375289549Srpaulo hapd = iface->bss[j]; 1376289549Srpaulo break; 1377214501Srpaulo } 1378214501Srpaulo } 1379214501Srpaulo 1380214501Srpaulo ieee802_1x_receive(hapd, src, data, data_len); 1381214501Srpaulo} 1382214501Srpaulo 1383337817Scy#endif /* HOSTAPD */ 1384214501Srpaulo 1385337817Scy 1386281806Srpaulostatic struct hostapd_channel_data * hostapd_get_mode_channel( 1387281806Srpaulo struct hostapd_iface *iface, unsigned int freq) 1388281806Srpaulo{ 1389281806Srpaulo int i; 1390281806Srpaulo struct hostapd_channel_data *chan; 1391281806Srpaulo 1392281806Srpaulo for (i = 0; i < iface->current_mode->num_channels; i++) { 1393281806Srpaulo chan = &iface->current_mode->channels[i]; 1394281806Srpaulo if ((unsigned int) chan->freq == freq) 1395281806Srpaulo return chan; 1396281806Srpaulo } 1397281806Srpaulo 1398281806Srpaulo return NULL; 1399281806Srpaulo} 1400281806Srpaulo 1401281806Srpaulo 1402281806Srpaulostatic void hostapd_update_nf(struct hostapd_iface *iface, 1403281806Srpaulo struct hostapd_channel_data *chan, 1404281806Srpaulo struct freq_survey *survey) 1405281806Srpaulo{ 1406281806Srpaulo if (!iface->chans_surveyed) { 1407281806Srpaulo chan->min_nf = survey->nf; 1408281806Srpaulo iface->lowest_nf = survey->nf; 1409281806Srpaulo } else { 1410281806Srpaulo if (dl_list_empty(&chan->survey_list)) 1411281806Srpaulo chan->min_nf = survey->nf; 1412281806Srpaulo else if (survey->nf < chan->min_nf) 1413281806Srpaulo chan->min_nf = survey->nf; 1414281806Srpaulo if (survey->nf < iface->lowest_nf) 1415281806Srpaulo iface->lowest_nf = survey->nf; 1416281806Srpaulo } 1417281806Srpaulo} 1418281806Srpaulo 1419281806Srpaulo 1420281806Srpaulostatic void hostapd_single_channel_get_survey(struct hostapd_iface *iface, 1421281806Srpaulo struct survey_results *survey_res) 1422281806Srpaulo{ 1423281806Srpaulo struct hostapd_channel_data *chan; 1424281806Srpaulo struct freq_survey *survey; 1425281806Srpaulo u64 divisor, dividend; 1426281806Srpaulo 1427281806Srpaulo survey = dl_list_first(&survey_res->survey_list, struct freq_survey, 1428281806Srpaulo list); 1429281806Srpaulo if (!survey || !survey->freq) 1430281806Srpaulo return; 1431281806Srpaulo 1432281806Srpaulo chan = hostapd_get_mode_channel(iface, survey->freq); 1433281806Srpaulo if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED) 1434281806Srpaulo return; 1435281806Srpaulo 1436289549Srpaulo wpa_printf(MSG_DEBUG, 1437289549Srpaulo "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", 1438281806Srpaulo survey->freq, 1439281806Srpaulo (unsigned long int) survey->channel_time, 1440281806Srpaulo (unsigned long int) survey->channel_time_busy); 1441281806Srpaulo 1442281806Srpaulo if (survey->channel_time > iface->last_channel_time && 1443281806Srpaulo survey->channel_time > survey->channel_time_busy) { 1444281806Srpaulo dividend = survey->channel_time_busy - 1445281806Srpaulo iface->last_channel_time_busy; 1446281806Srpaulo divisor = survey->channel_time - iface->last_channel_time; 1447281806Srpaulo 1448281806Srpaulo iface->channel_utilization = dividend * 255 / divisor; 1449281806Srpaulo wpa_printf(MSG_DEBUG, "Channel Utilization: %d", 1450281806Srpaulo iface->channel_utilization); 1451281806Srpaulo } 1452281806Srpaulo iface->last_channel_time = survey->channel_time; 1453281806Srpaulo iface->last_channel_time_busy = survey->channel_time_busy; 1454281806Srpaulo} 1455281806Srpaulo 1456281806Srpaulo 1457337817Scyvoid hostapd_event_get_survey(struct hostapd_iface *iface, 1458337817Scy struct survey_results *survey_results) 1459281806Srpaulo{ 1460281806Srpaulo struct freq_survey *survey, *tmp; 1461281806Srpaulo struct hostapd_channel_data *chan; 1462281806Srpaulo 1463281806Srpaulo if (dl_list_empty(&survey_results->survey_list)) { 1464281806Srpaulo wpa_printf(MSG_DEBUG, "No survey data received"); 1465281806Srpaulo return; 1466281806Srpaulo } 1467281806Srpaulo 1468281806Srpaulo if (survey_results->freq_filter) { 1469281806Srpaulo hostapd_single_channel_get_survey(iface, survey_results); 1470281806Srpaulo return; 1471281806Srpaulo } 1472281806Srpaulo 1473281806Srpaulo dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, 1474281806Srpaulo struct freq_survey, list) { 1475281806Srpaulo chan = hostapd_get_mode_channel(iface, survey->freq); 1476281806Srpaulo if (!chan) 1477281806Srpaulo continue; 1478281806Srpaulo if (chan->flag & HOSTAPD_CHAN_DISABLED) 1479281806Srpaulo continue; 1480281806Srpaulo 1481281806Srpaulo dl_list_del(&survey->list); 1482281806Srpaulo dl_list_add_tail(&chan->survey_list, &survey->list); 1483281806Srpaulo 1484281806Srpaulo hostapd_update_nf(iface, chan, survey); 1485281806Srpaulo 1486281806Srpaulo iface->chans_surveyed++; 1487281806Srpaulo } 1488281806Srpaulo} 1489281806Srpaulo 1490281806Srpaulo 1491337817Scy#ifdef HOSTAPD 1492281806Srpaulo#ifdef NEED_AP_MLME 1493281806Srpaulo 1494281806Srpaulostatic void hostapd_event_iface_unavailable(struct hostapd_data *hapd) 1495281806Srpaulo{ 1496281806Srpaulo wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped", 1497281806Srpaulo hapd->conf->iface); 1498281806Srpaulo 1499281806Srpaulo if (hapd->csa_in_progress) { 1500281806Srpaulo wpa_printf(MSG_INFO, "CSA failed (%s was stopped)", 1501281806Srpaulo hapd->conf->iface); 1502281806Srpaulo hostapd_switch_channel_fallback(hapd->iface, 1503281806Srpaulo &hapd->cs_freq_params); 1504281806Srpaulo } 1505281806Srpaulo} 1506281806Srpaulo 1507281806Srpaulo 1508281806Srpaulostatic void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd, 1509281806Srpaulo struct dfs_event *radar) 1510281806Srpaulo{ 1511281806Srpaulo wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq); 1512281806Srpaulo hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled, 1513281806Srpaulo radar->chan_offset, radar->chan_width, 1514281806Srpaulo radar->cf1, radar->cf2); 1515281806Srpaulo} 1516281806Srpaulo 1517281806Srpaulo 1518346981Scystatic void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd, 1519346981Scy struct dfs_event *radar) 1520346981Scy{ 1521346981Scy wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq); 1522346981Scy hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled, 1523346981Scy radar->chan_offset, radar->chan_width, 1524346981Scy radar->cf1, radar->cf2); 1525346981Scy} 1526346981Scy 1527346981Scy 1528281806Srpaulostatic void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd, 1529281806Srpaulo struct dfs_event *radar) 1530281806Srpaulo{ 1531281806Srpaulo wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq); 1532281806Srpaulo hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled, 1533281806Srpaulo radar->chan_offset, radar->chan_width, 1534281806Srpaulo radar->cf1, radar->cf2); 1535281806Srpaulo} 1536281806Srpaulo 1537281806Srpaulo 1538281806Srpaulostatic void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd, 1539281806Srpaulo struct dfs_event *radar) 1540281806Srpaulo{ 1541281806Srpaulo wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq); 1542281806Srpaulo hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled, 1543281806Srpaulo radar->chan_offset, radar->chan_width, 1544281806Srpaulo radar->cf1, radar->cf2); 1545281806Srpaulo} 1546281806Srpaulo 1547281806Srpaulo 1548281806Srpaulostatic void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd, 1549281806Srpaulo struct dfs_event *radar) 1550281806Srpaulo{ 1551281806Srpaulo wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq); 1552281806Srpaulo hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled, 1553281806Srpaulo radar->chan_offset, radar->chan_width, 1554281806Srpaulo radar->cf1, radar->cf2); 1555281806Srpaulo} 1556281806Srpaulo 1557281806Srpaulo 1558281806Srpaulostatic void hostapd_event_dfs_cac_started(struct hostapd_data *hapd, 1559281806Srpaulo struct dfs_event *radar) 1560281806Srpaulo{ 1561281806Srpaulo wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq); 1562281806Srpaulo hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled, 1563281806Srpaulo radar->chan_offset, radar->chan_width, 1564281806Srpaulo radar->cf1, radar->cf2); 1565281806Srpaulo} 1566281806Srpaulo 1567281806Srpaulo#endif /* NEED_AP_MLME */ 1568281806Srpaulo 1569281806Srpaulo 1570346981Scystatic void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd, 1571346981Scy int istatus, 1572346981Scy const char *ifname, 1573346981Scy const u8 *addr) 1574346981Scy{ 1575346981Scy struct sta_info *sta = ap_get_sta(hapd, addr); 1576346981Scy 1577346981Scy if (sta) { 1578346981Scy os_free(sta->ifname_wds); 1579346981Scy if (istatus == INTERFACE_ADDED) 1580346981Scy sta->ifname_wds = os_strdup(ifname); 1581346981Scy else 1582346981Scy sta->ifname_wds = NULL; 1583346981Scy } 1584346981Scy 1585346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR, 1586346981Scy istatus == INTERFACE_ADDED ? 1587346981Scy WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED, 1588346981Scy ifname, MAC2STR(addr)); 1589346981Scy} 1590346981Scy 1591346981Scy 1592351611Scy#ifdef CONFIG_OWE 1593351611Scystatic int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, 1594351611Scy const u8 *peer, const u8 *ie, 1595351611Scy size_t ie_len) 1596351611Scy{ 1597351611Scy u16 status; 1598351611Scy struct sta_info *sta; 1599351611Scy struct ieee802_11_elems elems; 1600351611Scy 1601351611Scy if (!hapd || !hapd->wpa_auth) { 1602351611Scy wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context"); 1603351611Scy return -1; 1604351611Scy } 1605351611Scy if (!peer) { 1606351611Scy wpa_printf(MSG_DEBUG, "OWE: Peer unknown"); 1607351611Scy return -1; 1608351611Scy } 1609351611Scy if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) { 1610351611Scy wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured"); 1611351611Scy status = WLAN_STATUS_AKMP_NOT_VALID; 1612351611Scy goto err; 1613351611Scy } 1614351611Scy if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) { 1615351611Scy wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for " 1616351611Scy MACSTR, MAC2STR(peer)); 1617351611Scy status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1618351611Scy goto err; 1619351611Scy } 1620351611Scy status = owe_validate_request(hapd, peer, elems.rsn_ie, 1621351611Scy elems.rsn_ie_len, 1622351611Scy elems.owe_dh, elems.owe_dh_len); 1623351611Scy if (status != WLAN_STATUS_SUCCESS) 1624351611Scy goto err; 1625351611Scy 1626351611Scy sta = ap_get_sta(hapd, peer); 1627351611Scy if (sta) { 1628351611Scy ap_sta_no_session_timeout(hapd, sta); 1629351611Scy accounting_sta_stop(hapd, sta); 1630351611Scy 1631351611Scy /* 1632351611Scy * Make sure that the previously registered inactivity timer 1633351611Scy * will not remove the STA immediately. 1634351611Scy */ 1635351611Scy sta->timeout_next = STA_NULLFUNC; 1636351611Scy } else { 1637351611Scy sta = ap_sta_add(hapd, peer); 1638351611Scy if (!sta) { 1639351611Scy status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1640351611Scy goto err; 1641351611Scy } 1642351611Scy } 1643351611Scy sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 1644351611Scy 1645351611Scy status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, 1646351611Scy elems.rsn_ie_len, elems.owe_dh, 1647351611Scy elems.owe_dh_len); 1648351611Scy if (status != WLAN_STATUS_SUCCESS) 1649351611Scy ap_free_sta(hapd, sta); 1650351611Scy 1651351611Scy return 0; 1652351611Scyerr: 1653351611Scy hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0); 1654351611Scy return 0; 1655351611Scy} 1656351611Scy#endif /* CONFIG_OWE */ 1657351611Scy 1658351611Scy 1659214501Srpaulovoid wpa_supplicant_event(void *ctx, enum wpa_event_type event, 1660214501Srpaulo union wpa_event_data *data) 1661214501Srpaulo{ 1662214501Srpaulo struct hostapd_data *hapd = ctx; 1663252726Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG 1664252726Srpaulo int level = MSG_DEBUG; 1665214501Srpaulo 1666252726Srpaulo if (event == EVENT_RX_MGMT && data->rx_mgmt.frame && 1667252726Srpaulo data->rx_mgmt.frame_len >= 24) { 1668252726Srpaulo const struct ieee80211_hdr *hdr; 1669252726Srpaulo u16 fc; 1670289549Srpaulo 1671252726Srpaulo hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; 1672252726Srpaulo fc = le_to_host16(hdr->frame_control); 1673252726Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1674252726Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1675252726Srpaulo level = MSG_EXCESSIVE; 1676281806Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1677281806Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) 1678281806Srpaulo level = MSG_EXCESSIVE; 1679252726Srpaulo } 1680252726Srpaulo 1681252726Srpaulo wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", 1682252726Srpaulo event_to_string(event), event); 1683252726Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */ 1684252726Srpaulo 1685214501Srpaulo switch (event) { 1686214501Srpaulo case EVENT_MICHAEL_MIC_FAILURE: 1687214501Srpaulo michael_mic_failure(hapd, data->michael_mic_failure.src, 1); 1688214501Srpaulo break; 1689214501Srpaulo case EVENT_SCAN_RESULTS: 1690214501Srpaulo if (hapd->iface->scan_cb) 1691214501Srpaulo hapd->iface->scan_cb(hapd->iface); 1692214501Srpaulo break; 1693214501Srpaulo case EVENT_WPS_BUTTON_PUSHED: 1694252726Srpaulo hostapd_wps_button_pushed(hapd, NULL); 1695214501Srpaulo break; 1696214501Srpaulo#ifdef NEED_AP_MLME 1697214501Srpaulo case EVENT_TX_STATUS: 1698214501Srpaulo switch (data->tx_status.type) { 1699214501Srpaulo case WLAN_FC_TYPE_MGMT: 1700214501Srpaulo hostapd_mgmt_tx_cb(hapd, data->tx_status.data, 1701214501Srpaulo data->tx_status.data_len, 1702214501Srpaulo data->tx_status.stype, 1703214501Srpaulo data->tx_status.ack); 1704214501Srpaulo break; 1705214501Srpaulo case WLAN_FC_TYPE_DATA: 1706214501Srpaulo hostapd_tx_status(hapd, data->tx_status.dst, 1707214501Srpaulo data->tx_status.data, 1708214501Srpaulo data->tx_status.data_len, 1709214501Srpaulo data->tx_status.ack); 1710214501Srpaulo break; 1711214501Srpaulo } 1712214501Srpaulo break; 1713252726Srpaulo case EVENT_EAPOL_TX_STATUS: 1714252726Srpaulo hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, 1715252726Srpaulo data->eapol_tx_status.data, 1716252726Srpaulo data->eapol_tx_status.data_len, 1717252726Srpaulo data->eapol_tx_status.ack); 1718252726Srpaulo break; 1719252726Srpaulo case EVENT_DRIVER_CLIENT_POLL_OK: 1720252726Srpaulo hostapd_client_poll_ok(hapd, data->client_poll.addr); 1721252726Srpaulo break; 1722214501Srpaulo case EVENT_RX_FROM_UNKNOWN: 1723252726Srpaulo hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, 1724252726Srpaulo data->rx_from_unknown.addr, 1725252726Srpaulo data->rx_from_unknown.wds); 1726214501Srpaulo break; 1727281806Srpaulo#endif /* NEED_AP_MLME */ 1728214501Srpaulo case EVENT_RX_MGMT: 1729281806Srpaulo if (!data->rx_mgmt.frame) 1730281806Srpaulo break; 1731281806Srpaulo#ifdef NEED_AP_MLME 1732346981Scy hostapd_mgmt_rx(hapd, &data->rx_mgmt); 1733346981Scy#else /* NEED_AP_MLME */ 1734346981Scy hostapd_action_rx(hapd, &data->rx_mgmt); 1735281806Srpaulo#endif /* NEED_AP_MLME */ 1736214501Srpaulo break; 1737214501Srpaulo case EVENT_RX_PROBE_REQ: 1738252726Srpaulo if (data->rx_probe_req.sa == NULL || 1739252726Srpaulo data->rx_probe_req.ie == NULL) 1740252726Srpaulo break; 1741214501Srpaulo hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, 1742252726Srpaulo data->rx_probe_req.da, 1743252726Srpaulo data->rx_probe_req.bssid, 1744214501Srpaulo data->rx_probe_req.ie, 1745252726Srpaulo data->rx_probe_req.ie_len, 1746252726Srpaulo data->rx_probe_req.ssi_signal); 1747214501Srpaulo break; 1748214501Srpaulo case EVENT_NEW_STA: 1749214501Srpaulo hostapd_event_new_sta(hapd, data->new_sta.addr); 1750214501Srpaulo break; 1751214501Srpaulo case EVENT_EAPOL_RX: 1752214501Srpaulo hostapd_event_eapol_rx(hapd, data->eapol_rx.src, 1753214501Srpaulo data->eapol_rx.data, 1754214501Srpaulo data->eapol_rx.data_len); 1755214501Srpaulo break; 1756214501Srpaulo case EVENT_ASSOC: 1757281806Srpaulo if (!data) 1758281806Srpaulo return; 1759214501Srpaulo hostapd_notif_assoc(hapd, data->assoc_info.addr, 1760214501Srpaulo data->assoc_info.req_ies, 1761252726Srpaulo data->assoc_info.req_ies_len, 1762252726Srpaulo data->assoc_info.reassoc); 1763214501Srpaulo break; 1764351611Scy#ifdef CONFIG_OWE 1765351611Scy case EVENT_UPDATE_DH: 1766351611Scy if (!data) 1767351611Scy return; 1768351611Scy hostapd_notif_update_dh_ie(hapd, data->update_dh.peer, 1769351611Scy data->update_dh.ie, 1770351611Scy data->update_dh.ie_len); 1771351611Scy break; 1772351611Scy#endif /* CONFIG_OWE */ 1773214501Srpaulo case EVENT_DISASSOC: 1774214501Srpaulo if (data) 1775214501Srpaulo hostapd_notif_disassoc(hapd, data->disassoc_info.addr); 1776214501Srpaulo break; 1777214501Srpaulo case EVENT_DEAUTH: 1778214501Srpaulo if (data) 1779214501Srpaulo hostapd_notif_disassoc(hapd, data->deauth_info.addr); 1780214501Srpaulo break; 1781252726Srpaulo case EVENT_STATION_LOW_ACK: 1782252726Srpaulo if (!data) 1783252726Srpaulo break; 1784252726Srpaulo hostapd_event_sta_low_ack(hapd, data->low_ack.addr); 1785252726Srpaulo break; 1786252726Srpaulo case EVENT_AUTH: 1787252726Srpaulo hostapd_notif_auth(hapd, &data->auth); 1788252726Srpaulo break; 1789351611Scy case EVENT_CH_SWITCH_STARTED: 1790252726Srpaulo case EVENT_CH_SWITCH: 1791252726Srpaulo if (!data) 1792252726Srpaulo break; 1793252726Srpaulo hostapd_event_ch_switch(hapd, data->ch_switch.freq, 1794252726Srpaulo data->ch_switch.ht_enabled, 1795281806Srpaulo data->ch_switch.ch_offset, 1796281806Srpaulo data->ch_switch.ch_width, 1797281806Srpaulo data->ch_switch.cf1, 1798351611Scy data->ch_switch.cf2, 1799351611Scy event == EVENT_CH_SWITCH); 1800252726Srpaulo break; 1801281806Srpaulo case EVENT_CONNECT_FAILED_REASON: 1802281806Srpaulo if (!data) 1803281806Srpaulo break; 1804281806Srpaulo hostapd_event_connect_failed_reason( 1805281806Srpaulo hapd, data->connect_failed_reason.addr, 1806281806Srpaulo data->connect_failed_reason.code); 1807281806Srpaulo break; 1808281806Srpaulo case EVENT_SURVEY: 1809337817Scy hostapd_event_get_survey(hapd->iface, &data->survey_results); 1810281806Srpaulo break; 1811281806Srpaulo#ifdef NEED_AP_MLME 1812281806Srpaulo case EVENT_INTERFACE_UNAVAILABLE: 1813281806Srpaulo hostapd_event_iface_unavailable(hapd); 1814281806Srpaulo break; 1815281806Srpaulo case EVENT_DFS_RADAR_DETECTED: 1816281806Srpaulo if (!data) 1817281806Srpaulo break; 1818281806Srpaulo hostapd_event_dfs_radar_detected(hapd, &data->dfs_event); 1819281806Srpaulo break; 1820346981Scy case EVENT_DFS_PRE_CAC_EXPIRED: 1821346981Scy if (!data) 1822346981Scy break; 1823346981Scy hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event); 1824346981Scy break; 1825281806Srpaulo case EVENT_DFS_CAC_FINISHED: 1826281806Srpaulo if (!data) 1827281806Srpaulo break; 1828281806Srpaulo hostapd_event_dfs_cac_finished(hapd, &data->dfs_event); 1829281806Srpaulo break; 1830281806Srpaulo case EVENT_DFS_CAC_ABORTED: 1831281806Srpaulo if (!data) 1832281806Srpaulo break; 1833281806Srpaulo hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event); 1834281806Srpaulo break; 1835281806Srpaulo case EVENT_DFS_NOP_FINISHED: 1836281806Srpaulo if (!data) 1837281806Srpaulo break; 1838281806Srpaulo hostapd_event_dfs_nop_finished(hapd, &data->dfs_event); 1839281806Srpaulo break; 1840281806Srpaulo case EVENT_CHANNEL_LIST_CHANGED: 1841281806Srpaulo /* channel list changed (regulatory?), update channel list */ 1842281806Srpaulo /* TODO: check this. hostapd_get_hw_features() initializes 1843281806Srpaulo * too much stuff. */ 1844281806Srpaulo /* hostapd_get_hw_features(hapd->iface); */ 1845281806Srpaulo hostapd_channel_list_updated( 1846281806Srpaulo hapd->iface, data->channel_list_changed.initiator); 1847281806Srpaulo break; 1848281806Srpaulo case EVENT_DFS_CAC_STARTED: 1849281806Srpaulo if (!data) 1850281806Srpaulo break; 1851281806Srpaulo hostapd_event_dfs_cac_started(hapd, &data->dfs_event); 1852281806Srpaulo break; 1853281806Srpaulo#endif /* NEED_AP_MLME */ 1854281806Srpaulo case EVENT_INTERFACE_ENABLED: 1855281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED); 1856281806Srpaulo if (hapd->disabled && hapd->started) { 1857281806Srpaulo hapd->disabled = 0; 1858281806Srpaulo /* 1859281806Srpaulo * Try to re-enable interface if the driver stopped it 1860281806Srpaulo * when the interface got disabled. 1861281806Srpaulo */ 1862346981Scy if (hapd->wpa_auth) 1863346981Scy wpa_auth_reconfig_group_keys(hapd->wpa_auth); 1864346981Scy else 1865346981Scy hostapd_reconfig_encryption(hapd); 1866281806Srpaulo hapd->reenable_beacon = 1; 1867281806Srpaulo ieee802_11_set_beacon(hapd); 1868346981Scy#ifdef NEED_AP_MLME 1869346981Scy } else if (hapd->disabled && hapd->iface->cac_started) { 1870346981Scy wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC"); 1871346981Scy hostapd_handle_dfs(hapd->iface); 1872346981Scy#endif /* NEED_AP_MLME */ 1873281806Srpaulo } 1874281806Srpaulo break; 1875281806Srpaulo case EVENT_INTERFACE_DISABLED: 1876281806Srpaulo hostapd_free_stas(hapd); 1877281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED); 1878281806Srpaulo hapd->disabled = 1; 1879281806Srpaulo break; 1880281806Srpaulo#ifdef CONFIG_ACS 1881281806Srpaulo case EVENT_ACS_CHANNEL_SELECTED: 1882289549Srpaulo hostapd_acs_channel_selected(hapd, 1883289549Srpaulo &data->acs_selected_channels); 1884281806Srpaulo break; 1885281806Srpaulo#endif /* CONFIG_ACS */ 1886346981Scy case EVENT_STATION_OPMODE_CHANGED: 1887346981Scy hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr, 1888346981Scy data->sta_opmode.smps_mode, 1889346981Scy data->sta_opmode.chan_width, 1890346981Scy data->sta_opmode.rx_nss); 1891346981Scy break; 1892346981Scy case EVENT_WDS_STA_INTERFACE_STATUS: 1893346981Scy hostapd_event_wds_sta_interface_status( 1894346981Scy hapd, data->wds_sta_interface.istatus, 1895346981Scy data->wds_sta_interface.ifname, 1896346981Scy data->wds_sta_interface.sta_addr); 1897346981Scy break; 1898214501Srpaulo default: 1899214501Srpaulo wpa_printf(MSG_DEBUG, "Unknown event %d", event); 1900214501Srpaulo break; 1901214501Srpaulo } 1902214501Srpaulo} 1903214501Srpaulo 1904337817Scy 1905337817Scyvoid wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, 1906337817Scy union wpa_event_data *data) 1907337817Scy{ 1908337817Scy struct hapd_interfaces *interfaces = ctx; 1909337817Scy struct hostapd_data *hapd; 1910337817Scy 1911337817Scy if (event != EVENT_INTERFACE_STATUS) 1912337817Scy return; 1913337817Scy 1914337817Scy hapd = hostapd_get_iface(interfaces, data->interface_status.ifname); 1915337817Scy if (hapd && hapd->driver && hapd->driver->get_ifindex && 1916337817Scy hapd->drv_priv) { 1917337817Scy unsigned int ifindex; 1918337817Scy 1919337817Scy ifindex = hapd->driver->get_ifindex(hapd->drv_priv); 1920337817Scy if (ifindex != data->interface_status.ifindex) { 1921337817Scy wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 1922337817Scy "interface status ifindex %d mismatch (%d)", 1923337817Scy ifindex, data->interface_status.ifindex); 1924337817Scy return; 1925337817Scy } 1926337817Scy } 1927337817Scy if (hapd) 1928337817Scy wpa_supplicant_event(hapd, event, data); 1929337817Scy} 1930337817Scy 1931214501Srpaulo#endif /* HOSTAPD */ 1932