xref: /freebsd/contrib/wpa/src/ap/drv_callbacks.c (revision 5b9c547c072b84410b50897cc53710c75b2f6b74)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * hostapd / Callback functions for driver wrappers
3*5b9c547cSRui 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"
12*5b9c547cSRui 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"
17*5b9c547cSRui Paulo #include "common/wpa_ctrl.h"
18f05cddf9SRui Paulo #include "crypto/random.h"
19f05cddf9SRui Paulo #include "p2p/p2p.h"
20f05cddf9SRui Paulo #include "wps/wps.h"
21f05cddf9SRui Paulo #include "wnm_ap.h"
22e28a4053SRui Paulo #include "hostapd.h"
23e28a4053SRui Paulo #include "ieee802_11.h"
24e28a4053SRui Paulo #include "sta_info.h"
25e28a4053SRui Paulo #include "accounting.h"
26e28a4053SRui Paulo #include "tkip_countermeasures.h"
27e28a4053SRui Paulo #include "ieee802_1x.h"
28e28a4053SRui Paulo #include "wpa_auth.h"
29e28a4053SRui Paulo #include "wps_hostapd.h"
30f05cddf9SRui Paulo #include "ap_drv_ops.h"
31e28a4053SRui Paulo #include "ap_config.h"
32f05cddf9SRui Paulo #include "hw_features.h"
33*5b9c547cSRui Paulo #include "dfs.h"
34*5b9c547cSRui Paulo #include "beacon.h"
35e28a4053SRui Paulo 
36e28a4053SRui Paulo 
37e28a4053SRui Paulo int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
38f05cddf9SRui Paulo 			const u8 *req_ies, size_t req_ies_len, int reassoc)
39e28a4053SRui Paulo {
40e28a4053SRui Paulo 	struct sta_info *sta;
41e28a4053SRui Paulo 	int new_assoc, res;
42e28a4053SRui Paulo 	struct ieee802_11_elems elems;
43f05cddf9SRui Paulo 	const u8 *ie;
44f05cddf9SRui Paulo 	size_t ielen;
45f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
46f05cddf9SRui Paulo 	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
47f05cddf9SRui Paulo 	u8 *p = buf;
48f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
49f05cddf9SRui Paulo 	u16 reason = WLAN_REASON_UNSPECIFIED;
50f05cddf9SRui Paulo 	u16 status = WLAN_STATUS_SUCCESS;
51*5b9c547cSRui Paulo 	const u8 *p2p_dev_addr = NULL;
52e28a4053SRui Paulo 
53e28a4053SRui Paulo 	if (addr == NULL) {
54e28a4053SRui Paulo 		/*
55e28a4053SRui Paulo 		 * This could potentially happen with unexpected event from the
56e28a4053SRui Paulo 		 * driver wrapper. This was seen at least in one case where the
57e28a4053SRui Paulo 		 * driver ended up being set to station mode while hostapd was
58e28a4053SRui Paulo 		 * running, so better make sure we stop processing such an
59e28a4053SRui Paulo 		 * event here.
60e28a4053SRui Paulo 		 */
61e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
62e28a4053SRui Paulo 			   "no address");
63e28a4053SRui Paulo 		return -1;
64e28a4053SRui Paulo 	}
65f05cddf9SRui Paulo 	random_add_randomness(addr, ETH_ALEN);
66e28a4053SRui Paulo 
67e28a4053SRui Paulo 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
68e28a4053SRui Paulo 		       HOSTAPD_LEVEL_INFO, "associated");
69e28a4053SRui Paulo 
70f05cddf9SRui Paulo 	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
71e28a4053SRui Paulo 	if (elems.wps_ie) {
72e28a4053SRui Paulo 		ie = elems.wps_ie - 2;
73e28a4053SRui Paulo 		ielen = elems.wps_ie_len + 2;
74e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
75e28a4053SRui Paulo 	} else if (elems.rsn_ie) {
76e28a4053SRui Paulo 		ie = elems.rsn_ie - 2;
77e28a4053SRui Paulo 		ielen = elems.rsn_ie_len + 2;
78e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
79e28a4053SRui Paulo 	} else if (elems.wpa_ie) {
80e28a4053SRui Paulo 		ie = elems.wpa_ie - 2;
81e28a4053SRui Paulo 		ielen = elems.wpa_ie_len + 2;
82e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
83*5b9c547cSRui Paulo #ifdef CONFIG_HS20
84*5b9c547cSRui Paulo 	} else if (elems.osen) {
85*5b9c547cSRui Paulo 		ie = elems.osen - 2;
86*5b9c547cSRui Paulo 		ielen = elems.osen_len + 2;
87*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
88*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */
89e28a4053SRui Paulo 	} else {
90e28a4053SRui Paulo 		ie = NULL;
91e28a4053SRui Paulo 		ielen = 0;
92e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
93e28a4053SRui Paulo 			   "(Re)AssocReq");
94e28a4053SRui Paulo 	}
95e28a4053SRui Paulo 
96e28a4053SRui Paulo 	sta = ap_get_sta(hapd, addr);
97e28a4053SRui Paulo 	if (sta) {
98*5b9c547cSRui Paulo 		ap_sta_no_session_timeout(hapd, sta);
99e28a4053SRui Paulo 		accounting_sta_stop(hapd, sta);
100f05cddf9SRui Paulo 
101f05cddf9SRui Paulo 		/*
102f05cddf9SRui Paulo 		 * Make sure that the previously registered inactivity timer
103f05cddf9SRui Paulo 		 * will not remove the STA immediately.
104f05cddf9SRui Paulo 		 */
105f05cddf9SRui Paulo 		sta->timeout_next = STA_NULLFUNC;
106e28a4053SRui Paulo 	} else {
107e28a4053SRui Paulo 		sta = ap_sta_add(hapd, addr);
108f05cddf9SRui Paulo 		if (sta == NULL) {
109f05cddf9SRui Paulo 			hostapd_drv_sta_disassoc(hapd, addr,
110f05cddf9SRui Paulo 						 WLAN_REASON_DISASSOC_AP_BUSY);
111e28a4053SRui Paulo 			return -1;
112e28a4053SRui Paulo 		}
113f05cddf9SRui Paulo 	}
114f05cddf9SRui Paulo 	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
115f05cddf9SRui Paulo 
116f05cddf9SRui Paulo #ifdef CONFIG_P2P
117f05cddf9SRui Paulo 	if (elems.p2p) {
118f05cddf9SRui Paulo 		wpabuf_free(sta->p2p_ie);
119f05cddf9SRui Paulo 		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
120f05cddf9SRui Paulo 							  P2P_IE_VENDOR_TYPE);
121*5b9c547cSRui Paulo 		if (sta->p2p_ie)
122*5b9c547cSRui Paulo 			p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
123f05cddf9SRui Paulo 	}
124f05cddf9SRui Paulo #endif /* CONFIG_P2P */
125f05cddf9SRui Paulo 
126*5b9c547cSRui Paulo #ifdef CONFIG_IEEE80211N
127*5b9c547cSRui Paulo #ifdef NEED_AP_MLME
128*5b9c547cSRui Paulo 	if (elems.ht_capabilities &&
129*5b9c547cSRui Paulo 	    elems.ht_capabilities_len >=
130*5b9c547cSRui Paulo 	    sizeof(struct ieee80211_ht_capabilities) &&
131*5b9c547cSRui Paulo 	    (hapd->iface->conf->ht_capab &
132*5b9c547cSRui Paulo 	     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
133*5b9c547cSRui Paulo 		struct ieee80211_ht_capabilities *ht_cap =
134*5b9c547cSRui Paulo 			(struct ieee80211_ht_capabilities *)
135*5b9c547cSRui Paulo 			elems.ht_capabilities;
136*5b9c547cSRui Paulo 
137*5b9c547cSRui Paulo 		if (le_to_host16(ht_cap->ht_capabilities_info) &
138*5b9c547cSRui Paulo 		    HT_CAP_INFO_40MHZ_INTOLERANT)
139*5b9c547cSRui Paulo 			ht40_intolerant_add(hapd->iface, sta);
140*5b9c547cSRui Paulo 	}
141*5b9c547cSRui Paulo #endif /* NEED_AP_MLME */
142*5b9c547cSRui Paulo #endif /* CONFIG_IEEE80211N */
143*5b9c547cSRui Paulo 
144*5b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING
145*5b9c547cSRui Paulo 	if (elems.ext_capab && elems.ext_capab_len > 4) {
146*5b9c547cSRui Paulo 		if (elems.ext_capab[4] & 0x01)
147*5b9c547cSRui Paulo 			sta->qos_map_enabled = 1;
148*5b9c547cSRui Paulo 	}
149*5b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */
150*5b9c547cSRui Paulo 
151f05cddf9SRui Paulo #ifdef CONFIG_HS20
152f05cddf9SRui Paulo 	wpabuf_free(sta->hs20_ie);
153f05cddf9SRui Paulo 	if (elems.hs20 && elems.hs20_len > 4) {
154f05cddf9SRui Paulo 		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
155f05cddf9SRui Paulo 						 elems.hs20_len - 4);
156f05cddf9SRui Paulo 	} else
157f05cddf9SRui Paulo 		sta->hs20_ie = NULL;
158f05cddf9SRui Paulo #endif /* CONFIG_HS20 */
159e28a4053SRui Paulo 
160e28a4053SRui Paulo 	if (hapd->conf->wpa) {
161e28a4053SRui Paulo 		if (ie == NULL || ielen == 0) {
162f05cddf9SRui Paulo #ifdef CONFIG_WPS
163e28a4053SRui Paulo 			if (hapd->conf->wps_state) {
164e28a4053SRui Paulo 				wpa_printf(MSG_DEBUG, "STA did not include "
165e28a4053SRui Paulo 					   "WPA/RSN IE in (Re)Association "
166e28a4053SRui Paulo 					   "Request - possible WPS use");
167e28a4053SRui Paulo 				sta->flags |= WLAN_STA_MAYBE_WPS;
168e28a4053SRui Paulo 				goto skip_wpa_check;
169e28a4053SRui Paulo 			}
170f05cddf9SRui Paulo #endif /* CONFIG_WPS */
171e28a4053SRui Paulo 
172e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
173e28a4053SRui Paulo 			return -1;
174e28a4053SRui Paulo 		}
175f05cddf9SRui Paulo #ifdef CONFIG_WPS
176e28a4053SRui Paulo 		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
177e28a4053SRui Paulo 		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
178f05cddf9SRui Paulo 			struct wpabuf *wps;
179e28a4053SRui Paulo 			sta->flags |= WLAN_STA_WPS;
180f05cddf9SRui Paulo 			wps = ieee802_11_vendor_ie_concat(ie, ielen,
181f05cddf9SRui Paulo 							  WPS_IE_VENDOR_TYPE);
182f05cddf9SRui Paulo 			if (wps) {
183f05cddf9SRui Paulo 				if (wps_is_20(wps)) {
184f05cddf9SRui Paulo 					wpa_printf(MSG_DEBUG, "WPS: STA "
185f05cddf9SRui Paulo 						   "supports WPS 2.0");
186f05cddf9SRui Paulo 					sta->flags |= WLAN_STA_WPS2;
187f05cddf9SRui Paulo 				}
188f05cddf9SRui Paulo 				wpabuf_free(wps);
189f05cddf9SRui Paulo 			}
190e28a4053SRui Paulo 			goto skip_wpa_check;
191e28a4053SRui Paulo 		}
192f05cddf9SRui Paulo #endif /* CONFIG_WPS */
193e28a4053SRui Paulo 
194e28a4053SRui Paulo 		if (sta->wpa_sm == NULL)
195e28a4053SRui Paulo 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
196*5b9c547cSRui Paulo 							sta->addr,
197*5b9c547cSRui Paulo 							p2p_dev_addr);
198e28a4053SRui Paulo 		if (sta->wpa_sm == NULL) {
199e28a4053SRui Paulo 			wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
200e28a4053SRui Paulo 				   "machine");
201e28a4053SRui Paulo 			return -1;
202e28a4053SRui Paulo 		}
203e28a4053SRui Paulo 		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
204f05cddf9SRui Paulo 					  ie, ielen,
205f05cddf9SRui Paulo 					  elems.mdie, elems.mdie_len);
206e28a4053SRui Paulo 		if (res != WPA_IE_OK) {
207e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
208e28a4053SRui Paulo 				   "rejected? (res %u)", res);
209e28a4053SRui Paulo 			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
210f05cddf9SRui Paulo 			if (res == WPA_INVALID_GROUP) {
211f05cddf9SRui Paulo 				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
212f05cddf9SRui Paulo 				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
213f05cddf9SRui Paulo 			} else if (res == WPA_INVALID_PAIRWISE) {
214f05cddf9SRui Paulo 				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
215f05cddf9SRui Paulo 				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
216f05cddf9SRui Paulo 			} else if (res == WPA_INVALID_AKMP) {
217f05cddf9SRui Paulo 				reason = WLAN_REASON_AKMP_NOT_VALID;
218f05cddf9SRui Paulo 				status = WLAN_STATUS_AKMP_NOT_VALID;
219e28a4053SRui Paulo 			}
220f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W
221f05cddf9SRui Paulo 			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
222f05cddf9SRui Paulo 				reason = WLAN_REASON_INVALID_IE;
223f05cddf9SRui Paulo 				status = WLAN_STATUS_INVALID_IE;
224f05cddf9SRui Paulo 			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
225f05cddf9SRui Paulo 				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
226f05cddf9SRui Paulo 				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
227f05cddf9SRui Paulo 			}
228f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */
229f05cddf9SRui Paulo 			else {
230f05cddf9SRui Paulo 				reason = WLAN_REASON_INVALID_IE;
231f05cddf9SRui Paulo 				status = WLAN_STATUS_INVALID_IE;
232f05cddf9SRui Paulo 			}
233f05cddf9SRui Paulo 			goto fail;
234f05cddf9SRui Paulo 		}
235f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W
236f05cddf9SRui Paulo 		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
237f05cddf9SRui Paulo 		    sta->sa_query_count > 0)
238f05cddf9SRui Paulo 			ap_check_sa_query_timeout(hapd, sta);
239f05cddf9SRui Paulo 		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
240f05cddf9SRui Paulo 		    (sta->auth_alg != WLAN_AUTH_FT)) {
241f05cddf9SRui Paulo 			/*
242f05cddf9SRui Paulo 			 * STA has already been associated with MFP and SA
243f05cddf9SRui Paulo 			 * Query timeout has not been reached. Reject the
244f05cddf9SRui Paulo 			 * association attempt temporarily and start SA Query,
245f05cddf9SRui Paulo 			 * if one is not pending.
246f05cddf9SRui Paulo 			 */
247f05cddf9SRui Paulo 
248f05cddf9SRui Paulo 			if (sta->sa_query_count == 0)
249f05cddf9SRui Paulo 				ap_sta_start_sa_query(hapd, sta);
250f05cddf9SRui Paulo 
251f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
252f05cddf9SRui Paulo 			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
253f05cddf9SRui Paulo 
254f05cddf9SRui Paulo 			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
255f05cddf9SRui Paulo 
256f05cddf9SRui Paulo 			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
257f05cddf9SRui Paulo 					  p - buf);
258f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
259f05cddf9SRui Paulo 			return 0;
260f05cddf9SRui Paulo 		}
261f05cddf9SRui Paulo 
262f05cddf9SRui Paulo 		if (wpa_auth_uses_mfp(sta->wpa_sm))
263f05cddf9SRui Paulo 			sta->flags |= WLAN_STA_MFP;
264f05cddf9SRui Paulo 		else
265f05cddf9SRui Paulo 			sta->flags &= ~WLAN_STA_MFP;
266f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */
267f05cddf9SRui Paulo 
268f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
269f05cddf9SRui Paulo 		if (sta->auth_alg == WLAN_AUTH_FT) {
270f05cddf9SRui Paulo 			status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
271f05cddf9SRui Paulo 							 req_ies_len);
272f05cddf9SRui Paulo 			if (status != WLAN_STATUS_SUCCESS) {
273f05cddf9SRui Paulo 				if (status == WLAN_STATUS_INVALID_PMKID)
274f05cddf9SRui Paulo 					reason = WLAN_REASON_INVALID_IE;
275f05cddf9SRui Paulo 				if (status == WLAN_STATUS_INVALID_MDIE)
276f05cddf9SRui Paulo 					reason = WLAN_REASON_INVALID_IE;
277f05cddf9SRui Paulo 				if (status == WLAN_STATUS_INVALID_FTIE)
278f05cddf9SRui Paulo 					reason = WLAN_REASON_INVALID_IE;
279f05cddf9SRui Paulo 				goto fail;
280f05cddf9SRui Paulo 			}
281f05cddf9SRui Paulo 		}
282f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
283e28a4053SRui Paulo 	} else if (hapd->conf->wps_state) {
284f05cddf9SRui Paulo #ifdef CONFIG_WPS
285f05cddf9SRui Paulo 		struct wpabuf *wps;
286f05cddf9SRui Paulo 		if (req_ies)
287f05cddf9SRui Paulo 			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
288f05cddf9SRui Paulo 							  WPS_IE_VENDOR_TYPE);
289f05cddf9SRui Paulo 		else
290f05cddf9SRui Paulo 			wps = NULL;
291f05cddf9SRui Paulo #ifdef CONFIG_WPS_STRICT
292f05cddf9SRui Paulo 		if (wps && wps_validate_assoc_req(wps) < 0) {
293f05cddf9SRui Paulo 			reason = WLAN_REASON_INVALID_IE;
294f05cddf9SRui Paulo 			status = WLAN_STATUS_INVALID_IE;
295f05cddf9SRui Paulo 			wpabuf_free(wps);
296f05cddf9SRui Paulo 			goto fail;
297f05cddf9SRui Paulo 		}
298f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
299f05cddf9SRui Paulo 		if (wps) {
300e28a4053SRui Paulo 			sta->flags |= WLAN_STA_WPS;
301f05cddf9SRui Paulo 			if (wps_is_20(wps)) {
302f05cddf9SRui Paulo 				wpa_printf(MSG_DEBUG, "WPS: STA supports "
303f05cddf9SRui Paulo 					   "WPS 2.0");
304f05cddf9SRui Paulo 				sta->flags |= WLAN_STA_WPS2;
305f05cddf9SRui Paulo 			}
306e28a4053SRui Paulo 		} else
307e28a4053SRui Paulo 			sta->flags |= WLAN_STA_MAYBE_WPS;
308f05cddf9SRui Paulo 		wpabuf_free(wps);
309f05cddf9SRui Paulo #endif /* CONFIG_WPS */
310*5b9c547cSRui Paulo #ifdef CONFIG_HS20
311*5b9c547cSRui Paulo 	} else if (hapd->conf->osen) {
312*5b9c547cSRui Paulo 		if (elems.osen == NULL) {
313*5b9c547cSRui Paulo 			hostapd_logger(
314*5b9c547cSRui Paulo 				hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
315*5b9c547cSRui Paulo 				HOSTAPD_LEVEL_INFO,
316*5b9c547cSRui Paulo 				"No HS 2.0 OSEN element in association request");
317*5b9c547cSRui Paulo 			return WLAN_STATUS_INVALID_IE;
318*5b9c547cSRui Paulo 		}
319*5b9c547cSRui Paulo 
320*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
321*5b9c547cSRui Paulo 		if (sta->wpa_sm == NULL)
322*5b9c547cSRui Paulo 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
323*5b9c547cSRui Paulo 							sta->addr, NULL);
324*5b9c547cSRui Paulo 		if (sta->wpa_sm == NULL) {
325*5b9c547cSRui Paulo 			wpa_printf(MSG_WARNING, "Failed to initialize WPA "
326*5b9c547cSRui Paulo 				   "state machine");
327*5b9c547cSRui Paulo 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
328*5b9c547cSRui Paulo 		}
329*5b9c547cSRui Paulo 		if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
330*5b9c547cSRui Paulo 				      elems.osen - 2, elems.osen_len + 2) < 0)
331*5b9c547cSRui Paulo 			return WLAN_STATUS_INVALID_IE;
332*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */
333e28a4053SRui Paulo 	}
334f05cddf9SRui Paulo #ifdef CONFIG_WPS
335e28a4053SRui Paulo skip_wpa_check:
336f05cddf9SRui Paulo #endif /* CONFIG_WPS */
337f05cddf9SRui Paulo 
338f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
339f05cddf9SRui Paulo 	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
340f05cddf9SRui Paulo 					sta->auth_alg, req_ies, req_ies_len);
341f05cddf9SRui Paulo 
342f05cddf9SRui Paulo 	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
343*5b9c547cSRui Paulo 
344*5b9c547cSRui Paulo 	if (sta->auth_alg == WLAN_AUTH_FT)
345*5b9c547cSRui Paulo 		ap_sta_set_authorized(hapd, sta, 1);
346f05cddf9SRui Paulo #else /* CONFIG_IEEE80211R */
347f05cddf9SRui Paulo 	/* Keep compiler silent about unused variables */
348f05cddf9SRui Paulo 	if (status) {
349f05cddf9SRui Paulo 	}
350f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
351e28a4053SRui Paulo 
352e28a4053SRui Paulo 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
353e28a4053SRui Paulo 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
354*5b9c547cSRui Paulo 	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
355*5b9c547cSRui Paulo 
356*5b9c547cSRui Paulo 	hostapd_set_sta_flags(hapd, sta);
357f05cddf9SRui Paulo 
358f05cddf9SRui Paulo 	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
359f05cddf9SRui Paulo 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
360f05cddf9SRui Paulo 	else
361e28a4053SRui Paulo 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
362e28a4053SRui Paulo 
363e28a4053SRui Paulo 	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
364e28a4053SRui Paulo 
365e28a4053SRui Paulo 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
366e28a4053SRui Paulo 
367f05cddf9SRui Paulo #ifdef CONFIG_P2P
368f05cddf9SRui Paulo 	if (req_ies) {
369f05cddf9SRui Paulo 		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
370f05cddf9SRui Paulo 				      req_ies, req_ies_len);
371f05cddf9SRui Paulo 	}
372f05cddf9SRui Paulo #endif /* CONFIG_P2P */
373f05cddf9SRui Paulo 
374e28a4053SRui Paulo 	return 0;
375f05cddf9SRui Paulo 
376f05cddf9SRui Paulo fail:
377f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
378f05cddf9SRui Paulo 	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
379f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
380f05cddf9SRui Paulo 	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
381f05cddf9SRui Paulo 	ap_free_sta(hapd, sta);
382f05cddf9SRui Paulo 	return -1;
383e28a4053SRui Paulo }
384e28a4053SRui Paulo 
385e28a4053SRui Paulo 
386e28a4053SRui Paulo void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
387e28a4053SRui Paulo {
388e28a4053SRui Paulo 	struct sta_info *sta;
389e28a4053SRui Paulo 
390f05cddf9SRui Paulo 	if (addr == NULL) {
391f05cddf9SRui Paulo 		/*
392f05cddf9SRui Paulo 		 * This could potentially happen with unexpected event from the
393f05cddf9SRui Paulo 		 * driver wrapper. This was seen at least in one case where the
394f05cddf9SRui Paulo 		 * driver ended up reporting a station mode event while hostapd
395f05cddf9SRui Paulo 		 * was running, so better make sure we stop processing such an
396f05cddf9SRui Paulo 		 * event here.
397f05cddf9SRui Paulo 		 */
398f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
399f05cddf9SRui Paulo 			   "with no address");
400f05cddf9SRui Paulo 		return;
401f05cddf9SRui Paulo 	}
402f05cddf9SRui Paulo 
403e28a4053SRui Paulo 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
404e28a4053SRui Paulo 		       HOSTAPD_LEVEL_INFO, "disassociated");
405e28a4053SRui Paulo 
406e28a4053SRui Paulo 	sta = ap_get_sta(hapd, addr);
407e28a4053SRui Paulo 	if (sta == NULL) {
408e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Disassociation notification for "
409e28a4053SRui Paulo 			   "unknown STA " MACSTR, MAC2STR(addr));
410e28a4053SRui Paulo 		return;
411e28a4053SRui Paulo 	}
412e28a4053SRui Paulo 
413f05cddf9SRui Paulo 	ap_sta_set_authorized(hapd, sta, 0);
414e28a4053SRui Paulo 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
415e28a4053SRui Paulo 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
416e28a4053SRui Paulo 	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
417e28a4053SRui Paulo 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
418e28a4053SRui Paulo 	ap_free_sta(hapd, sta);
419e28a4053SRui Paulo }
420e28a4053SRui Paulo 
421e28a4053SRui Paulo 
422f05cddf9SRui Paulo void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
423f05cddf9SRui Paulo {
424f05cddf9SRui Paulo 	struct sta_info *sta = ap_get_sta(hapd, addr);
425f05cddf9SRui Paulo 
426f05cddf9SRui Paulo 	if (!sta || !hapd->conf->disassoc_low_ack)
427f05cddf9SRui Paulo 		return;
428f05cddf9SRui Paulo 
429f05cddf9SRui Paulo 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
430f05cddf9SRui Paulo 		       HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
431f05cddf9SRui Paulo 		       "missing ACKs");
432f05cddf9SRui Paulo 	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
433f05cddf9SRui Paulo 	if (sta)
434f05cddf9SRui Paulo 		ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
435f05cddf9SRui Paulo }
436f05cddf9SRui Paulo 
437f05cddf9SRui Paulo 
438f05cddf9SRui Paulo void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
439*5b9c547cSRui Paulo 			     int offset, int width, int cf1, int cf2)
440f05cddf9SRui Paulo {
441f05cddf9SRui Paulo #ifdef NEED_AP_MLME
442*5b9c547cSRui Paulo 	int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
443f05cddf9SRui Paulo 
444f05cddf9SRui Paulo 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
445*5b9c547cSRui Paulo 		       HOSTAPD_LEVEL_INFO,
446*5b9c547cSRui Paulo 		       "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
447*5b9c547cSRui Paulo 		       freq, ht, offset, width, channel_width_to_string(width),
448*5b9c547cSRui Paulo 		       cf1, cf2);
449f05cddf9SRui Paulo 
450f05cddf9SRui Paulo 	hapd->iface->freq = freq;
451f05cddf9SRui Paulo 
452f05cddf9SRui Paulo 	channel = hostapd_hw_get_channel(hapd, freq);
453f05cddf9SRui Paulo 	if (!channel) {
454f05cddf9SRui Paulo 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
455f05cddf9SRui Paulo 			       HOSTAPD_LEVEL_WARNING, "driver switched to "
456f05cddf9SRui Paulo 			       "bad channel!");
457f05cddf9SRui Paulo 		return;
458f05cddf9SRui Paulo 	}
459f05cddf9SRui Paulo 
460*5b9c547cSRui Paulo 	switch (width) {
461*5b9c547cSRui Paulo 	case CHAN_WIDTH_80:
462*5b9c547cSRui Paulo 		chwidth = VHT_CHANWIDTH_80MHZ;
463*5b9c547cSRui Paulo 		break;
464*5b9c547cSRui Paulo 	case CHAN_WIDTH_80P80:
465*5b9c547cSRui Paulo 		chwidth = VHT_CHANWIDTH_80P80MHZ;
466*5b9c547cSRui Paulo 		break;
467*5b9c547cSRui Paulo 	case CHAN_WIDTH_160:
468*5b9c547cSRui Paulo 		chwidth = VHT_CHANWIDTH_160MHZ;
469*5b9c547cSRui Paulo 		break;
470*5b9c547cSRui Paulo 	case CHAN_WIDTH_20_NOHT:
471*5b9c547cSRui Paulo 	case CHAN_WIDTH_20:
472*5b9c547cSRui Paulo 	case CHAN_WIDTH_40:
473*5b9c547cSRui Paulo 	default:
474*5b9c547cSRui Paulo 		chwidth = VHT_CHANWIDTH_USE_HT;
475*5b9c547cSRui Paulo 		break;
476*5b9c547cSRui Paulo 	}
477*5b9c547cSRui Paulo 
478*5b9c547cSRui Paulo 	switch (hapd->iface->current_mode->mode) {
479*5b9c547cSRui Paulo 	case HOSTAPD_MODE_IEEE80211A:
480*5b9c547cSRui Paulo 		if (cf1 > 5000)
481*5b9c547cSRui Paulo 			seg0_idx = (cf1 - 5000) / 5;
482*5b9c547cSRui Paulo 		if (cf2 > 5000)
483*5b9c547cSRui Paulo 			seg1_idx = (cf2 - 5000) / 5;
484*5b9c547cSRui Paulo 		break;
485*5b9c547cSRui Paulo 	default:
486*5b9c547cSRui Paulo 		seg0_idx = hostapd_hw_get_channel(hapd, cf1);
487*5b9c547cSRui Paulo 		seg1_idx = hostapd_hw_get_channel(hapd, cf2);
488*5b9c547cSRui Paulo 		break;
489*5b9c547cSRui Paulo 	}
490*5b9c547cSRui Paulo 
491f05cddf9SRui Paulo 	hapd->iconf->channel = channel;
492f05cddf9SRui Paulo 	hapd->iconf->ieee80211n = ht;
493*5b9c547cSRui Paulo 	if (!ht)
494*5b9c547cSRui Paulo 		hapd->iconf->ieee80211ac = 0;
495f05cddf9SRui Paulo 	hapd->iconf->secondary_channel = offset;
496*5b9c547cSRui Paulo 	hapd->iconf->vht_oper_chwidth = chwidth;
497*5b9c547cSRui Paulo 	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
498*5b9c547cSRui Paulo 	hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
499*5b9c547cSRui Paulo 
500*5b9c547cSRui Paulo 	is_dfs = ieee80211_is_dfs(freq);
501*5b9c547cSRui Paulo 
502*5b9c547cSRui Paulo 	if (hapd->csa_in_progress &&
503*5b9c547cSRui Paulo 	    freq == hapd->cs_freq_params.freq) {
504*5b9c547cSRui Paulo 		hostapd_cleanup_cs_params(hapd);
505*5b9c547cSRui Paulo 		ieee802_11_set_beacon(hapd);
506*5b9c547cSRui Paulo 
507*5b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
508*5b9c547cSRui Paulo 			"freq=%d dfs=%d", freq, is_dfs);
509*5b9c547cSRui Paulo 	} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
510*5b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
511*5b9c547cSRui Paulo 			"freq=%d dfs=%d", freq, is_dfs);
512*5b9c547cSRui Paulo 	}
513f05cddf9SRui Paulo #endif /* NEED_AP_MLME */
514f05cddf9SRui Paulo }
515f05cddf9SRui Paulo 
516f05cddf9SRui Paulo 
517*5b9c547cSRui Paulo void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
518*5b9c547cSRui Paulo 					 const u8 *addr, int reason_code)
519*5b9c547cSRui Paulo {
520*5b9c547cSRui Paulo 	switch (reason_code) {
521*5b9c547cSRui Paulo 	case MAX_CLIENT_REACHED:
522*5b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
523*5b9c547cSRui Paulo 			MAC2STR(addr));
524*5b9c547cSRui Paulo 		break;
525*5b9c547cSRui Paulo 	case BLOCKED_CLIENT:
526*5b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
527*5b9c547cSRui Paulo 			MAC2STR(addr));
528*5b9c547cSRui Paulo 		break;
529*5b9c547cSRui Paulo 	}
530*5b9c547cSRui Paulo }
531*5b9c547cSRui Paulo 
532*5b9c547cSRui Paulo 
533*5b9c547cSRui Paulo #ifdef CONFIG_ACS
534*5b9c547cSRui Paulo static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
535*5b9c547cSRui Paulo 					 u8 pri_channel, u8 sec_channel)
536*5b9c547cSRui Paulo {
537*5b9c547cSRui Paulo 	int channel;
538*5b9c547cSRui Paulo 	int ret;
539*5b9c547cSRui Paulo 
540*5b9c547cSRui Paulo 	if (hapd->iconf->channel) {
541*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
542*5b9c547cSRui Paulo 			   hapd->iconf->channel);
543*5b9c547cSRui Paulo 		return;
544*5b9c547cSRui Paulo 	}
545*5b9c547cSRui Paulo 
546*5b9c547cSRui Paulo 	hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
547*5b9c547cSRui Paulo 
548*5b9c547cSRui Paulo 	channel = pri_channel;
549*5b9c547cSRui Paulo 	if (!channel) {
550*5b9c547cSRui Paulo 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
551*5b9c547cSRui Paulo 			       HOSTAPD_LEVEL_WARNING,
552*5b9c547cSRui Paulo 			       "driver switched to bad channel");
553*5b9c547cSRui Paulo 		return;
554*5b9c547cSRui Paulo 	}
555*5b9c547cSRui Paulo 
556*5b9c547cSRui Paulo 	hapd->iconf->channel = channel;
557*5b9c547cSRui Paulo 
558*5b9c547cSRui Paulo 	if (sec_channel == 0)
559*5b9c547cSRui Paulo 		hapd->iconf->secondary_channel = 0;
560*5b9c547cSRui Paulo 	else if (sec_channel < pri_channel)
561*5b9c547cSRui Paulo 		hapd->iconf->secondary_channel = -1;
562*5b9c547cSRui Paulo 	else if (sec_channel > pri_channel)
563*5b9c547cSRui Paulo 		hapd->iconf->secondary_channel = 1;
564*5b9c547cSRui Paulo 	else {
565*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "Invalid secondary channel!");
566*5b9c547cSRui Paulo 		return;
567*5b9c547cSRui Paulo 	}
568*5b9c547cSRui Paulo 
569*5b9c547cSRui Paulo 	ret = hostapd_acs_completed(hapd->iface, 0);
570*5b9c547cSRui Paulo 	if (ret) {
571*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR,
572*5b9c547cSRui Paulo 			   "ACS: Possibly channel configuration is invalid");
573*5b9c547cSRui Paulo 	}
574*5b9c547cSRui Paulo }
575*5b9c547cSRui Paulo #endif /* CONFIG_ACS */
576*5b9c547cSRui Paulo 
577*5b9c547cSRui Paulo 
578f05cddf9SRui Paulo int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
579f05cddf9SRui Paulo 			 const u8 *bssid, const u8 *ie, size_t ie_len,
580f05cddf9SRui Paulo 			 int ssi_signal)
581f05cddf9SRui Paulo {
582f05cddf9SRui Paulo 	size_t i;
583f05cddf9SRui Paulo 	int ret = 0;
584f05cddf9SRui Paulo 
585f05cddf9SRui Paulo 	if (sa == NULL || ie == NULL)
586f05cddf9SRui Paulo 		return -1;
587f05cddf9SRui Paulo 
588f05cddf9SRui Paulo 	random_add_randomness(sa, ETH_ALEN);
589f05cddf9SRui Paulo 	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
590f05cddf9SRui Paulo 		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
591f05cddf9SRui Paulo 					    sa, da, bssid, ie, ie_len,
592f05cddf9SRui Paulo 					    ssi_signal) > 0) {
593f05cddf9SRui Paulo 			ret = 1;
594f05cddf9SRui Paulo 			break;
595f05cddf9SRui Paulo 		}
596f05cddf9SRui Paulo 	}
597f05cddf9SRui Paulo 	return ret;
598f05cddf9SRui Paulo }
599f05cddf9SRui Paulo 
600f05cddf9SRui Paulo 
601e28a4053SRui Paulo #ifdef HOSTAPD
602e28a4053SRui Paulo 
603f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
604f05cddf9SRui Paulo static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
605f05cddf9SRui Paulo 					  const u8 *bssid,
606f05cddf9SRui Paulo 					  u16 auth_transaction, u16 status,
607f05cddf9SRui Paulo 					  const u8 *ies, size_t ies_len)
608e28a4053SRui Paulo {
609f05cddf9SRui Paulo 	struct hostapd_data *hapd = ctx;
610f05cddf9SRui Paulo 	struct sta_info *sta;
611e28a4053SRui Paulo 
612f05cddf9SRui Paulo 	sta = ap_get_sta(hapd, dst);
613f05cddf9SRui Paulo 	if (sta == NULL)
614f05cddf9SRui Paulo 		return;
615e28a4053SRui Paulo 
616f05cddf9SRui Paulo 	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
617f05cddf9SRui Paulo 		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
618f05cddf9SRui Paulo 	sta->flags |= WLAN_STA_AUTH;
619e28a4053SRui Paulo 
620f05cddf9SRui Paulo 	hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
621e28a4053SRui Paulo }
622f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
623f05cddf9SRui Paulo 
624f05cddf9SRui Paulo 
625f05cddf9SRui Paulo static void hostapd_notif_auth(struct hostapd_data *hapd,
626f05cddf9SRui Paulo 			       struct auth_info *rx_auth)
627f05cddf9SRui Paulo {
628f05cddf9SRui Paulo 	struct sta_info *sta;
629f05cddf9SRui Paulo 	u16 status = WLAN_STATUS_SUCCESS;
630f05cddf9SRui Paulo 	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
631f05cddf9SRui Paulo 	size_t resp_ies_len = 0;
632f05cddf9SRui Paulo 
633f05cddf9SRui Paulo 	sta = ap_get_sta(hapd, rx_auth->peer);
634f05cddf9SRui Paulo 	if (!sta) {
635f05cddf9SRui Paulo 		sta = ap_sta_add(hapd, rx_auth->peer);
636f05cddf9SRui Paulo 		if (sta == NULL) {
637*5b9c547cSRui Paulo 			status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
638f05cddf9SRui Paulo 			goto fail;
639e28a4053SRui Paulo 		}
640e28a4053SRui Paulo 	}
641f05cddf9SRui Paulo 	sta->flags &= ~WLAN_STA_PREAUTH;
642f05cddf9SRui Paulo 	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
643f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
644f05cddf9SRui Paulo 	if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
645f05cddf9SRui Paulo 		sta->auth_alg = WLAN_AUTH_FT;
646f05cddf9SRui Paulo 		if (sta->wpa_sm == NULL)
647f05cddf9SRui Paulo 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
648*5b9c547cSRui Paulo 							sta->addr, NULL);
649f05cddf9SRui Paulo 		if (sta->wpa_sm == NULL) {
650f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
651f05cddf9SRui Paulo 				   "state machine");
652f05cddf9SRui Paulo 			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
653f05cddf9SRui Paulo 			goto fail;
654f05cddf9SRui Paulo 		}
655f05cddf9SRui Paulo 		wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
656f05cddf9SRui Paulo 				    rx_auth->auth_transaction, rx_auth->ies,
657f05cddf9SRui Paulo 				    rx_auth->ies_len,
658f05cddf9SRui Paulo 				    hostapd_notify_auth_ft_finish, hapd);
659f05cddf9SRui Paulo 		return;
660f05cddf9SRui Paulo 	}
661f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
662f05cddf9SRui Paulo fail:
663f05cddf9SRui Paulo 	hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
664f05cddf9SRui Paulo 			 status, resp_ies, resp_ies_len);
665f05cddf9SRui Paulo }
666e28a4053SRui Paulo 
667e28a4053SRui Paulo 
668f05cddf9SRui Paulo static void hostapd_action_rx(struct hostapd_data *hapd,
669*5b9c547cSRui Paulo 			      struct rx_mgmt *drv_mgmt)
670f05cddf9SRui Paulo {
671*5b9c547cSRui Paulo 	struct ieee80211_mgmt *mgmt;
672f05cddf9SRui Paulo 	struct sta_info *sta;
673*5b9c547cSRui Paulo 	size_t plen __maybe_unused;
674*5b9c547cSRui Paulo 	u16 fc;
675*5b9c547cSRui Paulo 
676*5b9c547cSRui Paulo 	if (drv_mgmt->frame_len < 24 + 1)
677*5b9c547cSRui Paulo 		return;
678*5b9c547cSRui Paulo 
679*5b9c547cSRui Paulo 	plen = drv_mgmt->frame_len - 24 - 1;
680*5b9c547cSRui Paulo 
681*5b9c547cSRui Paulo 	mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
682*5b9c547cSRui Paulo 	fc = le_to_host16(mgmt->frame_control);
683*5b9c547cSRui Paulo 	if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
684*5b9c547cSRui Paulo 		return; /* handled by the driver */
685f05cddf9SRui Paulo 
686f05cddf9SRui Paulo         wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
687*5b9c547cSRui Paulo 		   mgmt->u.action.category, (int) plen);
688f05cddf9SRui Paulo 
689*5b9c547cSRui Paulo 	sta = ap_get_sta(hapd, mgmt->sa);
690f05cddf9SRui Paulo 	if (sta == NULL) {
691f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
692f05cddf9SRui Paulo 		return;
693f05cddf9SRui Paulo 	}
694f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211R
695*5b9c547cSRui Paulo 	if (mgmt->u.action.category == WLAN_ACTION_FT) {
696*5b9c547cSRui Paulo 		const u8 *payload = drv_mgmt->frame + 24 + 1;
697*5b9c547cSRui Paulo 		wpa_ft_action_rx(sta->wpa_sm, payload, plen);
698f05cddf9SRui Paulo 	}
699f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211R */
700f05cddf9SRui Paulo #ifdef CONFIG_IEEE80211W
701*5b9c547cSRui Paulo 	if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
702*5b9c547cSRui Paulo 		ieee802_11_sa_query_action(
703*5b9c547cSRui Paulo 			hapd, mgmt->sa,
704*5b9c547cSRui Paulo 			mgmt->u.action.u.sa_query_resp.action,
705*5b9c547cSRui Paulo 			mgmt->u.action.u.sa_query_resp.trans_id);
706f05cddf9SRui Paulo 	}
707f05cddf9SRui Paulo #endif /* CONFIG_IEEE80211W */
708f05cddf9SRui Paulo #ifdef CONFIG_WNM
709*5b9c547cSRui Paulo 	if (mgmt->u.action.category == WLAN_ACTION_WNM) {
710*5b9c547cSRui Paulo 		ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
711f05cddf9SRui Paulo 	}
712f05cddf9SRui Paulo #endif /* CONFIG_WNM */
713f05cddf9SRui Paulo }
714f05cddf9SRui Paulo 
715f05cddf9SRui Paulo 
716f05cddf9SRui Paulo #ifdef NEED_AP_MLME
717f05cddf9SRui Paulo 
718e28a4053SRui Paulo #define HAPD_BROADCAST ((struct hostapd_data *) -1)
719e28a4053SRui Paulo 
720e28a4053SRui Paulo static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
721e28a4053SRui Paulo 					    const u8 *bssid)
722e28a4053SRui Paulo {
723e28a4053SRui Paulo 	size_t i;
724e28a4053SRui Paulo 
725e28a4053SRui Paulo 	if (bssid == NULL)
726e28a4053SRui Paulo 		return NULL;
727e28a4053SRui Paulo 	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
728e28a4053SRui Paulo 	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
729e28a4053SRui Paulo 		return HAPD_BROADCAST;
730e28a4053SRui Paulo 
731e28a4053SRui Paulo 	for (i = 0; i < iface->num_bss; i++) {
732e28a4053SRui Paulo 		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
733e28a4053SRui Paulo 			return iface->bss[i];
734e28a4053SRui Paulo 	}
735e28a4053SRui Paulo 
736e28a4053SRui Paulo 	return NULL;
737e28a4053SRui Paulo }
738e28a4053SRui Paulo 
739e28a4053SRui Paulo 
740e28a4053SRui Paulo static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
741f05cddf9SRui Paulo 					const u8 *bssid, const u8 *addr,
742f05cddf9SRui Paulo 					int wds)
743e28a4053SRui Paulo {
744f05cddf9SRui Paulo 	hapd = get_hapd_bssid(hapd->iface, bssid);
745e28a4053SRui Paulo 	if (hapd == NULL || hapd == HAPD_BROADCAST)
746e28a4053SRui Paulo 		return;
747e28a4053SRui Paulo 
748f05cddf9SRui Paulo 	ieee802_11_rx_from_unknown(hapd, addr, wds);
749e28a4053SRui Paulo }
750e28a4053SRui Paulo 
751e28a4053SRui Paulo 
752*5b9c547cSRui Paulo static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
753e28a4053SRui Paulo {
754e28a4053SRui Paulo 	struct hostapd_iface *iface = hapd->iface;
755e28a4053SRui Paulo 	const struct ieee80211_hdr *hdr;
756e28a4053SRui Paulo 	const u8 *bssid;
757e28a4053SRui Paulo 	struct hostapd_frame_info fi;
758*5b9c547cSRui Paulo 	int ret;
759*5b9c547cSRui Paulo 
760*5b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS
761*5b9c547cSRui Paulo 	if (hapd->ext_mgmt_frame_handling) {
762*5b9c547cSRui Paulo 		size_t hex_len = 2 * rx_mgmt->frame_len + 1;
763*5b9c547cSRui Paulo 		char *hex = os_malloc(hex_len);
764*5b9c547cSRui Paulo 		if (hex) {
765*5b9c547cSRui Paulo 			wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
766*5b9c547cSRui Paulo 					 rx_mgmt->frame_len);
767*5b9c547cSRui Paulo 			wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
768*5b9c547cSRui Paulo 			os_free(hex);
769*5b9c547cSRui Paulo 		}
770*5b9c547cSRui Paulo 		return 1;
771*5b9c547cSRui Paulo 	}
772*5b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
773e28a4053SRui Paulo 
774e28a4053SRui Paulo 	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
775e28a4053SRui Paulo 	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
776e28a4053SRui Paulo 	if (bssid == NULL)
777*5b9c547cSRui Paulo 		return 0;
778e28a4053SRui Paulo 
779e28a4053SRui Paulo 	hapd = get_hapd_bssid(iface, bssid);
780e28a4053SRui Paulo 	if (hapd == NULL) {
781e28a4053SRui Paulo 		u16 fc;
782e28a4053SRui Paulo 		fc = le_to_host16(hdr->frame_control);
783e28a4053SRui Paulo 
784e28a4053SRui Paulo 		/*
785e28a4053SRui Paulo 		 * Drop frames to unknown BSSIDs except for Beacon frames which
786e28a4053SRui Paulo 		 * could be used to update neighbor information.
787e28a4053SRui Paulo 		 */
788e28a4053SRui Paulo 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
789e28a4053SRui Paulo 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
790e28a4053SRui Paulo 			hapd = iface->bss[0];
791e28a4053SRui Paulo 		else
792*5b9c547cSRui Paulo 			return 0;
793e28a4053SRui Paulo 	}
794e28a4053SRui Paulo 
795e28a4053SRui Paulo 	os_memset(&fi, 0, sizeof(fi));
796e28a4053SRui Paulo 	fi.datarate = rx_mgmt->datarate;
797e28a4053SRui Paulo 	fi.ssi_signal = rx_mgmt->ssi_signal;
798e28a4053SRui Paulo 
799e28a4053SRui Paulo 	if (hapd == HAPD_BROADCAST) {
800e28a4053SRui Paulo 		size_t i;
801*5b9c547cSRui Paulo 		ret = 0;
802*5b9c547cSRui Paulo 		for (i = 0; i < iface->num_bss; i++) {
803*5b9c547cSRui Paulo 			/* if bss is set, driver will call this function for
804*5b9c547cSRui Paulo 			 * each bss individually. */
805*5b9c547cSRui Paulo 			if (rx_mgmt->drv_priv &&
806*5b9c547cSRui Paulo 			    (iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
807*5b9c547cSRui Paulo 				continue;
808*5b9c547cSRui Paulo 
809*5b9c547cSRui Paulo 			if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
810*5b9c547cSRui Paulo 					    rx_mgmt->frame_len, &fi) > 0)
811*5b9c547cSRui Paulo 				ret = 1;
812*5b9c547cSRui Paulo 		}
813e28a4053SRui Paulo 	} else
814*5b9c547cSRui Paulo 		ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
815*5b9c547cSRui Paulo 				      &fi);
816f05cddf9SRui Paulo 
817f05cddf9SRui Paulo 	random_add_randomness(&fi, sizeof(fi));
818f05cddf9SRui Paulo 
819*5b9c547cSRui Paulo 	return ret;
820e28a4053SRui Paulo }
821e28a4053SRui Paulo 
822e28a4053SRui Paulo 
823e28a4053SRui Paulo static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
824e28a4053SRui Paulo 			       size_t len, u16 stype, int ok)
825e28a4053SRui Paulo {
826e28a4053SRui Paulo 	struct ieee80211_hdr *hdr;
827e28a4053SRui Paulo 	hdr = (struct ieee80211_hdr *) buf;
828e28a4053SRui Paulo 	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
829e28a4053SRui Paulo 	if (hapd == NULL || hapd == HAPD_BROADCAST)
830e28a4053SRui Paulo 		return;
831e28a4053SRui Paulo 	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
832e28a4053SRui Paulo }
833e28a4053SRui Paulo 
834e28a4053SRui Paulo #endif /* NEED_AP_MLME */
835e28a4053SRui Paulo 
836e28a4053SRui Paulo 
837e28a4053SRui Paulo static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
838e28a4053SRui Paulo {
839e28a4053SRui Paulo 	struct sta_info *sta = ap_get_sta(hapd, addr);
840e28a4053SRui Paulo 	if (sta)
841e28a4053SRui Paulo 		return 0;
842e28a4053SRui Paulo 
843e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
844e28a4053SRui Paulo 		   " - adding a new STA", MAC2STR(addr));
845e28a4053SRui Paulo 	sta = ap_sta_add(hapd, addr);
846e28a4053SRui Paulo 	if (sta) {
847e28a4053SRui Paulo 		hostapd_new_assoc_sta(hapd, sta, 0);
848e28a4053SRui Paulo 	} else {
849e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
850e28a4053SRui Paulo 			   MAC2STR(addr));
851e28a4053SRui Paulo 		return -1;
852e28a4053SRui Paulo 	}
853e28a4053SRui Paulo 
854e28a4053SRui Paulo 	return 0;
855e28a4053SRui Paulo }
856e28a4053SRui Paulo 
857e28a4053SRui Paulo 
858e28a4053SRui Paulo static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
859e28a4053SRui Paulo 				   const u8 *data, size_t data_len)
860e28a4053SRui Paulo {
861e28a4053SRui Paulo 	struct hostapd_iface *iface = hapd->iface;
862f05cddf9SRui Paulo 	struct sta_info *sta;
863e28a4053SRui Paulo 	size_t j;
864e28a4053SRui Paulo 
865e28a4053SRui Paulo 	for (j = 0; j < iface->num_bss; j++) {
866f05cddf9SRui Paulo 		if ((sta = ap_get_sta(iface->bss[j], src))) {
867f05cddf9SRui Paulo 			if (sta->flags & WLAN_STA_ASSOC) {
868e28a4053SRui Paulo 				hapd = iface->bss[j];
869e28a4053SRui Paulo 				break;
870e28a4053SRui Paulo 			}
871e28a4053SRui Paulo 		}
872f05cddf9SRui Paulo 	}
873e28a4053SRui Paulo 
874e28a4053SRui Paulo 	ieee802_1x_receive(hapd, src, data, data_len);
875e28a4053SRui Paulo }
876e28a4053SRui Paulo 
877e28a4053SRui Paulo 
878*5b9c547cSRui Paulo static struct hostapd_channel_data * hostapd_get_mode_channel(
879*5b9c547cSRui Paulo 	struct hostapd_iface *iface, unsigned int freq)
880*5b9c547cSRui Paulo {
881*5b9c547cSRui Paulo 	int i;
882*5b9c547cSRui Paulo 	struct hostapd_channel_data *chan;
883*5b9c547cSRui Paulo 
884*5b9c547cSRui Paulo 	for (i = 0; i < iface->current_mode->num_channels; i++) {
885*5b9c547cSRui Paulo 		chan = &iface->current_mode->channels[i];
886*5b9c547cSRui Paulo 		if (!chan)
887*5b9c547cSRui Paulo 			return NULL;
888*5b9c547cSRui Paulo 		if ((unsigned int) chan->freq == freq)
889*5b9c547cSRui Paulo 			return chan;
890*5b9c547cSRui Paulo 	}
891*5b9c547cSRui Paulo 
892*5b9c547cSRui Paulo 	return NULL;
893*5b9c547cSRui Paulo }
894*5b9c547cSRui Paulo 
895*5b9c547cSRui Paulo 
896*5b9c547cSRui Paulo static void hostapd_update_nf(struct hostapd_iface *iface,
897*5b9c547cSRui Paulo 			      struct hostapd_channel_data *chan,
898*5b9c547cSRui Paulo 			      struct freq_survey *survey)
899*5b9c547cSRui Paulo {
900*5b9c547cSRui Paulo 	if (!iface->chans_surveyed) {
901*5b9c547cSRui Paulo 		chan->min_nf = survey->nf;
902*5b9c547cSRui Paulo 		iface->lowest_nf = survey->nf;
903*5b9c547cSRui Paulo 	} else {
904*5b9c547cSRui Paulo 		if (dl_list_empty(&chan->survey_list))
905*5b9c547cSRui Paulo 			chan->min_nf = survey->nf;
906*5b9c547cSRui Paulo 		else if (survey->nf < chan->min_nf)
907*5b9c547cSRui Paulo 			chan->min_nf = survey->nf;
908*5b9c547cSRui Paulo 		if (survey->nf < iface->lowest_nf)
909*5b9c547cSRui Paulo 			iface->lowest_nf = survey->nf;
910*5b9c547cSRui Paulo 	}
911*5b9c547cSRui Paulo }
912*5b9c547cSRui Paulo 
913*5b9c547cSRui Paulo 
914*5b9c547cSRui Paulo static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
915*5b9c547cSRui Paulo 					      struct survey_results *survey_res)
916*5b9c547cSRui Paulo {
917*5b9c547cSRui Paulo 	struct hostapd_channel_data *chan;
918*5b9c547cSRui Paulo 	struct freq_survey *survey;
919*5b9c547cSRui Paulo 	u64 divisor, dividend;
920*5b9c547cSRui Paulo 
921*5b9c547cSRui Paulo 	survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
922*5b9c547cSRui Paulo 			       list);
923*5b9c547cSRui Paulo 	if (!survey || !survey->freq)
924*5b9c547cSRui Paulo 		return;
925*5b9c547cSRui Paulo 
926*5b9c547cSRui Paulo 	chan = hostapd_get_mode_channel(iface, survey->freq);
927*5b9c547cSRui Paulo 	if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
928*5b9c547cSRui Paulo 		return;
929*5b9c547cSRui Paulo 
930*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
931*5b9c547cSRui Paulo 		   survey->freq,
932*5b9c547cSRui Paulo 		   (unsigned long int) survey->channel_time,
933*5b9c547cSRui Paulo 		   (unsigned long int) survey->channel_time_busy);
934*5b9c547cSRui Paulo 
935*5b9c547cSRui Paulo 	if (survey->channel_time > iface->last_channel_time &&
936*5b9c547cSRui Paulo 	    survey->channel_time > survey->channel_time_busy) {
937*5b9c547cSRui Paulo 		dividend = survey->channel_time_busy -
938*5b9c547cSRui Paulo 			iface->last_channel_time_busy;
939*5b9c547cSRui Paulo 		divisor = survey->channel_time - iface->last_channel_time;
940*5b9c547cSRui Paulo 
941*5b9c547cSRui Paulo 		iface->channel_utilization = dividend * 255 / divisor;
942*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
943*5b9c547cSRui Paulo 			   iface->channel_utilization);
944*5b9c547cSRui Paulo 	}
945*5b9c547cSRui Paulo 	iface->last_channel_time = survey->channel_time;
946*5b9c547cSRui Paulo 	iface->last_channel_time_busy = survey->channel_time_busy;
947*5b9c547cSRui Paulo }
948*5b9c547cSRui Paulo 
949*5b9c547cSRui Paulo 
950*5b9c547cSRui Paulo static void hostapd_event_get_survey(struct hostapd_data *hapd,
951*5b9c547cSRui Paulo 				     struct survey_results *survey_results)
952*5b9c547cSRui Paulo {
953*5b9c547cSRui Paulo 	struct hostapd_iface *iface = hapd->iface;
954*5b9c547cSRui Paulo 	struct freq_survey *survey, *tmp;
955*5b9c547cSRui Paulo 	struct hostapd_channel_data *chan;
956*5b9c547cSRui Paulo 
957*5b9c547cSRui Paulo 	if (dl_list_empty(&survey_results->survey_list)) {
958*5b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "No survey data received");
959*5b9c547cSRui Paulo 		return;
960*5b9c547cSRui Paulo 	}
961*5b9c547cSRui Paulo 
962*5b9c547cSRui Paulo 	if (survey_results->freq_filter) {
963*5b9c547cSRui Paulo 		hostapd_single_channel_get_survey(iface, survey_results);
964*5b9c547cSRui Paulo 		return;
965*5b9c547cSRui Paulo 	}
966*5b9c547cSRui Paulo 
967*5b9c547cSRui Paulo 	dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
968*5b9c547cSRui Paulo 			      struct freq_survey, list) {
969*5b9c547cSRui Paulo 		chan = hostapd_get_mode_channel(iface, survey->freq);
970*5b9c547cSRui Paulo 		if (!chan)
971*5b9c547cSRui Paulo 			continue;
972*5b9c547cSRui Paulo 		if (chan->flag & HOSTAPD_CHAN_DISABLED)
973*5b9c547cSRui Paulo 			continue;
974*5b9c547cSRui Paulo 
975*5b9c547cSRui Paulo 		dl_list_del(&survey->list);
976*5b9c547cSRui Paulo 		dl_list_add_tail(&chan->survey_list, &survey->list);
977*5b9c547cSRui Paulo 
978*5b9c547cSRui Paulo 		hostapd_update_nf(iface, chan, survey);
979*5b9c547cSRui Paulo 
980*5b9c547cSRui Paulo 		iface->chans_surveyed++;
981*5b9c547cSRui Paulo 	}
982*5b9c547cSRui Paulo }
983*5b9c547cSRui Paulo 
984*5b9c547cSRui Paulo 
985*5b9c547cSRui Paulo #ifdef NEED_AP_MLME
986*5b9c547cSRui Paulo 
987*5b9c547cSRui Paulo static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
988*5b9c547cSRui Paulo {
989*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
990*5b9c547cSRui Paulo 		   hapd->conf->iface);
991*5b9c547cSRui Paulo 
992*5b9c547cSRui Paulo 	if (hapd->csa_in_progress) {
993*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
994*5b9c547cSRui Paulo 			   hapd->conf->iface);
995*5b9c547cSRui Paulo 		hostapd_switch_channel_fallback(hapd->iface,
996*5b9c547cSRui Paulo 						&hapd->cs_freq_params);
997*5b9c547cSRui Paulo 	}
998*5b9c547cSRui Paulo }
999*5b9c547cSRui Paulo 
1000*5b9c547cSRui Paulo 
1001*5b9c547cSRui Paulo static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
1002*5b9c547cSRui Paulo 					     struct dfs_event *radar)
1003*5b9c547cSRui Paulo {
1004*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
1005*5b9c547cSRui Paulo 	hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
1006*5b9c547cSRui Paulo 				   radar->chan_offset, radar->chan_width,
1007*5b9c547cSRui Paulo 				   radar->cf1, radar->cf2);
1008*5b9c547cSRui Paulo }
1009*5b9c547cSRui Paulo 
1010*5b9c547cSRui Paulo 
1011*5b9c547cSRui Paulo static void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
1012*5b9c547cSRui Paulo 					   struct dfs_event *radar)
1013*5b9c547cSRui Paulo {
1014*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
1015*5b9c547cSRui Paulo 	hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
1016*5b9c547cSRui Paulo 				 radar->chan_offset, radar->chan_width,
1017*5b9c547cSRui Paulo 				 radar->cf1, radar->cf2);
1018*5b9c547cSRui Paulo }
1019*5b9c547cSRui Paulo 
1020*5b9c547cSRui Paulo 
1021*5b9c547cSRui Paulo static void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
1022*5b9c547cSRui Paulo 					  struct dfs_event *radar)
1023*5b9c547cSRui Paulo {
1024*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
1025*5b9c547cSRui Paulo 	hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
1026*5b9c547cSRui Paulo 				 radar->chan_offset, radar->chan_width,
1027*5b9c547cSRui Paulo 				 radar->cf1, radar->cf2);
1028*5b9c547cSRui Paulo }
1029*5b9c547cSRui Paulo 
1030*5b9c547cSRui Paulo 
1031*5b9c547cSRui Paulo static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
1032*5b9c547cSRui Paulo 					   struct dfs_event *radar)
1033*5b9c547cSRui Paulo {
1034*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
1035*5b9c547cSRui Paulo 	hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
1036*5b9c547cSRui Paulo 				 radar->chan_offset, radar->chan_width,
1037*5b9c547cSRui Paulo 				 radar->cf1, radar->cf2);
1038*5b9c547cSRui Paulo }
1039*5b9c547cSRui Paulo 
1040*5b9c547cSRui Paulo 
1041*5b9c547cSRui Paulo static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
1042*5b9c547cSRui Paulo 					  struct dfs_event *radar)
1043*5b9c547cSRui Paulo {
1044*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
1045*5b9c547cSRui Paulo 	hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
1046*5b9c547cSRui Paulo 			      radar->chan_offset, radar->chan_width,
1047*5b9c547cSRui Paulo 			      radar->cf1, radar->cf2);
1048*5b9c547cSRui Paulo }
1049*5b9c547cSRui Paulo 
1050*5b9c547cSRui Paulo #endif /* NEED_AP_MLME */
1051*5b9c547cSRui Paulo 
1052*5b9c547cSRui Paulo 
1053e28a4053SRui Paulo void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
1054e28a4053SRui Paulo 			  union wpa_event_data *data)
1055e28a4053SRui Paulo {
1056e28a4053SRui Paulo 	struct hostapd_data *hapd = ctx;
1057f05cddf9SRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG
1058f05cddf9SRui Paulo 	int level = MSG_DEBUG;
1059f05cddf9SRui Paulo 
1060f05cddf9SRui Paulo 	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
1061f05cddf9SRui Paulo 	    data->rx_mgmt.frame_len >= 24) {
1062f05cddf9SRui Paulo 		const struct ieee80211_hdr *hdr;
1063f05cddf9SRui Paulo 		u16 fc;
1064f05cddf9SRui Paulo 		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
1065f05cddf9SRui Paulo 		fc = le_to_host16(hdr->frame_control);
1066f05cddf9SRui Paulo 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
1067f05cddf9SRui Paulo 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
1068f05cddf9SRui Paulo 			level = MSG_EXCESSIVE;
1069*5b9c547cSRui Paulo 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
1070*5b9c547cSRui Paulo 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
1071*5b9c547cSRui Paulo 			level = MSG_EXCESSIVE;
1072f05cddf9SRui Paulo 	}
1073f05cddf9SRui Paulo 
1074f05cddf9SRui Paulo 	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
1075f05cddf9SRui Paulo 		event_to_string(event), event);
1076f05cddf9SRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */
1077e28a4053SRui Paulo 
1078e28a4053SRui Paulo 	switch (event) {
1079e28a4053SRui Paulo 	case EVENT_MICHAEL_MIC_FAILURE:
1080e28a4053SRui Paulo 		michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
1081e28a4053SRui Paulo 		break;
1082e28a4053SRui Paulo 	case EVENT_SCAN_RESULTS:
1083e28a4053SRui Paulo 		if (hapd->iface->scan_cb)
1084e28a4053SRui Paulo 			hapd->iface->scan_cb(hapd->iface);
1085e28a4053SRui Paulo 		break;
1086e28a4053SRui Paulo 	case EVENT_WPS_BUTTON_PUSHED:
1087f05cddf9SRui Paulo 		hostapd_wps_button_pushed(hapd, NULL);
1088e28a4053SRui Paulo 		break;
1089e28a4053SRui Paulo #ifdef NEED_AP_MLME
1090e28a4053SRui Paulo 	case EVENT_TX_STATUS:
1091e28a4053SRui Paulo 		switch (data->tx_status.type) {
1092e28a4053SRui Paulo 		case WLAN_FC_TYPE_MGMT:
1093e28a4053SRui Paulo 			hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
1094e28a4053SRui Paulo 					   data->tx_status.data_len,
1095e28a4053SRui Paulo 					   data->tx_status.stype,
1096e28a4053SRui Paulo 					   data->tx_status.ack);
1097e28a4053SRui Paulo 			break;
1098e28a4053SRui Paulo 		case WLAN_FC_TYPE_DATA:
1099e28a4053SRui Paulo 			hostapd_tx_status(hapd, data->tx_status.dst,
1100e28a4053SRui Paulo 					  data->tx_status.data,
1101e28a4053SRui Paulo 					  data->tx_status.data_len,
1102e28a4053SRui Paulo 					  data->tx_status.ack);
1103e28a4053SRui Paulo 			break;
1104e28a4053SRui Paulo 		}
1105e28a4053SRui Paulo 		break;
1106f05cddf9SRui Paulo 	case EVENT_EAPOL_TX_STATUS:
1107f05cddf9SRui Paulo 		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
1108f05cddf9SRui Paulo 					data->eapol_tx_status.data,
1109f05cddf9SRui Paulo 					data->eapol_tx_status.data_len,
1110f05cddf9SRui Paulo 					data->eapol_tx_status.ack);
1111f05cddf9SRui Paulo 		break;
1112f05cddf9SRui Paulo 	case EVENT_DRIVER_CLIENT_POLL_OK:
1113f05cddf9SRui Paulo 		hostapd_client_poll_ok(hapd, data->client_poll.addr);
1114f05cddf9SRui Paulo 		break;
1115e28a4053SRui Paulo 	case EVENT_RX_FROM_UNKNOWN:
1116f05cddf9SRui Paulo 		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
1117f05cddf9SRui Paulo 					    data->rx_from_unknown.addr,
1118f05cddf9SRui Paulo 					    data->rx_from_unknown.wds);
1119e28a4053SRui Paulo 		break;
1120*5b9c547cSRui Paulo #endif /* NEED_AP_MLME */
1121e28a4053SRui Paulo 	case EVENT_RX_MGMT:
1122*5b9c547cSRui Paulo 		if (!data->rx_mgmt.frame)
1123*5b9c547cSRui Paulo 			break;
1124*5b9c547cSRui Paulo #ifdef NEED_AP_MLME
1125*5b9c547cSRui Paulo 		if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
1126e28a4053SRui Paulo 			break;
1127e28a4053SRui Paulo #endif /* NEED_AP_MLME */
1128*5b9c547cSRui Paulo 		hostapd_action_rx(hapd, &data->rx_mgmt);
1129*5b9c547cSRui Paulo 		break;
1130e28a4053SRui Paulo 	case EVENT_RX_PROBE_REQ:
1131f05cddf9SRui Paulo 		if (data->rx_probe_req.sa == NULL ||
1132f05cddf9SRui Paulo 		    data->rx_probe_req.ie == NULL)
1133f05cddf9SRui Paulo 			break;
1134e28a4053SRui Paulo 		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
1135f05cddf9SRui Paulo 				     data->rx_probe_req.da,
1136f05cddf9SRui Paulo 				     data->rx_probe_req.bssid,
1137e28a4053SRui Paulo 				     data->rx_probe_req.ie,
1138f05cddf9SRui Paulo 				     data->rx_probe_req.ie_len,
1139f05cddf9SRui Paulo 				     data->rx_probe_req.ssi_signal);
1140e28a4053SRui Paulo 		break;
1141e28a4053SRui Paulo 	case EVENT_NEW_STA:
1142e28a4053SRui Paulo 		hostapd_event_new_sta(hapd, data->new_sta.addr);
1143e28a4053SRui Paulo 		break;
1144e28a4053SRui Paulo 	case EVENT_EAPOL_RX:
1145e28a4053SRui Paulo 		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
1146e28a4053SRui Paulo 				       data->eapol_rx.data,
1147e28a4053SRui Paulo 				       data->eapol_rx.data_len);
1148e28a4053SRui Paulo 		break;
1149e28a4053SRui Paulo 	case EVENT_ASSOC:
1150*5b9c547cSRui Paulo 		if (!data)
1151*5b9c547cSRui Paulo 			return;
1152e28a4053SRui Paulo 		hostapd_notif_assoc(hapd, data->assoc_info.addr,
1153e28a4053SRui Paulo 				    data->assoc_info.req_ies,
1154f05cddf9SRui Paulo 				    data->assoc_info.req_ies_len,
1155f05cddf9SRui Paulo 				    data->assoc_info.reassoc);
1156e28a4053SRui Paulo 		break;
1157e28a4053SRui Paulo 	case EVENT_DISASSOC:
1158e28a4053SRui Paulo 		if (data)
1159e28a4053SRui Paulo 			hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
1160e28a4053SRui Paulo 		break;
1161e28a4053SRui Paulo 	case EVENT_DEAUTH:
1162e28a4053SRui Paulo 		if (data)
1163e28a4053SRui Paulo 			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
1164e28a4053SRui Paulo 		break;
1165f05cddf9SRui Paulo 	case EVENT_STATION_LOW_ACK:
1166f05cddf9SRui Paulo 		if (!data)
1167f05cddf9SRui Paulo 			break;
1168f05cddf9SRui Paulo 		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
1169f05cddf9SRui Paulo 		break;
1170f05cddf9SRui Paulo 	case EVENT_AUTH:
1171f05cddf9SRui Paulo 		hostapd_notif_auth(hapd, &data->auth);
1172f05cddf9SRui Paulo 		break;
1173f05cddf9SRui Paulo 	case EVENT_CH_SWITCH:
1174f05cddf9SRui Paulo 		if (!data)
1175f05cddf9SRui Paulo 			break;
1176f05cddf9SRui Paulo 		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
1177f05cddf9SRui Paulo 					data->ch_switch.ht_enabled,
1178*5b9c547cSRui Paulo 					data->ch_switch.ch_offset,
1179*5b9c547cSRui Paulo 					data->ch_switch.ch_width,
1180*5b9c547cSRui Paulo 					data->ch_switch.cf1,
1181*5b9c547cSRui Paulo 					data->ch_switch.cf2);
1182f05cddf9SRui Paulo 		break;
1183*5b9c547cSRui Paulo 	case EVENT_CONNECT_FAILED_REASON:
1184*5b9c547cSRui Paulo 		if (!data)
1185*5b9c547cSRui Paulo 			break;
1186*5b9c547cSRui Paulo 		hostapd_event_connect_failed_reason(
1187*5b9c547cSRui Paulo 			hapd, data->connect_failed_reason.addr,
1188*5b9c547cSRui Paulo 			data->connect_failed_reason.code);
1189*5b9c547cSRui Paulo 		break;
1190*5b9c547cSRui Paulo 	case EVENT_SURVEY:
1191*5b9c547cSRui Paulo 		hostapd_event_get_survey(hapd, &data->survey_results);
1192*5b9c547cSRui Paulo 		break;
1193*5b9c547cSRui Paulo #ifdef NEED_AP_MLME
1194*5b9c547cSRui Paulo 	case EVENT_INTERFACE_UNAVAILABLE:
1195*5b9c547cSRui Paulo 		hostapd_event_iface_unavailable(hapd);
1196*5b9c547cSRui Paulo 		break;
1197*5b9c547cSRui Paulo 	case EVENT_DFS_RADAR_DETECTED:
1198*5b9c547cSRui Paulo 		if (!data)
1199*5b9c547cSRui Paulo 			break;
1200*5b9c547cSRui Paulo 		hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
1201*5b9c547cSRui Paulo 		break;
1202*5b9c547cSRui Paulo 	case EVENT_DFS_CAC_FINISHED:
1203*5b9c547cSRui Paulo 		if (!data)
1204*5b9c547cSRui Paulo 			break;
1205*5b9c547cSRui Paulo 		hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
1206*5b9c547cSRui Paulo 		break;
1207*5b9c547cSRui Paulo 	case EVENT_DFS_CAC_ABORTED:
1208*5b9c547cSRui Paulo 		if (!data)
1209*5b9c547cSRui Paulo 			break;
1210*5b9c547cSRui Paulo 		hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
1211*5b9c547cSRui Paulo 		break;
1212*5b9c547cSRui Paulo 	case EVENT_DFS_NOP_FINISHED:
1213*5b9c547cSRui Paulo 		if (!data)
1214*5b9c547cSRui Paulo 			break;
1215*5b9c547cSRui Paulo 		hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
1216*5b9c547cSRui Paulo 		break;
1217*5b9c547cSRui Paulo 	case EVENT_CHANNEL_LIST_CHANGED:
1218*5b9c547cSRui Paulo 		/* channel list changed (regulatory?), update channel list */
1219*5b9c547cSRui Paulo 		/* TODO: check this. hostapd_get_hw_features() initializes
1220*5b9c547cSRui Paulo 		 * too much stuff. */
1221*5b9c547cSRui Paulo 		/* hostapd_get_hw_features(hapd->iface); */
1222*5b9c547cSRui Paulo 		hostapd_channel_list_updated(
1223*5b9c547cSRui Paulo 			hapd->iface, data->channel_list_changed.initiator);
1224*5b9c547cSRui Paulo 		break;
1225*5b9c547cSRui Paulo 	case EVENT_DFS_CAC_STARTED:
1226*5b9c547cSRui Paulo 		if (!data)
1227*5b9c547cSRui Paulo 			break;
1228*5b9c547cSRui Paulo 		hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
1229*5b9c547cSRui Paulo 		break;
1230*5b9c547cSRui Paulo #endif /* NEED_AP_MLME */
1231*5b9c547cSRui Paulo 	case EVENT_INTERFACE_ENABLED:
1232*5b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
1233*5b9c547cSRui Paulo 		if (hapd->disabled && hapd->started) {
1234*5b9c547cSRui Paulo 			hapd->disabled = 0;
1235*5b9c547cSRui Paulo 			/*
1236*5b9c547cSRui Paulo 			 * Try to re-enable interface if the driver stopped it
1237*5b9c547cSRui Paulo 			 * when the interface got disabled.
1238*5b9c547cSRui Paulo 			 */
1239*5b9c547cSRui Paulo 			wpa_auth_reconfig_group_keys(hapd->wpa_auth);
1240*5b9c547cSRui Paulo 			hapd->reenable_beacon = 1;
1241*5b9c547cSRui Paulo 			ieee802_11_set_beacon(hapd);
1242*5b9c547cSRui Paulo 		}
1243*5b9c547cSRui Paulo 		break;
1244*5b9c547cSRui Paulo 	case EVENT_INTERFACE_DISABLED:
1245*5b9c547cSRui Paulo 		hostapd_free_stas(hapd);
1246*5b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
1247*5b9c547cSRui Paulo 		hapd->disabled = 1;
1248*5b9c547cSRui Paulo 		break;
1249*5b9c547cSRui Paulo #ifdef CONFIG_ACS
1250*5b9c547cSRui Paulo 	case EVENT_ACS_CHANNEL_SELECTED:
1251*5b9c547cSRui Paulo 		hostapd_acs_channel_selected(
1252*5b9c547cSRui Paulo 			hapd, data->acs_selected_channels.pri_channel,
1253*5b9c547cSRui Paulo 			data->acs_selected_channels.sec_channel);
1254*5b9c547cSRui Paulo 		break;
1255*5b9c547cSRui Paulo #endif /* CONFIG_ACS */
1256e28a4053SRui Paulo 	default:
1257e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
1258e28a4053SRui Paulo 		break;
1259e28a4053SRui Paulo 	}
1260e28a4053SRui Paulo }
1261e28a4053SRui Paulo 
1262e28a4053SRui Paulo #endif /* HOSTAPD */
1263