drv_callbacks.c revision 281806
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" 18252726Srpaulo#include "crypto/random.h" 19252726Srpaulo#include "p2p/p2p.h" 20252726Srpaulo#include "wps/wps.h" 21252726Srpaulo#include "wnm_ap.h" 22214501Srpaulo#include "hostapd.h" 23214501Srpaulo#include "ieee802_11.h" 24214501Srpaulo#include "sta_info.h" 25214501Srpaulo#include "accounting.h" 26214501Srpaulo#include "tkip_countermeasures.h" 27214501Srpaulo#include "ieee802_1x.h" 28214501Srpaulo#include "wpa_auth.h" 29214501Srpaulo#include "wps_hostapd.h" 30252726Srpaulo#include "ap_drv_ops.h" 31214501Srpaulo#include "ap_config.h" 32252726Srpaulo#include "hw_features.h" 33281806Srpaulo#include "dfs.h" 34281806Srpaulo#include "beacon.h" 35214501Srpaulo 36214501Srpaulo 37214501Srpauloint hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, 38252726Srpaulo const u8 *req_ies, size_t req_ies_len, int reassoc) 39214501Srpaulo{ 40214501Srpaulo struct sta_info *sta; 41214501Srpaulo int new_assoc, res; 42214501Srpaulo struct ieee802_11_elems elems; 43252726Srpaulo const u8 *ie; 44252726Srpaulo size_t ielen; 45252726Srpaulo#ifdef CONFIG_IEEE80211R 46252726Srpaulo u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; 47252726Srpaulo u8 *p = buf; 48252726Srpaulo#endif /* CONFIG_IEEE80211R */ 49252726Srpaulo u16 reason = WLAN_REASON_UNSPECIFIED; 50252726Srpaulo u16 status = WLAN_STATUS_SUCCESS; 51281806Srpaulo const u8 *p2p_dev_addr = NULL; 52214501Srpaulo 53214501Srpaulo if (addr == NULL) { 54214501Srpaulo /* 55214501Srpaulo * This could potentially happen with unexpected event from the 56214501Srpaulo * driver wrapper. This was seen at least in one case where the 57214501Srpaulo * driver ended up being set to station mode while hostapd was 58214501Srpaulo * running, so better make sure we stop processing such an 59214501Srpaulo * event here. 60214501Srpaulo */ 61214501Srpaulo wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " 62214501Srpaulo "no address"); 63214501Srpaulo return -1; 64214501Srpaulo } 65252726Srpaulo random_add_randomness(addr, ETH_ALEN); 66214501Srpaulo 67214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 68214501Srpaulo HOSTAPD_LEVEL_INFO, "associated"); 69214501Srpaulo 70252726Srpaulo ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); 71214501Srpaulo if (elems.wps_ie) { 72214501Srpaulo ie = elems.wps_ie - 2; 73214501Srpaulo ielen = elems.wps_ie_len + 2; 74214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); 75214501Srpaulo } else if (elems.rsn_ie) { 76214501Srpaulo ie = elems.rsn_ie - 2; 77214501Srpaulo ielen = elems.rsn_ie_len + 2; 78214501Srpaulo wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); 79214501Srpaulo } else if (elems.wpa_ie) { 80214501Srpaulo ie = elems.wpa_ie - 2; 81214501Srpaulo ielen = elems.wpa_ie_len + 2; 82214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); 83281806Srpaulo#ifdef CONFIG_HS20 84281806Srpaulo } else if (elems.osen) { 85281806Srpaulo ie = elems.osen - 2; 86281806Srpaulo ielen = elems.osen_len + 2; 87281806Srpaulo wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq"); 88281806Srpaulo#endif /* CONFIG_HS20 */ 89214501Srpaulo } else { 90214501Srpaulo ie = NULL; 91214501Srpaulo ielen = 0; 92214501Srpaulo wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " 93214501Srpaulo "(Re)AssocReq"); 94214501Srpaulo } 95214501Srpaulo 96214501Srpaulo sta = ap_get_sta(hapd, addr); 97214501Srpaulo if (sta) { 98281806Srpaulo ap_sta_no_session_timeout(hapd, sta); 99214501Srpaulo accounting_sta_stop(hapd, sta); 100252726Srpaulo 101252726Srpaulo /* 102252726Srpaulo * Make sure that the previously registered inactivity timer 103252726Srpaulo * will not remove the STA immediately. 104252726Srpaulo */ 105252726Srpaulo sta->timeout_next = STA_NULLFUNC; 106214501Srpaulo } else { 107214501Srpaulo sta = ap_sta_add(hapd, addr); 108252726Srpaulo if (sta == NULL) { 109252726Srpaulo hostapd_drv_sta_disassoc(hapd, addr, 110252726Srpaulo WLAN_REASON_DISASSOC_AP_BUSY); 111214501Srpaulo return -1; 112252726Srpaulo } 113214501Srpaulo } 114252726Srpaulo sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 115214501Srpaulo 116252726Srpaulo#ifdef CONFIG_P2P 117252726Srpaulo if (elems.p2p) { 118252726Srpaulo wpabuf_free(sta->p2p_ie); 119252726Srpaulo sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 120252726Srpaulo P2P_IE_VENDOR_TYPE); 121281806Srpaulo if (sta->p2p_ie) 122281806Srpaulo p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); 123252726Srpaulo } 124252726Srpaulo#endif /* CONFIG_P2P */ 125252726Srpaulo 126281806Srpaulo#ifdef CONFIG_IEEE80211N 127281806Srpaulo#ifdef NEED_AP_MLME 128281806Srpaulo if (elems.ht_capabilities && 129281806Srpaulo elems.ht_capabilities_len >= 130281806Srpaulo sizeof(struct ieee80211_ht_capabilities) && 131281806Srpaulo (hapd->iface->conf->ht_capab & 132281806Srpaulo HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { 133281806Srpaulo struct ieee80211_ht_capabilities *ht_cap = 134281806Srpaulo (struct ieee80211_ht_capabilities *) 135281806Srpaulo elems.ht_capabilities; 136281806Srpaulo 137281806Srpaulo if (le_to_host16(ht_cap->ht_capabilities_info) & 138281806Srpaulo HT_CAP_INFO_40MHZ_INTOLERANT) 139281806Srpaulo ht40_intolerant_add(hapd->iface, sta); 140281806Srpaulo } 141281806Srpaulo#endif /* NEED_AP_MLME */ 142281806Srpaulo#endif /* CONFIG_IEEE80211N */ 143281806Srpaulo 144281806Srpaulo#ifdef CONFIG_INTERWORKING 145281806Srpaulo if (elems.ext_capab && elems.ext_capab_len > 4) { 146281806Srpaulo if (elems.ext_capab[4] & 0x01) 147281806Srpaulo sta->qos_map_enabled = 1; 148281806Srpaulo } 149281806Srpaulo#endif /* CONFIG_INTERWORKING */ 150281806Srpaulo 151252726Srpaulo#ifdef CONFIG_HS20 152252726Srpaulo wpabuf_free(sta->hs20_ie); 153252726Srpaulo if (elems.hs20 && elems.hs20_len > 4) { 154252726Srpaulo sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, 155252726Srpaulo elems.hs20_len - 4); 156252726Srpaulo } else 157252726Srpaulo sta->hs20_ie = NULL; 158252726Srpaulo#endif /* CONFIG_HS20 */ 159252726Srpaulo 160214501Srpaulo if (hapd->conf->wpa) { 161214501Srpaulo if (ie == NULL || ielen == 0) { 162252726Srpaulo#ifdef CONFIG_WPS 163214501Srpaulo if (hapd->conf->wps_state) { 164214501Srpaulo wpa_printf(MSG_DEBUG, "STA did not include " 165214501Srpaulo "WPA/RSN IE in (Re)Association " 166214501Srpaulo "Request - possible WPS use"); 167214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 168214501Srpaulo goto skip_wpa_check; 169214501Srpaulo } 170252726Srpaulo#endif /* CONFIG_WPS */ 171214501Srpaulo 172214501Srpaulo wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); 173214501Srpaulo return -1; 174214501Srpaulo } 175252726Srpaulo#ifdef CONFIG_WPS 176214501Srpaulo if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && 177214501Srpaulo os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { 178252726Srpaulo struct wpabuf *wps; 179214501Srpaulo sta->flags |= WLAN_STA_WPS; 180252726Srpaulo wps = ieee802_11_vendor_ie_concat(ie, ielen, 181252726Srpaulo WPS_IE_VENDOR_TYPE); 182252726Srpaulo if (wps) { 183252726Srpaulo if (wps_is_20(wps)) { 184252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: STA " 185252726Srpaulo "supports WPS 2.0"); 186252726Srpaulo sta->flags |= WLAN_STA_WPS2; 187252726Srpaulo } 188252726Srpaulo wpabuf_free(wps); 189252726Srpaulo } 190214501Srpaulo goto skip_wpa_check; 191214501Srpaulo } 192252726Srpaulo#endif /* CONFIG_WPS */ 193214501Srpaulo 194214501Srpaulo if (sta->wpa_sm == NULL) 195214501Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 196281806Srpaulo sta->addr, 197281806Srpaulo p2p_dev_addr); 198214501Srpaulo if (sta->wpa_sm == NULL) { 199214501Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize WPA state " 200214501Srpaulo "machine"); 201214501Srpaulo return -1; 202214501Srpaulo } 203214501Srpaulo res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 204252726Srpaulo ie, ielen, 205252726Srpaulo elems.mdie, elems.mdie_len); 206214501Srpaulo if (res != WPA_IE_OK) { 207214501Srpaulo wpa_printf(MSG_DEBUG, "WPA/RSN information element " 208214501Srpaulo "rejected? (res %u)", res); 209214501Srpaulo wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); 210252726Srpaulo if (res == WPA_INVALID_GROUP) { 211252726Srpaulo reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; 212252726Srpaulo status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 213252726Srpaulo } else if (res == WPA_INVALID_PAIRWISE) { 214252726Srpaulo reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; 215252726Srpaulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 216252726Srpaulo } else if (res == WPA_INVALID_AKMP) { 217252726Srpaulo reason = WLAN_REASON_AKMP_NOT_VALID; 218252726Srpaulo status = WLAN_STATUS_AKMP_NOT_VALID; 219252726Srpaulo } 220214501Srpaulo#ifdef CONFIG_IEEE80211W 221252726Srpaulo else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { 222252726Srpaulo reason = WLAN_REASON_INVALID_IE; 223252726Srpaulo status = WLAN_STATUS_INVALID_IE; 224252726Srpaulo } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { 225252726Srpaulo reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; 226252726Srpaulo status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 227252726Srpaulo } 228214501Srpaulo#endif /* CONFIG_IEEE80211W */ 229252726Srpaulo else { 230252726Srpaulo reason = WLAN_REASON_INVALID_IE; 231252726Srpaulo status = WLAN_STATUS_INVALID_IE; 232252726Srpaulo } 233252726Srpaulo goto fail; 234214501Srpaulo } 235252726Srpaulo#ifdef CONFIG_IEEE80211W 236252726Srpaulo if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && 237252726Srpaulo sta->sa_query_count > 0) 238252726Srpaulo ap_check_sa_query_timeout(hapd, sta); 239252726Srpaulo if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && 240252726Srpaulo (sta->auth_alg != WLAN_AUTH_FT)) { 241252726Srpaulo /* 242252726Srpaulo * STA has already been associated with MFP and SA 243252726Srpaulo * Query timeout has not been reached. Reject the 244252726Srpaulo * association attempt temporarily and start SA Query, 245252726Srpaulo * if one is not pending. 246252726Srpaulo */ 247252726Srpaulo 248252726Srpaulo if (sta->sa_query_count == 0) 249252726Srpaulo ap_sta_start_sa_query(hapd, sta); 250252726Srpaulo 251252726Srpaulo#ifdef CONFIG_IEEE80211R 252252726Srpaulo status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 253252726Srpaulo 254252726Srpaulo p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 255252726Srpaulo 256252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, 257252726Srpaulo p - buf); 258252726Srpaulo#endif /* CONFIG_IEEE80211R */ 259252726Srpaulo return 0; 260252726Srpaulo } 261252726Srpaulo 262252726Srpaulo if (wpa_auth_uses_mfp(sta->wpa_sm)) 263252726Srpaulo sta->flags |= WLAN_STA_MFP; 264252726Srpaulo else 265252726Srpaulo sta->flags &= ~WLAN_STA_MFP; 266252726Srpaulo#endif /* CONFIG_IEEE80211W */ 267252726Srpaulo 268252726Srpaulo#ifdef CONFIG_IEEE80211R 269252726Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) { 270252726Srpaulo status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, 271252726Srpaulo req_ies_len); 272252726Srpaulo if (status != WLAN_STATUS_SUCCESS) { 273252726Srpaulo if (status == WLAN_STATUS_INVALID_PMKID) 274252726Srpaulo reason = WLAN_REASON_INVALID_IE; 275252726Srpaulo if (status == WLAN_STATUS_INVALID_MDIE) 276252726Srpaulo reason = WLAN_REASON_INVALID_IE; 277252726Srpaulo if (status == WLAN_STATUS_INVALID_FTIE) 278252726Srpaulo reason = WLAN_REASON_INVALID_IE; 279252726Srpaulo goto fail; 280252726Srpaulo } 281252726Srpaulo } 282252726Srpaulo#endif /* CONFIG_IEEE80211R */ 283214501Srpaulo } else if (hapd->conf->wps_state) { 284252726Srpaulo#ifdef CONFIG_WPS 285252726Srpaulo struct wpabuf *wps; 286252726Srpaulo if (req_ies) 287252726Srpaulo wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 288252726Srpaulo WPS_IE_VENDOR_TYPE); 289252726Srpaulo else 290252726Srpaulo wps = NULL; 291252726Srpaulo#ifdef CONFIG_WPS_STRICT 292252726Srpaulo if (wps && wps_validate_assoc_req(wps) < 0) { 293252726Srpaulo reason = WLAN_REASON_INVALID_IE; 294252726Srpaulo status = WLAN_STATUS_INVALID_IE; 295252726Srpaulo wpabuf_free(wps); 296252726Srpaulo goto fail; 297252726Srpaulo } 298252726Srpaulo#endif /* CONFIG_WPS_STRICT */ 299252726Srpaulo if (wps) { 300214501Srpaulo sta->flags |= WLAN_STA_WPS; 301252726Srpaulo if (wps_is_20(wps)) { 302252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: STA supports " 303252726Srpaulo "WPS 2.0"); 304252726Srpaulo sta->flags |= WLAN_STA_WPS2; 305252726Srpaulo } 306214501Srpaulo } else 307214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 308252726Srpaulo wpabuf_free(wps); 309252726Srpaulo#endif /* CONFIG_WPS */ 310281806Srpaulo#ifdef CONFIG_HS20 311281806Srpaulo } else if (hapd->conf->osen) { 312281806Srpaulo if (elems.osen == NULL) { 313281806Srpaulo hostapd_logger( 314281806Srpaulo hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 315281806Srpaulo HOSTAPD_LEVEL_INFO, 316281806Srpaulo "No HS 2.0 OSEN element in association request"); 317281806Srpaulo return WLAN_STATUS_INVALID_IE; 318281806Srpaulo } 319281806Srpaulo 320281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association"); 321281806Srpaulo if (sta->wpa_sm == NULL) 322281806Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 323281806Srpaulo sta->addr, NULL); 324281806Srpaulo if (sta->wpa_sm == NULL) { 325281806Srpaulo wpa_printf(MSG_WARNING, "Failed to initialize WPA " 326281806Srpaulo "state machine"); 327281806Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 328281806Srpaulo } 329281806Srpaulo if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, 330281806Srpaulo elems.osen - 2, elems.osen_len + 2) < 0) 331281806Srpaulo return WLAN_STATUS_INVALID_IE; 332281806Srpaulo#endif /* CONFIG_HS20 */ 333214501Srpaulo } 334252726Srpaulo#ifdef CONFIG_WPS 335214501Srpauloskip_wpa_check: 336252726Srpaulo#endif /* CONFIG_WPS */ 337214501Srpaulo 338252726Srpaulo#ifdef CONFIG_IEEE80211R 339252726Srpaulo p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), 340252726Srpaulo sta->auth_alg, req_ies, req_ies_len); 341252726Srpaulo 342252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 343281806Srpaulo 344281806Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) 345281806Srpaulo ap_sta_set_authorized(hapd, sta, 1); 346252726Srpaulo#else /* CONFIG_IEEE80211R */ 347252726Srpaulo /* Keep compiler silent about unused variables */ 348252726Srpaulo if (status) { 349252726Srpaulo } 350252726Srpaulo#endif /* CONFIG_IEEE80211R */ 351252726Srpaulo 352214501Srpaulo new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 353214501Srpaulo sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 354281806Srpaulo sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; 355214501Srpaulo 356281806Srpaulo hostapd_set_sta_flags(hapd, sta); 357281806Srpaulo 358252726Srpaulo if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) 359252726Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 360252726Srpaulo else 361252726Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 362252726Srpaulo 363214501Srpaulo hostapd_new_assoc_sta(hapd, sta, !new_assoc); 364214501Srpaulo 365214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 366214501Srpaulo 367252726Srpaulo#ifdef CONFIG_P2P 368252726Srpaulo if (req_ies) { 369252726Srpaulo p2p_group_notif_assoc(hapd->p2p_group, sta->addr, 370252726Srpaulo req_ies, req_ies_len); 371252726Srpaulo } 372252726Srpaulo#endif /* CONFIG_P2P */ 373252726Srpaulo 374214501Srpaulo return 0; 375252726Srpaulo 376252726Srpaulofail: 377252726Srpaulo#ifdef CONFIG_IEEE80211R 378252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 379252726Srpaulo#endif /* CONFIG_IEEE80211R */ 380252726Srpaulo hostapd_drv_sta_disassoc(hapd, sta->addr, reason); 381252726Srpaulo ap_free_sta(hapd, sta); 382252726Srpaulo return -1; 383214501Srpaulo} 384214501Srpaulo 385214501Srpaulo 386214501Srpaulovoid hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) 387214501Srpaulo{ 388214501Srpaulo struct sta_info *sta; 389214501Srpaulo 390252726Srpaulo if (addr == NULL) { 391252726Srpaulo /* 392252726Srpaulo * This could potentially happen with unexpected event from the 393252726Srpaulo * driver wrapper. This was seen at least in one case where the 394252726Srpaulo * driver ended up reporting a station mode event while hostapd 395252726Srpaulo * was running, so better make sure we stop processing such an 396252726Srpaulo * event here. 397252726Srpaulo */ 398252726Srpaulo wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event " 399252726Srpaulo "with no address"); 400252726Srpaulo return; 401252726Srpaulo } 402252726Srpaulo 403214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 404214501Srpaulo HOSTAPD_LEVEL_INFO, "disassociated"); 405214501Srpaulo 406214501Srpaulo sta = ap_get_sta(hapd, addr); 407214501Srpaulo if (sta == NULL) { 408214501Srpaulo wpa_printf(MSG_DEBUG, "Disassociation notification for " 409214501Srpaulo "unknown STA " MACSTR, MAC2STR(addr)); 410214501Srpaulo return; 411214501Srpaulo } 412214501Srpaulo 413252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 414214501Srpaulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 415214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 416214501Srpaulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 417214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 418214501Srpaulo ap_free_sta(hapd, sta); 419214501Srpaulo} 420214501Srpaulo 421214501Srpaulo 422252726Srpaulovoid hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) 423252726Srpaulo{ 424252726Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 425214501Srpaulo 426252726Srpaulo if (!sta || !hapd->conf->disassoc_low_ack) 427252726Srpaulo return; 428252726Srpaulo 429252726Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 430252726Srpaulo HOSTAPD_LEVEL_INFO, "disconnected due to excessive " 431252726Srpaulo "missing ACKs"); 432252726Srpaulo hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); 433252726Srpaulo if (sta) 434252726Srpaulo ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); 435252726Srpaulo} 436252726Srpaulo 437252726Srpaulo 438252726Srpaulovoid hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, 439281806Srpaulo int offset, int width, int cf1, int cf2) 440252726Srpaulo{ 441214501Srpaulo#ifdef NEED_AP_MLME 442281806Srpaulo int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs; 443214501Srpaulo 444252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 445281806Srpaulo HOSTAPD_LEVEL_INFO, 446281806Srpaulo "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d", 447281806Srpaulo freq, ht, offset, width, channel_width_to_string(width), 448281806Srpaulo cf1, cf2); 449252726Srpaulo 450252726Srpaulo hapd->iface->freq = freq; 451252726Srpaulo 452252726Srpaulo channel = hostapd_hw_get_channel(hapd, freq); 453252726Srpaulo if (!channel) { 454252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 455252726Srpaulo HOSTAPD_LEVEL_WARNING, "driver switched to " 456252726Srpaulo "bad channel!"); 457252726Srpaulo return; 458252726Srpaulo } 459252726Srpaulo 460281806Srpaulo switch (width) { 461281806Srpaulo case CHAN_WIDTH_80: 462281806Srpaulo chwidth = VHT_CHANWIDTH_80MHZ; 463281806Srpaulo break; 464281806Srpaulo case CHAN_WIDTH_80P80: 465281806Srpaulo chwidth = VHT_CHANWIDTH_80P80MHZ; 466281806Srpaulo break; 467281806Srpaulo case CHAN_WIDTH_160: 468281806Srpaulo chwidth = VHT_CHANWIDTH_160MHZ; 469281806Srpaulo break; 470281806Srpaulo case CHAN_WIDTH_20_NOHT: 471281806Srpaulo case CHAN_WIDTH_20: 472281806Srpaulo case CHAN_WIDTH_40: 473281806Srpaulo default: 474281806Srpaulo chwidth = VHT_CHANWIDTH_USE_HT; 475281806Srpaulo break; 476281806Srpaulo } 477281806Srpaulo 478281806Srpaulo switch (hapd->iface->current_mode->mode) { 479281806Srpaulo case HOSTAPD_MODE_IEEE80211A: 480281806Srpaulo if (cf1 > 5000) 481281806Srpaulo seg0_idx = (cf1 - 5000) / 5; 482281806Srpaulo if (cf2 > 5000) 483281806Srpaulo seg1_idx = (cf2 - 5000) / 5; 484281806Srpaulo break; 485281806Srpaulo default: 486281806Srpaulo seg0_idx = hostapd_hw_get_channel(hapd, cf1); 487281806Srpaulo seg1_idx = hostapd_hw_get_channel(hapd, cf2); 488281806Srpaulo break; 489281806Srpaulo } 490281806Srpaulo 491252726Srpaulo hapd->iconf->channel = channel; 492252726Srpaulo hapd->iconf->ieee80211n = ht; 493281806Srpaulo if (!ht) 494281806Srpaulo hapd->iconf->ieee80211ac = 0; 495252726Srpaulo hapd->iconf->secondary_channel = offset; 496281806Srpaulo hapd->iconf->vht_oper_chwidth = chwidth; 497281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; 498281806Srpaulo hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; 499281806Srpaulo 500281806Srpaulo is_dfs = ieee80211_is_dfs(freq); 501281806Srpaulo 502281806Srpaulo if (hapd->csa_in_progress && 503281806Srpaulo freq == hapd->cs_freq_params.freq) { 504281806Srpaulo hostapd_cleanup_cs_params(hapd); 505281806Srpaulo ieee802_11_set_beacon(hapd); 506281806Srpaulo 507281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 508281806Srpaulo "freq=%d dfs=%d", freq, is_dfs); 509281806Srpaulo } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { 510281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED 511281806Srpaulo "freq=%d dfs=%d", freq, is_dfs); 512281806Srpaulo } 513252726Srpaulo#endif /* NEED_AP_MLME */ 514252726Srpaulo} 515252726Srpaulo 516252726Srpaulo 517281806Srpaulovoid hostapd_event_connect_failed_reason(struct hostapd_data *hapd, 518281806Srpaulo const u8 *addr, int reason_code) 519281806Srpaulo{ 520281806Srpaulo switch (reason_code) { 521281806Srpaulo case MAX_CLIENT_REACHED: 522281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR, 523281806Srpaulo MAC2STR(addr)); 524281806Srpaulo break; 525281806Srpaulo case BLOCKED_CLIENT: 526281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR, 527281806Srpaulo MAC2STR(addr)); 528281806Srpaulo break; 529281806Srpaulo } 530281806Srpaulo} 531281806Srpaulo 532281806Srpaulo 533281806Srpaulo#ifdef CONFIG_ACS 534281806Srpaulostatic void hostapd_acs_channel_selected(struct hostapd_data *hapd, 535281806Srpaulo u8 pri_channel, u8 sec_channel) 536281806Srpaulo{ 537281806Srpaulo int channel; 538281806Srpaulo int ret; 539281806Srpaulo 540281806Srpaulo if (hapd->iconf->channel) { 541281806Srpaulo wpa_printf(MSG_INFO, "ACS: Channel was already set to %d", 542281806Srpaulo hapd->iconf->channel); 543281806Srpaulo return; 544281806Srpaulo } 545281806Srpaulo 546281806Srpaulo hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel); 547281806Srpaulo 548281806Srpaulo channel = pri_channel; 549281806Srpaulo if (!channel) { 550281806Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 551281806Srpaulo HOSTAPD_LEVEL_WARNING, 552281806Srpaulo "driver switched to bad channel"); 553281806Srpaulo return; 554281806Srpaulo } 555281806Srpaulo 556281806Srpaulo hapd->iconf->channel = channel; 557281806Srpaulo 558281806Srpaulo if (sec_channel == 0) 559281806Srpaulo hapd->iconf->secondary_channel = 0; 560281806Srpaulo else if (sec_channel < pri_channel) 561281806Srpaulo hapd->iconf->secondary_channel = -1; 562281806Srpaulo else if (sec_channel > pri_channel) 563281806Srpaulo hapd->iconf->secondary_channel = 1; 564281806Srpaulo else { 565281806Srpaulo wpa_printf(MSG_ERROR, "Invalid secondary channel!"); 566281806Srpaulo return; 567281806Srpaulo } 568281806Srpaulo 569281806Srpaulo ret = hostapd_acs_completed(hapd->iface, 0); 570281806Srpaulo if (ret) { 571281806Srpaulo wpa_printf(MSG_ERROR, 572281806Srpaulo "ACS: Possibly channel configuration is invalid"); 573281806Srpaulo } 574281806Srpaulo} 575281806Srpaulo#endif /* CONFIG_ACS */ 576281806Srpaulo 577281806Srpaulo 578252726Srpauloint hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, 579252726Srpaulo const u8 *bssid, const u8 *ie, size_t ie_len, 580252726Srpaulo int ssi_signal) 581214501Srpaulo{ 582252726Srpaulo size_t i; 583252726Srpaulo int ret = 0; 584214501Srpaulo 585252726Srpaulo if (sa == NULL || ie == NULL) 586252726Srpaulo return -1; 587214501Srpaulo 588252726Srpaulo random_add_randomness(sa, ETH_ALEN); 589252726Srpaulo for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { 590252726Srpaulo if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 591252726Srpaulo sa, da, bssid, ie, ie_len, 592252726Srpaulo ssi_signal) > 0) { 593252726Srpaulo ret = 1; 594252726Srpaulo break; 595252726Srpaulo } 596252726Srpaulo } 597252726Srpaulo return ret; 598252726Srpaulo} 599214501Srpaulo 600252726Srpaulo 601252726Srpaulo#ifdef HOSTAPD 602252726Srpaulo 603252726Srpaulo#ifdef CONFIG_IEEE80211R 604252726Srpaulostatic void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, 605252726Srpaulo const u8 *bssid, 606252726Srpaulo u16 auth_transaction, u16 status, 607252726Srpaulo const u8 *ies, size_t ies_len) 608252726Srpaulo{ 609252726Srpaulo struct hostapd_data *hapd = ctx; 610252726Srpaulo struct sta_info *sta; 611252726Srpaulo 612252726Srpaulo sta = ap_get_sta(hapd, dst); 613252726Srpaulo if (sta == NULL) 614252726Srpaulo return; 615252726Srpaulo 616252726Srpaulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 617252726Srpaulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 618252726Srpaulo sta->flags |= WLAN_STA_AUTH; 619252726Srpaulo 620252726Srpaulo hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len); 621252726Srpaulo} 622252726Srpaulo#endif /* CONFIG_IEEE80211R */ 623252726Srpaulo 624252726Srpaulo 625252726Srpaulostatic void hostapd_notif_auth(struct hostapd_data *hapd, 626252726Srpaulo struct auth_info *rx_auth) 627252726Srpaulo{ 628252726Srpaulo struct sta_info *sta; 629252726Srpaulo u16 status = WLAN_STATUS_SUCCESS; 630252726Srpaulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 631252726Srpaulo size_t resp_ies_len = 0; 632252726Srpaulo 633252726Srpaulo sta = ap_get_sta(hapd, rx_auth->peer); 634252726Srpaulo if (!sta) { 635252726Srpaulo sta = ap_sta_add(hapd, rx_auth->peer); 636252726Srpaulo if (sta == NULL) { 637281806Srpaulo status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 638252726Srpaulo goto fail; 639214501Srpaulo } 640214501Srpaulo } 641252726Srpaulo sta->flags &= ~WLAN_STA_PREAUTH; 642252726Srpaulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 643252726Srpaulo#ifdef CONFIG_IEEE80211R 644252726Srpaulo if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { 645252726Srpaulo sta->auth_alg = WLAN_AUTH_FT; 646252726Srpaulo if (sta->wpa_sm == NULL) 647252726Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 648281806Srpaulo sta->addr, NULL); 649252726Srpaulo if (sta->wpa_sm == NULL) { 650252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " 651252726Srpaulo "state machine"); 652252726Srpaulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 653252726Srpaulo goto fail; 654252726Srpaulo } 655252726Srpaulo wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, 656252726Srpaulo rx_auth->auth_transaction, rx_auth->ies, 657252726Srpaulo rx_auth->ies_len, 658252726Srpaulo hostapd_notify_auth_ft_finish, hapd); 659252726Srpaulo return; 660252726Srpaulo } 661252726Srpaulo#endif /* CONFIG_IEEE80211R */ 662252726Srpaulofail: 663252726Srpaulo hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, 664252726Srpaulo status, resp_ies, resp_ies_len); 665214501Srpaulo} 666214501Srpaulo 667214501Srpaulo 668252726Srpaulostatic void hostapd_action_rx(struct hostapd_data *hapd, 669281806Srpaulo struct rx_mgmt *drv_mgmt) 670252726Srpaulo{ 671281806Srpaulo struct ieee80211_mgmt *mgmt; 672252726Srpaulo struct sta_info *sta; 673281806Srpaulo size_t plen __maybe_unused; 674281806Srpaulo u16 fc; 675252726Srpaulo 676281806Srpaulo if (drv_mgmt->frame_len < 24 + 1) 677281806Srpaulo return; 678281806Srpaulo 679281806Srpaulo plen = drv_mgmt->frame_len - 24 - 1; 680281806Srpaulo 681281806Srpaulo mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame; 682281806Srpaulo fc = le_to_host16(mgmt->frame_control); 683281806Srpaulo if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) 684281806Srpaulo return; /* handled by the driver */ 685281806Srpaulo 686252726Srpaulo wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", 687281806Srpaulo mgmt->u.action.category, (int) plen); 688252726Srpaulo 689281806Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 690252726Srpaulo if (sta == NULL) { 691252726Srpaulo wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 692252726Srpaulo return; 693252726Srpaulo } 694252726Srpaulo#ifdef CONFIG_IEEE80211R 695281806Srpaulo if (mgmt->u.action.category == WLAN_ACTION_FT) { 696281806Srpaulo const u8 *payload = drv_mgmt->frame + 24 + 1; 697281806Srpaulo wpa_ft_action_rx(sta->wpa_sm, payload, plen); 698252726Srpaulo } 699252726Srpaulo#endif /* CONFIG_IEEE80211R */ 700252726Srpaulo#ifdef CONFIG_IEEE80211W 701281806Srpaulo if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) { 702281806Srpaulo ieee802_11_sa_query_action( 703281806Srpaulo hapd, mgmt->sa, 704281806Srpaulo mgmt->u.action.u.sa_query_resp.action, 705281806Srpaulo mgmt->u.action.u.sa_query_resp.trans_id); 706252726Srpaulo } 707252726Srpaulo#endif /* CONFIG_IEEE80211W */ 708252726Srpaulo#ifdef CONFIG_WNM 709281806Srpaulo if (mgmt->u.action.category == WLAN_ACTION_WNM) { 710281806Srpaulo ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len); 711252726Srpaulo } 712252726Srpaulo#endif /* CONFIG_WNM */ 713252726Srpaulo} 714252726Srpaulo 715252726Srpaulo 716252726Srpaulo#ifdef NEED_AP_MLME 717252726Srpaulo 718214501Srpaulo#define HAPD_BROADCAST ((struct hostapd_data *) -1) 719214501Srpaulo 720214501Srpaulostatic struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, 721214501Srpaulo const u8 *bssid) 722214501Srpaulo{ 723214501Srpaulo size_t i; 724214501Srpaulo 725214501Srpaulo if (bssid == NULL) 726214501Srpaulo return NULL; 727214501Srpaulo if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && 728214501Srpaulo bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) 729214501Srpaulo return HAPD_BROADCAST; 730214501Srpaulo 731214501Srpaulo for (i = 0; i < iface->num_bss; i++) { 732214501Srpaulo if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) 733214501Srpaulo return iface->bss[i]; 734214501Srpaulo } 735214501Srpaulo 736214501Srpaulo return NULL; 737214501Srpaulo} 738214501Srpaulo 739214501Srpaulo 740214501Srpaulostatic void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, 741252726Srpaulo const u8 *bssid, const u8 *addr, 742252726Srpaulo int wds) 743214501Srpaulo{ 744252726Srpaulo hapd = get_hapd_bssid(hapd->iface, bssid); 745214501Srpaulo if (hapd == NULL || hapd == HAPD_BROADCAST) 746214501Srpaulo return; 747214501Srpaulo 748252726Srpaulo ieee802_11_rx_from_unknown(hapd, addr, wds); 749214501Srpaulo} 750214501Srpaulo 751214501Srpaulo 752281806Srpaulostatic int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) 753214501Srpaulo{ 754214501Srpaulo struct hostapd_iface *iface = hapd->iface; 755214501Srpaulo const struct ieee80211_hdr *hdr; 756214501Srpaulo const u8 *bssid; 757214501Srpaulo struct hostapd_frame_info fi; 758281806Srpaulo int ret; 759214501Srpaulo 760281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 761281806Srpaulo if (hapd->ext_mgmt_frame_handling) { 762281806Srpaulo size_t hex_len = 2 * rx_mgmt->frame_len + 1; 763281806Srpaulo char *hex = os_malloc(hex_len); 764281806Srpaulo if (hex) { 765281806Srpaulo wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame, 766281806Srpaulo rx_mgmt->frame_len); 767281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex); 768281806Srpaulo os_free(hex); 769281806Srpaulo } 770281806Srpaulo return 1; 771281806Srpaulo } 772281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 773281806Srpaulo 774214501Srpaulo hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; 775214501Srpaulo bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); 776214501Srpaulo if (bssid == NULL) 777281806Srpaulo return 0; 778214501Srpaulo 779214501Srpaulo hapd = get_hapd_bssid(iface, bssid); 780214501Srpaulo if (hapd == NULL) { 781214501Srpaulo u16 fc; 782214501Srpaulo fc = le_to_host16(hdr->frame_control); 783214501Srpaulo 784214501Srpaulo /* 785214501Srpaulo * Drop frames to unknown BSSIDs except for Beacon frames which 786214501Srpaulo * could be used to update neighbor information. 787214501Srpaulo */ 788214501Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 789214501Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 790214501Srpaulo hapd = iface->bss[0]; 791214501Srpaulo else 792281806Srpaulo return 0; 793214501Srpaulo } 794214501Srpaulo 795214501Srpaulo os_memset(&fi, 0, sizeof(fi)); 796214501Srpaulo fi.datarate = rx_mgmt->datarate; 797214501Srpaulo fi.ssi_signal = rx_mgmt->ssi_signal; 798214501Srpaulo 799214501Srpaulo if (hapd == HAPD_BROADCAST) { 800214501Srpaulo size_t i; 801281806Srpaulo ret = 0; 802281806Srpaulo for (i = 0; i < iface->num_bss; i++) { 803281806Srpaulo /* if bss is set, driver will call this function for 804281806Srpaulo * each bss individually. */ 805281806Srpaulo if (rx_mgmt->drv_priv && 806281806Srpaulo (iface->bss[i]->drv_priv != rx_mgmt->drv_priv)) 807281806Srpaulo continue; 808281806Srpaulo 809281806Srpaulo if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, 810281806Srpaulo rx_mgmt->frame_len, &fi) > 0) 811281806Srpaulo ret = 1; 812281806Srpaulo } 813214501Srpaulo } else 814281806Srpaulo ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, 815281806Srpaulo &fi); 816252726Srpaulo 817252726Srpaulo random_add_randomness(&fi, sizeof(fi)); 818214501Srpaulo 819281806Srpaulo return ret; 820252726Srpaulo} 821252726Srpaulo 822252726Srpaulo 823214501Srpaulostatic void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, 824214501Srpaulo size_t len, u16 stype, int ok) 825214501Srpaulo{ 826214501Srpaulo struct ieee80211_hdr *hdr; 827214501Srpaulo hdr = (struct ieee80211_hdr *) buf; 828214501Srpaulo hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); 829214501Srpaulo if (hapd == NULL || hapd == HAPD_BROADCAST) 830214501Srpaulo return; 831214501Srpaulo ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); 832214501Srpaulo} 833214501Srpaulo 834214501Srpaulo#endif /* NEED_AP_MLME */ 835214501Srpaulo 836214501Srpaulo 837214501Srpaulostatic int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) 838214501Srpaulo{ 839214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 840214501Srpaulo if (sta) 841214501Srpaulo return 0; 842214501Srpaulo 843214501Srpaulo wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR 844214501Srpaulo " - adding a new STA", MAC2STR(addr)); 845214501Srpaulo sta = ap_sta_add(hapd, addr); 846214501Srpaulo if (sta) { 847214501Srpaulo hostapd_new_assoc_sta(hapd, sta, 0); 848214501Srpaulo } else { 849214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, 850214501Srpaulo MAC2STR(addr)); 851214501Srpaulo return -1; 852214501Srpaulo } 853214501Srpaulo 854214501Srpaulo return 0; 855214501Srpaulo} 856214501Srpaulo 857214501Srpaulo 858214501Srpaulostatic void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, 859214501Srpaulo const u8 *data, size_t data_len) 860214501Srpaulo{ 861214501Srpaulo struct hostapd_iface *iface = hapd->iface; 862252726Srpaulo struct sta_info *sta; 863214501Srpaulo size_t j; 864214501Srpaulo 865214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 866252726Srpaulo if ((sta = ap_get_sta(iface->bss[j], src))) { 867252726Srpaulo if (sta->flags & WLAN_STA_ASSOC) { 868252726Srpaulo hapd = iface->bss[j]; 869252726Srpaulo break; 870252726Srpaulo } 871214501Srpaulo } 872214501Srpaulo } 873214501Srpaulo 874214501Srpaulo ieee802_1x_receive(hapd, src, data, data_len); 875214501Srpaulo} 876214501Srpaulo 877214501Srpaulo 878281806Srpaulostatic struct hostapd_channel_data * hostapd_get_mode_channel( 879281806Srpaulo struct hostapd_iface *iface, unsigned int freq) 880281806Srpaulo{ 881281806Srpaulo int i; 882281806Srpaulo struct hostapd_channel_data *chan; 883281806Srpaulo 884281806Srpaulo for (i = 0; i < iface->current_mode->num_channels; i++) { 885281806Srpaulo chan = &iface->current_mode->channels[i]; 886281806Srpaulo if (!chan) 887281806Srpaulo return NULL; 888281806Srpaulo if ((unsigned int) chan->freq == freq) 889281806Srpaulo return chan; 890281806Srpaulo } 891281806Srpaulo 892281806Srpaulo return NULL; 893281806Srpaulo} 894281806Srpaulo 895281806Srpaulo 896281806Srpaulostatic void hostapd_update_nf(struct hostapd_iface *iface, 897281806Srpaulo struct hostapd_channel_data *chan, 898281806Srpaulo struct freq_survey *survey) 899281806Srpaulo{ 900281806Srpaulo if (!iface->chans_surveyed) { 901281806Srpaulo chan->min_nf = survey->nf; 902281806Srpaulo iface->lowest_nf = survey->nf; 903281806Srpaulo } else { 904281806Srpaulo if (dl_list_empty(&chan->survey_list)) 905281806Srpaulo chan->min_nf = survey->nf; 906281806Srpaulo else if (survey->nf < chan->min_nf) 907281806Srpaulo chan->min_nf = survey->nf; 908281806Srpaulo if (survey->nf < iface->lowest_nf) 909281806Srpaulo iface->lowest_nf = survey->nf; 910281806Srpaulo } 911281806Srpaulo} 912281806Srpaulo 913281806Srpaulo 914281806Srpaulostatic void hostapd_single_channel_get_survey(struct hostapd_iface *iface, 915281806Srpaulo struct survey_results *survey_res) 916281806Srpaulo{ 917281806Srpaulo struct hostapd_channel_data *chan; 918281806Srpaulo struct freq_survey *survey; 919281806Srpaulo u64 divisor, dividend; 920281806Srpaulo 921281806Srpaulo survey = dl_list_first(&survey_res->survey_list, struct freq_survey, 922281806Srpaulo list); 923281806Srpaulo if (!survey || !survey->freq) 924281806Srpaulo return; 925281806Srpaulo 926281806Srpaulo chan = hostapd_get_mode_channel(iface, survey->freq); 927281806Srpaulo if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED) 928281806Srpaulo return; 929281806Srpaulo 930281806Srpaulo wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)", 931281806Srpaulo survey->freq, 932281806Srpaulo (unsigned long int) survey->channel_time, 933281806Srpaulo (unsigned long int) survey->channel_time_busy); 934281806Srpaulo 935281806Srpaulo if (survey->channel_time > iface->last_channel_time && 936281806Srpaulo survey->channel_time > survey->channel_time_busy) { 937281806Srpaulo dividend = survey->channel_time_busy - 938281806Srpaulo iface->last_channel_time_busy; 939281806Srpaulo divisor = survey->channel_time - iface->last_channel_time; 940281806Srpaulo 941281806Srpaulo iface->channel_utilization = dividend * 255 / divisor; 942281806Srpaulo wpa_printf(MSG_DEBUG, "Channel Utilization: %d", 943281806Srpaulo iface->channel_utilization); 944281806Srpaulo } 945281806Srpaulo iface->last_channel_time = survey->channel_time; 946281806Srpaulo iface->last_channel_time_busy = survey->channel_time_busy; 947281806Srpaulo} 948281806Srpaulo 949281806Srpaulo 950281806Srpaulostatic void hostapd_event_get_survey(struct hostapd_data *hapd, 951281806Srpaulo struct survey_results *survey_results) 952281806Srpaulo{ 953281806Srpaulo struct hostapd_iface *iface = hapd->iface; 954281806Srpaulo struct freq_survey *survey, *tmp; 955281806Srpaulo struct hostapd_channel_data *chan; 956281806Srpaulo 957281806Srpaulo if (dl_list_empty(&survey_results->survey_list)) { 958281806Srpaulo wpa_printf(MSG_DEBUG, "No survey data received"); 959281806Srpaulo return; 960281806Srpaulo } 961281806Srpaulo 962281806Srpaulo if (survey_results->freq_filter) { 963281806Srpaulo hostapd_single_channel_get_survey(iface, survey_results); 964281806Srpaulo return; 965281806Srpaulo } 966281806Srpaulo 967281806Srpaulo dl_list_for_each_safe(survey, tmp, &survey_results->survey_list, 968281806Srpaulo struct freq_survey, list) { 969281806Srpaulo chan = hostapd_get_mode_channel(iface, survey->freq); 970281806Srpaulo if (!chan) 971281806Srpaulo continue; 972281806Srpaulo if (chan->flag & HOSTAPD_CHAN_DISABLED) 973281806Srpaulo continue; 974281806Srpaulo 975281806Srpaulo dl_list_del(&survey->list); 976281806Srpaulo dl_list_add_tail(&chan->survey_list, &survey->list); 977281806Srpaulo 978281806Srpaulo hostapd_update_nf(iface, chan, survey); 979281806Srpaulo 980281806Srpaulo iface->chans_surveyed++; 981281806Srpaulo } 982281806Srpaulo} 983281806Srpaulo 984281806Srpaulo 985281806Srpaulo#ifdef NEED_AP_MLME 986281806Srpaulo 987281806Srpaulostatic void hostapd_event_iface_unavailable(struct hostapd_data *hapd) 988281806Srpaulo{ 989281806Srpaulo wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped", 990281806Srpaulo hapd->conf->iface); 991281806Srpaulo 992281806Srpaulo if (hapd->csa_in_progress) { 993281806Srpaulo wpa_printf(MSG_INFO, "CSA failed (%s was stopped)", 994281806Srpaulo hapd->conf->iface); 995281806Srpaulo hostapd_switch_channel_fallback(hapd->iface, 996281806Srpaulo &hapd->cs_freq_params); 997281806Srpaulo } 998281806Srpaulo} 999281806Srpaulo 1000281806Srpaulo 1001281806Srpaulostatic void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd, 1002281806Srpaulo struct dfs_event *radar) 1003281806Srpaulo{ 1004281806Srpaulo wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq); 1005281806Srpaulo hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled, 1006281806Srpaulo radar->chan_offset, radar->chan_width, 1007281806Srpaulo radar->cf1, radar->cf2); 1008281806Srpaulo} 1009281806Srpaulo 1010281806Srpaulo 1011281806Srpaulostatic void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd, 1012281806Srpaulo struct dfs_event *radar) 1013281806Srpaulo{ 1014281806Srpaulo wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq); 1015281806Srpaulo hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled, 1016281806Srpaulo radar->chan_offset, radar->chan_width, 1017281806Srpaulo radar->cf1, radar->cf2); 1018281806Srpaulo} 1019281806Srpaulo 1020281806Srpaulo 1021281806Srpaulostatic void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd, 1022281806Srpaulo struct dfs_event *radar) 1023281806Srpaulo{ 1024281806Srpaulo wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq); 1025281806Srpaulo hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled, 1026281806Srpaulo radar->chan_offset, radar->chan_width, 1027281806Srpaulo radar->cf1, radar->cf2); 1028281806Srpaulo} 1029281806Srpaulo 1030281806Srpaulo 1031281806Srpaulostatic void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd, 1032281806Srpaulo struct dfs_event *radar) 1033281806Srpaulo{ 1034281806Srpaulo wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq); 1035281806Srpaulo hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled, 1036281806Srpaulo radar->chan_offset, radar->chan_width, 1037281806Srpaulo radar->cf1, radar->cf2); 1038281806Srpaulo} 1039281806Srpaulo 1040281806Srpaulo 1041281806Srpaulostatic void hostapd_event_dfs_cac_started(struct hostapd_data *hapd, 1042281806Srpaulo struct dfs_event *radar) 1043281806Srpaulo{ 1044281806Srpaulo wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq); 1045281806Srpaulo hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled, 1046281806Srpaulo radar->chan_offset, radar->chan_width, 1047281806Srpaulo radar->cf1, radar->cf2); 1048281806Srpaulo} 1049281806Srpaulo 1050281806Srpaulo#endif /* NEED_AP_MLME */ 1051281806Srpaulo 1052281806Srpaulo 1053214501Srpaulovoid wpa_supplicant_event(void *ctx, enum wpa_event_type event, 1054214501Srpaulo union wpa_event_data *data) 1055214501Srpaulo{ 1056214501Srpaulo struct hostapd_data *hapd = ctx; 1057252726Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG 1058252726Srpaulo int level = MSG_DEBUG; 1059214501Srpaulo 1060252726Srpaulo if (event == EVENT_RX_MGMT && data->rx_mgmt.frame && 1061252726Srpaulo data->rx_mgmt.frame_len >= 24) { 1062252726Srpaulo const struct ieee80211_hdr *hdr; 1063252726Srpaulo u16 fc; 1064252726Srpaulo hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; 1065252726Srpaulo fc = le_to_host16(hdr->frame_control); 1066252726Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1067252726Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 1068252726Srpaulo level = MSG_EXCESSIVE; 1069281806Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 1070281806Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) 1071281806Srpaulo level = MSG_EXCESSIVE; 1072252726Srpaulo } 1073252726Srpaulo 1074252726Srpaulo wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", 1075252726Srpaulo event_to_string(event), event); 1076252726Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */ 1077252726Srpaulo 1078214501Srpaulo switch (event) { 1079214501Srpaulo case EVENT_MICHAEL_MIC_FAILURE: 1080214501Srpaulo michael_mic_failure(hapd, data->michael_mic_failure.src, 1); 1081214501Srpaulo break; 1082214501Srpaulo case EVENT_SCAN_RESULTS: 1083214501Srpaulo if (hapd->iface->scan_cb) 1084214501Srpaulo hapd->iface->scan_cb(hapd->iface); 1085214501Srpaulo break; 1086214501Srpaulo case EVENT_WPS_BUTTON_PUSHED: 1087252726Srpaulo hostapd_wps_button_pushed(hapd, NULL); 1088214501Srpaulo break; 1089214501Srpaulo#ifdef NEED_AP_MLME 1090214501Srpaulo case EVENT_TX_STATUS: 1091214501Srpaulo switch (data->tx_status.type) { 1092214501Srpaulo case WLAN_FC_TYPE_MGMT: 1093214501Srpaulo hostapd_mgmt_tx_cb(hapd, data->tx_status.data, 1094214501Srpaulo data->tx_status.data_len, 1095214501Srpaulo data->tx_status.stype, 1096214501Srpaulo data->tx_status.ack); 1097214501Srpaulo break; 1098214501Srpaulo case WLAN_FC_TYPE_DATA: 1099214501Srpaulo hostapd_tx_status(hapd, data->tx_status.dst, 1100214501Srpaulo data->tx_status.data, 1101214501Srpaulo data->tx_status.data_len, 1102214501Srpaulo data->tx_status.ack); 1103214501Srpaulo break; 1104214501Srpaulo } 1105214501Srpaulo break; 1106252726Srpaulo case EVENT_EAPOL_TX_STATUS: 1107252726Srpaulo hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, 1108252726Srpaulo data->eapol_tx_status.data, 1109252726Srpaulo data->eapol_tx_status.data_len, 1110252726Srpaulo data->eapol_tx_status.ack); 1111252726Srpaulo break; 1112252726Srpaulo case EVENT_DRIVER_CLIENT_POLL_OK: 1113252726Srpaulo hostapd_client_poll_ok(hapd, data->client_poll.addr); 1114252726Srpaulo break; 1115214501Srpaulo case EVENT_RX_FROM_UNKNOWN: 1116252726Srpaulo hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, 1117252726Srpaulo data->rx_from_unknown.addr, 1118252726Srpaulo data->rx_from_unknown.wds); 1119214501Srpaulo break; 1120281806Srpaulo#endif /* NEED_AP_MLME */ 1121214501Srpaulo case EVENT_RX_MGMT: 1122281806Srpaulo if (!data->rx_mgmt.frame) 1123281806Srpaulo break; 1124281806Srpaulo#ifdef NEED_AP_MLME 1125281806Srpaulo if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0) 1126281806Srpaulo break; 1127281806Srpaulo#endif /* NEED_AP_MLME */ 1128281806Srpaulo hostapd_action_rx(hapd, &data->rx_mgmt); 1129214501Srpaulo break; 1130214501Srpaulo case EVENT_RX_PROBE_REQ: 1131252726Srpaulo if (data->rx_probe_req.sa == NULL || 1132252726Srpaulo data->rx_probe_req.ie == NULL) 1133252726Srpaulo break; 1134214501Srpaulo hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, 1135252726Srpaulo data->rx_probe_req.da, 1136252726Srpaulo data->rx_probe_req.bssid, 1137214501Srpaulo data->rx_probe_req.ie, 1138252726Srpaulo data->rx_probe_req.ie_len, 1139252726Srpaulo data->rx_probe_req.ssi_signal); 1140214501Srpaulo break; 1141214501Srpaulo case EVENT_NEW_STA: 1142214501Srpaulo hostapd_event_new_sta(hapd, data->new_sta.addr); 1143214501Srpaulo break; 1144214501Srpaulo case EVENT_EAPOL_RX: 1145214501Srpaulo hostapd_event_eapol_rx(hapd, data->eapol_rx.src, 1146214501Srpaulo data->eapol_rx.data, 1147214501Srpaulo data->eapol_rx.data_len); 1148214501Srpaulo break; 1149214501Srpaulo case EVENT_ASSOC: 1150281806Srpaulo if (!data) 1151281806Srpaulo return; 1152214501Srpaulo hostapd_notif_assoc(hapd, data->assoc_info.addr, 1153214501Srpaulo data->assoc_info.req_ies, 1154252726Srpaulo data->assoc_info.req_ies_len, 1155252726Srpaulo data->assoc_info.reassoc); 1156214501Srpaulo break; 1157214501Srpaulo case EVENT_DISASSOC: 1158214501Srpaulo if (data) 1159214501Srpaulo hostapd_notif_disassoc(hapd, data->disassoc_info.addr); 1160214501Srpaulo break; 1161214501Srpaulo case EVENT_DEAUTH: 1162214501Srpaulo if (data) 1163214501Srpaulo hostapd_notif_disassoc(hapd, data->deauth_info.addr); 1164214501Srpaulo break; 1165252726Srpaulo case EVENT_STATION_LOW_ACK: 1166252726Srpaulo if (!data) 1167252726Srpaulo break; 1168252726Srpaulo hostapd_event_sta_low_ack(hapd, data->low_ack.addr); 1169252726Srpaulo break; 1170252726Srpaulo case EVENT_AUTH: 1171252726Srpaulo hostapd_notif_auth(hapd, &data->auth); 1172252726Srpaulo break; 1173252726Srpaulo case EVENT_CH_SWITCH: 1174252726Srpaulo if (!data) 1175252726Srpaulo break; 1176252726Srpaulo hostapd_event_ch_switch(hapd, data->ch_switch.freq, 1177252726Srpaulo data->ch_switch.ht_enabled, 1178281806Srpaulo data->ch_switch.ch_offset, 1179281806Srpaulo data->ch_switch.ch_width, 1180281806Srpaulo data->ch_switch.cf1, 1181281806Srpaulo data->ch_switch.cf2); 1182252726Srpaulo break; 1183281806Srpaulo case EVENT_CONNECT_FAILED_REASON: 1184281806Srpaulo if (!data) 1185281806Srpaulo break; 1186281806Srpaulo hostapd_event_connect_failed_reason( 1187281806Srpaulo hapd, data->connect_failed_reason.addr, 1188281806Srpaulo data->connect_failed_reason.code); 1189281806Srpaulo break; 1190281806Srpaulo case EVENT_SURVEY: 1191281806Srpaulo hostapd_event_get_survey(hapd, &data->survey_results); 1192281806Srpaulo break; 1193281806Srpaulo#ifdef NEED_AP_MLME 1194281806Srpaulo case EVENT_INTERFACE_UNAVAILABLE: 1195281806Srpaulo hostapd_event_iface_unavailable(hapd); 1196281806Srpaulo break; 1197281806Srpaulo case EVENT_DFS_RADAR_DETECTED: 1198281806Srpaulo if (!data) 1199281806Srpaulo break; 1200281806Srpaulo hostapd_event_dfs_radar_detected(hapd, &data->dfs_event); 1201281806Srpaulo break; 1202281806Srpaulo case EVENT_DFS_CAC_FINISHED: 1203281806Srpaulo if (!data) 1204281806Srpaulo break; 1205281806Srpaulo hostapd_event_dfs_cac_finished(hapd, &data->dfs_event); 1206281806Srpaulo break; 1207281806Srpaulo case EVENT_DFS_CAC_ABORTED: 1208281806Srpaulo if (!data) 1209281806Srpaulo break; 1210281806Srpaulo hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event); 1211281806Srpaulo break; 1212281806Srpaulo case EVENT_DFS_NOP_FINISHED: 1213281806Srpaulo if (!data) 1214281806Srpaulo break; 1215281806Srpaulo hostapd_event_dfs_nop_finished(hapd, &data->dfs_event); 1216281806Srpaulo break; 1217281806Srpaulo case EVENT_CHANNEL_LIST_CHANGED: 1218281806Srpaulo /* channel list changed (regulatory?), update channel list */ 1219281806Srpaulo /* TODO: check this. hostapd_get_hw_features() initializes 1220281806Srpaulo * too much stuff. */ 1221281806Srpaulo /* hostapd_get_hw_features(hapd->iface); */ 1222281806Srpaulo hostapd_channel_list_updated( 1223281806Srpaulo hapd->iface, data->channel_list_changed.initiator); 1224281806Srpaulo break; 1225281806Srpaulo case EVENT_DFS_CAC_STARTED: 1226281806Srpaulo if (!data) 1227281806Srpaulo break; 1228281806Srpaulo hostapd_event_dfs_cac_started(hapd, &data->dfs_event); 1229281806Srpaulo break; 1230281806Srpaulo#endif /* NEED_AP_MLME */ 1231281806Srpaulo case EVENT_INTERFACE_ENABLED: 1232281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED); 1233281806Srpaulo if (hapd->disabled && hapd->started) { 1234281806Srpaulo hapd->disabled = 0; 1235281806Srpaulo /* 1236281806Srpaulo * Try to re-enable interface if the driver stopped it 1237281806Srpaulo * when the interface got disabled. 1238281806Srpaulo */ 1239281806Srpaulo wpa_auth_reconfig_group_keys(hapd->wpa_auth); 1240281806Srpaulo hapd->reenable_beacon = 1; 1241281806Srpaulo ieee802_11_set_beacon(hapd); 1242281806Srpaulo } 1243281806Srpaulo break; 1244281806Srpaulo case EVENT_INTERFACE_DISABLED: 1245281806Srpaulo hostapd_free_stas(hapd); 1246281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED); 1247281806Srpaulo hapd->disabled = 1; 1248281806Srpaulo break; 1249281806Srpaulo#ifdef CONFIG_ACS 1250281806Srpaulo case EVENT_ACS_CHANNEL_SELECTED: 1251281806Srpaulo hostapd_acs_channel_selected( 1252281806Srpaulo hapd, data->acs_selected_channels.pri_channel, 1253281806Srpaulo data->acs_selected_channels.sec_channel); 1254281806Srpaulo break; 1255281806Srpaulo#endif /* CONFIG_ACS */ 1256214501Srpaulo default: 1257214501Srpaulo wpa_printf(MSG_DEBUG, "Unknown event %d", event); 1258214501Srpaulo break; 1259214501Srpaulo } 1260214501Srpaulo} 1261214501Srpaulo 1262214501Srpaulo#endif /* HOSTAPD */ 1263