xref: /freebsd/contrib/wpa/src/ap/drv_callbacks.c (revision 206b73d0429edb7c49b612537544e677fa568e83)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * hostapd / Callback functions for driver wrappers
35b9c547cSRui Paulo  * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "utils/includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "utils/common.h"
125b9c547cSRui Paulo #include "utils/eloop.h"
13e28a4053SRui Paulo #include "radius/radius.h"
14e28a4053SRui Paulo #include "drivers/driver.h"
15e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
16e28a4053SRui Paulo #include "common/ieee802_11_common.h"
175b9c547cSRui Paulo #include "common/wpa_ctrl.h"
184bc52338SCy Schubert #include "common/dpp.h"
19f05cddf9SRui Paulo #include "crypto/random.h"
20f05cddf9SRui Paulo #include "p2p/p2p.h"
21f05cddf9SRui Paulo #include "wps/wps.h"
22325151a3SRui Paulo #include "fst/fst.h"
23f05cddf9SRui Paulo #include "wnm_ap.h"
24e28a4053SRui Paulo #include "hostapd.h"
25e28a4053SRui Paulo #include "ieee802_11.h"
26780fb4a2SCy Schubert #include "ieee802_11_auth.h"
27e28a4053SRui Paulo #include "sta_info.h"
28e28a4053SRui Paulo #include "accounting.h"
29e28a4053SRui Paulo #include "tkip_countermeasures.h"
30e28a4053SRui Paulo #include "ieee802_1x.h"
31e28a4053SRui Paulo #include "wpa_auth.h"
32e28a4053SRui Paulo #include "wps_hostapd.h"
33f05cddf9SRui Paulo #include "ap_drv_ops.h"
34e28a4053SRui Paulo #include "ap_config.h"
3585732ac8SCy Schubert #include "ap_mlme.h"
36f05cddf9SRui Paulo #include "hw_features.h"
375b9c547cSRui Paulo #include "dfs.h"
385b9c547cSRui Paulo #include "beacon.h"
39780fb4a2SCy Schubert #include "mbo_ap.h"
4085732ac8SCy Schubert #include "dpp_hostapd.h"
4185732ac8SCy Schubert #include "fils_hlp.h"
424bc52338SCy Schubert #include "neighbor_db.h"
4385732ac8SCy Schubert 
4485732ac8SCy Schubert 
4585732ac8SCy Schubert #ifdef CONFIG_FILS
4685732ac8SCy Schubert void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd,
4785732ac8SCy Schubert 				      struct sta_info *sta)
4885732ac8SCy Schubert {
4985732ac8SCy Schubert 	u16 reply_res = WLAN_STATUS_SUCCESS;
5085732ac8SCy Schubert 	struct ieee802_11_elems elems;
5185732ac8SCy Schubert 	u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf;
5285732ac8SCy Schubert 	int new_assoc;
5385732ac8SCy Schubert 
5485732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR,
5585732ac8SCy Schubert 		   __func__, MAC2STR(sta->addr));
5685732ac8SCy Schubert 	eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
5785732ac8SCy Schubert 	if (!sta->fils_pending_assoc_req)
5885732ac8SCy Schubert 		return;
5985732ac8SCy Schubert 
6085732ac8SCy Schubert 	ieee802_11_parse_elems(sta->fils_pending_assoc_req,
6185732ac8SCy Schubert 			       sta->fils_pending_assoc_req_len, &elems, 0);
6285732ac8SCy Schubert 	if (!elems.fils_session) {
6385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element",
6485732ac8SCy Schubert 			   __func__);
6585732ac8SCy Schubert 		return;
6685732ac8SCy Schubert 	}
6785732ac8SCy Schubert 
6885732ac8SCy Schubert 	p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
6985732ac8SCy Schubert 					   elems.fils_session,
7085732ac8SCy Schubert 					   sta->fils_hlp_resp);
7185732ac8SCy Schubert 
7285732ac8SCy Schubert 	reply_res = hostapd_sta_assoc(hapd, sta->addr,
7385732ac8SCy Schubert 				      sta->fils_pending_assoc_is_reassoc,
7485732ac8SCy Schubert 				      WLAN_STATUS_SUCCESS,
7585732ac8SCy Schubert 				      buf, p - buf);
7685732ac8SCy Schubert 	ap_sta_set_authorized(hapd, sta, 1);
7785732ac8SCy Schubert 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
7885732ac8SCy Schubert 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
7985732ac8SCy Schubert 	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
8085732ac8SCy Schubert 	hostapd_set_sta_flags(hapd, sta);
8185732ac8SCy Schubert 	wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
8285732ac8SCy Schubert 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
8385732ac8SCy Schubert 	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
8485732ac8SCy Schubert 	os_free(sta->fils_pending_assoc_req);
8585732ac8SCy Schubert 	sta->fils_pending_assoc_req = NULL;
8685732ac8SCy Schubert 	sta->fils_pending_assoc_req_len = 0;
8785732ac8SCy Schubert 	wpabuf_free(sta->fils_hlp_resp);
8885732ac8SCy Schubert 	sta->fils_hlp_resp = NULL;
8985732ac8SCy Schubert 	wpabuf_free(sta->hlp_dhcp_discover);
9085732ac8SCy Schubert 	sta->hlp_dhcp_discover = NULL;
9185732ac8SCy Schubert 	fils_hlp_deinit(hapd);
9285732ac8SCy Schubert 
9385732ac8SCy Schubert 	/*
9485732ac8SCy Schubert 	 * Remove the station in case transmission of a success response fails
9585732ac8SCy Schubert 	 * (the STA was added associated to the driver) or if the station was
9685732ac8SCy Schubert 	 * previously added unassociated.
9785732ac8SCy Schubert 	 */
9885732ac8SCy Schubert 	if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
9985732ac8SCy Schubert 		hostapd_drv_sta_remove(hapd, sta->addr);
10085732ac8SCy Schubert 		sta->added_unassoc = 0;
10185732ac8SCy Schubert 	}
10285732ac8SCy Schubert }
10385732ac8SCy Schubert #endif /* CONFIG_FILS */
104e28a4053SRui Paulo 
105e28a4053SRui Paulo 
106e28a4053SRui Paulo int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
107f05cddf9SRui Paulo 			const u8 *req_ies, size_t req_ies_len, int reassoc)
108e28a4053SRui Paulo {
109e28a4053SRui Paulo 	struct sta_info *sta;
110e28a4053SRui Paulo 	int new_assoc, res;
111e28a4053SRui Paulo 	struct ieee802_11_elems elems;
112f05cddf9SRui Paulo 	const u8 *ie;
113f05cddf9SRui Paulo 	size_t ielen;
11485732ac8SCy Schubert #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
115f05cddf9SRui Paulo 	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
116f05cddf9SRui Paulo 	u8 *p = buf;
11785732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP || CONFIG_IEEE80211W || CONFIG_FILS || CONFIG_OWE */
118f05cddf9SRui Paulo 	u16 reason = WLAN_REASON_UNSPECIFIED;
119f05cddf9SRui Paulo 	u16 status = WLAN_STATUS_SUCCESS;
1205b9c547cSRui Paulo 	const u8 *p2p_dev_addr = NULL;
121e28a4053SRui Paulo 
122e28a4053SRui Paulo 	if (addr == NULL) {
123e28a4053SRui Paulo 		/*
124e28a4053SRui Paulo 		 * This could potentially happen with unexpected event from the
125e28a4053SRui Paulo 		 * driver wrapper. This was seen at least in one case where the
126e28a4053SRui Paulo 		 * driver ended up being set to station mode while hostapd was
127e28a4053SRui Paulo 		 * running, so better make sure we stop processing such an
128e28a4053SRui Paulo 		 * event here.
129e28a4053SRui Paulo 		 */
130325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
131325151a3SRui Paulo 			   "hostapd_notif_assoc: Skip event with no address");
132e28a4053SRui Paulo 		return -1;
133e28a4053SRui Paulo 	}
134f05cddf9SRui Paulo 	random_add_randomness(addr, ETH_ALEN);
135e28a4053SRui Paulo 
136e28a4053SRui Paulo 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
137e28a4053SRui Paulo 		       HOSTAPD_LEVEL_INFO, "associated");
138e28a4053SRui Paulo 
139f05cddf9SRui Paulo 	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
140e28a4053SRui Paulo 	if (elems.wps_ie) {
141e28a4053SRui Paulo 		ie = elems.wps_ie - 2;
142e28a4053SRui Paulo 		ielen = elems.wps_ie_len + 2;
143e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
144e28a4053SRui Paulo 	} else if (elems.rsn_ie) {
145e28a4053SRui Paulo 		ie = elems.rsn_ie - 2;
146e28a4053SRui Paulo 		ielen = elems.rsn_ie_len + 2;
147e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
148e28a4053SRui Paulo 	} else if (elems.wpa_ie) {
149e28a4053SRui Paulo 		ie = elems.wpa_ie - 2;
150e28a4053SRui Paulo 		ielen = elems.wpa_ie_len + 2;
151e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
1525b9c547cSRui Paulo #ifdef CONFIG_HS20
1535b9c547cSRui Paulo 	} else if (elems.osen) {
1545b9c547cSRui Paulo 		ie = elems.osen - 2;
1555b9c547cSRui Paulo 		ielen = elems.osen_len + 2;
1565b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
1575b9c547cSRui Paulo #endif /* CONFIG_HS20 */
158e28a4053SRui Paulo 	} else {
159e28a4053SRui Paulo 		ie = NULL;
160e28a4053SRui Paulo 		ielen = 0;
161325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
162325151a3SRui Paulo 			   "STA did not include WPS/RSN/WPA IE in (Re)AssocReq");
163e28a4053SRui Paulo 	}
164e28a4053SRui Paulo 
165e28a4053SRui Paulo 	sta = ap_get_sta(hapd, addr);
166e28a4053SRui Paulo 	if (sta) {
1675b9c547cSRui Paulo 		ap_sta_no_session_timeout(hapd, sta);
168e28a4053SRui Paulo 		accounting_sta_stop(hapd, sta);
169f05cddf9SRui Paulo 
170f05cddf9SRui Paulo 		/*
171f05cddf9SRui Paulo 		 * Make sure that the previously registered inactivity timer
172f05cddf9SRui Paulo 		 * will not remove the STA immediately.
173f05cddf9SRui Paulo 		 */
174f05cddf9SRui Paulo 		sta->timeout_next = STA_NULLFUNC;
175e28a4053SRui Paulo 	} else {
176e28a4053SRui Paulo 		sta = ap_sta_add(hapd, addr);
177f05cddf9SRui Paulo 		if (sta == NULL) {
178f05cddf9SRui Paulo 			hostapd_drv_sta_disassoc(hapd, addr,
179f05cddf9SRui Paulo 						 WLAN_REASON_DISASSOC_AP_BUSY);
180e28a4053SRui Paulo 			return -1;
181e28a4053SRui Paulo 		}
182f05cddf9SRui Paulo 	}
183f05cddf9SRui Paulo 	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
184f05cddf9SRui Paulo 
185780fb4a2SCy Schubert 	/*
186780fb4a2SCy Schubert 	 * ACL configurations to the drivers (implementing AP SME and ACL
187780fb4a2SCy Schubert 	 * offload) without hostapd's knowledge, can result in a disconnection
188780fb4a2SCy Schubert 	 * though the driver accepts the connection. Skip the hostapd check for
189780fb4a2SCy Schubert 	 * ACL if the driver supports ACL offload to avoid potentially
190780fb4a2SCy Schubert 	 * conflicting ACL rules.
191780fb4a2SCy Schubert 	 */
192780fb4a2SCy Schubert 	if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
193780fb4a2SCy Schubert 	    hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
194780fb4a2SCy Schubert 		wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
195780fb4a2SCy Schubert 			   MAC2STR(addr));
196780fb4a2SCy Schubert 		reason = WLAN_REASON_UNSPECIFIED;
197780fb4a2SCy Schubert 		goto fail;
198780fb4a2SCy Schubert 	}
199780fb4a2SCy Schubert 
200f05cddf9SRui Paulo #ifdef CONFIG_P2P
201f05cddf9SRui Paulo 	if (elems.p2p) {
202f05cddf9SRui Paulo 		wpabuf_free(sta->p2p_ie);
203f05cddf9SRui Paulo 		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
204f05cddf9SRui Paulo 							  P2P_IE_VENDOR_TYPE);
2055b9c547cSRui Paulo 		if (sta->p2p_ie)
2065b9c547cSRui Paulo 			p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
207f05cddf9SRui Paulo 	}
208f05cddf9SRui Paulo #endif /* CONFIG_P2P */
209f05cddf9SRui Paulo 
2105b9c547cSRui Paulo #ifdef CONFIG_IEEE80211N
2115b9c547cSRui Paulo #ifdef NEED_AP_MLME
2125b9c547cSRui Paulo 	if (elems.ht_capabilities &&
2135b9c547cSRui Paulo 	    (hapd->iface->conf->ht_capab &
2145b9c547cSRui Paulo 	     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
2155b9c547cSRui Paulo 		struct ieee80211_ht_capabilities *ht_cap =
2165b9c547cSRui Paulo 			(struct ieee80211_ht_capabilities *)
2175b9c547cSRui Paulo 			elems.ht_capabilities;
2185b9c547cSRui Paulo 
2195b9c547cSRui Paulo 		if (le_to_host16(ht_cap->ht_capabilities_info) &
2205b9c547cSRui Paulo 		    HT_CAP_INFO_40MHZ_INTOLERANT)
2215b9c547cSRui Paulo 			ht40_intolerant_add(hapd->iface, sta);
2225b9c547cSRui Paulo 	}
2235b9c547cSRui Paulo #endif /* NEED_AP_MLME */
2245b9c547cSRui Paulo #endif /* CONFIG_IEEE80211N */
2255b9c547cSRui Paulo 
2265b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING
2275b9c547cSRui Paulo 	if (elems.ext_capab && elems.ext_capab_len > 4) {
2285b9c547cSRui Paulo 		if (elems.ext_capab[4] & 0x01)
2295b9c547cSRui Paulo 			sta->qos_map_enabled = 1;
2305b9c547cSRui Paulo 	}
2315b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */
2325b9c547cSRui Paulo 
233f05cddf9SRui Paulo #ifdef CONFIG_HS20
234f05cddf9SRui Paulo 	wpabuf_free(sta->hs20_ie);
235f05cddf9SRui Paulo 	if (elems.hs20 && elems.hs20_len > 4) {
236f05cddf9SRui Paulo 		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
237f05cddf9SRui Paulo 						 elems.hs20_len - 4);
238f05cddf9SRui Paulo 	} else
239f05cddf9SRui Paulo 		sta->hs20_ie = NULL;
24085732ac8SCy Schubert 
24185732ac8SCy Schubert 	wpabuf_free(sta->roaming_consortium);
24285732ac8SCy Schubert 	if (elems.roaming_cons_sel)
24385732ac8SCy Schubert 		sta->roaming_consortium = wpabuf_alloc_copy(
24485732ac8SCy Schubert 			elems.roaming_cons_sel + 4,
24585732ac8SCy Schubert 			elems.roaming_cons_sel_len - 4);
24685732ac8SCy Schubert 	else
24785732ac8SCy Schubert 		sta->roaming_consortium = NULL;
248f05cddf9SRui Paulo #endif /* CONFIG_HS20 */
249e28a4053SRui Paulo 
250325151a3SRui Paulo #ifdef CONFIG_FST
251325151a3SRui Paulo 	wpabuf_free(sta->mb_ies);
252325151a3SRui Paulo 	if (hapd->iface->fst)
253325151a3SRui Paulo 		sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
254325151a3SRui Paulo 	else
255325151a3SRui Paulo 		sta->mb_ies = NULL;
256325151a3SRui Paulo #endif /* CONFIG_FST */
257325151a3SRui Paulo 
258780fb4a2SCy Schubert 	mbo_ap_check_sta_assoc(hapd, sta, &elems);
259780fb4a2SCy Schubert 
260780fb4a2SCy Schubert 	ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
261780fb4a2SCy Schubert 				    elems.supp_op_classes_len);
262780fb4a2SCy Schubert 
263e28a4053SRui Paulo 	if (hapd->conf->wpa) {
264e28a4053SRui Paulo 		if (ie == NULL || ielen == 0) {
265f05cddf9SRui Paulo #ifdef CONFIG_WPS
266e28a4053SRui Paulo 			if (hapd->conf->wps_state) {
267325151a3SRui Paulo 				wpa_printf(MSG_DEBUG,
268325151a3SRui Paulo 					   "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use");
269e28a4053SRui Paulo 				sta->flags |= WLAN_STA_MAYBE_WPS;
270e28a4053SRui Paulo 				goto skip_wpa_check;
271e28a4053SRui Paulo 			}
272f05cddf9SRui Paulo #endif /* CONFIG_WPS */
273e28a4053SRui Paulo 
274e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
27585732ac8SCy Schubert 			reason = WLAN_REASON_INVALID_IE;
27685732ac8SCy Schubert 			status = WLAN_STATUS_INVALID_IE;
27785732ac8SCy Schubert 			goto fail;
278e28a4053SRui Paulo 		}
279f05cddf9SRui Paulo #ifdef CONFIG_WPS
280e28a4053SRui Paulo 		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
281e28a4053SRui Paulo 		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
282f05cddf9SRui Paulo 			struct wpabuf *wps;
283325151a3SRui Paulo 
284e28a4053SRui Paulo 			sta->flags |= WLAN_STA_WPS;
285f05cddf9SRui Paulo 			wps = ieee802_11_vendor_ie_concat(ie, ielen,
286f05cddf9SRui Paulo 							  WPS_IE_VENDOR_TYPE);
287f05cddf9SRui Paulo 			if (wps) {
288f05cddf9SRui Paulo 				if (wps_is_20(wps)) {
289325151a3SRui Paulo 					wpa_printf(MSG_DEBUG,
290325151a3SRui Paulo 						   "WPS: STA supports WPS 2.0");
291f05cddf9SRui Paulo 					sta->flags |= WLAN_STA_WPS2;
292f05cddf9SRui Paulo 				}
293f05cddf9SRui Paulo 				wpabuf_free(wps);
294f05cddf9SRui Paulo 			}
295e28a4053SRui Paulo 			goto skip_wpa_check;
296e28a4053SRui Paulo 		}
297f05cddf9SRui Paulo #endif /* CONFIG_WPS */
298e28a4053SRui Paulo 
299e28a4053SRui Paulo 		if (sta->wpa_sm == NULL)
300e28a4053SRui Paulo 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
3015b9c547cSRui Paulo 							sta->addr,
3025b9c547cSRui Paulo 							p2p_dev_addr);
303e28a4053SRui Paulo 		if (sta->wpa_sm == NULL) {
304325151a3SRui Paulo 			wpa_printf(MSG_ERROR,
305325151a3SRui Paulo 				   "Failed to initialize WPA state machine");
306e28a4053SRui Paulo 			return -1;
307e28a4053SRui Paulo 		}
308e28a4053SRui Paulo 		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
3094bc52338SCy Schubert 					  hapd->iface->freq,
310f05cddf9SRui Paulo 					  ie, ielen,
31185732ac8SCy Schubert 					  elems.mdie, elems.mdie_len,
31285732ac8SCy Schubert 					  elems.owe_dh, elems.owe_dh_len);
313e28a4053SRui Paulo 		if (res != WPA_IE_OK) {
314325151a3SRui Paulo 			wpa_printf(MSG_DEBUG,
315325151a3SRui Paulo 				   "WPA/RSN information element rejected? (res %u)",
316325151a3SRui Paulo 				   res);
317e28a4053SRui Paulo 			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
318f05cddf9SRui Paulo 			if (res == WPA_INVALID_GROUP) {
319f05cddf9SRui Paulo 				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
320f05cddf9SRui Paulo 				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
321f05cddf9SRui Paulo 			} else if (res == WPA_INVALID_PAIRWISE) {
322f05cddf9SRui Paulo 				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
323f05cddf9SRui Paulo 				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
324f05cddf9SRui Paulo 			} else if (res == WPA_INVALID_AKMP) {
325f05cddf9SRui Paulo 				reason = WLAN_REASON_AKMP_NOT_VALID;
326f05cddf9SRui Paulo 				status = WLAN_STATUS_AKMP_NOT_VALID;
327e28a4053SRui Paulo 			}
328f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W
329f05cddf9SRui Paulo 			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
330f05cddf9SRui Paulo 				reason = WLAN_REASON_INVALID_IE;
331f05cddf9SRui Paulo 				status = WLAN_STATUS_INVALID_IE;
332f05cddf9SRui Paulo 			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
33385732ac8SCy Schubert 				reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
33485732ac8SCy Schubert 				status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
335f05cddf9SRui Paulo 			}
336f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */
337f05cddf9SRui Paulo 			else {
338f05cddf9SRui Paulo 				reason = WLAN_REASON_INVALID_IE;
339f05cddf9SRui Paulo 				status = WLAN_STATUS_INVALID_IE;
340f05cddf9SRui Paulo 			}
341f05cddf9SRui Paulo 			goto fail;
342f05cddf9SRui Paulo 		}
343f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W
34485732ac8SCy Schubert 		if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
34585732ac8SCy Schubert 		    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
34685732ac8SCy Schubert 		    !sta->sa_query_timed_out &&
347f05cddf9SRui Paulo 		    sta->sa_query_count > 0)
348f05cddf9SRui Paulo 			ap_check_sa_query_timeout(hapd, sta);
34985732ac8SCy Schubert 		if ((sta->flags & (WLAN_STA_ASSOC | WLAN_STA_MFP)) ==
35085732ac8SCy Schubert 		    (WLAN_STA_ASSOC | WLAN_STA_MFP) &&
35185732ac8SCy Schubert 		    !sta->sa_query_timed_out &&
352f05cddf9SRui Paulo 		    (sta->auth_alg != WLAN_AUTH_FT)) {
353f05cddf9SRui Paulo 			/*
354f05cddf9SRui Paulo 			 * STA has already been associated with MFP and SA
355f05cddf9SRui Paulo 			 * Query timeout has not been reached. Reject the
356f05cddf9SRui Paulo 			 * association attempt temporarily and start SA Query,
357f05cddf9SRui Paulo 			 * if one is not pending.
358f05cddf9SRui Paulo 			 */
359f05cddf9SRui Paulo 
360f05cddf9SRui Paulo 			if (sta->sa_query_count == 0)
361f05cddf9SRui Paulo 				ap_sta_start_sa_query(hapd, sta);
362f05cddf9SRui Paulo 
363f05cddf9SRui Paulo 			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
364f05cddf9SRui Paulo 
365f05cddf9SRui Paulo 			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
366f05cddf9SRui Paulo 
367f05cddf9SRui Paulo 			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
368f05cddf9SRui Paulo 					  p - buf);
369f05cddf9SRui Paulo 			return 0;
370f05cddf9SRui Paulo 		}
371f05cddf9SRui Paulo 
372f05cddf9SRui Paulo 		if (wpa_auth_uses_mfp(sta->wpa_sm))
373f05cddf9SRui Paulo 			sta->flags |= WLAN_STA_MFP;
374f05cddf9SRui Paulo 		else
375f05cddf9SRui Paulo 			sta->flags &= ~WLAN_STA_MFP;
376f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */
377f05cddf9SRui Paulo 
37885732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
379f05cddf9SRui Paulo 		if (sta->auth_alg == WLAN_AUTH_FT) {
380f05cddf9SRui Paulo 			status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
381f05cddf9SRui Paulo 							 req_ies_len);
382f05cddf9SRui Paulo 			if (status != WLAN_STATUS_SUCCESS) {
383f05cddf9SRui Paulo 				if (status == WLAN_STATUS_INVALID_PMKID)
384f05cddf9SRui Paulo 					reason = WLAN_REASON_INVALID_IE;
385f05cddf9SRui Paulo 				if (status == WLAN_STATUS_INVALID_MDIE)
386f05cddf9SRui Paulo 					reason = WLAN_REASON_INVALID_IE;
387f05cddf9SRui Paulo 				if (status == WLAN_STATUS_INVALID_FTIE)
388f05cddf9SRui Paulo 					reason = WLAN_REASON_INVALID_IE;
389f05cddf9SRui Paulo 				goto fail;
390f05cddf9SRui Paulo 			}
391f05cddf9SRui Paulo 		}
39285732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
393e28a4053SRui Paulo 	} else if (hapd->conf->wps_state) {
394f05cddf9SRui Paulo #ifdef CONFIG_WPS
395f05cddf9SRui Paulo 		struct wpabuf *wps;
396325151a3SRui Paulo 
397f05cddf9SRui Paulo 		if (req_ies)
398f05cddf9SRui Paulo 			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
399f05cddf9SRui Paulo 							  WPS_IE_VENDOR_TYPE);
400f05cddf9SRui Paulo 		else
401f05cddf9SRui Paulo 			wps = NULL;
402f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT
403f05cddf9SRui Paulo 		if (wps && wps_validate_assoc_req(wps) < 0) {
404f05cddf9SRui Paulo 			reason = WLAN_REASON_INVALID_IE;
405f05cddf9SRui Paulo 			status = WLAN_STATUS_INVALID_IE;
406f05cddf9SRui Paulo 			wpabuf_free(wps);
407f05cddf9SRui Paulo 			goto fail;
408f05cddf9SRui Paulo 		}
409f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
410f05cddf9SRui Paulo 		if (wps) {
411e28a4053SRui Paulo 			sta->flags |= WLAN_STA_WPS;
412f05cddf9SRui Paulo 			if (wps_is_20(wps)) {
413325151a3SRui Paulo 				wpa_printf(MSG_DEBUG,
414325151a3SRui Paulo 					   "WPS: STA supports WPS 2.0");
415f05cddf9SRui Paulo 				sta->flags |= WLAN_STA_WPS2;
416f05cddf9SRui Paulo 			}
417e28a4053SRui Paulo 		} else
418e28a4053SRui Paulo 			sta->flags |= WLAN_STA_MAYBE_WPS;
419f05cddf9SRui Paulo 		wpabuf_free(wps);
420f05cddf9SRui Paulo #endif /* CONFIG_WPS */
4215b9c547cSRui Paulo #ifdef CONFIG_HS20
4225b9c547cSRui Paulo 	} else if (hapd->conf->osen) {
4235b9c547cSRui Paulo 		if (elems.osen == NULL) {
4245b9c547cSRui Paulo 			hostapd_logger(
4255b9c547cSRui Paulo 				hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
4265b9c547cSRui Paulo 				HOSTAPD_LEVEL_INFO,
4275b9c547cSRui Paulo 				"No HS 2.0 OSEN element in association request");
4285b9c547cSRui Paulo 			return WLAN_STATUS_INVALID_IE;
4295b9c547cSRui Paulo 		}
4305b9c547cSRui Paulo 
4315b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
4325b9c547cSRui Paulo 		if (sta->wpa_sm == NULL)
4335b9c547cSRui Paulo 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
4345b9c547cSRui Paulo 							sta->addr, NULL);
4355b9c547cSRui Paulo 		if (sta->wpa_sm == NULL) {
436325151a3SRui Paulo 			wpa_printf(MSG_WARNING,
437325151a3SRui Paulo 				   "Failed to initialize WPA state machine");
4385b9c547cSRui Paulo 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
4395b9c547cSRui Paulo 		}
4405b9c547cSRui Paulo 		if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
4415b9c547cSRui Paulo 				      elems.osen - 2, elems.osen_len + 2) < 0)
4425b9c547cSRui Paulo 			return WLAN_STATUS_INVALID_IE;
4435b9c547cSRui Paulo #endif /* CONFIG_HS20 */
444e28a4053SRui Paulo 	}
445780fb4a2SCy Schubert 
446780fb4a2SCy Schubert #ifdef CONFIG_MBO
447780fb4a2SCy Schubert 	if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
448780fb4a2SCy Schubert 	    elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
449780fb4a2SCy Schubert 	    hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
450780fb4a2SCy Schubert 		wpa_printf(MSG_INFO,
451780fb4a2SCy Schubert 			   "MBO: Reject WPA2 association without PMF");
452780fb4a2SCy Schubert 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
453780fb4a2SCy Schubert 	}
454780fb4a2SCy Schubert #endif /* CONFIG_MBO */
455780fb4a2SCy Schubert 
456f05cddf9SRui Paulo #ifdef CONFIG_WPS
457e28a4053SRui Paulo skip_wpa_check:
458f05cddf9SRui Paulo #endif /* CONFIG_WPS */
459f05cddf9SRui Paulo 
46085732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
461f05cddf9SRui Paulo 	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
462f05cddf9SRui Paulo 					sta->auth_alg, req_ies, req_ies_len);
46385732ac8SCy Schubert 	if (!p) {
46485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs");
46585732ac8SCy Schubert 		return WLAN_STATUS_UNSPECIFIED_FAILURE;
46685732ac8SCy Schubert 	}
46785732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
468f05cddf9SRui Paulo 
46985732ac8SCy Schubert #ifdef CONFIG_FILS
47085732ac8SCy Schubert 	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
47185732ac8SCy Schubert 	    sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
47285732ac8SCy Schubert 	    sta->auth_alg == WLAN_AUTH_FILS_PK) {
47385732ac8SCy Schubert 		int delay_assoc = 0;
47485732ac8SCy Schubert 
47585732ac8SCy Schubert 		if (!req_ies)
47685732ac8SCy Schubert 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
47785732ac8SCy Schubert 
47885732ac8SCy Schubert 		if (!wpa_fils_validate_fils_session(sta->wpa_sm, req_ies,
47985732ac8SCy Schubert 						    req_ies_len,
48085732ac8SCy Schubert 						    sta->fils_session)) {
48185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
48285732ac8SCy Schubert 				   "FILS: Session validation failed");
48385732ac8SCy Schubert 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
48485732ac8SCy Schubert 		}
48585732ac8SCy Schubert 
48685732ac8SCy Schubert 		res = wpa_fils_validate_key_confirm(sta->wpa_sm, req_ies,
48785732ac8SCy Schubert 						    req_ies_len);
48885732ac8SCy Schubert 		if (res < 0) {
48985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
49085732ac8SCy Schubert 				   "FILS: Key Confirm validation failed");
49185732ac8SCy Schubert 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
49285732ac8SCy Schubert 		}
49385732ac8SCy Schubert 
49485732ac8SCy Schubert 		if (fils_process_hlp(hapd, sta, req_ies, req_ies_len) > 0) {
49585732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
49685732ac8SCy Schubert 				   "FILS: Delaying Assoc Response (HLP)");
49785732ac8SCy Schubert 			delay_assoc = 1;
49885732ac8SCy Schubert 		} else {
49985732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
50085732ac8SCy Schubert 				   "FILS: Going ahead with Assoc Response (no HLP)");
50185732ac8SCy Schubert 		}
50285732ac8SCy Schubert 
50385732ac8SCy Schubert 		if (sta) {
50485732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "FILS: HLP callback cleanup");
50585732ac8SCy Schubert 			eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
50685732ac8SCy Schubert 			os_free(sta->fils_pending_assoc_req);
50785732ac8SCy Schubert 			sta->fils_pending_assoc_req = NULL;
50885732ac8SCy Schubert 			sta->fils_pending_assoc_req_len = 0;
50985732ac8SCy Schubert 			wpabuf_free(sta->fils_hlp_resp);
51085732ac8SCy Schubert 			sta->fils_hlp_resp = NULL;
51185732ac8SCy Schubert 			sta->fils_drv_assoc_finish = 0;
51285732ac8SCy Schubert 		}
51385732ac8SCy Schubert 
51485732ac8SCy Schubert 		if (sta && delay_assoc && status == WLAN_STATUS_SUCCESS) {
51585732ac8SCy Schubert 			u8 *req_tmp;
51685732ac8SCy Schubert 
51785732ac8SCy Schubert 			req_tmp = os_malloc(req_ies_len);
51885732ac8SCy Schubert 			if (!req_tmp) {
51985732ac8SCy Schubert 				wpa_printf(MSG_DEBUG,
52085732ac8SCy Schubert 					   "FILS: buffer allocation failed for assoc req");
52185732ac8SCy Schubert 				goto fail;
52285732ac8SCy Schubert 			}
52385732ac8SCy Schubert 			os_memcpy(req_tmp, req_ies, req_ies_len);
52485732ac8SCy Schubert 			sta->fils_pending_assoc_req = req_tmp;
52585732ac8SCy Schubert 			sta->fils_pending_assoc_req_len = req_ies_len;
52685732ac8SCy Schubert 			sta->fils_pending_assoc_is_reassoc = reassoc;
52785732ac8SCy Schubert 			sta->fils_drv_assoc_finish = 1;
52885732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
52985732ac8SCy Schubert 				   "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
53085732ac8SCy Schubert 				   MACSTR, MAC2STR(sta->addr));
53185732ac8SCy Schubert 			eloop_register_timeout(
53285732ac8SCy Schubert 				0, hapd->conf->fils_hlp_wait_time * 1024,
53385732ac8SCy Schubert 				fils_hlp_timeout, hapd, sta);
53485732ac8SCy Schubert 			return 0;
53585732ac8SCy Schubert 		}
53685732ac8SCy Schubert 		p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
53785732ac8SCy Schubert 						   elems.fils_session,
53885732ac8SCy Schubert 						   sta->fils_hlp_resp);
53985732ac8SCy Schubert 		wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
54085732ac8SCy Schubert 			    buf, p - buf);
54185732ac8SCy Schubert 	}
54285732ac8SCy Schubert #endif /* CONFIG_FILS */
54385732ac8SCy Schubert 
54485732ac8SCy Schubert #ifdef CONFIG_OWE
54585732ac8SCy Schubert 	if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
54685732ac8SCy Schubert 	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE &&
54785732ac8SCy Schubert 	    elems.owe_dh) {
54885732ac8SCy Schubert 		u8 *npos;
54985732ac8SCy Schubert 
55085732ac8SCy Schubert 		npos = owe_assoc_req_process(hapd, sta,
55185732ac8SCy Schubert 					     elems.owe_dh, elems.owe_dh_len,
55285732ac8SCy Schubert 					     p, sizeof(buf) - (p - buf),
55385732ac8SCy Schubert 					     &reason);
55485732ac8SCy Schubert 		if (npos)
55585732ac8SCy Schubert 			p = npos;
55685732ac8SCy Schubert 		if (!npos &&
55785732ac8SCy Schubert 		    reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
55885732ac8SCy Schubert 			status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
55985732ac8SCy Schubert 			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
56085732ac8SCy Schubert 					  p - buf);
56185732ac8SCy Schubert 			return 0;
56285732ac8SCy Schubert 		}
56385732ac8SCy Schubert 
56485732ac8SCy Schubert 		if (!npos || reason != WLAN_STATUS_SUCCESS)
56585732ac8SCy Schubert 			goto fail;
56685732ac8SCy Schubert 	}
56785732ac8SCy Schubert #endif /* CONFIG_OWE */
56885732ac8SCy Schubert 
5694bc52338SCy Schubert #ifdef CONFIG_DPP2
5704bc52338SCy Schubert 		dpp_pfs_free(sta->dpp_pfs);
5714bc52338SCy Schubert 		sta->dpp_pfs = NULL;
5724bc52338SCy Schubert 
5734bc52338SCy Schubert 		if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) &&
5744bc52338SCy Schubert 		    hapd->conf->dpp_netaccesskey && sta->wpa_sm &&
5754bc52338SCy Schubert 		    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP &&
5764bc52338SCy Schubert 		    elems.owe_dh) {
5774bc52338SCy Schubert 			sta->dpp_pfs = dpp_pfs_init(
5784bc52338SCy Schubert 				wpabuf_head(hapd->conf->dpp_netaccesskey),
5794bc52338SCy Schubert 				wpabuf_len(hapd->conf->dpp_netaccesskey));
5804bc52338SCy Schubert 			if (!sta->dpp_pfs) {
5814bc52338SCy Schubert 				wpa_printf(MSG_DEBUG,
5824bc52338SCy Schubert 					   "DPP: Could not initialize PFS");
5834bc52338SCy Schubert 				/* Try to continue without PFS */
5844bc52338SCy Schubert 				goto pfs_fail;
5854bc52338SCy Schubert 			}
5864bc52338SCy Schubert 
5874bc52338SCy Schubert 			if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh,
5884bc52338SCy Schubert 					    elems.owe_dh_len) < 0) {
5894bc52338SCy Schubert 				dpp_pfs_free(sta->dpp_pfs);
5904bc52338SCy Schubert 				sta->dpp_pfs = NULL;
5914bc52338SCy Schubert 				reason = WLAN_REASON_UNSPECIFIED;
5924bc52338SCy Schubert 				goto fail;
5934bc52338SCy Schubert 			}
5944bc52338SCy Schubert 		}
5954bc52338SCy Schubert 
5964bc52338SCy Schubert 		wpa_auth_set_dpp_z(sta->wpa_sm, sta->dpp_pfs ?
5974bc52338SCy Schubert 				   sta->dpp_pfs->secret : NULL);
5984bc52338SCy Schubert 	pfs_fail:
5994bc52338SCy Schubert #endif /* CONFIG_DPP2 */
6004bc52338SCy Schubert 
60185732ac8SCy Schubert #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE)
602f05cddf9SRui Paulo 	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
6035b9c547cSRui Paulo 
60485732ac8SCy Schubert 	if (sta->auth_alg == WLAN_AUTH_FT ||
60585732ac8SCy Schubert 	    sta->auth_alg == WLAN_AUTH_FILS_SK ||
60685732ac8SCy Schubert 	    sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
60785732ac8SCy Schubert 	    sta->auth_alg == WLAN_AUTH_FILS_PK)
6085b9c547cSRui Paulo 		ap_sta_set_authorized(hapd, sta, 1);
60985732ac8SCy Schubert #else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
610f05cddf9SRui Paulo 	/* Keep compiler silent about unused variables */
611f05cddf9SRui Paulo 	if (status) {
612f05cddf9SRui Paulo 	}
61385732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
614e28a4053SRui Paulo 
615e28a4053SRui Paulo 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
616e28a4053SRui Paulo 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
6175b9c547cSRui Paulo 	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
6185b9c547cSRui Paulo 
6195b9c547cSRui Paulo 	hostapd_set_sta_flags(hapd, sta);
620f05cddf9SRui Paulo 
621f05cddf9SRui Paulo 	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
622f05cddf9SRui Paulo 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
62385732ac8SCy Schubert #ifdef CONFIG_FILS
62485732ac8SCy Schubert 	else if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
62585732ac8SCy Schubert 		 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
62685732ac8SCy Schubert 		 sta->auth_alg == WLAN_AUTH_FILS_PK)
62785732ac8SCy Schubert 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
62885732ac8SCy Schubert #endif /* CONFIG_FILS */
629f05cddf9SRui Paulo 	else
630e28a4053SRui Paulo 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
631e28a4053SRui Paulo 
632e28a4053SRui Paulo 	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
633e28a4053SRui Paulo 
634e28a4053SRui Paulo 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
635e28a4053SRui Paulo 
636f05cddf9SRui Paulo #ifdef CONFIG_P2P
637f05cddf9SRui Paulo 	if (req_ies) {
638f05cddf9SRui Paulo 		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
639f05cddf9SRui Paulo 				      req_ies, req_ies_len);
640f05cddf9SRui Paulo 	}
641f05cddf9SRui Paulo #endif /* CONFIG_P2P */
642f05cddf9SRui Paulo 
643e28a4053SRui Paulo 	return 0;
644f05cddf9SRui Paulo 
645f05cddf9SRui Paulo fail:
64685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
647f05cddf9SRui Paulo 	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
64885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
649f05cddf9SRui Paulo 	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
650f05cddf9SRui Paulo 	ap_free_sta(hapd, sta);
651f05cddf9SRui Paulo 	return -1;
652e28a4053SRui Paulo }
653e28a4053SRui Paulo 
654e28a4053SRui Paulo 
655e28a4053SRui Paulo void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
656e28a4053SRui Paulo {
657e28a4053SRui Paulo 	struct sta_info *sta;
658e28a4053SRui Paulo 
659f05cddf9SRui Paulo 	if (addr == NULL) {
660f05cddf9SRui Paulo 		/*
661f05cddf9SRui Paulo 		 * This could potentially happen with unexpected event from the
662f05cddf9SRui Paulo 		 * driver wrapper. This was seen at least in one case where the
663f05cddf9SRui Paulo 		 * driver ended up reporting a station mode event while hostapd
664f05cddf9SRui Paulo 		 * was running, so better make sure we stop processing such an
665f05cddf9SRui Paulo 		 * event here.
666f05cddf9SRui Paulo 		 */
667325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
668325151a3SRui Paulo 			   "hostapd_notif_disassoc: Skip event with no address");
669f05cddf9SRui Paulo 		return;
670f05cddf9SRui Paulo 	}
671f05cddf9SRui Paulo 
672e28a4053SRui Paulo 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
673e28a4053SRui Paulo 		       HOSTAPD_LEVEL_INFO, "disassociated");
674e28a4053SRui Paulo 
675e28a4053SRui Paulo 	sta = ap_get_sta(hapd, addr);
676e28a4053SRui Paulo 	if (sta == NULL) {
677325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
678325151a3SRui Paulo 			   "Disassociation notification for unknown STA "
679325151a3SRui Paulo 			   MACSTR, MAC2STR(addr));
680e28a4053SRui Paulo 		return;
681e28a4053SRui Paulo 	}
682e28a4053SRui Paulo 
683f05cddf9SRui Paulo 	ap_sta_set_authorized(hapd, sta, 0);
684e28a4053SRui Paulo 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
685e28a4053SRui Paulo 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
686e28a4053SRui Paulo 	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
687e28a4053SRui Paulo 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
688e28a4053SRui Paulo 	ap_free_sta(hapd, sta);
689e28a4053SRui Paulo }
690e28a4053SRui Paulo 
691e28a4053SRui Paulo 
692f05cddf9SRui Paulo void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
693f05cddf9SRui Paulo {
694f05cddf9SRui Paulo 	struct sta_info *sta = ap_get_sta(hapd, addr);
695f05cddf9SRui Paulo 
69685732ac8SCy Schubert 	if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
697f05cddf9SRui Paulo 		return;
698f05cddf9SRui Paulo 
699f05cddf9SRui Paulo 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
700325151a3SRui Paulo 		       HOSTAPD_LEVEL_INFO,
701325151a3SRui Paulo 		       "disconnected due to excessive missing ACKs");
702f05cddf9SRui Paulo 	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
703f05cddf9SRui Paulo 	ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
704f05cddf9SRui Paulo }
705f05cddf9SRui Paulo 
706f05cddf9SRui Paulo 
70785732ac8SCy Schubert void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr,
70885732ac8SCy Schubert 				      enum smps_mode smps_mode,
70985732ac8SCy Schubert 				      enum chan_width chan_width, u8 rx_nss)
71085732ac8SCy Schubert {
71185732ac8SCy Schubert 	struct sta_info *sta = ap_get_sta(hapd, addr);
71285732ac8SCy Schubert 	const char *txt;
71385732ac8SCy Schubert 
71485732ac8SCy Schubert 	if (!sta)
71585732ac8SCy Schubert 		return;
71685732ac8SCy Schubert 
71785732ac8SCy Schubert 	switch (smps_mode) {
71885732ac8SCy Schubert 	case SMPS_AUTOMATIC:
71985732ac8SCy Schubert 		txt = "automatic";
72085732ac8SCy Schubert 		break;
72185732ac8SCy Schubert 	case SMPS_OFF:
72285732ac8SCy Schubert 		txt = "off";
72385732ac8SCy Schubert 		break;
72485732ac8SCy Schubert 	case SMPS_DYNAMIC:
72585732ac8SCy Schubert 		txt = "dynamic";
72685732ac8SCy Schubert 		break;
72785732ac8SCy Schubert 	case SMPS_STATIC:
72885732ac8SCy Schubert 		txt = "static";
72985732ac8SCy Schubert 		break;
73085732ac8SCy Schubert 	default:
73185732ac8SCy Schubert 		txt = NULL;
73285732ac8SCy Schubert 		break;
73385732ac8SCy Schubert 	}
73485732ac8SCy Schubert 	if (txt) {
73585732ac8SCy Schubert 		wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_SMPS_MODE_CHANGED
73685732ac8SCy Schubert 			MACSTR " %s", MAC2STR(addr), txt);
73785732ac8SCy Schubert 	}
73885732ac8SCy Schubert 
73985732ac8SCy Schubert 	switch (chan_width) {
74085732ac8SCy Schubert 	case CHAN_WIDTH_20_NOHT:
74185732ac8SCy Schubert 		txt = "20(no-HT)";
74285732ac8SCy Schubert 		break;
74385732ac8SCy Schubert 	case CHAN_WIDTH_20:
74485732ac8SCy Schubert 		txt = "20";
74585732ac8SCy Schubert 		break;
74685732ac8SCy Schubert 	case CHAN_WIDTH_40:
74785732ac8SCy Schubert 		txt = "40";
74885732ac8SCy Schubert 		break;
74985732ac8SCy Schubert 	case CHAN_WIDTH_80:
75085732ac8SCy Schubert 		txt = "80";
75185732ac8SCy Schubert 		break;
75285732ac8SCy Schubert 	case CHAN_WIDTH_80P80:
75385732ac8SCy Schubert 		txt = "80+80";
75485732ac8SCy Schubert 		break;
75585732ac8SCy Schubert 	case CHAN_WIDTH_160:
75685732ac8SCy Schubert 		txt = "160";
75785732ac8SCy Schubert 		break;
75885732ac8SCy Schubert 	default:
75985732ac8SCy Schubert 		txt = NULL;
76085732ac8SCy Schubert 		break;
76185732ac8SCy Schubert 	}
76285732ac8SCy Schubert 	if (txt) {
76385732ac8SCy Schubert 		wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_MAX_BW_CHANGED
76485732ac8SCy Schubert 			MACSTR " %s", MAC2STR(addr), txt);
76585732ac8SCy Schubert 	}
76685732ac8SCy Schubert 
76785732ac8SCy Schubert 	if (rx_nss != 0xff) {
76885732ac8SCy Schubert 		wpa_msg(hapd->msg_ctx, MSG_INFO, STA_OPMODE_N_SS_CHANGED
76985732ac8SCy Schubert 			MACSTR " %d", MAC2STR(addr), rx_nss);
77085732ac8SCy Schubert 	}
77185732ac8SCy Schubert }
77285732ac8SCy Schubert 
77385732ac8SCy Schubert 
774f05cddf9SRui Paulo void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
775*206b73d0SCy Schubert 			     int offset, int width, int cf1, int cf2,
776*206b73d0SCy Schubert 			     int finished)
777f05cddf9SRui Paulo {
7784bc52338SCy Schubert 	/* TODO: If OCV is enabled deauth STAs that don't perform a SA Query */
7794bc52338SCy Schubert 
780f05cddf9SRui Paulo #ifdef NEED_AP_MLME
781780fb4a2SCy Schubert 	int channel, chwidth, is_dfs;
782780fb4a2SCy Schubert 	u8 seg0_idx = 0, seg1_idx = 0;
7834bc52338SCy Schubert 	size_t i;
784f05cddf9SRui Paulo 
785f05cddf9SRui Paulo 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
7865b9c547cSRui Paulo 		       HOSTAPD_LEVEL_INFO,
787*206b73d0SCy Schubert 		       "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
788*206b73d0SCy Schubert 		       finished ? "had" : "starting",
78985732ac8SCy Schubert 		       freq, ht, hapd->iconf->ch_switch_vht_config, offset,
79085732ac8SCy Schubert 		       width, channel_width_to_string(width), cf1, cf2);
791f05cddf9SRui Paulo 
792*206b73d0SCy Schubert 	if (!hapd->iface->current_mode) {
793*206b73d0SCy Schubert 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
794*206b73d0SCy Schubert 			       HOSTAPD_LEVEL_WARNING,
795*206b73d0SCy Schubert 			       "ignore channel switch since the interface is not yet ready");
796*206b73d0SCy Schubert 		return;
797*206b73d0SCy Schubert 	}
798*206b73d0SCy Schubert 
799f05cddf9SRui Paulo 	hapd->iface->freq = freq;
800f05cddf9SRui Paulo 
801f05cddf9SRui Paulo 	channel = hostapd_hw_get_channel(hapd, freq);
802f05cddf9SRui Paulo 	if (!channel) {
803f05cddf9SRui Paulo 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
804325151a3SRui Paulo 			       HOSTAPD_LEVEL_WARNING,
805325151a3SRui Paulo 			       "driver switched to bad channel!");
806f05cddf9SRui Paulo 		return;
807f05cddf9SRui Paulo 	}
808f05cddf9SRui Paulo 
8095b9c547cSRui Paulo 	switch (width) {
8105b9c547cSRui Paulo 	case CHAN_WIDTH_80:
811*206b73d0SCy Schubert 		chwidth = CHANWIDTH_80MHZ;
8125b9c547cSRui Paulo 		break;
8135b9c547cSRui Paulo 	case CHAN_WIDTH_80P80:
814*206b73d0SCy Schubert 		chwidth = CHANWIDTH_80P80MHZ;
8155b9c547cSRui Paulo 		break;
8165b9c547cSRui Paulo 	case CHAN_WIDTH_160:
817*206b73d0SCy Schubert 		chwidth = CHANWIDTH_160MHZ;
8185b9c547cSRui Paulo 		break;
8195b9c547cSRui Paulo 	case CHAN_WIDTH_20_NOHT:
8205b9c547cSRui Paulo 	case CHAN_WIDTH_20:
8215b9c547cSRui Paulo 	case CHAN_WIDTH_40:
8225b9c547cSRui Paulo 	default:
823*206b73d0SCy Schubert 		chwidth = CHANWIDTH_USE_HT;
8245b9c547cSRui Paulo 		break;
8255b9c547cSRui Paulo 	}
8265b9c547cSRui Paulo 
8275b9c547cSRui Paulo 	switch (hapd->iface->current_mode->mode) {
8285b9c547cSRui Paulo 	case HOSTAPD_MODE_IEEE80211A:
8295b9c547cSRui Paulo 		if (cf1 > 5000)
8305b9c547cSRui Paulo 			seg0_idx = (cf1 - 5000) / 5;
8315b9c547cSRui Paulo 		if (cf2 > 5000)
8325b9c547cSRui Paulo 			seg1_idx = (cf2 - 5000) / 5;
8335b9c547cSRui Paulo 		break;
8345b9c547cSRui Paulo 	default:
835780fb4a2SCy Schubert 		ieee80211_freq_to_chan(cf1, &seg0_idx);
836780fb4a2SCy Schubert 		ieee80211_freq_to_chan(cf2, &seg1_idx);
8375b9c547cSRui Paulo 		break;
8385b9c547cSRui Paulo 	}
8395b9c547cSRui Paulo 
840f05cddf9SRui Paulo 	hapd->iconf->channel = channel;
841f05cddf9SRui Paulo 	hapd->iconf->ieee80211n = ht;
84285732ac8SCy Schubert 	if (!ht) {
8435b9c547cSRui Paulo 		hapd->iconf->ieee80211ac = 0;
84485732ac8SCy Schubert 	} else if (hapd->iconf->ch_switch_vht_config) {
84585732ac8SCy Schubert 		/* CHAN_SWITCH VHT config */
84685732ac8SCy Schubert 		if (hapd->iconf->ch_switch_vht_config &
84785732ac8SCy Schubert 		    CH_SWITCH_VHT_ENABLED)
84885732ac8SCy Schubert 			hapd->iconf->ieee80211ac = 1;
84985732ac8SCy Schubert 		else if (hapd->iconf->ch_switch_vht_config &
85085732ac8SCy Schubert 			 CH_SWITCH_VHT_DISABLED)
85185732ac8SCy Schubert 			hapd->iconf->ieee80211ac = 0;
85285732ac8SCy Schubert 	}
85385732ac8SCy Schubert 	hapd->iconf->ch_switch_vht_config = 0;
85485732ac8SCy Schubert 
855f05cddf9SRui Paulo 	hapd->iconf->secondary_channel = offset;
856*206b73d0SCy Schubert 	hostapd_set_oper_chwidth(hapd->iconf, chwidth);
857*206b73d0SCy Schubert 	hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx);
858*206b73d0SCy Schubert 	hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx);
8595b9c547cSRui Paulo 
86085732ac8SCy Schubert 	is_dfs = ieee80211_is_dfs(freq, hapd->iface->hw_features,
86185732ac8SCy Schubert 				  hapd->iface->num_hw_features);
8625b9c547cSRui Paulo 
863*206b73d0SCy Schubert 	wpa_msg(hapd->msg_ctx, MSG_INFO,
864*206b73d0SCy Schubert 		"%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d",
865*206b73d0SCy Schubert 		finished ? WPA_EVENT_CHANNEL_SWITCH :
866*206b73d0SCy Schubert 		WPA_EVENT_CHANNEL_SWITCH_STARTED,
867*206b73d0SCy Schubert 		freq, ht, offset, channel_width_to_string(width),
868*206b73d0SCy Schubert 		cf1, cf2, is_dfs);
869*206b73d0SCy Schubert 	if (!finished)
870*206b73d0SCy Schubert 		return;
871*206b73d0SCy Schubert 
8725b9c547cSRui Paulo 	if (hapd->csa_in_progress &&
8735b9c547cSRui Paulo 	    freq == hapd->cs_freq_params.freq) {
8745b9c547cSRui Paulo 		hostapd_cleanup_cs_params(hapd);
8755b9c547cSRui Paulo 		ieee802_11_set_beacon(hapd);
8765b9c547cSRui Paulo 
8775b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
8785b9c547cSRui Paulo 			"freq=%d dfs=%d", freq, is_dfs);
8795b9c547cSRui Paulo 	} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
8805b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
8815b9c547cSRui Paulo 			"freq=%d dfs=%d", freq, is_dfs);
8825b9c547cSRui Paulo 	}
8834bc52338SCy Schubert 
8844bc52338SCy Schubert 	for (i = 0; i < hapd->iface->num_bss; i++)
8854bc52338SCy Schubert 		hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
886f05cddf9SRui Paulo #endif /* NEED_AP_MLME */
887f05cddf9SRui Paulo }
888f05cddf9SRui Paulo 
889f05cddf9SRui Paulo 
8905b9c547cSRui Paulo void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
8915b9c547cSRui Paulo 					 const u8 *addr, int reason_code)
8925b9c547cSRui Paulo {
8935b9c547cSRui Paulo 	switch (reason_code) {
8945b9c547cSRui Paulo 	case MAX_CLIENT_REACHED:
8955b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
8965b9c547cSRui Paulo 			MAC2STR(addr));
8975b9c547cSRui Paulo 		break;
8985b9c547cSRui Paulo 	case BLOCKED_CLIENT:
8995b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
9005b9c547cSRui Paulo 			MAC2STR(addr));
9015b9c547cSRui Paulo 		break;
9025b9c547cSRui Paulo 	}
9035b9c547cSRui Paulo }
9045b9c547cSRui Paulo 
9055b9c547cSRui Paulo 
9065b9c547cSRui Paulo #ifdef CONFIG_ACS
907780fb4a2SCy Schubert void hostapd_acs_channel_selected(struct hostapd_data *hapd,
908325151a3SRui Paulo 				  struct acs_selected_channels *acs_res)
9095b9c547cSRui Paulo {
910325151a3SRui Paulo 	int ret, i;
911780fb4a2SCy Schubert 	int err = 0;
9125b9c547cSRui Paulo 
9135b9c547cSRui Paulo 	if (hapd->iconf->channel) {
9145b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
9155b9c547cSRui Paulo 			   hapd->iconf->channel);
9165b9c547cSRui Paulo 		return;
9175b9c547cSRui Paulo 	}
9185b9c547cSRui Paulo 
919325151a3SRui Paulo 	if (!hapd->iface->current_mode) {
920325151a3SRui Paulo 		for (i = 0; i < hapd->iface->num_hw_features; i++) {
921325151a3SRui Paulo 			struct hostapd_hw_modes *mode =
922325151a3SRui Paulo 				&hapd->iface->hw_features[i];
9235b9c547cSRui Paulo 
924325151a3SRui Paulo 			if (mode->mode == acs_res->hw_mode) {
925325151a3SRui Paulo 				hapd->iface->current_mode = mode;
926325151a3SRui Paulo 				break;
927325151a3SRui Paulo 			}
928325151a3SRui Paulo 		}
929325151a3SRui Paulo 		if (!hapd->iface->current_mode) {
930325151a3SRui Paulo 			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
931325151a3SRui Paulo 				       HOSTAPD_LEVEL_WARNING,
932325151a3SRui Paulo 				       "driver selected to bad hw_mode");
933780fb4a2SCy Schubert 			err = 1;
934780fb4a2SCy Schubert 			goto out;
935325151a3SRui Paulo 		}
936325151a3SRui Paulo 	}
937325151a3SRui Paulo 
938325151a3SRui Paulo 	hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
939325151a3SRui Paulo 
940325151a3SRui Paulo 	if (!acs_res->pri_channel) {
9415b9c547cSRui Paulo 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
9425b9c547cSRui Paulo 			       HOSTAPD_LEVEL_WARNING,
9435b9c547cSRui Paulo 			       "driver switched to bad channel");
944780fb4a2SCy Schubert 		err = 1;
945780fb4a2SCy Schubert 		goto out;
9465b9c547cSRui Paulo 	}
9475b9c547cSRui Paulo 
948325151a3SRui Paulo 	hapd->iconf->channel = acs_res->pri_channel;
949325151a3SRui Paulo 	hapd->iconf->acs = 1;
9505b9c547cSRui Paulo 
951325151a3SRui Paulo 	if (acs_res->sec_channel == 0)
9525b9c547cSRui Paulo 		hapd->iconf->secondary_channel = 0;
953325151a3SRui Paulo 	else if (acs_res->sec_channel < acs_res->pri_channel)
9545b9c547cSRui Paulo 		hapd->iconf->secondary_channel = -1;
955325151a3SRui Paulo 	else if (acs_res->sec_channel > acs_res->pri_channel)
9565b9c547cSRui Paulo 		hapd->iconf->secondary_channel = 1;
9575b9c547cSRui Paulo 	else {
9585b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "Invalid secondary channel!");
959780fb4a2SCy Schubert 		err = 1;
960780fb4a2SCy Schubert 		goto out;
9615b9c547cSRui Paulo 	}
9625b9c547cSRui Paulo 
963*206b73d0SCy Schubert 	if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) {
964325151a3SRui Paulo 		/* set defaults for backwards compatibility */
965*206b73d0SCy Schubert 		hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0);
966*206b73d0SCy Schubert 		hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0);
967*206b73d0SCy Schubert 		hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT);
968325151a3SRui Paulo 		if (acs_res->ch_width == 80) {
969*206b73d0SCy Schubert 			hostapd_set_oper_centr_freq_seg0_idx(
970*206b73d0SCy Schubert 				hapd->iconf, acs_res->vht_seg0_center_ch);
971*206b73d0SCy Schubert 			hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ);
972325151a3SRui Paulo 		} else if (acs_res->ch_width == 160) {
973325151a3SRui Paulo 			if (acs_res->vht_seg1_center_ch == 0) {
974*206b73d0SCy Schubert 				hostapd_set_oper_centr_freq_seg0_idx(
975*206b73d0SCy Schubert 					hapd->iconf,
976*206b73d0SCy Schubert 					acs_res->vht_seg0_center_ch);
977*206b73d0SCy Schubert 				hostapd_set_oper_chwidth(hapd->iconf,
978*206b73d0SCy Schubert 							 CHANWIDTH_160MHZ);
979325151a3SRui Paulo 			} else {
980*206b73d0SCy Schubert 				hostapd_set_oper_centr_freq_seg0_idx(
981*206b73d0SCy Schubert 					hapd->iconf,
982*206b73d0SCy Schubert 					acs_res->vht_seg0_center_ch);
983*206b73d0SCy Schubert 				hostapd_set_oper_centr_freq_seg1_idx(
984*206b73d0SCy Schubert 					hapd->iconf,
985*206b73d0SCy Schubert 					acs_res->vht_seg1_center_ch);
986*206b73d0SCy Schubert 				hostapd_set_oper_chwidth(hapd->iconf,
987*206b73d0SCy Schubert 							 CHANWIDTH_80P80MHZ);
988325151a3SRui Paulo 			}
989325151a3SRui Paulo 		}
990325151a3SRui Paulo 	}
991325151a3SRui Paulo 
992780fb4a2SCy Schubert out:
993780fb4a2SCy Schubert 	ret = hostapd_acs_completed(hapd->iface, err);
9945b9c547cSRui Paulo 	if (ret) {
9955b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
9965b9c547cSRui Paulo 			   "ACS: Possibly channel configuration is invalid");
9975b9c547cSRui Paulo 	}
9985b9c547cSRui Paulo }
9995b9c547cSRui Paulo #endif /* CONFIG_ACS */
10005b9c547cSRui Paulo 
10015b9c547cSRui Paulo 
1002f05cddf9SRui Paulo int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
1003f05cddf9SRui Paulo 			 const u8 *bssid, const u8 *ie, size_t ie_len,
1004f05cddf9SRui Paulo 			 int ssi_signal)
1005f05cddf9SRui Paulo {
1006f05cddf9SRui Paulo 	size_t i;
1007f05cddf9SRui Paulo 	int ret = 0;
1008f05cddf9SRui Paulo 
1009f05cddf9SRui Paulo 	if (sa == NULL || ie == NULL)
1010f05cddf9SRui Paulo 		return -1;
1011f05cddf9SRui Paulo 
1012f05cddf9SRui Paulo 	random_add_randomness(sa, ETH_ALEN);
1013f05cddf9SRui Paulo 	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
1014f05cddf9SRui Paulo 		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
1015f05cddf9SRui Paulo 					    sa, da, bssid, ie, ie_len,
1016f05cddf9SRui Paulo 					    ssi_signal) > 0) {
1017f05cddf9SRui Paulo 			ret = 1;
1018f05cddf9SRui Paulo 			break;
1019f05cddf9SRui Paulo 		}
1020f05cddf9SRui Paulo 	}
1021f05cddf9SRui Paulo 	return ret;
1022f05cddf9SRui Paulo }
1023f05cddf9SRui Paulo 
1024f05cddf9SRui Paulo 
1025e28a4053SRui Paulo #ifdef HOSTAPD
1026e28a4053SRui Paulo 
102785732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
1028f05cddf9SRui Paulo static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
1029f05cddf9SRui Paulo 					  const u8 *bssid,
1030f05cddf9SRui Paulo 					  u16 auth_transaction, u16 status,
1031f05cddf9SRui Paulo 					  const u8 *ies, size_t ies_len)
1032e28a4053SRui Paulo {
1033f05cddf9SRui Paulo 	struct hostapd_data *hapd = ctx;
1034f05cddf9SRui Paulo 	struct sta_info *sta;
1035e28a4053SRui Paulo 
1036f05cddf9SRui Paulo 	sta = ap_get_sta(hapd, dst);
1037f05cddf9SRui Paulo 	if (sta == NULL)
1038f05cddf9SRui Paulo 		return;
1039e28a4053SRui Paulo 
1040f05cddf9SRui Paulo 	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
1041f05cddf9SRui Paulo 		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
1042f05cddf9SRui Paulo 	sta->flags |= WLAN_STA_AUTH;
1043e28a4053SRui Paulo 
1044f05cddf9SRui Paulo 	hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
1045e28a4053SRui Paulo }
104685732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
104785732ac8SCy Schubert 
104885732ac8SCy Schubert 
104985732ac8SCy Schubert #ifdef CONFIG_FILS
105085732ac8SCy Schubert static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd,
105185732ac8SCy Schubert 					    struct sta_info *sta, u16 resp,
105285732ac8SCy Schubert 					    struct wpabuf *data, int pub)
105385732ac8SCy Schubert {
105485732ac8SCy Schubert 	if (resp == WLAN_STATUS_SUCCESS) {
105585732ac8SCy Schubert 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
105685732ac8SCy Schubert 			       HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)");
105785732ac8SCy Schubert 		sta->flags |= WLAN_STA_AUTH;
105885732ac8SCy Schubert 		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
105985732ac8SCy Schubert 		sta->auth_alg = WLAN_AUTH_FILS_SK;
106085732ac8SCy Schubert 		mlme_authenticate_indication(hapd, sta);
106185732ac8SCy Schubert 	} else {
106285732ac8SCy Schubert 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
106385732ac8SCy Schubert 			       HOSTAPD_LEVEL_DEBUG,
106485732ac8SCy Schubert 			       "authentication failed (FILS)");
106585732ac8SCy Schubert 	}
106685732ac8SCy Schubert 
106785732ac8SCy Schubert 	hostapd_sta_auth(hapd, sta->addr, 2, resp,
106885732ac8SCy Schubert 			 data ? wpabuf_head(data) : NULL,
106985732ac8SCy Schubert 			 data ? wpabuf_len(data) : 0);
107085732ac8SCy Schubert 	wpabuf_free(data);
107185732ac8SCy Schubert }
107285732ac8SCy Schubert #endif /* CONFIG_FILS */
1073f05cddf9SRui Paulo 
1074f05cddf9SRui Paulo 
1075f05cddf9SRui Paulo static void hostapd_notif_auth(struct hostapd_data *hapd,
1076f05cddf9SRui Paulo 			       struct auth_info *rx_auth)
1077f05cddf9SRui Paulo {
1078f05cddf9SRui Paulo 	struct sta_info *sta;
1079f05cddf9SRui Paulo 	u16 status = WLAN_STATUS_SUCCESS;
1080f05cddf9SRui Paulo 	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
1081f05cddf9SRui Paulo 	size_t resp_ies_len = 0;
1082f05cddf9SRui Paulo 
1083f05cddf9SRui Paulo 	sta = ap_get_sta(hapd, rx_auth->peer);
1084f05cddf9SRui Paulo 	if (!sta) {
1085f05cddf9SRui Paulo 		sta = ap_sta_add(hapd, rx_auth->peer);
1086f05cddf9SRui Paulo 		if (sta == NULL) {
10875b9c547cSRui Paulo 			status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
1088f05cddf9SRui Paulo 			goto fail;
1089e28a4053SRui Paulo 		}
1090e28a4053SRui Paulo 	}
1091f05cddf9SRui Paulo 	sta->flags &= ~WLAN_STA_PREAUTH;
1092f05cddf9SRui Paulo 	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
109385732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
1094f05cddf9SRui Paulo 	if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
1095f05cddf9SRui Paulo 		sta->auth_alg = WLAN_AUTH_FT;
1096f05cddf9SRui Paulo 		if (sta->wpa_sm == NULL)
1097f05cddf9SRui Paulo 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
10985b9c547cSRui Paulo 							sta->addr, NULL);
1099f05cddf9SRui Paulo 		if (sta->wpa_sm == NULL) {
1100325151a3SRui Paulo 			wpa_printf(MSG_DEBUG,
1101325151a3SRui Paulo 				   "FT: Failed to initialize WPA state machine");
1102f05cddf9SRui Paulo 			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1103f05cddf9SRui Paulo 			goto fail;
1104f05cddf9SRui Paulo 		}
1105f05cddf9SRui Paulo 		wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
1106f05cddf9SRui Paulo 				    rx_auth->auth_transaction, rx_auth->ies,
1107f05cddf9SRui Paulo 				    rx_auth->ies_len,
1108f05cddf9SRui Paulo 				    hostapd_notify_auth_ft_finish, hapd);
1109f05cddf9SRui Paulo 		return;
1110f05cddf9SRui Paulo 	}
111185732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
111285732ac8SCy Schubert 
111385732ac8SCy Schubert #ifdef CONFIG_FILS
111485732ac8SCy Schubert 	if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) {
111585732ac8SCy Schubert 		sta->auth_alg = WLAN_AUTH_FILS_SK;
111685732ac8SCy Schubert 		handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len,
111785732ac8SCy Schubert 				 rx_auth->auth_type, rx_auth->auth_transaction,
111885732ac8SCy Schubert 				 rx_auth->status_code,
111985732ac8SCy Schubert 				 hostapd_notify_auth_fils_finish);
112085732ac8SCy Schubert 		return;
112185732ac8SCy Schubert 	}
112285732ac8SCy Schubert #endif /* CONFIG_FILS */
112385732ac8SCy Schubert 
1124f05cddf9SRui Paulo fail:
1125f05cddf9SRui Paulo 	hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
1126f05cddf9SRui Paulo 			 status, resp_ies, resp_ies_len);
1127f05cddf9SRui Paulo }
1128e28a4053SRui Paulo 
1129e28a4053SRui Paulo 
11304bc52338SCy Schubert #ifndef NEED_AP_MLME
1131f05cddf9SRui Paulo static void hostapd_action_rx(struct hostapd_data *hapd,
11325b9c547cSRui Paulo 			      struct rx_mgmt *drv_mgmt)
1133f05cddf9SRui Paulo {
11345b9c547cSRui Paulo 	struct ieee80211_mgmt *mgmt;
1135f05cddf9SRui Paulo 	struct sta_info *sta;
11365b9c547cSRui Paulo 	size_t plen __maybe_unused;
11375b9c547cSRui Paulo 	u16 fc;
113885732ac8SCy Schubert 	u8 *action __maybe_unused;
11395b9c547cSRui Paulo 
114085732ac8SCy Schubert 	if (drv_mgmt->frame_len < IEEE80211_HDRLEN + 2 + 1)
11415b9c547cSRui Paulo 		return;
11425b9c547cSRui Paulo 
11434bc52338SCy Schubert 	plen = drv_mgmt->frame_len - IEEE80211_HDRLEN;
11445b9c547cSRui Paulo 
11455b9c547cSRui Paulo 	mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
11465b9c547cSRui Paulo 	fc = le_to_host16(mgmt->frame_control);
11475b9c547cSRui Paulo 	if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
11485b9c547cSRui Paulo 		return; /* handled by the driver */
1149f05cddf9SRui Paulo 
115085732ac8SCy Schubert 	action = (u8 *) &mgmt->u.action.u;
115185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "RX_ACTION category %u action %u sa " MACSTR
115285732ac8SCy Schubert 		   " da " MACSTR " plen %d",
115385732ac8SCy Schubert 		   mgmt->u.action.category, *action,
115485732ac8SCy Schubert 		   MAC2STR(mgmt->sa), MAC2STR(mgmt->da), (int) plen);
1155f05cddf9SRui Paulo 
11565b9c547cSRui Paulo 	sta = ap_get_sta(hapd, mgmt->sa);
1157f05cddf9SRui Paulo 	if (sta == NULL) {
1158f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
1159f05cddf9SRui Paulo 		return;
1160f05cddf9SRui Paulo 	}
116185732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
11625b9c547cSRui Paulo 	if (mgmt->u.action.category == WLAN_ACTION_FT) {
11634bc52338SCy Schubert 		wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, plen);
11644bc52338SCy Schubert 		return;
1165f05cddf9SRui Paulo 	}
116685732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
1167f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W
11684bc52338SCy Schubert 	if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY) {
11694bc52338SCy Schubert 		ieee802_11_sa_query_action(hapd, mgmt, drv_mgmt->frame_len);
11704bc52338SCy Schubert 		return;
1171f05cddf9SRui Paulo 	}
1172f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */
117385732ac8SCy Schubert #ifdef CONFIG_WNM_AP
11745b9c547cSRui Paulo 	if (mgmt->u.action.category == WLAN_ACTION_WNM) {
11755b9c547cSRui Paulo 		ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
11764bc52338SCy Schubert 		return;
1177f05cddf9SRui Paulo 	}
117885732ac8SCy Schubert #endif /* CONFIG_WNM_AP */
1179325151a3SRui Paulo #ifdef CONFIG_FST
1180325151a3SRui Paulo 	if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
1181325151a3SRui Paulo 		fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
1182325151a3SRui Paulo 		return;
1183325151a3SRui Paulo 	}
1184325151a3SRui Paulo #endif /* CONFIG_FST */
118585732ac8SCy Schubert #ifdef CONFIG_DPP
11864bc52338SCy Schubert 	if (plen >= 2 + 4 &&
118785732ac8SCy Schubert 	    mgmt->u.action.u.vs_public_action.action ==
118885732ac8SCy Schubert 	    WLAN_PA_VENDOR_SPECIFIC &&
118985732ac8SCy Schubert 	    WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) ==
119085732ac8SCy Schubert 	    OUI_WFA &&
119185732ac8SCy Schubert 	    mgmt->u.action.u.vs_public_action.variable[0] ==
119285732ac8SCy Schubert 	    DPP_OUI_TYPE) {
119385732ac8SCy Schubert 		const u8 *pos, *end;
1194325151a3SRui Paulo 
119585732ac8SCy Schubert 		pos = mgmt->u.action.u.vs_public_action.oui;
119685732ac8SCy Schubert 		end = drv_mgmt->frame + drv_mgmt->frame_len;
119785732ac8SCy Schubert 		hostapd_dpp_rx_action(hapd, mgmt->sa, pos, end - pos,
119885732ac8SCy Schubert 				      drv_mgmt->freq);
119985732ac8SCy Schubert 		return;
120085732ac8SCy Schubert 	}
120185732ac8SCy Schubert #endif /* CONFIG_DPP */
1202f05cddf9SRui Paulo }
12034bc52338SCy Schubert #endif /* NEED_AP_MLME */
1204f05cddf9SRui Paulo 
1205f05cddf9SRui Paulo 
1206f05cddf9SRui Paulo #ifdef NEED_AP_MLME
1207f05cddf9SRui Paulo 
1208e28a4053SRui Paulo #define HAPD_BROADCAST ((struct hostapd_data *) -1)
1209e28a4053SRui Paulo 
1210e28a4053SRui Paulo static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
1211e28a4053SRui Paulo 					    const u8 *bssid)
1212e28a4053SRui Paulo {
1213e28a4053SRui Paulo 	size_t i;
1214e28a4053SRui Paulo 
1215e28a4053SRui Paulo 	if (bssid == NULL)
1216e28a4053SRui Paulo 		return NULL;
1217e28a4053SRui Paulo 	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
1218e28a4053SRui Paulo 	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
1219e28a4053SRui Paulo 		return HAPD_BROADCAST;
1220e28a4053SRui Paulo 
1221e28a4053SRui Paulo 	for (i = 0; i < iface->num_bss; i++) {
1222e28a4053SRui Paulo 		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
1223e28a4053SRui Paulo 			return iface->bss[i];
1224e28a4053SRui Paulo 	}
1225e28a4053SRui Paulo 
1226e28a4053SRui Paulo 	return NULL;
1227e28a4053SRui Paulo }
1228e28a4053SRui Paulo 
1229e28a4053SRui Paulo 
1230e28a4053SRui Paulo static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
1231f05cddf9SRui Paulo 					const u8 *bssid, const u8 *addr,
1232f05cddf9SRui Paulo 					int wds)
1233e28a4053SRui Paulo {
1234f05cddf9SRui Paulo 	hapd = get_hapd_bssid(hapd->iface, bssid);
1235e28a4053SRui Paulo 	if (hapd == NULL || hapd == HAPD_BROADCAST)
1236e28a4053SRui Paulo 		return;
1237e28a4053SRui Paulo 
1238f05cddf9SRui Paulo 	ieee802_11_rx_from_unknown(hapd, addr, wds);
1239e28a4053SRui Paulo }
1240e28a4053SRui Paulo 
1241e28a4053SRui Paulo 
12425b9c547cSRui Paulo static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
1243e28a4053SRui Paulo {
1244e28a4053SRui Paulo 	struct hostapd_iface *iface = hapd->iface;
1245e28a4053SRui Paulo 	const struct ieee80211_hdr *hdr;
1246e28a4053SRui Paulo 	const u8 *bssid;
1247e28a4053SRui Paulo 	struct hostapd_frame_info fi;
12485b9c547cSRui Paulo 	int ret;
12495b9c547cSRui Paulo 
12505b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
12515b9c547cSRui Paulo 	if (hapd->ext_mgmt_frame_handling) {
12525b9c547cSRui Paulo 		size_t hex_len = 2 * rx_mgmt->frame_len + 1;
12535b9c547cSRui Paulo 		char *hex = os_malloc(hex_len);
1254325151a3SRui Paulo 
12555b9c547cSRui Paulo 		if (hex) {
12565b9c547cSRui Paulo 			wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
12575b9c547cSRui Paulo 					 rx_mgmt->frame_len);
12585b9c547cSRui Paulo 			wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
12595b9c547cSRui Paulo 			os_free(hex);
12605b9c547cSRui Paulo 		}
12615b9c547cSRui Paulo 		return 1;
12625b9c547cSRui Paulo 	}
12635b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
1264e28a4053SRui Paulo 
1265e28a4053SRui Paulo 	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
1266e28a4053SRui Paulo 	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
1267e28a4053SRui Paulo 	if (bssid == NULL)
12685b9c547cSRui Paulo 		return 0;
1269e28a4053SRui Paulo 
1270e28a4053SRui Paulo 	hapd = get_hapd_bssid(iface, bssid);
1271e28a4053SRui Paulo 	if (hapd == NULL) {
1272325151a3SRui Paulo 		u16 fc = le_to_host16(hdr->frame_control);
1273e28a4053SRui Paulo 
1274e28a4053SRui Paulo 		/*
1275e28a4053SRui Paulo 		 * Drop frames to unknown BSSIDs except for Beacon frames which
1276e28a4053SRui Paulo 		 * could be used to update neighbor information.
1277e28a4053SRui Paulo 		 */
1278e28a4053SRui Paulo 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
1279e28a4053SRui Paulo 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
1280e28a4053SRui Paulo 			hapd = iface->bss[0];
1281e28a4053SRui Paulo 		else
12825b9c547cSRui Paulo 			return 0;
1283e28a4053SRui Paulo 	}
1284e28a4053SRui Paulo 
1285e28a4053SRui Paulo 	os_memset(&fi, 0, sizeof(fi));
128685732ac8SCy Schubert 	fi.freq = rx_mgmt->freq;
1287e28a4053SRui Paulo 	fi.datarate = rx_mgmt->datarate;
1288e28a4053SRui Paulo 	fi.ssi_signal = rx_mgmt->ssi_signal;
1289e28a4053SRui Paulo 
1290e28a4053SRui Paulo 	if (hapd == HAPD_BROADCAST) {
1291e28a4053SRui Paulo 		size_t i;
1292325151a3SRui Paulo 
12935b9c547cSRui Paulo 		ret = 0;
12945b9c547cSRui Paulo 		for (i = 0; i < iface->num_bss; i++) {
12955b9c547cSRui Paulo 			/* if bss is set, driver will call this function for
12965b9c547cSRui Paulo 			 * each bss individually. */
12975b9c547cSRui Paulo 			if (rx_mgmt->drv_priv &&
12985b9c547cSRui Paulo 			    (iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
12995b9c547cSRui Paulo 				continue;
13005b9c547cSRui Paulo 
13015b9c547cSRui Paulo 			if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
13025b9c547cSRui Paulo 					    rx_mgmt->frame_len, &fi) > 0)
13035b9c547cSRui Paulo 				ret = 1;
13045b9c547cSRui Paulo 		}
1305e28a4053SRui Paulo 	} else
13065b9c547cSRui Paulo 		ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
13075b9c547cSRui Paulo 				      &fi);
1308f05cddf9SRui Paulo 
1309f05cddf9SRui Paulo 	random_add_randomness(&fi, sizeof(fi));
1310f05cddf9SRui Paulo 
13115b9c547cSRui Paulo 	return ret;
1312e28a4053SRui Paulo }
1313e28a4053SRui Paulo 
1314e28a4053SRui Paulo 
1315e28a4053SRui Paulo static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
1316e28a4053SRui Paulo 			       size_t len, u16 stype, int ok)
1317e28a4053SRui Paulo {
1318e28a4053SRui Paulo 	struct ieee80211_hdr *hdr;
1319780fb4a2SCy Schubert 	struct hostapd_data *orig_hapd = hapd;
1320325151a3SRui Paulo 
1321e28a4053SRui Paulo 	hdr = (struct ieee80211_hdr *) buf;
1322e28a4053SRui Paulo 	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
1323780fb4a2SCy Schubert 	if (!hapd)
1324e28a4053SRui Paulo 		return;
1325780fb4a2SCy Schubert 	if (hapd == HAPD_BROADCAST) {
1326780fb4a2SCy Schubert 		if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
1327780fb4a2SCy Schubert 		    buf[24] != WLAN_ACTION_PUBLIC)
1328780fb4a2SCy Schubert 			return;
1329780fb4a2SCy Schubert 		hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
1330780fb4a2SCy Schubert 		if (!hapd || hapd == HAPD_BROADCAST)
1331780fb4a2SCy Schubert 			return;
1332780fb4a2SCy Schubert 		/*
1333780fb4a2SCy Schubert 		 * Allow processing of TX status for a Public Action frame that
1334780fb4a2SCy Schubert 		 * used wildcard BBSID.
1335780fb4a2SCy Schubert 		 */
1336780fb4a2SCy Schubert 	}
1337e28a4053SRui Paulo 	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
1338e28a4053SRui Paulo }
1339e28a4053SRui Paulo 
1340e28a4053SRui Paulo #endif /* NEED_AP_MLME */
1341e28a4053SRui Paulo 
1342e28a4053SRui Paulo 
1343e28a4053SRui Paulo static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
1344e28a4053SRui Paulo {
1345e28a4053SRui Paulo 	struct sta_info *sta = ap_get_sta(hapd, addr);
1346325151a3SRui Paulo 
1347e28a4053SRui Paulo 	if (sta)
1348e28a4053SRui Paulo 		return 0;
1349e28a4053SRui Paulo 
1350e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
1351e28a4053SRui Paulo 		   " - adding a new STA", MAC2STR(addr));
1352e28a4053SRui Paulo 	sta = ap_sta_add(hapd, addr);
1353e28a4053SRui Paulo 	if (sta) {
1354e28a4053SRui Paulo 		hostapd_new_assoc_sta(hapd, sta, 0);
1355e28a4053SRui Paulo 	} else {
1356e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
1357e28a4053SRui Paulo 			   MAC2STR(addr));
1358e28a4053SRui Paulo 		return -1;
1359e28a4053SRui Paulo 	}
1360e28a4053SRui Paulo 
1361e28a4053SRui Paulo 	return 0;
1362e28a4053SRui Paulo }
1363e28a4053SRui Paulo 
1364e28a4053SRui Paulo 
1365e28a4053SRui Paulo static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
1366e28a4053SRui Paulo 				   const u8 *data, size_t data_len)
1367e28a4053SRui Paulo {
1368e28a4053SRui Paulo 	struct hostapd_iface *iface = hapd->iface;
1369f05cddf9SRui Paulo 	struct sta_info *sta;
1370e28a4053SRui Paulo 	size_t j;
1371e28a4053SRui Paulo 
1372e28a4053SRui Paulo 	for (j = 0; j < iface->num_bss; j++) {
1373325151a3SRui Paulo 		sta = ap_get_sta(iface->bss[j], src);
1374325151a3SRui Paulo 		if (sta && sta->flags & WLAN_STA_ASSOC) {
1375e28a4053SRui Paulo 			hapd = iface->bss[j];
1376e28a4053SRui Paulo 			break;
1377e28a4053SRui Paulo 		}
1378e28a4053SRui Paulo 	}
1379e28a4053SRui Paulo 
1380e28a4053SRui Paulo 	ieee802_1x_receive(hapd, src, data, data_len);
1381e28a4053SRui Paulo }
1382e28a4053SRui Paulo 
1383780fb4a2SCy Schubert #endif /* HOSTAPD */
1384780fb4a2SCy Schubert 
1385e28a4053SRui Paulo 
13865b9c547cSRui Paulo static struct hostapd_channel_data * hostapd_get_mode_channel(
13875b9c547cSRui Paulo 	struct hostapd_iface *iface, unsigned int freq)
13885b9c547cSRui Paulo {
13895b9c547cSRui Paulo 	int i;
13905b9c547cSRui Paulo 	struct hostapd_channel_data *chan;
13915b9c547cSRui Paulo 
13925b9c547cSRui Paulo 	for (i = 0; i < iface->current_mode->num_channels; i++) {
13935b9c547cSRui Paulo 		chan = &iface->current_mode->channels[i];
13945b9c547cSRui Paulo 		if ((unsigned int) chan->freq == freq)
13955b9c547cSRui Paulo 			return chan;
13965b9c547cSRui Paulo 	}
13975b9c547cSRui Paulo 
13985b9c547cSRui Paulo 	return NULL;
13995b9c547cSRui Paulo }
14005b9c547cSRui Paulo 
14015b9c547cSRui Paulo 
14025b9c547cSRui Paulo static void hostapd_update_nf(struct hostapd_iface *iface,
14035b9c547cSRui Paulo 			      struct hostapd_channel_data *chan,
14045b9c547cSRui Paulo 			      struct freq_survey *survey)
14055b9c547cSRui Paulo {
14065b9c547cSRui Paulo 	if (!iface->chans_surveyed) {
14075b9c547cSRui Paulo 		chan->min_nf = survey->nf;
14085b9c547cSRui Paulo 		iface->lowest_nf = survey->nf;
14095b9c547cSRui Paulo 	} else {
14105b9c547cSRui Paulo 		if (dl_list_empty(&chan->survey_list))
14115b9c547cSRui Paulo 			chan->min_nf = survey->nf;
14125b9c547cSRui Paulo 		else if (survey->nf < chan->min_nf)
14135b9c547cSRui Paulo 			chan->min_nf = survey->nf;
14145b9c547cSRui Paulo 		if (survey->nf < iface->lowest_nf)
14155b9c547cSRui Paulo 			iface->lowest_nf = survey->nf;
14165b9c547cSRui Paulo 	}
14175b9c547cSRui Paulo }
14185b9c547cSRui Paulo 
14195b9c547cSRui Paulo 
14205b9c547cSRui Paulo static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
14215b9c547cSRui Paulo 					      struct survey_results *survey_res)
14225b9c547cSRui Paulo {
14235b9c547cSRui Paulo 	struct hostapd_channel_data *chan;
14245b9c547cSRui Paulo 	struct freq_survey *survey;
14255b9c547cSRui Paulo 	u64 divisor, dividend;
14265b9c547cSRui Paulo 
14275b9c547cSRui Paulo 	survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
14285b9c547cSRui Paulo 			       list);
14295b9c547cSRui Paulo 	if (!survey || !survey->freq)
14305b9c547cSRui Paulo 		return;
14315b9c547cSRui Paulo 
14325b9c547cSRui Paulo 	chan = hostapd_get_mode_channel(iface, survey->freq);
14335b9c547cSRui Paulo 	if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
14345b9c547cSRui Paulo 		return;
14355b9c547cSRui Paulo 
1436325151a3SRui Paulo 	wpa_printf(MSG_DEBUG,
1437325151a3SRui Paulo 		   "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
14385b9c547cSRui Paulo 		   survey->freq,
14395b9c547cSRui Paulo 		   (unsigned long int) survey->channel_time,
14405b9c547cSRui Paulo 		   (unsigned long int) survey->channel_time_busy);
14415b9c547cSRui Paulo 
14425b9c547cSRui Paulo 	if (survey->channel_time > iface->last_channel_time &&
14435b9c547cSRui Paulo 	    survey->channel_time > survey->channel_time_busy) {
14445b9c547cSRui Paulo 		dividend = survey->channel_time_busy -
14455b9c547cSRui Paulo 			iface->last_channel_time_busy;
14465b9c547cSRui Paulo 		divisor = survey->channel_time - iface->last_channel_time;
14475b9c547cSRui Paulo 
14485b9c547cSRui Paulo 		iface->channel_utilization = dividend * 255 / divisor;
14495b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
14505b9c547cSRui Paulo 			   iface->channel_utilization);
14515b9c547cSRui Paulo 	}
14525b9c547cSRui Paulo 	iface->last_channel_time = survey->channel_time;
14535b9c547cSRui Paulo 	iface->last_channel_time_busy = survey->channel_time_busy;
14545b9c547cSRui Paulo }
14555b9c547cSRui Paulo 
14565b9c547cSRui Paulo 
1457780fb4a2SCy Schubert void hostapd_event_get_survey(struct hostapd_iface *iface,
14585b9c547cSRui Paulo 			      struct survey_results *survey_results)
14595b9c547cSRui Paulo {
14605b9c547cSRui Paulo 	struct freq_survey *survey, *tmp;
14615b9c547cSRui Paulo 	struct hostapd_channel_data *chan;
14625b9c547cSRui Paulo 
14635b9c547cSRui Paulo 	if (dl_list_empty(&survey_results->survey_list)) {
14645b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "No survey data received");
14655b9c547cSRui Paulo 		return;
14665b9c547cSRui Paulo 	}
14675b9c547cSRui Paulo 
14685b9c547cSRui Paulo 	if (survey_results->freq_filter) {
14695b9c547cSRui Paulo 		hostapd_single_channel_get_survey(iface, survey_results);
14705b9c547cSRui Paulo 		return;
14715b9c547cSRui Paulo 	}
14725b9c547cSRui Paulo 
14735b9c547cSRui Paulo 	dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
14745b9c547cSRui Paulo 			      struct freq_survey, list) {
14755b9c547cSRui Paulo 		chan = hostapd_get_mode_channel(iface, survey->freq);
14765b9c547cSRui Paulo 		if (!chan)
14775b9c547cSRui Paulo 			continue;
14785b9c547cSRui Paulo 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
14795b9c547cSRui Paulo 			continue;
14805b9c547cSRui Paulo 
14815b9c547cSRui Paulo 		dl_list_del(&survey->list);
14825b9c547cSRui Paulo 		dl_list_add_tail(&chan->survey_list, &survey->list);
14835b9c547cSRui Paulo 
14845b9c547cSRui Paulo 		hostapd_update_nf(iface, chan, survey);
14855b9c547cSRui Paulo 
14865b9c547cSRui Paulo 		iface->chans_surveyed++;
14875b9c547cSRui Paulo 	}
14885b9c547cSRui Paulo }
14895b9c547cSRui Paulo 
14905b9c547cSRui Paulo 
1491780fb4a2SCy Schubert #ifdef HOSTAPD
14925b9c547cSRui Paulo #ifdef NEED_AP_MLME
14935b9c547cSRui Paulo 
14945b9c547cSRui Paulo static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
14955b9c547cSRui Paulo {
14965b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
14975b9c547cSRui Paulo 		   hapd->conf->iface);
14985b9c547cSRui Paulo 
14995b9c547cSRui Paulo 	if (hapd->csa_in_progress) {
15005b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
15015b9c547cSRui Paulo 			   hapd->conf->iface);
15025b9c547cSRui Paulo 		hostapd_switch_channel_fallback(hapd->iface,
15035b9c547cSRui Paulo 						&hapd->cs_freq_params);
15045b9c547cSRui Paulo 	}
15055b9c547cSRui Paulo }
15065b9c547cSRui Paulo 
15075b9c547cSRui Paulo 
15085b9c547cSRui Paulo static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
15095b9c547cSRui Paulo 					     struct dfs_event *radar)
15105b9c547cSRui Paulo {
15115b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
15125b9c547cSRui Paulo 	hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
15135b9c547cSRui Paulo 				   radar->chan_offset, radar->chan_width,
15145b9c547cSRui Paulo 				   radar->cf1, radar->cf2);
15155b9c547cSRui Paulo }
15165b9c547cSRui Paulo 
15175b9c547cSRui Paulo 
151885732ac8SCy Schubert static void hostapd_event_dfs_pre_cac_expired(struct hostapd_data *hapd,
151985732ac8SCy Schubert 					      struct dfs_event *radar)
152085732ac8SCy Schubert {
152185732ac8SCy Schubert 	wpa_printf(MSG_DEBUG, "DFS Pre-CAC expired on %d MHz", radar->freq);
152285732ac8SCy Schubert 	hostapd_dfs_pre_cac_expired(hapd->iface, radar->freq, radar->ht_enabled,
152385732ac8SCy Schubert 				    radar->chan_offset, radar->chan_width,
152485732ac8SCy Schubert 				    radar->cf1, radar->cf2);
152585732ac8SCy Schubert }
152685732ac8SCy Schubert 
152785732ac8SCy Schubert 
15285b9c547cSRui Paulo static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
15295b9c547cSRui Paulo 					   struct dfs_event *radar)
15305b9c547cSRui Paulo {
15315b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
15325b9c547cSRui Paulo 	hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
15335b9c547cSRui Paulo 				 radar->chan_offset, radar->chan_width,
15345b9c547cSRui Paulo 				 radar->cf1, radar->cf2);
15355b9c547cSRui Paulo }
15365b9c547cSRui Paulo 
15375b9c547cSRui Paulo 
15385b9c547cSRui Paulo static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
15395b9c547cSRui Paulo 					  struct dfs_event *radar)
15405b9c547cSRui Paulo {
15415b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
15425b9c547cSRui Paulo 	hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
15435b9c547cSRui Paulo 				 radar->chan_offset, radar->chan_width,
15445b9c547cSRui Paulo 				 radar->cf1, radar->cf2);
15455b9c547cSRui Paulo }
15465b9c547cSRui Paulo 
15475b9c547cSRui Paulo 
15485b9c547cSRui Paulo static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
15495b9c547cSRui Paulo 					   struct dfs_event *radar)
15505b9c547cSRui Paulo {
15515b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
15525b9c547cSRui Paulo 	hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
15535b9c547cSRui Paulo 				 radar->chan_offset, radar->chan_width,
15545b9c547cSRui Paulo 				 radar->cf1, radar->cf2);
15555b9c547cSRui Paulo }
15565b9c547cSRui Paulo 
15575b9c547cSRui Paulo 
15585b9c547cSRui Paulo static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
15595b9c547cSRui Paulo 					  struct dfs_event *radar)
15605b9c547cSRui Paulo {
15615b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
15625b9c547cSRui Paulo 	hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
15635b9c547cSRui Paulo 			      radar->chan_offset, radar->chan_width,
15645b9c547cSRui Paulo 			      radar->cf1, radar->cf2);
15655b9c547cSRui Paulo }
15665b9c547cSRui Paulo 
15675b9c547cSRui Paulo #endif /* NEED_AP_MLME */
15685b9c547cSRui Paulo 
15695b9c547cSRui Paulo 
157085732ac8SCy Schubert static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
157185732ac8SCy Schubert 						   int istatus,
157285732ac8SCy Schubert 						   const char *ifname,
157385732ac8SCy Schubert 						   const u8 *addr)
157485732ac8SCy Schubert {
157585732ac8SCy Schubert 	struct sta_info *sta = ap_get_sta(hapd, addr);
157685732ac8SCy Schubert 
157785732ac8SCy Schubert 	if (sta) {
157885732ac8SCy Schubert 		os_free(sta->ifname_wds);
157985732ac8SCy Schubert 		if (istatus == INTERFACE_ADDED)
158085732ac8SCy Schubert 			sta->ifname_wds = os_strdup(ifname);
158185732ac8SCy Schubert 		else
158285732ac8SCy Schubert 			sta->ifname_wds = NULL;
158385732ac8SCy Schubert 	}
158485732ac8SCy Schubert 
158585732ac8SCy Schubert 	wpa_msg(hapd->msg_ctx, MSG_INFO, "%sifname=%s sta_addr=" MACSTR,
158685732ac8SCy Schubert 		istatus == INTERFACE_ADDED ?
158785732ac8SCy Schubert 		WDS_STA_INTERFACE_ADDED : WDS_STA_INTERFACE_REMOVED,
158885732ac8SCy Schubert 		ifname, MAC2STR(addr));
158985732ac8SCy Schubert }
159085732ac8SCy Schubert 
159185732ac8SCy Schubert 
1592*206b73d0SCy Schubert #ifdef CONFIG_OWE
1593*206b73d0SCy Schubert static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
1594*206b73d0SCy Schubert 				      const u8 *peer, const u8 *ie,
1595*206b73d0SCy Schubert 				      size_t ie_len)
1596*206b73d0SCy Schubert {
1597*206b73d0SCy Schubert 	u16 status;
1598*206b73d0SCy Schubert 	struct sta_info *sta;
1599*206b73d0SCy Schubert 	struct ieee802_11_elems elems;
1600*206b73d0SCy Schubert 
1601*206b73d0SCy Schubert 	if (!hapd || !hapd->wpa_auth) {
1602*206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
1603*206b73d0SCy Schubert 		return -1;
1604*206b73d0SCy Schubert 	}
1605*206b73d0SCy Schubert 	if (!peer) {
1606*206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
1607*206b73d0SCy Schubert 		return -1;
1608*206b73d0SCy Schubert 	}
1609*206b73d0SCy Schubert 	if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
1610*206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
1611*206b73d0SCy Schubert 		status = WLAN_STATUS_AKMP_NOT_VALID;
1612*206b73d0SCy Schubert 		goto err;
1613*206b73d0SCy Schubert 	}
1614*206b73d0SCy Schubert 	if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
1615*206b73d0SCy Schubert 		wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
1616*206b73d0SCy Schubert 			   MACSTR, MAC2STR(peer));
1617*206b73d0SCy Schubert 		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1618*206b73d0SCy Schubert 		goto err;
1619*206b73d0SCy Schubert 	}
1620*206b73d0SCy Schubert 	status = owe_validate_request(hapd, peer, elems.rsn_ie,
1621*206b73d0SCy Schubert 				      elems.rsn_ie_len,
1622*206b73d0SCy Schubert 				      elems.owe_dh, elems.owe_dh_len);
1623*206b73d0SCy Schubert 	if (status != WLAN_STATUS_SUCCESS)
1624*206b73d0SCy Schubert 		goto err;
1625*206b73d0SCy Schubert 
1626*206b73d0SCy Schubert 	sta = ap_get_sta(hapd, peer);
1627*206b73d0SCy Schubert 	if (sta) {
1628*206b73d0SCy Schubert 		ap_sta_no_session_timeout(hapd, sta);
1629*206b73d0SCy Schubert 		accounting_sta_stop(hapd, sta);
1630*206b73d0SCy Schubert 
1631*206b73d0SCy Schubert 		/*
1632*206b73d0SCy Schubert 		 * Make sure that the previously registered inactivity timer
1633*206b73d0SCy Schubert 		 * will not remove the STA immediately.
1634*206b73d0SCy Schubert 		 */
1635*206b73d0SCy Schubert 		sta->timeout_next = STA_NULLFUNC;
1636*206b73d0SCy Schubert 	} else {
1637*206b73d0SCy Schubert 		sta = ap_sta_add(hapd, peer);
1638*206b73d0SCy Schubert 		if (!sta) {
1639*206b73d0SCy Schubert 			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
1640*206b73d0SCy Schubert 			goto err;
1641*206b73d0SCy Schubert 		}
1642*206b73d0SCy Schubert 	}
1643*206b73d0SCy Schubert 	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
1644*206b73d0SCy Schubert 
1645*206b73d0SCy Schubert 	status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
1646*206b73d0SCy Schubert 				    elems.rsn_ie_len, elems.owe_dh,
1647*206b73d0SCy Schubert 				    elems.owe_dh_len);
1648*206b73d0SCy Schubert 	if (status != WLAN_STATUS_SUCCESS)
1649*206b73d0SCy Schubert 		ap_free_sta(hapd, sta);
1650*206b73d0SCy Schubert 
1651*206b73d0SCy Schubert 	return 0;
1652*206b73d0SCy Schubert err:
1653*206b73d0SCy Schubert 	hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0);
1654*206b73d0SCy Schubert 	return 0;
1655*206b73d0SCy Schubert }
1656*206b73d0SCy Schubert #endif /* CONFIG_OWE */
1657*206b73d0SCy Schubert 
1658*206b73d0SCy Schubert 
1659e28a4053SRui Paulo void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
1660e28a4053SRui Paulo 			  union wpa_event_data *data)
1661e28a4053SRui Paulo {
1662e28a4053SRui Paulo 	struct hostapd_data *hapd = ctx;
1663f05cddf9SRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG
1664f05cddf9SRui Paulo 	int level = MSG_DEBUG;
1665f05cddf9SRui Paulo 
1666f05cddf9SRui Paulo 	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
1667f05cddf9SRui Paulo 	    data->rx_mgmt.frame_len >= 24) {
1668f05cddf9SRui Paulo 		const struct ieee80211_hdr *hdr;
1669f05cddf9SRui Paulo 		u16 fc;
1670325151a3SRui Paulo 
1671f05cddf9SRui Paulo 		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
1672f05cddf9SRui Paulo 		fc = le_to_host16(hdr->frame_control);
1673f05cddf9SRui Paulo 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
1674f05cddf9SRui Paulo 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
1675f05cddf9SRui Paulo 			level = MSG_EXCESSIVE;
16765b9c547cSRui Paulo 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
16775b9c547cSRui Paulo 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
16785b9c547cSRui Paulo 			level = MSG_EXCESSIVE;
1679f05cddf9SRui Paulo 	}
1680f05cddf9SRui Paulo 
1681f05cddf9SRui Paulo 	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
1682f05cddf9SRui Paulo 		event_to_string(event), event);
1683f05cddf9SRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */
1684e28a4053SRui Paulo 
1685e28a4053SRui Paulo 	switch (event) {
1686e28a4053SRui Paulo 	case EVENT_MICHAEL_MIC_FAILURE:
1687e28a4053SRui Paulo 		michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
1688e28a4053SRui Paulo 		break;
1689e28a4053SRui Paulo 	case EVENT_SCAN_RESULTS:
1690e28a4053SRui Paulo 		if (hapd->iface->scan_cb)
1691e28a4053SRui Paulo 			hapd->iface->scan_cb(hapd->iface);
1692e28a4053SRui Paulo 		break;
1693e28a4053SRui Paulo 	case EVENT_WPS_BUTTON_PUSHED:
1694f05cddf9SRui Paulo 		hostapd_wps_button_pushed(hapd, NULL);
1695e28a4053SRui Paulo 		break;
1696e28a4053SRui Paulo #ifdef NEED_AP_MLME
1697e28a4053SRui Paulo 	case EVENT_TX_STATUS:
1698e28a4053SRui Paulo 		switch (data->tx_status.type) {
1699e28a4053SRui Paulo 		case WLAN_FC_TYPE_MGMT:
1700e28a4053SRui Paulo 			hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
1701e28a4053SRui Paulo 					   data->tx_status.data_len,
1702e28a4053SRui Paulo 					   data->tx_status.stype,
1703e28a4053SRui Paulo 					   data->tx_status.ack);
1704e28a4053SRui Paulo 			break;
1705e28a4053SRui Paulo 		case WLAN_FC_TYPE_DATA:
1706e28a4053SRui Paulo 			hostapd_tx_status(hapd, data->tx_status.dst,
1707e28a4053SRui Paulo 					  data->tx_status.data,
1708e28a4053SRui Paulo 					  data->tx_status.data_len,
1709e28a4053SRui Paulo 					  data->tx_status.ack);
1710e28a4053SRui Paulo 			break;
1711e28a4053SRui Paulo 		}
1712e28a4053SRui Paulo 		break;
1713f05cddf9SRui Paulo 	case EVENT_EAPOL_TX_STATUS:
1714f05cddf9SRui Paulo 		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
1715f05cddf9SRui Paulo 					data->eapol_tx_status.data,
1716f05cddf9SRui Paulo 					data->eapol_tx_status.data_len,
1717f05cddf9SRui Paulo 					data->eapol_tx_status.ack);
1718f05cddf9SRui Paulo 		break;
1719f05cddf9SRui Paulo 	case EVENT_DRIVER_CLIENT_POLL_OK:
1720f05cddf9SRui Paulo 		hostapd_client_poll_ok(hapd, data->client_poll.addr);
1721f05cddf9SRui Paulo 		break;
1722e28a4053SRui Paulo 	case EVENT_RX_FROM_UNKNOWN:
1723f05cddf9SRui Paulo 		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
1724f05cddf9SRui Paulo 					    data->rx_from_unknown.addr,
1725f05cddf9SRui Paulo 					    data->rx_from_unknown.wds);
1726e28a4053SRui Paulo 		break;
17275b9c547cSRui Paulo #endif /* NEED_AP_MLME */
1728e28a4053SRui Paulo 	case EVENT_RX_MGMT:
17295b9c547cSRui Paulo 		if (!data->rx_mgmt.frame)
17305b9c547cSRui Paulo 			break;
17315b9c547cSRui Paulo #ifdef NEED_AP_MLME
17324bc52338SCy Schubert 		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
17334bc52338SCy Schubert #else /* NEED_AP_MLME */
17345b9c547cSRui Paulo 		hostapd_action_rx(hapd, &data->rx_mgmt);
17354bc52338SCy Schubert #endif /* NEED_AP_MLME */
17365b9c547cSRui Paulo 		break;
1737e28a4053SRui Paulo 	case EVENT_RX_PROBE_REQ:
1738f05cddf9SRui Paulo 		if (data->rx_probe_req.sa == NULL ||
1739f05cddf9SRui Paulo 		    data->rx_probe_req.ie == NULL)
1740f05cddf9SRui Paulo 			break;
1741e28a4053SRui Paulo 		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
1742f05cddf9SRui Paulo 				     data->rx_probe_req.da,
1743f05cddf9SRui Paulo 				     data->rx_probe_req.bssid,
1744e28a4053SRui Paulo 				     data->rx_probe_req.ie,
1745f05cddf9SRui Paulo 				     data->rx_probe_req.ie_len,
1746f05cddf9SRui Paulo 				     data->rx_probe_req.ssi_signal);
1747e28a4053SRui Paulo 		break;
1748e28a4053SRui Paulo 	case EVENT_NEW_STA:
1749e28a4053SRui Paulo 		hostapd_event_new_sta(hapd, data->new_sta.addr);
1750e28a4053SRui Paulo 		break;
1751e28a4053SRui Paulo 	case EVENT_EAPOL_RX:
1752e28a4053SRui Paulo 		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
1753e28a4053SRui Paulo 				       data->eapol_rx.data,
1754e28a4053SRui Paulo 				       data->eapol_rx.data_len);
1755e28a4053SRui Paulo 		break;
1756e28a4053SRui Paulo 	case EVENT_ASSOC:
17575b9c547cSRui Paulo 		if (!data)
17585b9c547cSRui Paulo 			return;
1759e28a4053SRui Paulo 		hostapd_notif_assoc(hapd, data->assoc_info.addr,
1760e28a4053SRui Paulo 				    data->assoc_info.req_ies,
1761f05cddf9SRui Paulo 				    data->assoc_info.req_ies_len,
1762f05cddf9SRui Paulo 				    data->assoc_info.reassoc);
1763e28a4053SRui Paulo 		break;
1764*206b73d0SCy Schubert #ifdef CONFIG_OWE
1765*206b73d0SCy Schubert 	case EVENT_UPDATE_DH:
1766*206b73d0SCy Schubert 		if (!data)
1767*206b73d0SCy Schubert 			return;
1768*206b73d0SCy Schubert 		hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
1769*206b73d0SCy Schubert 					   data->update_dh.ie,
1770*206b73d0SCy Schubert 					   data->update_dh.ie_len);
1771*206b73d0SCy Schubert 		break;
1772*206b73d0SCy Schubert #endif /* CONFIG_OWE */
1773e28a4053SRui Paulo 	case EVENT_DISASSOC:
1774e28a4053SRui Paulo 		if (data)
1775e28a4053SRui Paulo 			hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
1776e28a4053SRui Paulo 		break;
1777e28a4053SRui Paulo 	case EVENT_DEAUTH:
1778e28a4053SRui Paulo 		if (data)
1779e28a4053SRui Paulo 			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
1780e28a4053SRui Paulo 		break;
1781f05cddf9SRui Paulo 	case EVENT_STATION_LOW_ACK:
1782f05cddf9SRui Paulo 		if (!data)
1783f05cddf9SRui Paulo 			break;
1784f05cddf9SRui Paulo 		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
1785f05cddf9SRui Paulo 		break;
1786f05cddf9SRui Paulo 	case EVENT_AUTH:
1787f05cddf9SRui Paulo 		hostapd_notif_auth(hapd, &data->auth);
1788f05cddf9SRui Paulo 		break;
1789*206b73d0SCy Schubert 	case EVENT_CH_SWITCH_STARTED:
1790f05cddf9SRui Paulo 	case EVENT_CH_SWITCH:
1791f05cddf9SRui Paulo 		if (!data)
1792f05cddf9SRui Paulo 			break;
1793f05cddf9SRui Paulo 		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
1794f05cddf9SRui Paulo 					data->ch_switch.ht_enabled,
17955b9c547cSRui Paulo 					data->ch_switch.ch_offset,
17965b9c547cSRui Paulo 					data->ch_switch.ch_width,
17975b9c547cSRui Paulo 					data->ch_switch.cf1,
1798*206b73d0SCy Schubert 					data->ch_switch.cf2,
1799*206b73d0SCy Schubert 					event == EVENT_CH_SWITCH);
1800f05cddf9SRui Paulo 		break;
18015b9c547cSRui Paulo 	case EVENT_CONNECT_FAILED_REASON:
18025b9c547cSRui Paulo 		if (!data)
18035b9c547cSRui Paulo 			break;
18045b9c547cSRui Paulo 		hostapd_event_connect_failed_reason(
18055b9c547cSRui Paulo 			hapd, data->connect_failed_reason.addr,
18065b9c547cSRui Paulo 			data->connect_failed_reason.code);
18075b9c547cSRui Paulo 		break;
18085b9c547cSRui Paulo 	case EVENT_SURVEY:
1809780fb4a2SCy Schubert 		hostapd_event_get_survey(hapd->iface, &data->survey_results);
18105b9c547cSRui Paulo 		break;
18115b9c547cSRui Paulo #ifdef NEED_AP_MLME
18125b9c547cSRui Paulo 	case EVENT_INTERFACE_UNAVAILABLE:
18135b9c547cSRui Paulo 		hostapd_event_iface_unavailable(hapd);
18145b9c547cSRui Paulo 		break;
18155b9c547cSRui Paulo 	case EVENT_DFS_RADAR_DETECTED:
18165b9c547cSRui Paulo 		if (!data)
18175b9c547cSRui Paulo 			break;
18185b9c547cSRui Paulo 		hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
18195b9c547cSRui Paulo 		break;
182085732ac8SCy Schubert 	case EVENT_DFS_PRE_CAC_EXPIRED:
182185732ac8SCy Schubert 		if (!data)
182285732ac8SCy Schubert 			break;
182385732ac8SCy Schubert 		hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event);
182485732ac8SCy Schubert 		break;
18255b9c547cSRui Paulo 	case EVENT_DFS_CAC_FINISHED:
18265b9c547cSRui Paulo 		if (!data)
18275b9c547cSRui Paulo 			break;
18285b9c547cSRui Paulo 		hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
18295b9c547cSRui Paulo 		break;
18305b9c547cSRui Paulo 	case EVENT_DFS_CAC_ABORTED:
18315b9c547cSRui Paulo 		if (!data)
18325b9c547cSRui Paulo 			break;
18335b9c547cSRui Paulo 		hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
18345b9c547cSRui Paulo 		break;
18355b9c547cSRui Paulo 	case EVENT_DFS_NOP_FINISHED:
18365b9c547cSRui Paulo 		if (!data)
18375b9c547cSRui Paulo 			break;
18385b9c547cSRui Paulo 		hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
18395b9c547cSRui Paulo 		break;
18405b9c547cSRui Paulo 	case EVENT_CHANNEL_LIST_CHANGED:
18415b9c547cSRui Paulo 		/* channel list changed (regulatory?), update channel list */
18425b9c547cSRui Paulo 		/* TODO: check this. hostapd_get_hw_features() initializes
18435b9c547cSRui Paulo 		 * too much stuff. */
18445b9c547cSRui Paulo 		/* hostapd_get_hw_features(hapd->iface); */
18455b9c547cSRui Paulo 		hostapd_channel_list_updated(
18465b9c547cSRui Paulo 			hapd->iface, data->channel_list_changed.initiator);
18475b9c547cSRui Paulo 		break;
18485b9c547cSRui Paulo 	case EVENT_DFS_CAC_STARTED:
18495b9c547cSRui Paulo 		if (!data)
18505b9c547cSRui Paulo 			break;
18515b9c547cSRui Paulo 		hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
18525b9c547cSRui Paulo 		break;
18535b9c547cSRui Paulo #endif /* NEED_AP_MLME */
18545b9c547cSRui Paulo 	case EVENT_INTERFACE_ENABLED:
18555b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
18565b9c547cSRui Paulo 		if (hapd->disabled && hapd->started) {
18575b9c547cSRui Paulo 			hapd->disabled = 0;
18585b9c547cSRui Paulo 			/*
18595b9c547cSRui Paulo 			 * Try to re-enable interface if the driver stopped it
18605b9c547cSRui Paulo 			 * when the interface got disabled.
18615b9c547cSRui Paulo 			 */
186285732ac8SCy Schubert 			if (hapd->wpa_auth)
18635b9c547cSRui Paulo 				wpa_auth_reconfig_group_keys(hapd->wpa_auth);
186485732ac8SCy Schubert 			else
186585732ac8SCy Schubert 				hostapd_reconfig_encryption(hapd);
18665b9c547cSRui Paulo 			hapd->reenable_beacon = 1;
18675b9c547cSRui Paulo 			ieee802_11_set_beacon(hapd);
18684bc52338SCy Schubert #ifdef NEED_AP_MLME
18694bc52338SCy Schubert 		} else if (hapd->disabled && hapd->iface->cac_started) {
18704bc52338SCy Schubert 			wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
18714bc52338SCy Schubert 			hostapd_handle_dfs(hapd->iface);
18724bc52338SCy Schubert #endif /* NEED_AP_MLME */
18735b9c547cSRui Paulo 		}
18745b9c547cSRui Paulo 		break;
18755b9c547cSRui Paulo 	case EVENT_INTERFACE_DISABLED:
18765b9c547cSRui Paulo 		hostapd_free_stas(hapd);
18775b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
18785b9c547cSRui Paulo 		hapd->disabled = 1;
18795b9c547cSRui Paulo 		break;
18805b9c547cSRui Paulo #ifdef CONFIG_ACS
18815b9c547cSRui Paulo 	case EVENT_ACS_CHANNEL_SELECTED:
1882325151a3SRui Paulo 		hostapd_acs_channel_selected(hapd,
1883325151a3SRui Paulo 					     &data->acs_selected_channels);
18845b9c547cSRui Paulo 		break;
18855b9c547cSRui Paulo #endif /* CONFIG_ACS */
188685732ac8SCy Schubert 	case EVENT_STATION_OPMODE_CHANGED:
188785732ac8SCy Schubert 		hostapd_event_sta_opmode_changed(hapd, data->sta_opmode.addr,
188885732ac8SCy Schubert 						 data->sta_opmode.smps_mode,
188985732ac8SCy Schubert 						 data->sta_opmode.chan_width,
189085732ac8SCy Schubert 						 data->sta_opmode.rx_nss);
189185732ac8SCy Schubert 		break;
189285732ac8SCy Schubert 	case EVENT_WDS_STA_INTERFACE_STATUS:
189385732ac8SCy Schubert 		hostapd_event_wds_sta_interface_status(
189485732ac8SCy Schubert 			hapd, data->wds_sta_interface.istatus,
189585732ac8SCy Schubert 			data->wds_sta_interface.ifname,
189685732ac8SCy Schubert 			data->wds_sta_interface.sta_addr);
189785732ac8SCy Schubert 		break;
1898e28a4053SRui Paulo 	default:
1899e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
1900e28a4053SRui Paulo 		break;
1901e28a4053SRui Paulo 	}
1902e28a4053SRui Paulo }
1903e28a4053SRui Paulo 
1904780fb4a2SCy Schubert 
1905780fb4a2SCy Schubert void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
1906780fb4a2SCy Schubert 				 union wpa_event_data *data)
1907780fb4a2SCy Schubert {
1908780fb4a2SCy Schubert 	struct hapd_interfaces *interfaces = ctx;
1909780fb4a2SCy Schubert 	struct hostapd_data *hapd;
1910780fb4a2SCy Schubert 
1911780fb4a2SCy Schubert 	if (event != EVENT_INTERFACE_STATUS)
1912780fb4a2SCy Schubert 		return;
1913780fb4a2SCy Schubert 
1914780fb4a2SCy Schubert 	hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
1915780fb4a2SCy Schubert 	if (hapd && hapd->driver && hapd->driver->get_ifindex &&
1916780fb4a2SCy Schubert 	    hapd->drv_priv) {
1917780fb4a2SCy Schubert 		unsigned int ifindex;
1918780fb4a2SCy Schubert 
1919780fb4a2SCy Schubert 		ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
1920780fb4a2SCy Schubert 		if (ifindex != data->interface_status.ifindex) {
1921780fb4a2SCy Schubert 			wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1922780fb4a2SCy Schubert 				"interface status ifindex %d mismatch (%d)",
1923780fb4a2SCy Schubert 				ifindex, data->interface_status.ifindex);
1924780fb4a2SCy Schubert 			return;
1925780fb4a2SCy Schubert 		}
1926780fb4a2SCy Schubert 	}
1927780fb4a2SCy Schubert 	if (hapd)
1928780fb4a2SCy Schubert 		wpa_supplicant_event(hapd, event, data);
1929780fb4a2SCy Schubert }
1930780fb4a2SCy Schubert 
1931e28a4053SRui Paulo #endif /* HOSTAPD */
1932