1214501Srpaulo/* 2214501Srpaulo * hostapd / Callback functions for driver wrappers 3214501Srpaulo * Copyright (c) 2002-2009, 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" 12214501Srpaulo#include "radius/radius.h" 13214501Srpaulo#include "drivers/driver.h" 14214501Srpaulo#include "common/ieee802_11_defs.h" 15214501Srpaulo#include "common/ieee802_11_common.h" 16252726Srpaulo#include "crypto/random.h" 17252726Srpaulo#include "p2p/p2p.h" 18252726Srpaulo#include "wps/wps.h" 19252726Srpaulo#include "wnm_ap.h" 20214501Srpaulo#include "hostapd.h" 21214501Srpaulo#include "ieee802_11.h" 22214501Srpaulo#include "sta_info.h" 23214501Srpaulo#include "accounting.h" 24214501Srpaulo#include "tkip_countermeasures.h" 25214501Srpaulo#include "ieee802_1x.h" 26214501Srpaulo#include "wpa_auth.h" 27214501Srpaulo#include "wps_hostapd.h" 28252726Srpaulo#include "ap_drv_ops.h" 29214501Srpaulo#include "ap_config.h" 30252726Srpaulo#include "hw_features.h" 31214501Srpaulo 32214501Srpaulo 33214501Srpauloint hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, 34252726Srpaulo const u8 *req_ies, size_t req_ies_len, int reassoc) 35214501Srpaulo{ 36214501Srpaulo struct sta_info *sta; 37214501Srpaulo int new_assoc, res; 38214501Srpaulo struct ieee802_11_elems elems; 39252726Srpaulo const u8 *ie; 40252726Srpaulo size_t ielen; 41252726Srpaulo#ifdef CONFIG_IEEE80211R 42252726Srpaulo u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; 43252726Srpaulo u8 *p = buf; 44252726Srpaulo#endif /* CONFIG_IEEE80211R */ 45252726Srpaulo u16 reason = WLAN_REASON_UNSPECIFIED; 46252726Srpaulo u16 status = WLAN_STATUS_SUCCESS; 47214501Srpaulo 48214501Srpaulo if (addr == NULL) { 49214501Srpaulo /* 50214501Srpaulo * This could potentially happen with unexpected event from the 51214501Srpaulo * driver wrapper. This was seen at least in one case where the 52214501Srpaulo * driver ended up being set to station mode while hostapd was 53214501Srpaulo * running, so better make sure we stop processing such an 54214501Srpaulo * event here. 55214501Srpaulo */ 56214501Srpaulo wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with " 57214501Srpaulo "no address"); 58214501Srpaulo return -1; 59214501Srpaulo } 60252726Srpaulo random_add_randomness(addr, ETH_ALEN); 61214501Srpaulo 62214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 63214501Srpaulo HOSTAPD_LEVEL_INFO, "associated"); 64214501Srpaulo 65252726Srpaulo ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); 66214501Srpaulo if (elems.wps_ie) { 67214501Srpaulo ie = elems.wps_ie - 2; 68214501Srpaulo ielen = elems.wps_ie_len + 2; 69214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq"); 70214501Srpaulo } else if (elems.rsn_ie) { 71214501Srpaulo ie = elems.rsn_ie - 2; 72214501Srpaulo ielen = elems.rsn_ie_len + 2; 73214501Srpaulo wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq"); 74214501Srpaulo } else if (elems.wpa_ie) { 75214501Srpaulo ie = elems.wpa_ie - 2; 76214501Srpaulo ielen = elems.wpa_ie_len + 2; 77214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq"); 78214501Srpaulo } else { 79214501Srpaulo ie = NULL; 80214501Srpaulo ielen = 0; 81214501Srpaulo wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in " 82214501Srpaulo "(Re)AssocReq"); 83214501Srpaulo } 84214501Srpaulo 85214501Srpaulo sta = ap_get_sta(hapd, addr); 86214501Srpaulo if (sta) { 87214501Srpaulo accounting_sta_stop(hapd, sta); 88252726Srpaulo 89252726Srpaulo /* 90252726Srpaulo * Make sure that the previously registered inactivity timer 91252726Srpaulo * will not remove the STA immediately. 92252726Srpaulo */ 93252726Srpaulo sta->timeout_next = STA_NULLFUNC; 94214501Srpaulo } else { 95214501Srpaulo sta = ap_sta_add(hapd, addr); 96252726Srpaulo if (sta == NULL) { 97252726Srpaulo hostapd_drv_sta_disassoc(hapd, addr, 98252726Srpaulo WLAN_REASON_DISASSOC_AP_BUSY); 99214501Srpaulo return -1; 100252726Srpaulo } 101214501Srpaulo } 102252726Srpaulo sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); 103214501Srpaulo 104252726Srpaulo#ifdef CONFIG_P2P 105252726Srpaulo if (elems.p2p) { 106252726Srpaulo wpabuf_free(sta->p2p_ie); 107252726Srpaulo sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 108252726Srpaulo P2P_IE_VENDOR_TYPE); 109252726Srpaulo } 110252726Srpaulo#endif /* CONFIG_P2P */ 111252726Srpaulo 112252726Srpaulo#ifdef CONFIG_HS20 113252726Srpaulo wpabuf_free(sta->hs20_ie); 114252726Srpaulo if (elems.hs20 && elems.hs20_len > 4) { 115252726Srpaulo sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, 116252726Srpaulo elems.hs20_len - 4); 117252726Srpaulo } else 118252726Srpaulo sta->hs20_ie = NULL; 119252726Srpaulo#endif /* CONFIG_HS20 */ 120252726Srpaulo 121214501Srpaulo if (hapd->conf->wpa) { 122214501Srpaulo if (ie == NULL || ielen == 0) { 123252726Srpaulo#ifdef CONFIG_WPS 124214501Srpaulo if (hapd->conf->wps_state) { 125214501Srpaulo wpa_printf(MSG_DEBUG, "STA did not include " 126214501Srpaulo "WPA/RSN IE in (Re)Association " 127214501Srpaulo "Request - possible WPS use"); 128214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 129214501Srpaulo goto skip_wpa_check; 130214501Srpaulo } 131252726Srpaulo#endif /* CONFIG_WPS */ 132214501Srpaulo 133214501Srpaulo wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA"); 134214501Srpaulo return -1; 135214501Srpaulo } 136252726Srpaulo#ifdef CONFIG_WPS 137214501Srpaulo if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && 138214501Srpaulo os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { 139252726Srpaulo struct wpabuf *wps; 140214501Srpaulo sta->flags |= WLAN_STA_WPS; 141252726Srpaulo wps = ieee802_11_vendor_ie_concat(ie, ielen, 142252726Srpaulo WPS_IE_VENDOR_TYPE); 143252726Srpaulo if (wps) { 144252726Srpaulo if (wps_is_20(wps)) { 145252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: STA " 146252726Srpaulo "supports WPS 2.0"); 147252726Srpaulo sta->flags |= WLAN_STA_WPS2; 148252726Srpaulo } 149252726Srpaulo wpabuf_free(wps); 150252726Srpaulo } 151214501Srpaulo goto skip_wpa_check; 152214501Srpaulo } 153252726Srpaulo#endif /* CONFIG_WPS */ 154214501Srpaulo 155214501Srpaulo if (sta->wpa_sm == NULL) 156214501Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 157214501Srpaulo sta->addr); 158214501Srpaulo if (sta->wpa_sm == NULL) { 159214501Srpaulo wpa_printf(MSG_ERROR, "Failed to initialize WPA state " 160214501Srpaulo "machine"); 161214501Srpaulo return -1; 162214501Srpaulo } 163214501Srpaulo res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 164252726Srpaulo ie, ielen, 165252726Srpaulo elems.mdie, elems.mdie_len); 166214501Srpaulo if (res != WPA_IE_OK) { 167214501Srpaulo wpa_printf(MSG_DEBUG, "WPA/RSN information element " 168214501Srpaulo "rejected? (res %u)", res); 169214501Srpaulo wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); 170252726Srpaulo if (res == WPA_INVALID_GROUP) { 171252726Srpaulo reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; 172252726Srpaulo status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 173252726Srpaulo } else if (res == WPA_INVALID_PAIRWISE) { 174252726Srpaulo reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; 175252726Srpaulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 176252726Srpaulo } else if (res == WPA_INVALID_AKMP) { 177252726Srpaulo reason = WLAN_REASON_AKMP_NOT_VALID; 178252726Srpaulo status = WLAN_STATUS_AKMP_NOT_VALID; 179252726Srpaulo } 180214501Srpaulo#ifdef CONFIG_IEEE80211W 181252726Srpaulo else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { 182252726Srpaulo reason = WLAN_REASON_INVALID_IE; 183252726Srpaulo status = WLAN_STATUS_INVALID_IE; 184252726Srpaulo } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { 185252726Srpaulo reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; 186252726Srpaulo status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 187252726Srpaulo } 188214501Srpaulo#endif /* CONFIG_IEEE80211W */ 189252726Srpaulo else { 190252726Srpaulo reason = WLAN_REASON_INVALID_IE; 191252726Srpaulo status = WLAN_STATUS_INVALID_IE; 192252726Srpaulo } 193252726Srpaulo goto fail; 194214501Srpaulo } 195252726Srpaulo#ifdef CONFIG_IEEE80211W 196252726Srpaulo if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && 197252726Srpaulo sta->sa_query_count > 0) 198252726Srpaulo ap_check_sa_query_timeout(hapd, sta); 199252726Srpaulo if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && 200252726Srpaulo (sta->auth_alg != WLAN_AUTH_FT)) { 201252726Srpaulo /* 202252726Srpaulo * STA has already been associated with MFP and SA 203252726Srpaulo * Query timeout has not been reached. Reject the 204252726Srpaulo * association attempt temporarily and start SA Query, 205252726Srpaulo * if one is not pending. 206252726Srpaulo */ 207252726Srpaulo 208252726Srpaulo if (sta->sa_query_count == 0) 209252726Srpaulo ap_sta_start_sa_query(hapd, sta); 210252726Srpaulo 211252726Srpaulo#ifdef CONFIG_IEEE80211R 212252726Srpaulo status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 213252726Srpaulo 214252726Srpaulo p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 215252726Srpaulo 216252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, 217252726Srpaulo p - buf); 218252726Srpaulo#endif /* CONFIG_IEEE80211R */ 219252726Srpaulo return 0; 220252726Srpaulo } 221252726Srpaulo 222252726Srpaulo if (wpa_auth_uses_mfp(sta->wpa_sm)) 223252726Srpaulo sta->flags |= WLAN_STA_MFP; 224252726Srpaulo else 225252726Srpaulo sta->flags &= ~WLAN_STA_MFP; 226252726Srpaulo#endif /* CONFIG_IEEE80211W */ 227252726Srpaulo 228252726Srpaulo#ifdef CONFIG_IEEE80211R 229252726Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) { 230252726Srpaulo status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies, 231252726Srpaulo req_ies_len); 232252726Srpaulo if (status != WLAN_STATUS_SUCCESS) { 233252726Srpaulo if (status == WLAN_STATUS_INVALID_PMKID) 234252726Srpaulo reason = WLAN_REASON_INVALID_IE; 235252726Srpaulo if (status == WLAN_STATUS_INVALID_MDIE) 236252726Srpaulo reason = WLAN_REASON_INVALID_IE; 237252726Srpaulo if (status == WLAN_STATUS_INVALID_FTIE) 238252726Srpaulo reason = WLAN_REASON_INVALID_IE; 239252726Srpaulo goto fail; 240252726Srpaulo } 241252726Srpaulo } 242252726Srpaulo#endif /* CONFIG_IEEE80211R */ 243214501Srpaulo } else if (hapd->conf->wps_state) { 244252726Srpaulo#ifdef CONFIG_WPS 245252726Srpaulo struct wpabuf *wps; 246252726Srpaulo if (req_ies) 247252726Srpaulo wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len, 248252726Srpaulo WPS_IE_VENDOR_TYPE); 249252726Srpaulo else 250252726Srpaulo wps = NULL; 251252726Srpaulo#ifdef CONFIG_WPS_STRICT 252252726Srpaulo if (wps && wps_validate_assoc_req(wps) < 0) { 253252726Srpaulo reason = WLAN_REASON_INVALID_IE; 254252726Srpaulo status = WLAN_STATUS_INVALID_IE; 255252726Srpaulo wpabuf_free(wps); 256252726Srpaulo goto fail; 257252726Srpaulo } 258252726Srpaulo#endif /* CONFIG_WPS_STRICT */ 259252726Srpaulo if (wps) { 260214501Srpaulo sta->flags |= WLAN_STA_WPS; 261252726Srpaulo if (wps_is_20(wps)) { 262252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: STA supports " 263252726Srpaulo "WPS 2.0"); 264252726Srpaulo sta->flags |= WLAN_STA_WPS2; 265252726Srpaulo } 266214501Srpaulo } else 267214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 268252726Srpaulo wpabuf_free(wps); 269252726Srpaulo#endif /* CONFIG_WPS */ 270214501Srpaulo } 271252726Srpaulo#ifdef CONFIG_WPS 272214501Srpauloskip_wpa_check: 273252726Srpaulo#endif /* CONFIG_WPS */ 274214501Srpaulo 275252726Srpaulo#ifdef CONFIG_IEEE80211R 276252726Srpaulo p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), 277252726Srpaulo sta->auth_alg, req_ies, req_ies_len); 278252726Srpaulo 279252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 280252726Srpaulo#else /* CONFIG_IEEE80211R */ 281252726Srpaulo /* Keep compiler silent about unused variables */ 282252726Srpaulo if (status) { 283252726Srpaulo } 284252726Srpaulo#endif /* CONFIG_IEEE80211R */ 285252726Srpaulo 286214501Srpaulo new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; 287214501Srpaulo sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 288214501Srpaulo 289252726Srpaulo if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) 290252726Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 291252726Srpaulo else 292252726Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 293252726Srpaulo 294214501Srpaulo hostapd_new_assoc_sta(hapd, sta, !new_assoc); 295214501Srpaulo 296214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 297214501Srpaulo 298252726Srpaulo#ifdef CONFIG_P2P 299252726Srpaulo if (req_ies) { 300252726Srpaulo p2p_group_notif_assoc(hapd->p2p_group, sta->addr, 301252726Srpaulo req_ies, req_ies_len); 302252726Srpaulo } 303252726Srpaulo#endif /* CONFIG_P2P */ 304252726Srpaulo 305214501Srpaulo return 0; 306252726Srpaulo 307252726Srpaulofail: 308252726Srpaulo#ifdef CONFIG_IEEE80211R 309252726Srpaulo hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); 310252726Srpaulo#endif /* CONFIG_IEEE80211R */ 311252726Srpaulo hostapd_drv_sta_disassoc(hapd, sta->addr, reason); 312252726Srpaulo ap_free_sta(hapd, sta); 313252726Srpaulo return -1; 314214501Srpaulo} 315214501Srpaulo 316214501Srpaulo 317214501Srpaulovoid hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) 318214501Srpaulo{ 319214501Srpaulo struct sta_info *sta; 320214501Srpaulo 321252726Srpaulo if (addr == NULL) { 322252726Srpaulo /* 323252726Srpaulo * This could potentially happen with unexpected event from the 324252726Srpaulo * driver wrapper. This was seen at least in one case where the 325252726Srpaulo * driver ended up reporting a station mode event while hostapd 326252726Srpaulo * was running, so better make sure we stop processing such an 327252726Srpaulo * event here. 328252726Srpaulo */ 329252726Srpaulo wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event " 330252726Srpaulo "with no address"); 331252726Srpaulo return; 332252726Srpaulo } 333252726Srpaulo 334214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 335214501Srpaulo HOSTAPD_LEVEL_INFO, "disassociated"); 336214501Srpaulo 337214501Srpaulo sta = ap_get_sta(hapd, addr); 338214501Srpaulo if (sta == NULL) { 339214501Srpaulo wpa_printf(MSG_DEBUG, "Disassociation notification for " 340214501Srpaulo "unknown STA " MACSTR, MAC2STR(addr)); 341214501Srpaulo return; 342214501Srpaulo } 343214501Srpaulo 344252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 345214501Srpaulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 346214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 347214501Srpaulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 348214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 349214501Srpaulo ap_free_sta(hapd, sta); 350214501Srpaulo} 351214501Srpaulo 352214501Srpaulo 353252726Srpaulovoid hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr) 354252726Srpaulo{ 355252726Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 356214501Srpaulo 357252726Srpaulo if (!sta || !hapd->conf->disassoc_low_ack) 358252726Srpaulo return; 359252726Srpaulo 360252726Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, 361252726Srpaulo HOSTAPD_LEVEL_INFO, "disconnected due to excessive " 362252726Srpaulo "missing ACKs"); 363252726Srpaulo hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK); 364252726Srpaulo if (sta) 365252726Srpaulo ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK); 366252726Srpaulo} 367252726Srpaulo 368252726Srpaulo 369252726Srpaulovoid hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, 370252726Srpaulo int offset) 371252726Srpaulo{ 372214501Srpaulo#ifdef NEED_AP_MLME 373252726Srpaulo int channel; 374214501Srpaulo 375252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 376252726Srpaulo HOSTAPD_LEVEL_INFO, "driver had channel switch: " 377252726Srpaulo "freq=%d, ht=%d, offset=%d", freq, ht, offset); 378252726Srpaulo 379252726Srpaulo hapd->iface->freq = freq; 380252726Srpaulo 381252726Srpaulo channel = hostapd_hw_get_channel(hapd, freq); 382252726Srpaulo if (!channel) { 383252726Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, 384252726Srpaulo HOSTAPD_LEVEL_WARNING, "driver switched to " 385252726Srpaulo "bad channel!"); 386252726Srpaulo return; 387252726Srpaulo } 388252726Srpaulo 389252726Srpaulo hapd->iconf->channel = channel; 390252726Srpaulo hapd->iconf->ieee80211n = ht; 391252726Srpaulo hapd->iconf->secondary_channel = offset; 392252726Srpaulo#endif /* NEED_AP_MLME */ 393252726Srpaulo} 394252726Srpaulo 395252726Srpaulo 396252726Srpauloint hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, 397252726Srpaulo const u8 *bssid, const u8 *ie, size_t ie_len, 398252726Srpaulo int ssi_signal) 399214501Srpaulo{ 400252726Srpaulo size_t i; 401252726Srpaulo int ret = 0; 402214501Srpaulo 403252726Srpaulo if (sa == NULL || ie == NULL) 404252726Srpaulo return -1; 405214501Srpaulo 406252726Srpaulo random_add_randomness(sa, ETH_ALEN); 407252726Srpaulo for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) { 408252726Srpaulo if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx, 409252726Srpaulo sa, da, bssid, ie, ie_len, 410252726Srpaulo ssi_signal) > 0) { 411252726Srpaulo ret = 1; 412252726Srpaulo break; 413252726Srpaulo } 414252726Srpaulo } 415252726Srpaulo return ret; 416252726Srpaulo} 417214501Srpaulo 418252726Srpaulo 419252726Srpaulo#ifdef HOSTAPD 420252726Srpaulo 421252726Srpaulo#ifdef CONFIG_IEEE80211R 422252726Srpaulostatic void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, 423252726Srpaulo const u8 *bssid, 424252726Srpaulo u16 auth_transaction, u16 status, 425252726Srpaulo const u8 *ies, size_t ies_len) 426252726Srpaulo{ 427252726Srpaulo struct hostapd_data *hapd = ctx; 428252726Srpaulo struct sta_info *sta; 429252726Srpaulo 430252726Srpaulo sta = ap_get_sta(hapd, dst); 431252726Srpaulo if (sta == NULL) 432252726Srpaulo return; 433252726Srpaulo 434252726Srpaulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 435252726Srpaulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 436252726Srpaulo sta->flags |= WLAN_STA_AUTH; 437252726Srpaulo 438252726Srpaulo hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len); 439252726Srpaulo} 440252726Srpaulo#endif /* CONFIG_IEEE80211R */ 441252726Srpaulo 442252726Srpaulo 443252726Srpaulostatic void hostapd_notif_auth(struct hostapd_data *hapd, 444252726Srpaulo struct auth_info *rx_auth) 445252726Srpaulo{ 446252726Srpaulo struct sta_info *sta; 447252726Srpaulo u16 status = WLAN_STATUS_SUCCESS; 448252726Srpaulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 449252726Srpaulo size_t resp_ies_len = 0; 450252726Srpaulo 451252726Srpaulo sta = ap_get_sta(hapd, rx_auth->peer); 452252726Srpaulo if (!sta) { 453252726Srpaulo sta = ap_sta_add(hapd, rx_auth->peer); 454252726Srpaulo if (sta == NULL) { 455252726Srpaulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 456252726Srpaulo goto fail; 457214501Srpaulo } 458214501Srpaulo } 459252726Srpaulo sta->flags &= ~WLAN_STA_PREAUTH; 460252726Srpaulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 461252726Srpaulo#ifdef CONFIG_IEEE80211R 462252726Srpaulo if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) { 463252726Srpaulo sta->auth_alg = WLAN_AUTH_FT; 464252726Srpaulo if (sta->wpa_sm == NULL) 465252726Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 466252726Srpaulo sta->addr); 467252726Srpaulo if (sta->wpa_sm == NULL) { 468252726Srpaulo wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " 469252726Srpaulo "state machine"); 470252726Srpaulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 471252726Srpaulo goto fail; 472252726Srpaulo } 473252726Srpaulo wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, 474252726Srpaulo rx_auth->auth_transaction, rx_auth->ies, 475252726Srpaulo rx_auth->ies_len, 476252726Srpaulo hostapd_notify_auth_ft_finish, hapd); 477252726Srpaulo return; 478252726Srpaulo } 479252726Srpaulo#endif /* CONFIG_IEEE80211R */ 480252726Srpaulofail: 481252726Srpaulo hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1, 482252726Srpaulo status, resp_ies, resp_ies_len); 483214501Srpaulo} 484214501Srpaulo 485214501Srpaulo 486252726Srpaulostatic void hostapd_action_rx(struct hostapd_data *hapd, 487252726Srpaulo struct rx_action *action) 488252726Srpaulo{ 489252726Srpaulo struct sta_info *sta; 490252726Srpaulo 491252726Srpaulo wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d", 492252726Srpaulo action->category, (int) action->len); 493252726Srpaulo 494252726Srpaulo sta = ap_get_sta(hapd, action->sa); 495252726Srpaulo if (sta == NULL) { 496252726Srpaulo wpa_printf(MSG_DEBUG, "%s: station not found", __func__); 497252726Srpaulo return; 498252726Srpaulo } 499252726Srpaulo#ifdef CONFIG_IEEE80211R 500252726Srpaulo if (action->category == WLAN_ACTION_FT) { 501252726Srpaulo wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d", 502252726Srpaulo __func__, (int) action->len); 503252726Srpaulo wpa_ft_action_rx(sta->wpa_sm, action->data, action->len); 504252726Srpaulo } 505252726Srpaulo#endif /* CONFIG_IEEE80211R */ 506252726Srpaulo#ifdef CONFIG_IEEE80211W 507252726Srpaulo if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) { 508252726Srpaulo wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d", 509252726Srpaulo __func__, (int) action->len); 510252726Srpaulo ieee802_11_sa_query_action(hapd, action->sa, 511252726Srpaulo *(action->data + 1), 512252726Srpaulo action->data + 2); 513252726Srpaulo } 514252726Srpaulo#endif /* CONFIG_IEEE80211W */ 515252726Srpaulo#ifdef CONFIG_WNM 516252726Srpaulo if (action->category == WLAN_ACTION_WNM) { 517252726Srpaulo wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d", 518252726Srpaulo __func__, (int) action->len); 519252726Srpaulo ieee802_11_rx_wnm_action_ap(hapd, action); 520252726Srpaulo } 521252726Srpaulo#endif /* CONFIG_WNM */ 522252726Srpaulo} 523252726Srpaulo 524252726Srpaulo 525252726Srpaulo#ifdef NEED_AP_MLME 526252726Srpaulo 527214501Srpaulo#define HAPD_BROADCAST ((struct hostapd_data *) -1) 528214501Srpaulo 529214501Srpaulostatic struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, 530214501Srpaulo const u8 *bssid) 531214501Srpaulo{ 532214501Srpaulo size_t i; 533214501Srpaulo 534214501Srpaulo if (bssid == NULL) 535214501Srpaulo return NULL; 536214501Srpaulo if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff && 537214501Srpaulo bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff) 538214501Srpaulo return HAPD_BROADCAST; 539214501Srpaulo 540214501Srpaulo for (i = 0; i < iface->num_bss; i++) { 541214501Srpaulo if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) 542214501Srpaulo return iface->bss[i]; 543214501Srpaulo } 544214501Srpaulo 545214501Srpaulo return NULL; 546214501Srpaulo} 547214501Srpaulo 548214501Srpaulo 549214501Srpaulostatic void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, 550252726Srpaulo const u8 *bssid, const u8 *addr, 551252726Srpaulo int wds) 552214501Srpaulo{ 553252726Srpaulo hapd = get_hapd_bssid(hapd->iface, bssid); 554214501Srpaulo if (hapd == NULL || hapd == HAPD_BROADCAST) 555214501Srpaulo return; 556214501Srpaulo 557252726Srpaulo ieee802_11_rx_from_unknown(hapd, addr, wds); 558214501Srpaulo} 559214501Srpaulo 560214501Srpaulo 561214501Srpaulostatic void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) 562214501Srpaulo{ 563214501Srpaulo struct hostapd_iface *iface = hapd->iface; 564214501Srpaulo const struct ieee80211_hdr *hdr; 565214501Srpaulo const u8 *bssid; 566214501Srpaulo struct hostapd_frame_info fi; 567214501Srpaulo 568214501Srpaulo hdr = (const struct ieee80211_hdr *) rx_mgmt->frame; 569214501Srpaulo bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len); 570214501Srpaulo if (bssid == NULL) 571214501Srpaulo return; 572214501Srpaulo 573214501Srpaulo hapd = get_hapd_bssid(iface, bssid); 574214501Srpaulo if (hapd == NULL) { 575214501Srpaulo u16 fc; 576214501Srpaulo fc = le_to_host16(hdr->frame_control); 577214501Srpaulo 578214501Srpaulo /* 579214501Srpaulo * Drop frames to unknown BSSIDs except for Beacon frames which 580214501Srpaulo * could be used to update neighbor information. 581214501Srpaulo */ 582214501Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 583214501Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 584214501Srpaulo hapd = iface->bss[0]; 585214501Srpaulo else 586214501Srpaulo return; 587214501Srpaulo } 588214501Srpaulo 589214501Srpaulo os_memset(&fi, 0, sizeof(fi)); 590214501Srpaulo fi.datarate = rx_mgmt->datarate; 591214501Srpaulo fi.ssi_signal = rx_mgmt->ssi_signal; 592214501Srpaulo 593214501Srpaulo if (hapd == HAPD_BROADCAST) { 594214501Srpaulo size_t i; 595214501Srpaulo for (i = 0; i < iface->num_bss; i++) 596214501Srpaulo ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame, 597214501Srpaulo rx_mgmt->frame_len, &fi); 598214501Srpaulo } else 599214501Srpaulo ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi); 600252726Srpaulo 601252726Srpaulo random_add_randomness(&fi, sizeof(fi)); 602214501Srpaulo} 603214501Srpaulo 604214501Srpaulo 605252726Srpaulostatic void hostapd_rx_action(struct hostapd_data *hapd, 606252726Srpaulo struct rx_action *rx_action) 607252726Srpaulo{ 608252726Srpaulo struct rx_mgmt rx_mgmt; 609252726Srpaulo u8 *buf; 610252726Srpaulo struct ieee80211_hdr *hdr; 611252726Srpaulo 612252726Srpaulo wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR 613252726Srpaulo " BSSID=" MACSTR " category=%u", 614252726Srpaulo MAC2STR(rx_action->da), MAC2STR(rx_action->sa), 615252726Srpaulo MAC2STR(rx_action->bssid), rx_action->category); 616252726Srpaulo wpa_hexdump(MSG_MSGDUMP, "Received action frame contents", 617252726Srpaulo rx_action->data, rx_action->len); 618252726Srpaulo 619252726Srpaulo buf = os_zalloc(24 + 1 + rx_action->len); 620252726Srpaulo if (buf == NULL) 621252726Srpaulo return; 622252726Srpaulo hdr = (struct ieee80211_hdr *) buf; 623252726Srpaulo hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 624252726Srpaulo WLAN_FC_STYPE_ACTION); 625252726Srpaulo if (rx_action->category == WLAN_ACTION_SA_QUERY) { 626252726Srpaulo /* 627252726Srpaulo * Assume frame was protected; it would have been dropped if 628252726Srpaulo * not. 629252726Srpaulo */ 630252726Srpaulo hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); 631252726Srpaulo } 632252726Srpaulo os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN); 633252726Srpaulo os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN); 634252726Srpaulo os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN); 635252726Srpaulo buf[24] = rx_action->category; 636252726Srpaulo os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len); 637252726Srpaulo os_memset(&rx_mgmt, 0, sizeof(rx_mgmt)); 638252726Srpaulo rx_mgmt.frame = buf; 639252726Srpaulo rx_mgmt.frame_len = 24 + 1 + rx_action->len; 640252726Srpaulo hostapd_mgmt_rx(hapd, &rx_mgmt); 641252726Srpaulo os_free(buf); 642252726Srpaulo} 643252726Srpaulo 644252726Srpaulo 645214501Srpaulostatic void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, 646214501Srpaulo size_t len, u16 stype, int ok) 647214501Srpaulo{ 648214501Srpaulo struct ieee80211_hdr *hdr; 649214501Srpaulo hdr = (struct ieee80211_hdr *) buf; 650214501Srpaulo hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); 651214501Srpaulo if (hapd == NULL || hapd == HAPD_BROADCAST) 652214501Srpaulo return; 653214501Srpaulo ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); 654214501Srpaulo} 655214501Srpaulo 656214501Srpaulo#endif /* NEED_AP_MLME */ 657214501Srpaulo 658214501Srpaulo 659214501Srpaulostatic int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) 660214501Srpaulo{ 661214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 662214501Srpaulo if (sta) 663214501Srpaulo return 0; 664214501Srpaulo 665214501Srpaulo wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR 666214501Srpaulo " - adding a new STA", MAC2STR(addr)); 667214501Srpaulo sta = ap_sta_add(hapd, addr); 668214501Srpaulo if (sta) { 669214501Srpaulo hostapd_new_assoc_sta(hapd, sta, 0); 670214501Srpaulo } else { 671214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR, 672214501Srpaulo MAC2STR(addr)); 673214501Srpaulo return -1; 674214501Srpaulo } 675214501Srpaulo 676214501Srpaulo return 0; 677214501Srpaulo} 678214501Srpaulo 679214501Srpaulo 680214501Srpaulostatic void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, 681214501Srpaulo const u8 *data, size_t data_len) 682214501Srpaulo{ 683214501Srpaulo struct hostapd_iface *iface = hapd->iface; 684252726Srpaulo struct sta_info *sta; 685214501Srpaulo size_t j; 686214501Srpaulo 687214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 688252726Srpaulo if ((sta = ap_get_sta(iface->bss[j], src))) { 689252726Srpaulo if (sta->flags & WLAN_STA_ASSOC) { 690252726Srpaulo hapd = iface->bss[j]; 691252726Srpaulo break; 692252726Srpaulo } 693214501Srpaulo } 694214501Srpaulo } 695214501Srpaulo 696214501Srpaulo ieee802_1x_receive(hapd, src, data, data_len); 697214501Srpaulo} 698214501Srpaulo 699214501Srpaulo 700214501Srpaulovoid wpa_supplicant_event(void *ctx, enum wpa_event_type event, 701214501Srpaulo union wpa_event_data *data) 702214501Srpaulo{ 703214501Srpaulo struct hostapd_data *hapd = ctx; 704252726Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG 705252726Srpaulo int level = MSG_DEBUG; 706214501Srpaulo 707252726Srpaulo if (event == EVENT_RX_MGMT && data->rx_mgmt.frame && 708252726Srpaulo data->rx_mgmt.frame_len >= 24) { 709252726Srpaulo const struct ieee80211_hdr *hdr; 710252726Srpaulo u16 fc; 711252726Srpaulo hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame; 712252726Srpaulo fc = le_to_host16(hdr->frame_control); 713252726Srpaulo if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && 714252726Srpaulo WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) 715252726Srpaulo level = MSG_EXCESSIVE; 716252726Srpaulo } 717252726Srpaulo 718252726Srpaulo wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received", 719252726Srpaulo event_to_string(event), event); 720252726Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */ 721252726Srpaulo 722214501Srpaulo switch (event) { 723214501Srpaulo case EVENT_MICHAEL_MIC_FAILURE: 724214501Srpaulo michael_mic_failure(hapd, data->michael_mic_failure.src, 1); 725214501Srpaulo break; 726214501Srpaulo case EVENT_SCAN_RESULTS: 727214501Srpaulo if (hapd->iface->scan_cb) 728214501Srpaulo hapd->iface->scan_cb(hapd->iface); 729214501Srpaulo break; 730214501Srpaulo#ifdef CONFIG_IEEE80211R 731214501Srpaulo case EVENT_FT_RRB_RX: 732214501Srpaulo wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src, 733214501Srpaulo data->ft_rrb_rx.data, data->ft_rrb_rx.data_len); 734214501Srpaulo break; 735214501Srpaulo#endif /* CONFIG_IEEE80211R */ 736214501Srpaulo case EVENT_WPS_BUTTON_PUSHED: 737252726Srpaulo hostapd_wps_button_pushed(hapd, NULL); 738214501Srpaulo break; 739214501Srpaulo#ifdef NEED_AP_MLME 740214501Srpaulo case EVENT_TX_STATUS: 741214501Srpaulo switch (data->tx_status.type) { 742214501Srpaulo case WLAN_FC_TYPE_MGMT: 743214501Srpaulo hostapd_mgmt_tx_cb(hapd, data->tx_status.data, 744214501Srpaulo data->tx_status.data_len, 745214501Srpaulo data->tx_status.stype, 746214501Srpaulo data->tx_status.ack); 747214501Srpaulo break; 748214501Srpaulo case WLAN_FC_TYPE_DATA: 749214501Srpaulo hostapd_tx_status(hapd, data->tx_status.dst, 750214501Srpaulo data->tx_status.data, 751214501Srpaulo data->tx_status.data_len, 752214501Srpaulo data->tx_status.ack); 753214501Srpaulo break; 754214501Srpaulo } 755214501Srpaulo break; 756252726Srpaulo case EVENT_EAPOL_TX_STATUS: 757252726Srpaulo hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, 758252726Srpaulo data->eapol_tx_status.data, 759252726Srpaulo data->eapol_tx_status.data_len, 760252726Srpaulo data->eapol_tx_status.ack); 761252726Srpaulo break; 762252726Srpaulo case EVENT_DRIVER_CLIENT_POLL_OK: 763252726Srpaulo hostapd_client_poll_ok(hapd, data->client_poll.addr); 764252726Srpaulo break; 765214501Srpaulo case EVENT_RX_FROM_UNKNOWN: 766252726Srpaulo hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid, 767252726Srpaulo data->rx_from_unknown.addr, 768252726Srpaulo data->rx_from_unknown.wds); 769214501Srpaulo break; 770214501Srpaulo case EVENT_RX_MGMT: 771214501Srpaulo hostapd_mgmt_rx(hapd, &data->rx_mgmt); 772214501Srpaulo break; 773214501Srpaulo#endif /* NEED_AP_MLME */ 774214501Srpaulo case EVENT_RX_PROBE_REQ: 775252726Srpaulo if (data->rx_probe_req.sa == NULL || 776252726Srpaulo data->rx_probe_req.ie == NULL) 777252726Srpaulo break; 778214501Srpaulo hostapd_probe_req_rx(hapd, data->rx_probe_req.sa, 779252726Srpaulo data->rx_probe_req.da, 780252726Srpaulo data->rx_probe_req.bssid, 781214501Srpaulo data->rx_probe_req.ie, 782252726Srpaulo data->rx_probe_req.ie_len, 783252726Srpaulo data->rx_probe_req.ssi_signal); 784214501Srpaulo break; 785214501Srpaulo case EVENT_NEW_STA: 786214501Srpaulo hostapd_event_new_sta(hapd, data->new_sta.addr); 787214501Srpaulo break; 788214501Srpaulo case EVENT_EAPOL_RX: 789214501Srpaulo hostapd_event_eapol_rx(hapd, data->eapol_rx.src, 790214501Srpaulo data->eapol_rx.data, 791214501Srpaulo data->eapol_rx.data_len); 792214501Srpaulo break; 793214501Srpaulo case EVENT_ASSOC: 794214501Srpaulo hostapd_notif_assoc(hapd, data->assoc_info.addr, 795214501Srpaulo data->assoc_info.req_ies, 796252726Srpaulo data->assoc_info.req_ies_len, 797252726Srpaulo data->assoc_info.reassoc); 798214501Srpaulo break; 799214501Srpaulo case EVENT_DISASSOC: 800214501Srpaulo if (data) 801214501Srpaulo hostapd_notif_disassoc(hapd, data->disassoc_info.addr); 802214501Srpaulo break; 803214501Srpaulo case EVENT_DEAUTH: 804214501Srpaulo if (data) 805214501Srpaulo hostapd_notif_disassoc(hapd, data->deauth_info.addr); 806214501Srpaulo break; 807252726Srpaulo case EVENT_STATION_LOW_ACK: 808252726Srpaulo if (!data) 809252726Srpaulo break; 810252726Srpaulo hostapd_event_sta_low_ack(hapd, data->low_ack.addr); 811252726Srpaulo break; 812252726Srpaulo case EVENT_RX_ACTION: 813252726Srpaulo if (data->rx_action.da == NULL || data->rx_action.sa == NULL || 814252726Srpaulo data->rx_action.bssid == NULL) 815252726Srpaulo break; 816252726Srpaulo#ifdef NEED_AP_MLME 817252726Srpaulo hostapd_rx_action(hapd, &data->rx_action); 818252726Srpaulo#endif /* NEED_AP_MLME */ 819252726Srpaulo hostapd_action_rx(hapd, &data->rx_action); 820252726Srpaulo break; 821252726Srpaulo case EVENT_AUTH: 822252726Srpaulo hostapd_notif_auth(hapd, &data->auth); 823252726Srpaulo break; 824252726Srpaulo case EVENT_CH_SWITCH: 825252726Srpaulo if (!data) 826252726Srpaulo break; 827252726Srpaulo hostapd_event_ch_switch(hapd, data->ch_switch.freq, 828252726Srpaulo data->ch_switch.ht_enabled, 829252726Srpaulo data->ch_switch.ch_offset); 830252726Srpaulo break; 831214501Srpaulo default: 832214501Srpaulo wpa_printf(MSG_DEBUG, "Unknown event %d", event); 833214501Srpaulo break; 834214501Srpaulo } 835214501Srpaulo} 836214501Srpaulo 837214501Srpaulo#endif /* HOSTAPD */ 838