drv_callbacks.c revision 346981
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, 775281806Srpaulo int offset, int width, int cf1, int cf2) 776252726Srpaulo{ 777346981Scy /* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */ 778346981Scy 779214501Srpaulo#ifdef NEED_AP_MLME 780337817Scy int channel, chwidth, is_dfs; 781337817Scy u8 seg0_idx = 0, seg1_idx = 0; 782346981Scy size_t i; 783214501Srpaulo 784252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 785281806Srpaulo HOSTAPD_LEVEL_INFO, 786346981Scy "driver had channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d", 787346981Scy freq, ht, hapd->iconf->ch_switch_vht_config, offset, 788346981Scy width, channel_width_to_string(width), cf1, cf2); 789252726Srpaulo 790252726Srpaulo hapd->iface->freq = freq; 791252726Srpaulo 792252726Srpaulo channel = hostapd_hw_get_channel(hapd, freq); 793252726Srpaulo if (!channel) { 794252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 795289549Srpaulo HOSTAPD_LEVEL_WARNING, 796289549Srpaulo "driver switched to bad channel!"); 797252726Srpaulo return; 798252726Srpaulo } 799252726Srpaulo 800281806Srpaulo switch (width) { 801281806Srpaulo case CHAN_WIDTH_80: 802281806Srpaulo chwidth = VHT_CHANWIDTH_80MHZ; 803281806Srpaulo break; 804281806Srpaulo case CHAN_WIDTH_80P80: 805281806Srpaulo chwidth = VHT_CHANWIDTH_80P80MHZ; 806281806Srpaulo break; 807281806Srpaulo case CHAN_WIDTH_160: 808281806Srpaulo chwidth = VHT_CHANWIDTH_160MHZ; 809281806Srpaulo break; 810281806Srpaulo case CHAN_WIDTH_20_NOHT: 811281806Srpaulo case CHAN_WIDTH_20: 812281806Srpaulo case CHAN_WIDTH_40: 813281806Srpaulo default: 814281806Srpaulo chwidth = VHT_CHANWIDTH_USE_HT; 815281806Srpaulo break; 816281806Srpaulo } 817281806Srpaulo 818281806Srpaulo switch (hapd->iface->current_mode->mode) { 819281806Srpaulo case HOSTAPD_MODE_IEEE80211A: 820281806Srpaulo if (cf1 > 5000) 821281806Srpaulo seg0_idx = (cf1 - 5000) / 5; 822281806Srpaulo if (cf2 > 5000) 823281806Srpaulo seg1_idx = (cf2 - 5000) / 5; 824281806Srpaulo break; 825281806Srpaulo default: 826337817Scy ieee80211_freq_to_chan(cf1, &seg0_idx); 827337817Scy ieee80211_freq_to_chan(cf2, &seg1_idx); 828281806Srpaulo break; 829281806Srpaulo } 830281806Srpaulo 831252726Srpaulo hapd->iconf->channel = channel; 832252726Srpaulo hapd->iconf->ieee80211n = ht; 833346981Scy if (!ht) { 834281806Srpaulo hapd->iconf->ieee80211ac = 0; 835346981Scy } else if (hapd->iconf->ch_switch_vht_config) { 836346981Scy /* CHAN_SWITCH VHT config */ 837346981Scy if (hapd->iconf->ch_switch_vht_config & 838346981Scy CH_SWITCH_VHT_ENABLED) 839346981Scy hapd->iconf->ieee80211ac = 1; 840346981Scy else if (hapd->iconf->ch_switch_vht_config & 841346981Scy CH_SWITCH_VHT_DISABLED) 842346981Scy hapd->iconf->ieee80211ac = 0; 843346981Scy } 844346981Scy hapd->iconf->ch_switch_vht_config = 0; 845346981Scy 846252726Srpaulo hapd->iconf->secondary_channel = offset; 847281806Srpaulo hapd->iconf->vht_oper_chwidth = chwidth; 848281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; 849281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; 850281806Srpaulo 851346981Scy is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features, 852346981Scy hapd->iface->num_hw_features); 853281806Srpaulo 854281806Srpaulo if (hapd->csa_in_progress && 855281806Srpaulo freq == hapd->cs_freq_params.freq) { 856281806Srpaulo hostapd_cleanup_cs_params(hapd); 857281806Srpaulo ieee802_11_set_beacon(hapd); 858281806Srpaulo 859281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 860281806Srpaulo "freq=%d dfs=%d", freq, is_dfs); 861281806Srpaulo } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { 862281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 863281806Srpaulo "freq=%d dfs=%d", freq, is_dfs); 864281806Srpaulo } 865346981Scy 866346981Scy for (i = 0; i < hapd->iface->num_bss; i++) 867346981Scy hostapd_neighbor_set_own_report(hapd->iface->bss[i]); 868252726Srpaulo#endif /* NEED_AP_MLME */ 869252726Srpaulo} 870252726Srpaulo 871252726Srpaulo 872281806Srpaulovoid hostapd_event_connect_failed_reason(struct hostapd_data *hapd, 873281806Srpaulo const u8 *addr, int reason_code) 874281806Srpaulo{ 875281806Srpaulo switch (reason_code) { 876281806Srpaulo case MAX_CLIENT_REACHED: 877281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR, 878281806Srpaulo MAC2STR(addr)); 879281806Srpaulo break; 880281806Srpaulo case BLOCKED_CLIENT: 881281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR, 882281806Srpaulo MAC2STR(addr)); 883281806Srpaulo break; 884281806Srpaulo } 885281806Srpaulo} 886281806Srpaulo 887281806Srpaulo 888281806Srpaulo#ifdef CONFIG_ACS 889337817Scyvoid hostapd_acs_channel_selected(struct hostapd_data *hapd, 890337817Scy struct acs_selected_channels *acs_res) 891281806Srpaulo{ 892289549Srpaulo int ret, i; 893337817Scy int err = 0; 894281806Srpaulo 895281806Srpaulo if (hapd->iconf->channel) { 896281806Srpaulo wpa_printf(MSG_INFO, "ACS: Channel was already set to %d", 897281806Srpaulo hapd->iconf->channel); 898281806Srpaulo return; 899281806Srpaulo } 900281806Srpaulo 901289549Srpaulo if (!hapd->iface->current_mode) { 902289549Srpaulo for (i = 0; i < hapd->iface->num_hw_features; i++) { 903289549Srpaulo struct hostapd_hw_modes *mode = 904289549Srpaulo &hapd->iface->hw_features[i]; 905281806Srpaulo 906289549Srpaulo if (mode->mode == acs_res->hw_mode) { 907289549Srpaulo hapd->iface->current_mode = mode; 908289549Srpaulo break; 909289549Srpaulo } 910289549Srpaulo } 911289549Srpaulo if (!hapd->iface->current_mode) { 912289549Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 913289549Srpaulo HOSTAPD_LEVEL_WARNING, 914289549Srpaulo "driver selected to bad hw_mode"); 915337817Scy err = 1; 916337817Scy goto out; 917289549Srpaulo } 918289549Srpaulo } 919289549Srpaulo 920289549Srpaulo hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel); 921289549Srpaulo 922289549Srpaulo if (!acs_res->pri_channel) { 923281806Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 924281806Srpaulo HOSTAPD_LEVEL_WARNING, 925281806Srpaulo "driver switched to bad channel"); 926337817Scy err = 1; 927337817Scy goto out; 928281806Srpaulo } 929281806Srpaulo 930289549Srpaulo hapd->iconf->channel = acs_res->pri_channel; 931289549Srpaulo hapd->iconf->acs = 1; 932281806Srpaulo 933289549Srpaulo if (acs_res->sec_channel == 0) 934281806Srpaulo hapd->iconf->secondary_channel = 0; 935289549Srpaulo else if (acs_res->sec_channel < acs_res->pri_channel) 936281806Srpaulo hapd->iconf->secondary_channel = -1; 937289549Srpaulo else if (acs_res->sec_channel > acs_res->pri_channel) 938281806Srpaulo hapd->iconf->secondary_channel = 1; 939281806Srpaulo else { 940281806Srpaulo wpa_printf(MSG_ERROR, "Invalid secondary channel!"); 941337817Scy err = 1; 942337817Scy goto out; 943281806Srpaulo } 944281806Srpaulo 945289549Srpaulo if (hapd->iface->conf->ieee80211ac) { 946289549Srpaulo /* set defaults for backwards compatibility */ 947289549Srpaulo hapd->iconf->vht_oper_centr_freq_seg1_idx = 0; 948289549Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx = 0; 949289549Srpaulo hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT; 950289549Srpaulo if (acs_res->ch_width == 80) { 951289549Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx = 952289549Srpaulo acs_res->vht_seg0_center_ch; 953289549Srpaulo hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ; 954289549Srpaulo } else if (acs_res->ch_width == 160) { 955289549Srpaulo if (acs_res->vht_seg1_center_ch == 0) { 956289549Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx = 957289549Srpaulo acs_res->vht_seg0_center_ch; 958289549Srpaulo hapd->iconf->vht_oper_chwidth = 959289549Srpaulo VHT_CHANWIDTH_160MHZ; 960289549Srpaulo } else { 961289549Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx = 962289549Srpaulo acs_res->vht_seg0_center_ch; 963289549Srpaulo hapd->iconf->vht_oper_centr_freq_seg1_idx = 964289549Srpaulo acs_res->vht_seg1_center_ch; 965289549Srpaulo hapd->iconf->vht_oper_chwidth = 966289549Srpaulo VHT_CHANWIDTH_80P80MHZ; 967289549Srpaulo } 968289549Srpaulo } 969289549Srpaulo } 970289549Srpaulo 971337817Scyout: 972337817Scy ret = hostapd_acs_completed(hapd->iface, err); 973281806Srpaulo if (ret) { 974281806Srpaulo wpa_printf(MSG_ERROR, 975281806Srpaulo "ACS: Possibly channel configuration is invalid"); 976281806Srpaulo } 977281806Srpaulo} 978281806Srpaulo#endif /* CONFIG_ACS */ 979281806Srpaulo 980281806Srpaulo 981252726Srpauloint hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, 982252726Srpaulo const u8 *bssid, const u8 *ie, size_t ie_len, 983252726Srpaulo int ssi_signal) 984214501Srpaulo{ 985252726Srpaulo size_t i; 986252726Srpaulo int ret = 0; 987214501Srpaulo 988252726Srpaulo if (sa == NULL || ie == NULL) 989252726Srpaulo return -1; 990214501Srpaulo 991252726Srpaulo random_add_randomness(sa, ETH_ALEN); 992252726Srpaulo for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { 993252726Srpaulo if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 994252726Srpaulo sa, da, bssid, ie, ie_len, 995252726Srpaulo ssi_signal) > 0) { 996252726Srpaulo ret = 1; 997252726Srpaulo break; 998252726Srpaulo } 999252726Srpaulo } 1000252726Srpaulo return ret; 1001252726Srpaulo} 1002214501Srpaulo 1003252726Srpaulo 1004252726Srpaulo#ifdef HOSTAPD 1005252726Srpaulo 1006346981Scy#ifdef CONFIG_IEEE80211R_AP 1007252726Srpaulostatic void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, 1008252726Srpaulo const u8 *bssid, 1009252726Srpaulo u16 auth_transaction, u16 status, 1010252726Srpaulo const u8 *ies, size_t ies_len) 1011252726Srpaulo{ 1012252726Srpaulo struct hostapd_data *hapd = ctx; 1013252726Srpaulo struct sta_info *sta; 1014252726Srpaulo 1015252726Srpaulo sta = ap_get_sta(hapd, dst); 1016252726Srpaulo if (sta == NULL) 1017252726Srpaulo return; 1018252726Srpaulo 1019252726Srpaulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 1020252726Srpaulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 1021252726Srpaulo sta->flags |= WLAN_STA_AUTH; 1022252726Srpaulo 1023252726Srpaulo hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len); 1024252726Srpaulo} 1025346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1026252726Srpaulo 1027252726Srpaulo 1028346981Scy#ifdef CONFIG_FILS 1029346981Scystatic void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd, 1030346981Scy struct sta_info *sta, u16 resp, 1031346981Scy struct wpabuf *data, int pub) 1032346981Scy{ 1033346981Scy if (resp == WLAN_STATUS_SUCCESS) { 1034346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1035346981Scy HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)"); 1036346981Scy sta->flags |= WLAN_STA_AUTH; 1037346981Scy wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 1038346981Scy sta->auth_alg = WLAN_AUTH_FILS_SK; 1039346981Scy mlme_authenticate_indication(hapd, sta); 1040346981Scy } else { 1041346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1042346981Scy HOSTAPD_LEVEL_DEBUG, 1043346981Scy "authentication failed (FILS)"); 1044346981Scy } 1045346981Scy 1046346981Scy hostapd_sta_auth(hapd, sta->addr, 2, resp, 1047346981Scy data ? wpabuf_head(data) : NULL, 1048346981Scy data ? wpabuf_len(data) : 0); 1049346981Scy wpabuf_free(data); 1050346981Scy} 1051346981Scy#endif /* CONFIG_FILS */ 1052346981Scy 1053346981Scy 1054252726Srpaulostatic void hostapd_notif_auth(struct hostapd_data *hapd, 1055252726Srpaulo struct auth_info *rx_auth) 1056252726Srpaulo{ 1057252726Srpaulo struct sta_info *sta; 1058252726Srpaulo u16 status = WLAN_STATUS_SUCCESS; 1059252726Srpaulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 1060252726Srpaulo size_t resp_ies_len = 0; 1061252726Srpaulo 1062252726Srpaulo sta = ap_get_sta(hapd, rx_auth->peer); 1063252726Srpaulo if (!sta) { 1064252726Srpaulo sta = ap_sta_add(hapd, rx_auth->peer); 1065252726Srpaulo if (sta == NULL) { 1066281806Srpaulo status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 1067252726Srpaulo goto fail; 1068214501Srpaulo } 1069214501Srpaulo } 1070252726Srpaulo sta->flags &= ~WLAN_STA_PREAUTH; 1071252726Srpaulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 1072346981Scy#ifdef CONFIG_IEEE80211R_AP 1073252726Srpaulo if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { 1074252726Srpaulo sta->auth_alg = WLAN_AUTH_FT; 1075252726Srpaulo if (sta->wpa_sm == NULL) 1076252726Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 1077281806Srpaulo sta->addr, NULL); 1078252726Srpaulo if (sta->wpa_sm == NULL) { 1079289549Srpaulo wpa_printf(MSG_DEBUG, 1080289549Srpaulo "FT: Failed to initialize WPA state machine"); 1081252726Srpaulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1082252726Srpaulo goto fail; 1083252726Srpaulo } 1084252726Srpaulo wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, 1085252726Srpaulo rx_auth->auth_transaction, rx_auth->ies, 1086252726Srpaulo rx_auth->ies_len, 1087252726Srpaulo hostapd_notify_auth_ft_finish, hapd); 1088252726Srpaulo return; 1089252726Srpaulo } 1090346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1091346981Scy 1092346981Scy#ifdef CONFIG_FILS 1093346981Scy if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) { 1094346981Scy sta->auth_alg = WLAN_AUTH_FILS_SK; 1095346981Scy handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len, 1096346981Scy rx_auth->auth_type, rx_auth->auth_transaction, 1097346981Scy rx_auth->status_code, 1098346981Scy hostapd_notify_auth_fils_finish); 1099346981Scy return; 1100346981Scy } 1101346981Scy#endif /* CONFIG_FILS */ 1102346981Scy 1103252726Srpaulofail: 1104252726Srpaulo hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, 1105252726Srpaulo status, resp_ies, resp_ies_len); 1106214501Srpaulo} 1107214501Srpaulo 1108214501Srpaulo 1109346981Scy#ifndef NEED_AP_MLME 1110252726Srpaulostatic void hostapd_action_rx(struct hostapd_data *hapd, 1111281806Srpaulo struct rx_mgmt *drv_mgmt) 1112252726Srpaulo{ 1113281806Srpaulo struct ieee80211_mgmt *mgmt; 1114252726Srpaulo struct sta_info *sta; 1115281806Srpaulo size_t plen __maybe_unused; 1116281806Srpaulo u16 fc; 1117346981Scy u8 *action __maybe_unused; 1118252726Srpaulo 1119346981Scy if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1) 1120281806Srpaulo return; 1121281806Srpaulo 1122346981Scy plen = drv_mgmt->frame_len - IEEE80211_HDRLEN; 1123281806Srpaulo 1124281806Srpaulo mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; 1125281806Srpaulo fc = le_to_host16(mgmt->frame_control); 1126281806Srpaulo if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) 1127281806Srpaulo return; /* handled by the driver */ 1128281806Srpaulo 1129346981Scy action = (u8 *) &mgmt->u.action.u; 1130346981Scy wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR 1131346981Scy " da " MACSTR " plen %d", 1132346981Scy mgmt->u.action.category, *action, 1133346981Scy MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen); 1134252726Srpaulo 1135281806Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 1136252726Srpaulo if (sta == NULL) { 1137252726Srpaulo wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 1138252726Srpaulo return; 1139252726Srpaulo } 1140346981Scy#ifdef CONFIG_IEEE80211R_AP 1141281806Srpaulo if (mgmt->u.action.category == WLAN_ACTION_FT) { 1142346981Scy wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen); 1143346981Scy return; 1144252726Srpaulo } 1145346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1146252726Srpaulo#ifdef CONFIG_IEEE80211W 1147346981Scy if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) { 1148346981Scy ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len); 1149346981Scy return; 1150252726Srpaulo } 1151252726Srpaulo#endif /* CONFIG_IEEE80211W */ 1152346981Scy#ifdef CONFIG_WNM_AP 1153281806Srpaulo if (mgmt->u.action.category == WLAN_ACTION_WNM) { 1154281806Srpaulo ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); 1155346981Scy return; 1156252726Srpaulo } 1157346981Scy#endif /* CONFIG_WNM_AP */ 1158289549Srpaulo#ifdef CONFIG_FST 1159289549Srpaulo if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) { 1160289549Srpaulo fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len); 1161289549Srpaulo return; 1162289549Srpaulo } 1163289549Srpaulo#endif /* CONFIG_FST */ 1164346981Scy#ifdef CONFIG_DPP 1165346981Scy if (plen >= 2 + 4 && 1166346981Scy mgmt->u.action.u.vs_public_action.action == 1167346981Scy WLAN_PA_VENDOR_SPECIFIC && 1168346981Scy WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == 1169346981Scy OUI_WFA && 1170346981Scy mgmt->u.action.u.vs_public_action.variable[0] == 1171346981Scy DPP_OUI_TYPE) { 1172346981Scy const u8 *pos, *end; 1173289549Srpaulo 1174346981Scy pos = mgmt->u.action.u.vs_public_action.oui; 1175346981Scy end = drv_mgmt->frame + drv_mgmt->frame_len; 1176346981Scy hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos, 1177346981Scy drv_mgmt->freq); 1178346981Scy return; 1179346981Scy } 1180346981Scy#endif /* CONFIG_DPP */ 1181252726Srpaulo} 1182346981Scy#endif /* NEED_AP_MLME */ 1183252726Srpaulo 1184252726Srpaulo 1185252726Srpaulo#ifdef NEED_AP_MLME 1186252726Srpaulo 1187214501Srpaulo#define HAPD_BROADCAST ((struct hostapd_data *) -1) 1188214501Srpaulo 1189214501Srpaulostatic struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, 1190214501Srpaulo const u8 *bssid) 1191214501Srpaulo{ 1192214501Srpaulo size_t i; 1193214501Srpaulo 1194214501Srpaulo if (bssid == NULL) 1195214501Srpaulo return NULL; 1196214501Srpaulo if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && 1197214501Srpaulo bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) 1198214501Srpaulo return HAPD_BROADCAST; 1199214501Srpaulo 1200214501Srpaulo for (i = 0; i < iface->num_bss; i++) { 1201214501Srpaulo if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) 1202214501Srpaulo return iface->bss[i]; 1203214501Srpaulo } 1204214501Srpaulo 1205214501Srpaulo return NULL; 1206214501Srpaulo} 1207214501Srpaulo 1208214501Srpaulo 1209214501Srpaulostatic void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, 1210252726Srpaulo const u8 *bssid, const u8 *addr, 1211252726Srpaulo int wds) 1212214501Srpaulo{ 1213252726Srpaulo hapd = get_hapd_bssid(hapd->iface, bssid); 1214214501Srpaulo if (hapd == NULL || hapd == HAPD_BROADCAST) 1215214501Srpaulo return; 1216214501Srpaulo 1217252726Srpaulo ieee802_11_rx_from_unknown(hapd, addr, wds); 1218214501Srpaulo} 1219214501Srpaulo 1220214501Srpaulo 1221281806Srpaulostatic int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) 1222214501Srpaulo{ 1223214501Srpaulo struct hostapd_iface *iface = hapd->iface; 1224214501Srpaulo const struct ieee80211_hdr *hdr; 1225214501Srpaulo const u8 *bssid; 1226214501Srpaulo struct hostapd_frame_info fi; 1227281806Srpaulo int ret; 1228214501Srpaulo 1229281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 1230281806Srpaulo if (hapd->ext_mgmt_frame_handling) { 1231281806Srpaulo size_t hex_len = 2 * rx_mgmt->frame_len + 1; 1232281806Srpaulo char *hex = os_malloc(hex_len); 1233289549Srpaulo 1234281806Srpaulo if (hex) { 1235281806Srpaulo wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame, 1236281806Srpaulo rx_mgmt->frame_len); 1237281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); 1238281806Srpaulo os_free(hex); 1239281806Srpaulo } 1240281806Srpaulo return 1; 1241281806Srpaulo } 1242281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 1243281806Srpaulo 1244214501Srpaulo hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; 1245214501Srpaulo bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); 1246214501Srpaulo if (bssid == NULL) 1247281806Srpaulo return 0; 1248214501Srpaulo 1249214501Srpaulo hapd = get_hapd_bssid(iface, bssid); 1250214501Srpaulo if (hapd == NULL) { 1251289549Srpaulo u16 fc = le_to_host16(hdr->frame_control); 1252214501Srpaulo 1253214501Srpaulo /* 1254214501Srpaulo * Drop frames to unknown BSSIDs except for Beacon frames which 1255214501Srpaulo * could be used to update neighbor information. 1256214501Srpaulo */ 1257214501Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1258214501Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1259214501Srpaulo hapd = iface->bss[0]; 1260214501Srpaulo else 1261281806Srpaulo return 0; 1262214501Srpaulo } 1263214501Srpaulo 1264214501Srpaulo os_memset(&fi, 0, sizeof(fi)); 1265346981Scy fi.freq = rx_mgmt->freq; 1266214501Srpaulo fi.datarate = rx_mgmt->datarate; 1267214501Srpaulo fi.ssi_signal = rx_mgmt->ssi_signal; 1268214501Srpaulo 1269214501Srpaulo if (hapd == HAPD_BROADCAST) { 1270214501Srpaulo size_t i; 1271289549Srpaulo 1272281806Srpaulo ret = 0; 1273281806Srpaulo for (i = 0; i < iface->num_bss; i++) { 1274281806Srpaulo /* if bss is set, driver will call this function for 1275281806Srpaulo * each bss individually. */ 1276281806Srpaulo if (rx_mgmt->drv_priv && 1277281806Srpaulo (iface->bss[i]->drv_priv != rx_mgmt->drv_priv)) 1278281806Srpaulo continue; 1279281806Srpaulo 1280281806Srpaulo if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, 1281281806Srpaulo rx_mgmt->frame_len, &fi) > 0) 1282281806Srpaulo ret = 1; 1283281806Srpaulo } 1284214501Srpaulo } else 1285281806Srpaulo ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, 1286281806Srpaulo &fi); 1287252726Srpaulo 1288252726Srpaulo random_add_randomness(&fi, sizeof(fi)); 1289214501Srpaulo 1290281806Srpaulo return ret; 1291252726Srpaulo} 1292252726Srpaulo 1293252726Srpaulo 1294214501Srpaulostatic void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, 1295214501Srpaulo size_t len, u16 stype, int ok) 1296214501Srpaulo{ 1297214501Srpaulo struct ieee80211_hdr *hdr; 1298337817Scy struct hostapd_data *orig_hapd = hapd; 1299289549Srpaulo 1300214501Srpaulo hdr = (struct ieee80211_hdr *) buf; 1301214501Srpaulo hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); 1302337817Scy if (!hapd) 1303214501Srpaulo return; 1304337817Scy if (hapd == HAPD_BROADCAST) { 1305337817Scy if (stype != WLAN_FC_STYPE_ACTION || len <= 25 || 1306337817Scy buf[24] != WLAN_ACTION_PUBLIC) 1307337817Scy return; 1308337817Scy hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2); 1309337817Scy if (!hapd || hapd == HAPD_BROADCAST) 1310337817Scy return; 1311337817Scy /* 1312337817Scy * Allow processing of TX status for a Public Action frame that 1313337817Scy * used wildcard BBSID. 1314337817Scy */ 1315337817Scy } 1316214501Srpaulo ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); 1317214501Srpaulo} 1318214501Srpaulo 1319214501Srpaulo#endif /* NEED_AP_MLME */ 1320214501Srpaulo 1321214501Srpaulo 1322214501Srpaulostatic int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) 1323214501Srpaulo{ 1324214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 1325289549Srpaulo 1326214501Srpaulo if (sta) 1327214501Srpaulo return 0; 1328214501Srpaulo 1329214501Srpaulo wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR 1330214501Srpaulo " - adding a new STA", MAC2STR(addr)); 1331214501Srpaulo sta = ap_sta_add(hapd, addr); 1332214501Srpaulo if (sta) { 1333214501Srpaulo hostapd_new_assoc_sta(hapd, sta, 0); 1334214501Srpaulo } else { 1335214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, 1336214501Srpaulo MAC2STR(addr)); 1337214501Srpaulo return -1; 1338214501Srpaulo } 1339214501Srpaulo 1340214501Srpaulo return 0; 1341214501Srpaulo} 1342214501Srpaulo 1343214501Srpaulo 1344214501Srpaulostatic void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, 1345214501Srpaulo const u8 *data, size_t data_len) 1346214501Srpaulo{ 1347214501Srpaulo struct hostapd_iface *iface = hapd->iface; 1348252726Srpaulo struct sta_info *sta; 1349214501Srpaulo size_t j; 1350214501Srpaulo 1351214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 1352289549Srpaulo sta = ap_get_sta(iface->bss[j], src); 1353289549Srpaulo if (sta && sta->flags & WLAN_STA_ASSOC) { 1354289549Srpaulo hapd = iface->bss[j]; 1355289549Srpaulo break; 1356214501Srpaulo } 1357214501Srpaulo } 1358214501Srpaulo 1359214501Srpaulo ieee802_1x_receive(hapd, src, data, data_len); 1360214501Srpaulo} 1361214501Srpaulo 1362337817Scy#endif /* HOSTAPD */ 1363214501Srpaulo 1364337817Scy 1365281806Srpaulostatic struct hostapd_channel_data * hostapd_get_mode_channel( 1366281806Srpaulo struct hostapd_iface *iface, unsigned int freq) 1367281806Srpaulo{ 1368281806Srpaulo int i; 1369281806Srpaulo struct hostapd_channel_data *chan; 1370281806Srpaulo 1371281806Srpaulo for (i = 0; i < iface->current_mode->num_channels; i++) { 1372281806Srpaulo chan = &iface->current_mode->channels[i]; 1373281806Srpaulo if ((unsigned int) chan->freq == freq) 1374281806Srpaulo return chan; 1375281806Srpaulo } 1376281806Srpaulo 1377281806Srpaulo return NULL; 1378281806Srpaulo} 1379281806Srpaulo 1380281806Srpaulo 1381281806Srpaulostatic void hostapd_update_nf(struct hostapd_iface *iface, 1382281806Srpaulo struct hostapd_channel_data *chan, 1383281806Srpaulo struct freq_survey *survey) 1384281806Srpaulo{ 1385281806Srpaulo if (!iface->chans_surveyed) { 1386281806Srpaulo chan->min_nf = survey->nf; 1387281806Srpaulo iface->lowest_nf = survey->nf; 1388281806Srpaulo } else { 1389281806Srpaulo if (dl_list_empty(&chan->survey_list)) 1390281806Srpaulo chan->min_nf = survey->nf; 1391281806Srpaulo else if (survey->nf < chan->min_nf) 1392281806Srpaulo chan->min_nf = survey->nf; 1393281806Srpaulo if (survey->nf < iface->lowest_nf) 1394281806Srpaulo iface->lowest_nf = survey->nf; 1395281806Srpaulo } 1396281806Srpaulo} 1397281806Srpaulo 1398281806Srpaulo 1399281806Srpaulostatic void hostapd_single_channel_get_survey(struct hostapd_iface *iface, 1400281806Srpaulo struct survey_results *survey_res) 1401281806Srpaulo{ 1402281806Srpaulo struct hostapd_channel_data *chan; 1403281806Srpaulo struct freq_survey *survey; 1404281806Srpaulo u64 divisor, dividend; 1405281806Srpaulo 1406281806Srpaulo survey = dl_list_first(&survey_res->survey_list, struct freq_survey, 1407281806Srpaulo list); 1408281806Srpaulo if (!survey || !survey->freq) 1409281806Srpaulo return; 1410281806Srpaulo 1411281806Srpaulo chan = hostapd_get_mode_channel(iface, survey->freq); 1412281806Srpaulo if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED) 1413281806Srpaulo return; 1414281806Srpaulo 1415289549Srpaulo wpa_printf(MSG_DEBUG, 1416289549Srpaulo "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", 1417281806Srpaulo survey->freq, 1418281806Srpaulo (unsigned long int) survey->channel_time, 1419281806Srpaulo (unsigned long int) survey->channel_time_busy); 1420281806Srpaulo 1421281806Srpaulo if (survey->channel_time > iface->last_channel_time && 1422281806Srpaulo survey->channel_time > survey->channel_time_busy) { 1423281806Srpaulo dividend = survey->channel_time_busy - 1424281806Srpaulo iface->last_channel_time_busy; 1425281806Srpaulo divisor = survey->channel_time - iface->last_channel_time; 1426281806Srpaulo 1427281806Srpaulo iface->channel_utilization = dividend * 255 / divisor; 1428281806Srpaulo wpa_printf(MSG_DEBUG, "Channel Utilization: %d", 1429281806Srpaulo iface->channel_utilization); 1430281806Srpaulo } 1431281806Srpaulo iface->last_channel_time = survey->channel_time; 1432281806Srpaulo iface->last_channel_time_busy = survey->channel_time_busy; 1433281806Srpaulo} 1434281806Srpaulo 1435281806Srpaulo 1436337817Scyvoid hostapd_event_get_survey(struct hostapd_iface *iface, 1437337817Scy struct survey_results *survey_results) 1438281806Srpaulo{ 1439281806Srpaulo struct freq_survey *survey, *tmp; 1440281806Srpaulo struct hostapd_channel_data *chan; 1441281806Srpaulo 1442281806Srpaulo if (dl_list_empty(&survey_results->survey_list)) { 1443281806Srpaulo wpa_printf(MSG_DEBUG, "No survey data received"); 1444281806Srpaulo return; 1445281806Srpaulo } 1446281806Srpaulo 1447281806Srpaulo if (survey_results->freq_filter) { 1448281806Srpaulo hostapd_single_channel_get_survey(iface, survey_results); 1449281806Srpaulo return; 1450281806Srpaulo } 1451281806Srpaulo 1452281806Srpaulo dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, 1453281806Srpaulo struct freq_survey, list) { 1454281806Srpaulo chan = hostapd_get_mode_channel(iface, survey->freq); 1455281806Srpaulo if (!chan) 1456281806Srpaulo continue; 1457281806Srpaulo if (chan->flag & HOSTAPD_CHAN_DISABLED) 1458281806Srpaulo continue; 1459281806Srpaulo 1460281806Srpaulo dl_list_del(&survey->list); 1461281806Srpaulo dl_list_add_tail(&chan->survey_list, &survey->list); 1462281806Srpaulo 1463281806Srpaulo hostapd_update_nf(iface, chan, survey); 1464281806Srpaulo 1465281806Srpaulo iface->chans_surveyed++; 1466281806Srpaulo } 1467281806Srpaulo} 1468281806Srpaulo 1469281806Srpaulo 1470337817Scy#ifdef HOSTAPD 1471281806Srpaulo#ifdef NEED_AP_MLME 1472281806Srpaulo 1473281806Srpaulostatic void hostapd_event_iface_unavailable(struct hostapd_data *hapd) 1474281806Srpaulo{ 1475281806Srpaulo wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped", 1476281806Srpaulo hapd->conf->iface); 1477281806Srpaulo 1478281806Srpaulo if (hapd->csa_in_progress) { 1479281806Srpaulo wpa_printf(MSG_INFO, "CSA failed (%s was stopped)", 1480281806Srpaulo hapd->conf->iface); 1481281806Srpaulo hostapd_switch_channel_fallback(hapd->iface, 1482281806Srpaulo &hapd->cs_freq_params); 1483281806Srpaulo } 1484281806Srpaulo} 1485281806Srpaulo 1486281806Srpaulo 1487281806Srpaulostatic void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd, 1488281806Srpaulo struct dfs_event *radar) 1489281806Srpaulo{ 1490281806Srpaulo wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq); 1491281806Srpaulo hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled, 1492281806Srpaulo radar->chan_offset, radar->chan_width, 1493281806Srpaulo radar->cf1, radar->cf2); 1494281806Srpaulo} 1495281806Srpaulo 1496281806Srpaulo 1497346981Scystatic void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd, 1498346981Scy struct dfs_event *radar) 1499346981Scy{ 1500346981Scy wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq); 1501346981Scy hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled, 1502346981Scy radar->chan_offset, radar->chan_width, 1503346981Scy radar->cf1, radar->cf2); 1504346981Scy} 1505346981Scy 1506346981Scy 1507281806Srpaulostatic void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd, 1508281806Srpaulo struct dfs_event *radar) 1509281806Srpaulo{ 1510281806Srpaulo wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq); 1511281806Srpaulo hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled, 1512281806Srpaulo radar->chan_offset, radar->chan_width, 1513281806Srpaulo radar->cf1, radar->cf2); 1514281806Srpaulo} 1515281806Srpaulo 1516281806Srpaulo 1517281806Srpaulostatic void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd, 1518281806Srpaulo struct dfs_event *radar) 1519281806Srpaulo{ 1520281806Srpaulo wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq); 1521281806Srpaulo hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled, 1522281806Srpaulo radar->chan_offset, radar->chan_width, 1523281806Srpaulo radar->cf1, radar->cf2); 1524281806Srpaulo} 1525281806Srpaulo 1526281806Srpaulo 1527281806Srpaulostatic void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd, 1528281806Srpaulo struct dfs_event *radar) 1529281806Srpaulo{ 1530281806Srpaulo wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq); 1531281806Srpaulo hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled, 1532281806Srpaulo radar->chan_offset, radar->chan_width, 1533281806Srpaulo radar->cf1, radar->cf2); 1534281806Srpaulo} 1535281806Srpaulo 1536281806Srpaulo 1537281806Srpaulostatic void hostapd_event_dfs_cac_started(struct hostapd_data *hapd, 1538281806Srpaulo struct dfs_event *radar) 1539281806Srpaulo{ 1540281806Srpaulo wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq); 1541281806Srpaulo hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled, 1542281806Srpaulo radar->chan_offset, radar->chan_width, 1543281806Srpaulo radar->cf1, radar->cf2); 1544281806Srpaulo} 1545281806Srpaulo 1546281806Srpaulo#endif /* NEED_AP_MLME */ 1547281806Srpaulo 1548281806Srpaulo 1549346981Scystatic void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd, 1550346981Scy int istatus, 1551346981Scy const char *ifname, 1552346981Scy const u8 *addr) 1553346981Scy{ 1554346981Scy struct sta_info *sta = ap_get_sta(hapd, addr); 1555346981Scy 1556346981Scy if (sta) { 1557346981Scy os_free(sta->ifname_wds); 1558346981Scy if (istatus == INTERFACE_ADDED) 1559346981Scy sta->ifname_wds = os_strdup(ifname); 1560346981Scy else 1561346981Scy sta->ifname_wds = NULL; 1562346981Scy } 1563346981Scy 1564346981Scy wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR, 1565346981Scy istatus == INTERFACE_ADDED ? 1566346981Scy WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED, 1567346981Scy ifname, MAC2STR(addr)); 1568346981Scy} 1569346981Scy 1570346981Scy 1571214501Srpaulovoid wpa_supplicant_event(void *ctx, enum wpa_event_type event, 1572214501Srpaulo union wpa_event_data *data) 1573214501Srpaulo{ 1574214501Srpaulo struct hostapd_data *hapd = ctx; 1575252726Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG 1576252726Srpaulo int level = MSG_DEBUG; 1577214501Srpaulo 1578252726Srpaulo if (event == EVENT_RX_MGMT && data->rx_mgmt.frame && 1579252726Srpaulo data->rx_mgmt.frame_len >= 24) { 1580252726Srpaulo const struct ieee80211_hdr *hdr; 1581252726Srpaulo u16 fc; 1582289549Srpaulo 1583252726Srpaulo hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; 1584252726Srpaulo fc = le_to_host16(hdr->frame_control); 1585252726Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1586252726Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1587252726Srpaulo level = MSG_EXCESSIVE; 1588281806Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1589281806Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) 1590281806Srpaulo level = MSG_EXCESSIVE; 1591252726Srpaulo } 1592252726Srpaulo 1593252726Srpaulo wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", 1594252726Srpaulo event_to_string(event), event); 1595252726Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */ 1596252726Srpaulo 1597214501Srpaulo switch (event) { 1598214501Srpaulo case EVENT_MICHAEL_MIC_FAILURE: 1599214501Srpaulo michael_mic_failure(hapd, data->michael_mic_failure.src, 1); 1600214501Srpaulo break; 1601214501Srpaulo case EVENT_SCAN_RESULTS: 1602214501Srpaulo if (hapd->iface->scan_cb) 1603214501Srpaulo hapd->iface->scan_cb(hapd->iface); 1604214501Srpaulo break; 1605214501Srpaulo case EVENT_WPS_BUTTON_PUSHED: 1606252726Srpaulo hostapd_wps_button_pushed(hapd, NULL); 1607214501Srpaulo break; 1608214501Srpaulo#ifdef NEED_AP_MLME 1609214501Srpaulo case EVENT_TX_STATUS: 1610214501Srpaulo switch (data->tx_status.type) { 1611214501Srpaulo case WLAN_FC_TYPE_MGMT: 1612214501Srpaulo hostapd_mgmt_tx_cb(hapd, data->tx_status.data, 1613214501Srpaulo data->tx_status.data_len, 1614214501Srpaulo data->tx_status.stype, 1615214501Srpaulo data->tx_status.ack); 1616214501Srpaulo break; 1617214501Srpaulo case WLAN_FC_TYPE_DATA: 1618214501Srpaulo hostapd_tx_status(hapd, data->tx_status.dst, 1619214501Srpaulo data->tx_status.data, 1620214501Srpaulo data->tx_status.data_len, 1621214501Srpaulo data->tx_status.ack); 1622214501Srpaulo break; 1623214501Srpaulo } 1624214501Srpaulo break; 1625252726Srpaulo case EVENT_EAPOL_TX_STATUS: 1626252726Srpaulo hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, 1627252726Srpaulo data->eapol_tx_status.data, 1628252726Srpaulo data->eapol_tx_status.data_len, 1629252726Srpaulo data->eapol_tx_status.ack); 1630252726Srpaulo break; 1631252726Srpaulo case EVENT_DRIVER_CLIENT_POLL_OK: 1632252726Srpaulo hostapd_client_poll_ok(hapd, data->client_poll.addr); 1633252726Srpaulo break; 1634214501Srpaulo case EVENT_RX_FROM_UNKNOWN: 1635252726Srpaulo hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, 1636252726Srpaulo data->rx_from_unknown.addr, 1637252726Srpaulo data->rx_from_unknown.wds); 1638214501Srpaulo break; 1639281806Srpaulo#endif /* NEED_AP_MLME */ 1640214501Srpaulo case EVENT_RX_MGMT: 1641281806Srpaulo if (!data->rx_mgmt.frame) 1642281806Srpaulo break; 1643281806Srpaulo#ifdef NEED_AP_MLME 1644346981Scy hostapd_mgmt_rx(hapd, &data->rx_mgmt); 1645346981Scy#else /* NEED_AP_MLME */ 1646346981Scy hostapd_action_rx(hapd, &data->rx_mgmt); 1647281806Srpaulo#endif /* NEED_AP_MLME */ 1648214501Srpaulo break; 1649214501Srpaulo case EVENT_RX_PROBE_REQ: 1650252726Srpaulo if (data->rx_probe_req.sa == NULL || 1651252726Srpaulo data->rx_probe_req.ie == NULL) 1652252726Srpaulo break; 1653214501Srpaulo hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, 1654252726Srpaulo data->rx_probe_req.da, 1655252726Srpaulo data->rx_probe_req.bssid, 1656214501Srpaulo data->rx_probe_req.ie, 1657252726Srpaulo data->rx_probe_req.ie_len, 1658252726Srpaulo data->rx_probe_req.ssi_signal); 1659214501Srpaulo break; 1660214501Srpaulo case EVENT_NEW_STA: 1661214501Srpaulo hostapd_event_new_sta(hapd, data->new_sta.addr); 1662214501Srpaulo break; 1663214501Srpaulo case EVENT_EAPOL_RX: 1664214501Srpaulo hostapd_event_eapol_rx(hapd, data->eapol_rx.src, 1665214501Srpaulo data->eapol_rx.data, 1666214501Srpaulo data->eapol_rx.data_len); 1667214501Srpaulo break; 1668214501Srpaulo case EVENT_ASSOC: 1669281806Srpaulo if (!data) 1670281806Srpaulo return; 1671214501Srpaulo hostapd_notif_assoc(hapd, data->assoc_info.addr, 1672214501Srpaulo data->assoc_info.req_ies, 1673252726Srpaulo data->assoc_info.req_ies_len, 1674252726Srpaulo data->assoc_info.reassoc); 1675214501Srpaulo break; 1676214501Srpaulo case EVENT_DISASSOC: 1677214501Srpaulo if (data) 1678214501Srpaulo hostapd_notif_disassoc(hapd, data->disassoc_info.addr); 1679214501Srpaulo break; 1680214501Srpaulo case EVENT_DEAUTH: 1681214501Srpaulo if (data) 1682214501Srpaulo hostapd_notif_disassoc(hapd, data->deauth_info.addr); 1683214501Srpaulo break; 1684252726Srpaulo case EVENT_STATION_LOW_ACK: 1685252726Srpaulo if (!data) 1686252726Srpaulo break; 1687252726Srpaulo hostapd_event_sta_low_ack(hapd, data->low_ack.addr); 1688252726Srpaulo break; 1689252726Srpaulo case EVENT_AUTH: 1690252726Srpaulo hostapd_notif_auth(hapd, &data->auth); 1691252726Srpaulo break; 1692252726Srpaulo case EVENT_CH_SWITCH: 1693252726Srpaulo if (!data) 1694252726Srpaulo break; 1695252726Srpaulo hostapd_event_ch_switch(hapd, data->ch_switch.freq, 1696252726Srpaulo data->ch_switch.ht_enabled, 1697281806Srpaulo data->ch_switch.ch_offset, 1698281806Srpaulo data->ch_switch.ch_width, 1699281806Srpaulo data->ch_switch.cf1, 1700281806Srpaulo data->ch_switch.cf2); 1701252726Srpaulo break; 1702281806Srpaulo case EVENT_CONNECT_FAILED_REASON: 1703281806Srpaulo if (!data) 1704281806Srpaulo break; 1705281806Srpaulo hostapd_event_connect_failed_reason( 1706281806Srpaulo hapd, data->connect_failed_reason.addr, 1707281806Srpaulo data->connect_failed_reason.code); 1708281806Srpaulo break; 1709281806Srpaulo case EVENT_SURVEY: 1710337817Scy hostapd_event_get_survey(hapd->iface, &data->survey_results); 1711281806Srpaulo break; 1712281806Srpaulo#ifdef NEED_AP_MLME 1713281806Srpaulo case EVENT_INTERFACE_UNAVAILABLE: 1714281806Srpaulo hostapd_event_iface_unavailable(hapd); 1715281806Srpaulo break; 1716281806Srpaulo case EVENT_DFS_RADAR_DETECTED: 1717281806Srpaulo if (!data) 1718281806Srpaulo break; 1719281806Srpaulo hostapd_event_dfs_radar_detected(hapd, &data->dfs_event); 1720281806Srpaulo break; 1721346981Scy case EVENT_DFS_PRE_CAC_EXPIRED: 1722346981Scy if (!data) 1723346981Scy break; 1724346981Scy hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event); 1725346981Scy break; 1726281806Srpaulo case EVENT_DFS_CAC_FINISHED: 1727281806Srpaulo if (!data) 1728281806Srpaulo break; 1729281806Srpaulo hostapd_event_dfs_cac_finished(hapd, &data->dfs_event); 1730281806Srpaulo break; 1731281806Srpaulo case EVENT_DFS_CAC_ABORTED: 1732281806Srpaulo if (!data) 1733281806Srpaulo break; 1734281806Srpaulo hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event); 1735281806Srpaulo break; 1736281806Srpaulo case EVENT_DFS_NOP_FINISHED: 1737281806Srpaulo if (!data) 1738281806Srpaulo break; 1739281806Srpaulo hostapd_event_dfs_nop_finished(hapd, &data->dfs_event); 1740281806Srpaulo break; 1741281806Srpaulo case EVENT_CHANNEL_LIST_CHANGED: 1742281806Srpaulo /* channel list changed (regulatory?), update channel list */ 1743281806Srpaulo /* TODO: check this. hostapd_get_hw_features() initializes 1744281806Srpaulo * too much stuff. */ 1745281806Srpaulo /* hostapd_get_hw_features(hapd->iface); */ 1746281806Srpaulo hostapd_channel_list_updated( 1747281806Srpaulo hapd->iface, data->channel_list_changed.initiator); 1748281806Srpaulo break; 1749281806Srpaulo case EVENT_DFS_CAC_STARTED: 1750281806Srpaulo if (!data) 1751281806Srpaulo break; 1752281806Srpaulo hostapd_event_dfs_cac_started(hapd, &data->dfs_event); 1753281806Srpaulo break; 1754281806Srpaulo#endif /* NEED_AP_MLME */ 1755281806Srpaulo case EVENT_INTERFACE_ENABLED: 1756281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED); 1757281806Srpaulo if (hapd->disabled && hapd->started) { 1758281806Srpaulo hapd->disabled = 0; 1759281806Srpaulo /* 1760281806Srpaulo * Try to re-enable interface if the driver stopped it 1761281806Srpaulo * when the interface got disabled. 1762281806Srpaulo */ 1763346981Scy if (hapd->wpa_auth) 1764346981Scy wpa_auth_reconfig_group_keys(hapd->wpa_auth); 1765346981Scy else 1766346981Scy hostapd_reconfig_encryption(hapd); 1767281806Srpaulo hapd->reenable_beacon = 1; 1768281806Srpaulo ieee802_11_set_beacon(hapd); 1769346981Scy#ifdef NEED_AP_MLME 1770346981Scy } else if (hapd->disabled && hapd->iface->cac_started) { 1771346981Scy wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC"); 1772346981Scy hostapd_handle_dfs(hapd->iface); 1773346981Scy#endif /* NEED_AP_MLME */ 1774281806Srpaulo } 1775281806Srpaulo break; 1776281806Srpaulo case EVENT_INTERFACE_DISABLED: 1777281806Srpaulo hostapd_free_stas(hapd); 1778281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED); 1779281806Srpaulo hapd->disabled = 1; 1780281806Srpaulo break; 1781281806Srpaulo#ifdef CONFIG_ACS 1782281806Srpaulo case EVENT_ACS_CHANNEL_SELECTED: 1783289549Srpaulo hostapd_acs_channel_selected(hapd, 1784289549Srpaulo &data->acs_selected_channels); 1785281806Srpaulo break; 1786281806Srpaulo#endif /* CONFIG_ACS */ 1787346981Scy case EVENT_STATION_OPMODE_CHANGED: 1788346981Scy hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr, 1789346981Scy data->sta_opmode.smps_mode, 1790346981Scy data->sta_opmode.chan_width, 1791346981Scy data->sta_opmode.rx_nss); 1792346981Scy break; 1793346981Scy case EVENT_WDS_STA_INTERFACE_STATUS: 1794346981Scy hostapd_event_wds_sta_interface_status( 1795346981Scy hapd, data->wds_sta_interface.istatus, 1796346981Scy data->wds_sta_interface.ifname, 1797346981Scy data->wds_sta_interface.sta_addr); 1798346981Scy break; 1799214501Srpaulo default: 1800214501Srpaulo wpa_printf(MSG_DEBUG, "Unknown event %d", event); 1801214501Srpaulo break; 1802214501Srpaulo } 1803214501Srpaulo} 1804214501Srpaulo 1805337817Scy 1806337817Scyvoid wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, 1807337817Scy union wpa_event_data *data) 1808337817Scy{ 1809337817Scy struct hapd_interfaces *interfaces = ctx; 1810337817Scy struct hostapd_data *hapd; 1811337817Scy 1812337817Scy if (event != EVENT_INTERFACE_STATUS) 1813337817Scy return; 1814337817Scy 1815337817Scy hapd = hostapd_get_iface(interfaces, data->interface_status.ifname); 1816337817Scy if (hapd && hapd->driver && hapd->driver->get_ifindex && 1817337817Scy hapd->drv_priv) { 1818337817Scy unsigned int ifindex; 1819337817Scy 1820337817Scy ifindex = hapd->driver->get_ifindex(hapd->drv_priv); 1821337817Scy if (ifindex != data->interface_status.ifindex) { 1822337817Scy wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 1823337817Scy "interface status ifindex %d mismatch (%d)", 1824337817Scy ifindex, data->interface_status.ifindex); 1825337817Scy return; 1826337817Scy } 1827337817Scy } 1828337817Scy if (hapd) 1829337817Scy wpa_supplicant_event(hapd, event, data); 1830337817Scy} 1831337817Scy 1832214501Srpaulo#endif /* HOSTAPD */ 1833