drv_callbacks.c revision 337817
1214501Srpaulo/*
2214501Srpaulo * hostapd / Callback functions for driver wrappers
3281806Srpaulo * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "utils/includes.h"
10214501Srpaulo
11214501Srpaulo#include "utils/common.h"
12281806Srpaulo#include "utils/eloop.h"
13214501Srpaulo#include "radius/radius.h"
14214501Srpaulo#include "drivers/driver.h"
15214501Srpaulo#include "common/ieee802_11_defs.h"
16214501Srpaulo#include "common/ieee802_11_common.h"
17281806Srpaulo#include "common/wpa_ctrl.h"
18252726Srpaulo#include "crypto/random.h"
19252726Srpaulo#include "p2p/p2p.h"
20252726Srpaulo#include "wps/wps.h"
21289549Srpaulo#include "fst/fst.h"
22252726Srpaulo#include "wnm_ap.h"
23214501Srpaulo#include "hostapd.h"
24214501Srpaulo#include "ieee802_11.h"
25337817Scy#include "ieee802_11_auth.h"
26214501Srpaulo#include "sta_info.h"
27214501Srpaulo#include "accounting.h"
28214501Srpaulo#include "tkip_countermeasures.h"
29214501Srpaulo#include "ieee802_1x.h"
30214501Srpaulo#include "wpa_auth.h"
31214501Srpaulo#include "wps_hostapd.h"
32252726Srpaulo#include "ap_drv_ops.h"
33214501Srpaulo#include "ap_config.h"
34252726Srpaulo#include "hw_features.h"
35281806Srpaulo#include "dfs.h"
36281806Srpaulo#include "beacon.h"
37337817Scy#include "mbo_ap.h"
38214501Srpaulo
39214501Srpaulo
40214501Srpauloint hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
41252726Srpaulo			const u8 *req_ies, size_t req_ies_len, int reassoc)
42214501Srpaulo{
43214501Srpaulo	struct sta_info *sta;
44214501Srpaulo	int new_assoc, res;
45214501Srpaulo	struct ieee802_11_elems elems;
46252726Srpaulo	const u8 *ie;
47252726Srpaulo	size_t ielen;
48289549Srpaulo#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
49252726Srpaulo	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
50252726Srpaulo	u8 *p = buf;
51289549Srpaulo#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
52252726Srpaulo	u16 reason = WLAN_REASON_UNSPECIFIED;
53252726Srpaulo	u16 status = WLAN_STATUS_SUCCESS;
54281806Srpaulo	const u8 *p2p_dev_addr = NULL;
55214501Srpaulo
56214501Srpaulo	if (addr == NULL) {
57214501Srpaulo		/*
58214501Srpaulo		 * This could potentially happen with unexpected event from the
59214501Srpaulo		 * driver wrapper. This was seen at least in one case where the
60214501Srpaulo		 * driver ended up being set to station mode while hostapd was
61214501Srpaulo		 * running, so better make sure we stop processing such an
62214501Srpaulo		 * event here.
63214501Srpaulo		 */
64289549Srpaulo		wpa_printf(MSG_DEBUG,
65289549Srpaulo			   "hostapd_notif_assoc: Skip event with no address");
66214501Srpaulo		return -1;
67214501Srpaulo	}
68252726Srpaulo	random_add_randomness(addr, ETH_ALEN);
69214501Srpaulo
70214501Srpaulo	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
71214501Srpaulo		       HOSTAPD_LEVEL_INFO, "associated");
72214501Srpaulo
73252726Srpaulo	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
74214501Srpaulo	if (elems.wps_ie) {
75214501Srpaulo		ie = elems.wps_ie - 2;
76214501Srpaulo		ielen = elems.wps_ie_len + 2;
77214501Srpaulo		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
78214501Srpaulo	} else if (elems.rsn_ie) {
79214501Srpaulo		ie = elems.rsn_ie - 2;
80214501Srpaulo		ielen = elems.rsn_ie_len + 2;
81214501Srpaulo		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
82214501Srpaulo	} else if (elems.wpa_ie) {
83214501Srpaulo		ie = elems.wpa_ie - 2;
84214501Srpaulo		ielen = elems.wpa_ie_len + 2;
85214501Srpaulo		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
86281806Srpaulo#ifdef CONFIG_HS20
87281806Srpaulo	} else if (elems.osen) {
88281806Srpaulo		ie = elems.osen - 2;
89281806Srpaulo		ielen = elems.osen_len + 2;
90281806Srpaulo		wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
91281806Srpaulo#endif /* CONFIG_HS20 */
92214501Srpaulo	} else {
93214501Srpaulo		ie = NULL;
94214501Srpaulo		ielen = 0;
95289549Srpaulo		wpa_printf(MSG_DEBUG,
96289549Srpaulo			   "STA did not include WPS/RSN/WPA IE in (Re)AssocReq");
97214501Srpaulo	}
98214501Srpaulo
99214501Srpaulo	sta = ap_get_sta(hapd, addr);
100214501Srpaulo	if (sta) {
101281806Srpaulo		ap_sta_no_session_timeout(hapd, sta);
102214501Srpaulo		accounting_sta_stop(hapd, sta);
103252726Srpaulo
104252726Srpaulo		/*
105252726Srpaulo		 * Make sure that the previously registered inactivity timer
106252726Srpaulo		 * will not remove the STA immediately.
107252726Srpaulo		 */
108252726Srpaulo		sta->timeout_next = STA_NULLFUNC;
109214501Srpaulo	} else {
110214501Srpaulo		sta = ap_sta_add(hapd, addr);
111252726Srpaulo		if (sta == NULL) {
112252726Srpaulo			hostapd_drv_sta_disassoc(hapd, addr,
113252726Srpaulo						 WLAN_REASON_DISASSOC_AP_BUSY);
114214501Srpaulo			return -1;
115252726Srpaulo		}
116214501Srpaulo	}
117252726Srpaulo	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
118214501Srpaulo
119337817Scy	/*
120337817Scy	 * ACL configurations to the drivers (implementing AP SME and ACL
121337817Scy	 * offload) without hostapd's knowledge, can result in a disconnection
122337817Scy	 * though the driver accepts the connection. Skip the hostapd check for
123337817Scy	 * ACL if the driver supports ACL offload to avoid potentially
124337817Scy	 * conflicting ACL rules.
125337817Scy	 */
126337817Scy	if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
127337817Scy	    hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
128337817Scy		wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
129337817Scy			   MAC2STR(addr));
130337817Scy		reason = WLAN_REASON_UNSPECIFIED;
131337817Scy		goto fail;
132337817Scy	}
133337817Scy
134252726Srpaulo#ifdef CONFIG_P2P
135252726Srpaulo	if (elems.p2p) {
136252726Srpaulo		wpabuf_free(sta->p2p_ie);
137252726Srpaulo		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
138252726Srpaulo							  P2P_IE_VENDOR_TYPE);
139281806Srpaulo		if (sta->p2p_ie)
140281806Srpaulo			p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
141252726Srpaulo	}
142252726Srpaulo#endif /* CONFIG_P2P */
143252726Srpaulo
144281806Srpaulo#ifdef CONFIG_IEEE80211N
145281806Srpaulo#ifdef NEED_AP_MLME
146281806Srpaulo	if (elems.ht_capabilities &&
147281806Srpaulo	    (hapd->iface->conf->ht_capab &
148281806Srpaulo	     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
149281806Srpaulo		struct ieee80211_ht_capabilities *ht_cap =
150281806Srpaulo			(struct ieee80211_ht_capabilities *)
151281806Srpaulo			elems.ht_capabilities;
152281806Srpaulo
153281806Srpaulo		if (le_to_host16(ht_cap->ht_capabilities_info) &
154281806Srpaulo		    HT_CAP_INFO_40MHZ_INTOLERANT)
155281806Srpaulo			ht40_intolerant_add(hapd->iface, sta);
156281806Srpaulo	}
157281806Srpaulo#endif /* NEED_AP_MLME */
158281806Srpaulo#endif /* CONFIG_IEEE80211N */
159281806Srpaulo
160281806Srpaulo#ifdef CONFIG_INTERWORKING
161281806Srpaulo	if (elems.ext_capab && elems.ext_capab_len > 4) {
162281806Srpaulo		if (elems.ext_capab[4] & 0x01)
163281806Srpaulo			sta->qos_map_enabled = 1;
164281806Srpaulo	}
165281806Srpaulo#endif /* CONFIG_INTERWORKING */
166281806Srpaulo
167252726Srpaulo#ifdef CONFIG_HS20
168252726Srpaulo	wpabuf_free(sta->hs20_ie);
169252726Srpaulo	if (elems.hs20 && elems.hs20_len > 4) {
170252726Srpaulo		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
171252726Srpaulo						 elems.hs20_len - 4);
172252726Srpaulo	} else
173252726Srpaulo		sta->hs20_ie = NULL;
174252726Srpaulo#endif /* CONFIG_HS20 */
175252726Srpaulo
176289549Srpaulo#ifdef CONFIG_FST
177289549Srpaulo	wpabuf_free(sta->mb_ies);
178289549Srpaulo	if (hapd->iface->fst)
179289549Srpaulo		sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
180289549Srpaulo	else
181289549Srpaulo		sta->mb_ies = NULL;
182289549Srpaulo#endif /* CONFIG_FST */
183289549Srpaulo
184337817Scy	mbo_ap_check_sta_assoc(hapd, sta, &elems);
185337817Scy
186337817Scy	ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes,
187337817Scy				    elems.supp_op_classes_len);
188337817Scy
189214501Srpaulo	if (hapd->conf->wpa) {
190214501Srpaulo		if (ie == NULL || ielen == 0) {
191252726Srpaulo#ifdef CONFIG_WPS
192214501Srpaulo			if (hapd->conf->wps_state) {
193289549Srpaulo				wpa_printf(MSG_DEBUG,
194289549Srpaulo					   "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use");
195214501Srpaulo				sta->flags |= WLAN_STA_MAYBE_WPS;
196214501Srpaulo				goto skip_wpa_check;
197214501Srpaulo			}
198252726Srpaulo#endif /* CONFIG_WPS */
199214501Srpaulo
200214501Srpaulo			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
201214501Srpaulo			return -1;
202214501Srpaulo		}
203252726Srpaulo#ifdef CONFIG_WPS
204214501Srpaulo		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
205214501Srpaulo		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
206252726Srpaulo			struct wpabuf *wps;
207289549Srpaulo
208214501Srpaulo			sta->flags |= WLAN_STA_WPS;
209252726Srpaulo			wps = ieee802_11_vendor_ie_concat(ie, ielen,
210252726Srpaulo							  WPS_IE_VENDOR_TYPE);
211252726Srpaulo			if (wps) {
212252726Srpaulo				if (wps_is_20(wps)) {
213289549Srpaulo					wpa_printf(MSG_DEBUG,
214289549Srpaulo						   "WPS: STA supports WPS 2.0");
215252726Srpaulo					sta->flags |= WLAN_STA_WPS2;
216252726Srpaulo				}
217252726Srpaulo				wpabuf_free(wps);
218252726Srpaulo			}
219214501Srpaulo			goto skip_wpa_check;
220214501Srpaulo		}
221252726Srpaulo#endif /* CONFIG_WPS */
222214501Srpaulo
223214501Srpaulo		if (sta->wpa_sm == NULL)
224214501Srpaulo			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
225281806Srpaulo							sta->addr,
226281806Srpaulo							p2p_dev_addr);
227214501Srpaulo		if (sta->wpa_sm == NULL) {
228289549Srpaulo			wpa_printf(MSG_ERROR,
229289549Srpaulo				   "Failed to initialize WPA state machine");
230214501Srpaulo			return -1;
231214501Srpaulo		}
232214501Srpaulo		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
233252726Srpaulo					  ie, ielen,
234252726Srpaulo					  elems.mdie, elems.mdie_len);
235214501Srpaulo		if (res != WPA_IE_OK) {
236289549Srpaulo			wpa_printf(MSG_DEBUG,
237289549Srpaulo				   "WPA/RSN information element rejected? (res %u)",
238289549Srpaulo				   res);
239214501Srpaulo			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
240252726Srpaulo			if (res == WPA_INVALID_GROUP) {
241252726Srpaulo				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
242252726Srpaulo				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
243252726Srpaulo			} else if (res == WPA_INVALID_PAIRWISE) {
244252726Srpaulo				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
245252726Srpaulo				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
246252726Srpaulo			} else if (res == WPA_INVALID_AKMP) {
247252726Srpaulo				reason = WLAN_REASON_AKMP_NOT_VALID;
248252726Srpaulo				status = WLAN_STATUS_AKMP_NOT_VALID;
249252726Srpaulo			}
250214501Srpaulo#ifdef CONFIG_IEEE80211W
251252726Srpaulo			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
252252726Srpaulo				reason = WLAN_REASON_INVALID_IE;
253252726Srpaulo				status = WLAN_STATUS_INVALID_IE;
254252726Srpaulo			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
255252726Srpaulo				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
256252726Srpaulo				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
257252726Srpaulo			}
258214501Srpaulo#endif /* CONFIG_IEEE80211W */
259252726Srpaulo			else {
260252726Srpaulo				reason = WLAN_REASON_INVALID_IE;
261252726Srpaulo				status = WLAN_STATUS_INVALID_IE;
262252726Srpaulo			}
263252726Srpaulo			goto fail;
264214501Srpaulo		}
265252726Srpaulo#ifdef CONFIG_IEEE80211W
266252726Srpaulo		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
267252726Srpaulo		    sta->sa_query_count > 0)
268252726Srpaulo			ap_check_sa_query_timeout(hapd, sta);
269252726Srpaulo		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
270252726Srpaulo		    (sta->auth_alg != WLAN_AUTH_FT)) {
271252726Srpaulo			/*
272252726Srpaulo			 * STA has already been associated with MFP and SA
273252726Srpaulo			 * Query timeout has not been reached. Reject the
274252726Srpaulo			 * association attempt temporarily and start SA Query,
275252726Srpaulo			 * if one is not pending.
276252726Srpaulo			 */
277252726Srpaulo
278252726Srpaulo			if (sta->sa_query_count == 0)
279252726Srpaulo				ap_sta_start_sa_query(hapd, sta);
280252726Srpaulo
281252726Srpaulo			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
282252726Srpaulo
283252726Srpaulo			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
284252726Srpaulo
285252726Srpaulo			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
286252726Srpaulo					  p - buf);
287252726Srpaulo			return 0;
288252726Srpaulo		}
289252726Srpaulo
290252726Srpaulo		if (wpa_auth_uses_mfp(sta->wpa_sm))
291252726Srpaulo			sta->flags |= WLAN_STA_MFP;
292252726Srpaulo		else
293252726Srpaulo			sta->flags &= ~WLAN_STA_MFP;
294252726Srpaulo#endif /* CONFIG_IEEE80211W */
295252726Srpaulo
296252726Srpaulo#ifdef CONFIG_IEEE80211R
297252726Srpaulo		if (sta->auth_alg == WLAN_AUTH_FT) {
298252726Srpaulo			status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
299252726Srpaulo							 req_ies_len);
300252726Srpaulo			if (status != WLAN_STATUS_SUCCESS) {
301252726Srpaulo				if (status == WLAN_STATUS_INVALID_PMKID)
302252726Srpaulo					reason = WLAN_REASON_INVALID_IE;
303252726Srpaulo				if (status == WLAN_STATUS_INVALID_MDIE)
304252726Srpaulo					reason = WLAN_REASON_INVALID_IE;
305252726Srpaulo				if (status == WLAN_STATUS_INVALID_FTIE)
306252726Srpaulo					reason = WLAN_REASON_INVALID_IE;
307252726Srpaulo				goto fail;
308252726Srpaulo			}
309252726Srpaulo		}
310252726Srpaulo#endif /* CONFIG_IEEE80211R */
311214501Srpaulo	} else if (hapd->conf->wps_state) {
312252726Srpaulo#ifdef CONFIG_WPS
313252726Srpaulo		struct wpabuf *wps;
314289549Srpaulo
315252726Srpaulo		if (req_ies)
316252726Srpaulo			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
317252726Srpaulo							  WPS_IE_VENDOR_TYPE);
318252726Srpaulo		else
319252726Srpaulo			wps = NULL;
320252726Srpaulo#ifdef CONFIG_WPS_STRICT
321252726Srpaulo		if (wps && wps_validate_assoc_req(wps) < 0) {
322252726Srpaulo			reason = WLAN_REASON_INVALID_IE;
323252726Srpaulo			status = WLAN_STATUS_INVALID_IE;
324252726Srpaulo			wpabuf_free(wps);
325252726Srpaulo			goto fail;
326252726Srpaulo		}
327252726Srpaulo#endif /* CONFIG_WPS_STRICT */
328252726Srpaulo		if (wps) {
329214501Srpaulo			sta->flags |= WLAN_STA_WPS;
330252726Srpaulo			if (wps_is_20(wps)) {
331289549Srpaulo				wpa_printf(MSG_DEBUG,
332289549Srpaulo					   "WPS: STA supports WPS 2.0");
333252726Srpaulo				sta->flags |= WLAN_STA_WPS2;
334252726Srpaulo			}
335214501Srpaulo		} else
336214501Srpaulo			sta->flags |= WLAN_STA_MAYBE_WPS;
337252726Srpaulo		wpabuf_free(wps);
338252726Srpaulo#endif /* CONFIG_WPS */
339281806Srpaulo#ifdef CONFIG_HS20
340281806Srpaulo	} else if (hapd->conf->osen) {
341281806Srpaulo		if (elems.osen == NULL) {
342281806Srpaulo			hostapd_logger(
343281806Srpaulo				hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
344281806Srpaulo				HOSTAPD_LEVEL_INFO,
345281806Srpaulo				"No HS 2.0 OSEN element in association request");
346281806Srpaulo			return WLAN_STATUS_INVALID_IE;
347281806Srpaulo		}
348281806Srpaulo
349281806Srpaulo		wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
350281806Srpaulo		if (sta->wpa_sm == NULL)
351281806Srpaulo			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
352281806Srpaulo							sta->addr, NULL);
353281806Srpaulo		if (sta->wpa_sm == NULL) {
354289549Srpaulo			wpa_printf(MSG_WARNING,
355289549Srpaulo				   "Failed to initialize WPA state machine");
356281806Srpaulo			return WLAN_STATUS_UNSPECIFIED_FAILURE;
357281806Srpaulo		}
358281806Srpaulo		if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
359281806Srpaulo				      elems.osen - 2, elems.osen_len + 2) < 0)
360281806Srpaulo			return WLAN_STATUS_INVALID_IE;
361281806Srpaulo#endif /* CONFIG_HS20 */
362214501Srpaulo	}
363337817Scy
364337817Scy#ifdef CONFIG_MBO
365337817Scy	if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) &&
366337817Scy	    elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) &&
367337817Scy	    hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
368337817Scy		wpa_printf(MSG_INFO,
369337817Scy			   "MBO: Reject WPA2 association without PMF");
370337817Scy		return WLAN_STATUS_UNSPECIFIED_FAILURE;
371337817Scy	}
372337817Scy#endif /* CONFIG_MBO */
373337817Scy
374252726Srpaulo#ifdef CONFIG_WPS
375214501Srpauloskip_wpa_check:
376252726Srpaulo#endif /* CONFIG_WPS */
377214501Srpaulo
378252726Srpaulo#ifdef CONFIG_IEEE80211R
379252726Srpaulo	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
380252726Srpaulo					sta->auth_alg, req_ies, req_ies_len);
381252726Srpaulo
382252726Srpaulo	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
383281806Srpaulo
384281806Srpaulo	if (sta->auth_alg == WLAN_AUTH_FT)
385281806Srpaulo		ap_sta_set_authorized(hapd, sta, 1);
386252726Srpaulo#else /* CONFIG_IEEE80211R */
387252726Srpaulo	/* Keep compiler silent about unused variables */
388252726Srpaulo	if (status) {
389252726Srpaulo	}
390252726Srpaulo#endif /* CONFIG_IEEE80211R */
391252726Srpaulo
392214501Srpaulo	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
393214501Srpaulo	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
394281806Srpaulo	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
395214501Srpaulo
396281806Srpaulo	hostapd_set_sta_flags(hapd, sta);
397281806Srpaulo
398252726Srpaulo	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
399252726Srpaulo		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
400252726Srpaulo	else
401252726Srpaulo		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
402252726Srpaulo
403214501Srpaulo	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
404214501Srpaulo
405214501Srpaulo	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
406214501Srpaulo
407252726Srpaulo#ifdef CONFIG_P2P
408252726Srpaulo	if (req_ies) {
409252726Srpaulo		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
410252726Srpaulo				      req_ies, req_ies_len);
411252726Srpaulo	}
412252726Srpaulo#endif /* CONFIG_P2P */
413252726Srpaulo
414214501Srpaulo	return 0;
415252726Srpaulo
416252726Srpaulofail:
417252726Srpaulo#ifdef CONFIG_IEEE80211R
418252726Srpaulo	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
419252726Srpaulo#endif /* CONFIG_IEEE80211R */
420252726Srpaulo	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
421252726Srpaulo	ap_free_sta(hapd, sta);
422252726Srpaulo	return -1;
423214501Srpaulo}
424214501Srpaulo
425214501Srpaulo
426214501Srpaulovoid hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
427214501Srpaulo{
428214501Srpaulo	struct sta_info *sta;
429214501Srpaulo
430252726Srpaulo	if (addr == NULL) {
431252726Srpaulo		/*
432252726Srpaulo		 * This could potentially happen with unexpected event from the
433252726Srpaulo		 * driver wrapper. This was seen at least in one case where the
434252726Srpaulo		 * driver ended up reporting a station mode event while hostapd
435252726Srpaulo		 * was running, so better make sure we stop processing such an
436252726Srpaulo		 * event here.
437252726Srpaulo		 */
438289549Srpaulo		wpa_printf(MSG_DEBUG,
439289549Srpaulo			   "hostapd_notif_disassoc: Skip event with no address");
440252726Srpaulo		return;
441252726Srpaulo	}
442252726Srpaulo
443214501Srpaulo	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
444214501Srpaulo		       HOSTAPD_LEVEL_INFO, "disassociated");
445214501Srpaulo
446214501Srpaulo	sta = ap_get_sta(hapd, addr);
447214501Srpaulo	if (sta == NULL) {
448289549Srpaulo		wpa_printf(MSG_DEBUG,
449289549Srpaulo			   "Disassociation notification for unknown STA "
450289549Srpaulo			   MACSTR, MAC2STR(addr));
451214501Srpaulo		return;
452214501Srpaulo	}
453214501Srpaulo
454252726Srpaulo	ap_sta_set_authorized(hapd, sta, 0);
455214501Srpaulo	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
456214501Srpaulo	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
457214501Srpaulo	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
458214501Srpaulo	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
459214501Srpaulo	ap_free_sta(hapd, sta);
460214501Srpaulo}
461214501Srpaulo
462214501Srpaulo
463252726Srpaulovoid hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
464252726Srpaulo{
465252726Srpaulo	struct sta_info *sta = ap_get_sta(hapd, addr);
466214501Srpaulo
467252726Srpaulo	if (!sta || !hapd->conf->disassoc_low_ack)
468252726Srpaulo		return;
469252726Srpaulo
470252726Srpaulo	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
471289549Srpaulo		       HOSTAPD_LEVEL_INFO,
472289549Srpaulo		       "disconnected due to excessive missing ACKs");
473252726Srpaulo	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
474252726Srpaulo	if (sta)
475252726Srpaulo		ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
476252726Srpaulo}
477252726Srpaulo
478252726Srpaulo
479252726Srpaulovoid hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
480281806Srpaulo			     int offset, int width, int cf1, int cf2)
481252726Srpaulo{
482214501Srpaulo#ifdef NEED_AP_MLME
483337817Scy	int channel, chwidth, is_dfs;
484337817Scy	u8 seg0_idx = 0, seg1_idx = 0;
485214501Srpaulo
486252726Srpaulo	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
487281806Srpaulo		       HOSTAPD_LEVEL_INFO,
488281806Srpaulo		       "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
489281806Srpaulo		       freq, ht, offset, width, channel_width_to_string(width),
490281806Srpaulo		       cf1, cf2);
491252726Srpaulo
492252726Srpaulo	hapd->iface->freq = freq;
493252726Srpaulo
494252726Srpaulo	channel = hostapd_hw_get_channel(hapd, freq);
495252726Srpaulo	if (!channel) {
496252726Srpaulo		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
497289549Srpaulo			       HOSTAPD_LEVEL_WARNING,
498289549Srpaulo			       "driver switched to bad channel!");
499252726Srpaulo		return;
500252726Srpaulo	}
501252726Srpaulo
502281806Srpaulo	switch (width) {
503281806Srpaulo	case CHAN_WIDTH_80:
504281806Srpaulo		chwidth = VHT_CHANWIDTH_80MHZ;
505281806Srpaulo		break;
506281806Srpaulo	case CHAN_WIDTH_80P80:
507281806Srpaulo		chwidth = VHT_CHANWIDTH_80P80MHZ;
508281806Srpaulo		break;
509281806Srpaulo	case CHAN_WIDTH_160:
510281806Srpaulo		chwidth = VHT_CHANWIDTH_160MHZ;
511281806Srpaulo		break;
512281806Srpaulo	case CHAN_WIDTH_20_NOHT:
513281806Srpaulo	case CHAN_WIDTH_20:
514281806Srpaulo	case CHAN_WIDTH_40:
515281806Srpaulo	default:
516281806Srpaulo		chwidth = VHT_CHANWIDTH_USE_HT;
517281806Srpaulo		break;
518281806Srpaulo	}
519281806Srpaulo
520281806Srpaulo	switch (hapd->iface->current_mode->mode) {
521281806Srpaulo	case HOSTAPD_MODE_IEEE80211A:
522281806Srpaulo		if (cf1 > 5000)
523281806Srpaulo			seg0_idx = (cf1 - 5000) / 5;
524281806Srpaulo		if (cf2 > 5000)
525281806Srpaulo			seg1_idx = (cf2 - 5000) / 5;
526281806Srpaulo		break;
527281806Srpaulo	default:
528337817Scy		ieee80211_freq_to_chan(cf1, &seg0_idx);
529337817Scy		ieee80211_freq_to_chan(cf2, &seg1_idx);
530281806Srpaulo		break;
531281806Srpaulo	}
532281806Srpaulo
533252726Srpaulo	hapd->iconf->channel = channel;
534252726Srpaulo	hapd->iconf->ieee80211n = ht;
535281806Srpaulo	if (!ht)
536281806Srpaulo		hapd->iconf->ieee80211ac = 0;
537252726Srpaulo	hapd->iconf->secondary_channel = offset;
538281806Srpaulo	hapd->iconf->vht_oper_chwidth = chwidth;
539281806Srpaulo	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
540281806Srpaulo	hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
541281806Srpaulo
542281806Srpaulo	is_dfs = ieee80211_is_dfs(freq);
543281806Srpaulo
544281806Srpaulo	if (hapd->csa_in_progress &&
545281806Srpaulo	    freq == hapd->cs_freq_params.freq) {
546281806Srpaulo		hostapd_cleanup_cs_params(hapd);
547281806Srpaulo		ieee802_11_set_beacon(hapd);
548281806Srpaulo
549281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
550281806Srpaulo			"freq=%d dfs=%d", freq, is_dfs);
551281806Srpaulo	} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
552281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
553281806Srpaulo			"freq=%d dfs=%d", freq, is_dfs);
554281806Srpaulo	}
555252726Srpaulo#endif /* NEED_AP_MLME */
556252726Srpaulo}
557252726Srpaulo
558252726Srpaulo
559281806Srpaulovoid hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
560281806Srpaulo					 const u8 *addr, int reason_code)
561281806Srpaulo{
562281806Srpaulo	switch (reason_code) {
563281806Srpaulo	case MAX_CLIENT_REACHED:
564281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_MAX_STA MACSTR,
565281806Srpaulo			MAC2STR(addr));
566281806Srpaulo		break;
567281806Srpaulo	case BLOCKED_CLIENT:
568281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_REJECTED_BLOCKED_STA MACSTR,
569281806Srpaulo			MAC2STR(addr));
570281806Srpaulo		break;
571281806Srpaulo	}
572281806Srpaulo}
573281806Srpaulo
574281806Srpaulo
575281806Srpaulo#ifdef CONFIG_ACS
576337817Scyvoid hostapd_acs_channel_selected(struct hostapd_data *hapd,
577337817Scy				  struct acs_selected_channels *acs_res)
578281806Srpaulo{
579289549Srpaulo	int ret, i;
580337817Scy	int err = 0;
581281806Srpaulo
582281806Srpaulo	if (hapd->iconf->channel) {
583281806Srpaulo		wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
584281806Srpaulo			   hapd->iconf->channel);
585281806Srpaulo		return;
586281806Srpaulo	}
587281806Srpaulo
588289549Srpaulo	if (!hapd->iface->current_mode) {
589289549Srpaulo		for (i = 0; i < hapd->iface->num_hw_features; i++) {
590289549Srpaulo			struct hostapd_hw_modes *mode =
591289549Srpaulo				&hapd->iface->hw_features[i];
592281806Srpaulo
593289549Srpaulo			if (mode->mode == acs_res->hw_mode) {
594289549Srpaulo				hapd->iface->current_mode = mode;
595289549Srpaulo				break;
596289549Srpaulo			}
597289549Srpaulo		}
598289549Srpaulo		if (!hapd->iface->current_mode) {
599289549Srpaulo			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
600289549Srpaulo				       HOSTAPD_LEVEL_WARNING,
601289549Srpaulo				       "driver selected to bad hw_mode");
602337817Scy			err = 1;
603337817Scy			goto out;
604289549Srpaulo		}
605289549Srpaulo	}
606289549Srpaulo
607289549Srpaulo	hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
608289549Srpaulo
609289549Srpaulo	if (!acs_res->pri_channel) {
610281806Srpaulo		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
611281806Srpaulo			       HOSTAPD_LEVEL_WARNING,
612281806Srpaulo			       "driver switched to bad channel");
613337817Scy		err = 1;
614337817Scy		goto out;
615281806Srpaulo	}
616281806Srpaulo
617289549Srpaulo	hapd->iconf->channel = acs_res->pri_channel;
618289549Srpaulo	hapd->iconf->acs = 1;
619281806Srpaulo
620289549Srpaulo	if (acs_res->sec_channel == 0)
621281806Srpaulo		hapd->iconf->secondary_channel = 0;
622289549Srpaulo	else if (acs_res->sec_channel < acs_res->pri_channel)
623281806Srpaulo		hapd->iconf->secondary_channel = -1;
624289549Srpaulo	else if (acs_res->sec_channel > acs_res->pri_channel)
625281806Srpaulo		hapd->iconf->secondary_channel = 1;
626281806Srpaulo	else {
627281806Srpaulo		wpa_printf(MSG_ERROR, "Invalid secondary channel!");
628337817Scy		err = 1;
629337817Scy		goto out;
630281806Srpaulo	}
631281806Srpaulo
632289549Srpaulo	if (hapd->iface->conf->ieee80211ac) {
633289549Srpaulo		/* set defaults for backwards compatibility */
634289549Srpaulo		hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
635289549Srpaulo		hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
636289549Srpaulo		hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
637289549Srpaulo		if (acs_res->ch_width == 80) {
638289549Srpaulo			hapd->iconf->vht_oper_centr_freq_seg0_idx =
639289549Srpaulo				acs_res->vht_seg0_center_ch;
640289549Srpaulo			hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
641289549Srpaulo		} else if (acs_res->ch_width == 160) {
642289549Srpaulo			if (acs_res->vht_seg1_center_ch == 0) {
643289549Srpaulo				hapd->iconf->vht_oper_centr_freq_seg0_idx =
644289549Srpaulo					acs_res->vht_seg0_center_ch;
645289549Srpaulo				hapd->iconf->vht_oper_chwidth =
646289549Srpaulo					VHT_CHANWIDTH_160MHZ;
647289549Srpaulo			} else {
648289549Srpaulo				hapd->iconf->vht_oper_centr_freq_seg0_idx =
649289549Srpaulo					acs_res->vht_seg0_center_ch;
650289549Srpaulo				hapd->iconf->vht_oper_centr_freq_seg1_idx =
651289549Srpaulo					acs_res->vht_seg1_center_ch;
652289549Srpaulo				hapd->iconf->vht_oper_chwidth =
653289549Srpaulo					VHT_CHANWIDTH_80P80MHZ;
654289549Srpaulo			}
655289549Srpaulo		}
656289549Srpaulo	}
657289549Srpaulo
658337817Scyout:
659337817Scy	ret = hostapd_acs_completed(hapd->iface, err);
660281806Srpaulo	if (ret) {
661281806Srpaulo		wpa_printf(MSG_ERROR,
662281806Srpaulo			   "ACS: Possibly channel configuration is invalid");
663281806Srpaulo	}
664281806Srpaulo}
665281806Srpaulo#endif /* CONFIG_ACS */
666281806Srpaulo
667281806Srpaulo
668252726Srpauloint hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
669252726Srpaulo			 const u8 *bssid, const u8 *ie, size_t ie_len,
670252726Srpaulo			 int ssi_signal)
671214501Srpaulo{
672252726Srpaulo	size_t i;
673252726Srpaulo	int ret = 0;
674214501Srpaulo
675252726Srpaulo	if (sa == NULL || ie == NULL)
676252726Srpaulo		return -1;
677214501Srpaulo
678252726Srpaulo	random_add_randomness(sa, ETH_ALEN);
679252726Srpaulo	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
680252726Srpaulo		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
681252726Srpaulo					    sa, da, bssid, ie, ie_len,
682252726Srpaulo					    ssi_signal) > 0) {
683252726Srpaulo			ret = 1;
684252726Srpaulo			break;
685252726Srpaulo		}
686252726Srpaulo	}
687252726Srpaulo	return ret;
688252726Srpaulo}
689214501Srpaulo
690252726Srpaulo
691252726Srpaulo#ifdef HOSTAPD
692252726Srpaulo
693252726Srpaulo#ifdef CONFIG_IEEE80211R
694252726Srpaulostatic void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
695252726Srpaulo					  const u8 *bssid,
696252726Srpaulo					  u16 auth_transaction, u16 status,
697252726Srpaulo					  const u8 *ies, size_t ies_len)
698252726Srpaulo{
699252726Srpaulo	struct hostapd_data *hapd = ctx;
700252726Srpaulo	struct sta_info *sta;
701252726Srpaulo
702252726Srpaulo	sta = ap_get_sta(hapd, dst);
703252726Srpaulo	if (sta == NULL)
704252726Srpaulo		return;
705252726Srpaulo
706252726Srpaulo	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
707252726Srpaulo		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
708252726Srpaulo	sta->flags |= WLAN_STA_AUTH;
709252726Srpaulo
710252726Srpaulo	hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
711252726Srpaulo}
712252726Srpaulo#endif /* CONFIG_IEEE80211R */
713252726Srpaulo
714252726Srpaulo
715252726Srpaulostatic void hostapd_notif_auth(struct hostapd_data *hapd,
716252726Srpaulo			       struct auth_info *rx_auth)
717252726Srpaulo{
718252726Srpaulo	struct sta_info *sta;
719252726Srpaulo	u16 status = WLAN_STATUS_SUCCESS;
720252726Srpaulo	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
721252726Srpaulo	size_t resp_ies_len = 0;
722252726Srpaulo
723252726Srpaulo	sta = ap_get_sta(hapd, rx_auth->peer);
724252726Srpaulo	if (!sta) {
725252726Srpaulo		sta = ap_sta_add(hapd, rx_auth->peer);
726252726Srpaulo		if (sta == NULL) {
727281806Srpaulo			status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
728252726Srpaulo			goto fail;
729214501Srpaulo		}
730214501Srpaulo	}
731252726Srpaulo	sta->flags &= ~WLAN_STA_PREAUTH;
732252726Srpaulo	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
733252726Srpaulo#ifdef CONFIG_IEEE80211R
734252726Srpaulo	if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
735252726Srpaulo		sta->auth_alg = WLAN_AUTH_FT;
736252726Srpaulo		if (sta->wpa_sm == NULL)
737252726Srpaulo			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
738281806Srpaulo							sta->addr, NULL);
739252726Srpaulo		if (sta->wpa_sm == NULL) {
740289549Srpaulo			wpa_printf(MSG_DEBUG,
741289549Srpaulo				   "FT: Failed to initialize WPA state machine");
742252726Srpaulo			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
743252726Srpaulo			goto fail;
744252726Srpaulo		}
745252726Srpaulo		wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
746252726Srpaulo				    rx_auth->auth_transaction, rx_auth->ies,
747252726Srpaulo				    rx_auth->ies_len,
748252726Srpaulo				    hostapd_notify_auth_ft_finish, hapd);
749252726Srpaulo		return;
750252726Srpaulo	}
751252726Srpaulo#endif /* CONFIG_IEEE80211R */
752252726Srpaulofail:
753252726Srpaulo	hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
754252726Srpaulo			 status, resp_ies, resp_ies_len);
755214501Srpaulo}
756214501Srpaulo
757214501Srpaulo
758252726Srpaulostatic void hostapd_action_rx(struct hostapd_data *hapd,
759281806Srpaulo			      struct rx_mgmt *drv_mgmt)
760252726Srpaulo{
761281806Srpaulo	struct ieee80211_mgmt *mgmt;
762252726Srpaulo	struct sta_info *sta;
763281806Srpaulo	size_t plen __maybe_unused;
764281806Srpaulo	u16 fc;
765252726Srpaulo
766281806Srpaulo	if (drv_mgmt->frame_len < 24 + 1)
767281806Srpaulo		return;
768281806Srpaulo
769281806Srpaulo	plen = drv_mgmt->frame_len - 24 - 1;
770281806Srpaulo
771281806Srpaulo	mgmt = (struct ieee80211_mgmt *) drv_mgmt->frame;
772281806Srpaulo	fc = le_to_host16(mgmt->frame_control);
773281806Srpaulo	if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
774281806Srpaulo		return; /* handled by the driver */
775281806Srpaulo
776289549Srpaulo	wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
777281806Srpaulo		   mgmt->u.action.category, (int) plen);
778252726Srpaulo
779281806Srpaulo	sta = ap_get_sta(hapd, mgmt->sa);
780252726Srpaulo	if (sta == NULL) {
781252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
782252726Srpaulo		return;
783252726Srpaulo	}
784252726Srpaulo#ifdef CONFIG_IEEE80211R
785281806Srpaulo	if (mgmt->u.action.category == WLAN_ACTION_FT) {
786281806Srpaulo		const u8 *payload = drv_mgmt->frame + 24 + 1;
787289549Srpaulo
788281806Srpaulo		wpa_ft_action_rx(sta->wpa_sm, payload, plen);
789252726Srpaulo	}
790252726Srpaulo#endif /* CONFIG_IEEE80211R */
791252726Srpaulo#ifdef CONFIG_IEEE80211W
792281806Srpaulo	if (mgmt->u.action.category == WLAN_ACTION_SA_QUERY && plen >= 4) {
793281806Srpaulo		ieee802_11_sa_query_action(
794281806Srpaulo			hapd, mgmt->sa,
795281806Srpaulo			mgmt->u.action.u.sa_query_resp.action,
796281806Srpaulo			mgmt->u.action.u.sa_query_resp.trans_id);
797252726Srpaulo	}
798252726Srpaulo#endif /* CONFIG_IEEE80211W */
799252726Srpaulo#ifdef CONFIG_WNM
800281806Srpaulo	if (mgmt->u.action.category == WLAN_ACTION_WNM) {
801281806Srpaulo		ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
802252726Srpaulo	}
803252726Srpaulo#endif /* CONFIG_WNM */
804289549Srpaulo#ifdef CONFIG_FST
805289549Srpaulo	if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
806289549Srpaulo		fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
807289549Srpaulo		return;
808289549Srpaulo	}
809289549Srpaulo#endif /* CONFIG_FST */
810289549Srpaulo
811252726Srpaulo}
812252726Srpaulo
813252726Srpaulo
814252726Srpaulo#ifdef NEED_AP_MLME
815252726Srpaulo
816214501Srpaulo#define HAPD_BROADCAST ((struct hostapd_data *) -1)
817214501Srpaulo
818214501Srpaulostatic struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
819214501Srpaulo					    const u8 *bssid)
820214501Srpaulo{
821214501Srpaulo	size_t i;
822214501Srpaulo
823214501Srpaulo	if (bssid == NULL)
824214501Srpaulo		return NULL;
825214501Srpaulo	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
826214501Srpaulo	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
827214501Srpaulo		return HAPD_BROADCAST;
828214501Srpaulo
829214501Srpaulo	for (i = 0; i < iface->num_bss; i++) {
830214501Srpaulo		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
831214501Srpaulo			return iface->bss[i];
832214501Srpaulo	}
833214501Srpaulo
834214501Srpaulo	return NULL;
835214501Srpaulo}
836214501Srpaulo
837214501Srpaulo
838214501Srpaulostatic void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
839252726Srpaulo					const u8 *bssid, const u8 *addr,
840252726Srpaulo					int wds)
841214501Srpaulo{
842252726Srpaulo	hapd = get_hapd_bssid(hapd->iface, bssid);
843214501Srpaulo	if (hapd == NULL || hapd == HAPD_BROADCAST)
844214501Srpaulo		return;
845214501Srpaulo
846252726Srpaulo	ieee802_11_rx_from_unknown(hapd, addr, wds);
847214501Srpaulo}
848214501Srpaulo
849214501Srpaulo
850281806Srpaulostatic int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
851214501Srpaulo{
852214501Srpaulo	struct hostapd_iface *iface = hapd->iface;
853214501Srpaulo	const struct ieee80211_hdr *hdr;
854214501Srpaulo	const u8 *bssid;
855214501Srpaulo	struct hostapd_frame_info fi;
856281806Srpaulo	int ret;
857214501Srpaulo
858281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS
859281806Srpaulo	if (hapd->ext_mgmt_frame_handling) {
860281806Srpaulo		size_t hex_len = 2 * rx_mgmt->frame_len + 1;
861281806Srpaulo		char *hex = os_malloc(hex_len);
862289549Srpaulo
863281806Srpaulo		if (hex) {
864281806Srpaulo			wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
865281806Srpaulo					 rx_mgmt->frame_len);
866281806Srpaulo			wpa_msg(hapd->msg_ctx, MSG_INFO, "MGMT-RX %s", hex);
867281806Srpaulo			os_free(hex);
868281806Srpaulo		}
869281806Srpaulo		return 1;
870281806Srpaulo	}
871281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */
872281806Srpaulo
873214501Srpaulo	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
874214501Srpaulo	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
875214501Srpaulo	if (bssid == NULL)
876281806Srpaulo		return 0;
877214501Srpaulo
878214501Srpaulo	hapd = get_hapd_bssid(iface, bssid);
879214501Srpaulo	if (hapd == NULL) {
880289549Srpaulo		u16 fc = le_to_host16(hdr->frame_control);
881214501Srpaulo
882214501Srpaulo		/*
883214501Srpaulo		 * Drop frames to unknown BSSIDs except for Beacon frames which
884214501Srpaulo		 * could be used to update neighbor information.
885214501Srpaulo		 */
886214501Srpaulo		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
887214501Srpaulo		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
888214501Srpaulo			hapd = iface->bss[0];
889214501Srpaulo		else
890281806Srpaulo			return 0;
891214501Srpaulo	}
892214501Srpaulo
893214501Srpaulo	os_memset(&fi, 0, sizeof(fi));
894214501Srpaulo	fi.datarate = rx_mgmt->datarate;
895214501Srpaulo	fi.ssi_signal = rx_mgmt->ssi_signal;
896214501Srpaulo
897214501Srpaulo	if (hapd == HAPD_BROADCAST) {
898214501Srpaulo		size_t i;
899289549Srpaulo
900281806Srpaulo		ret = 0;
901281806Srpaulo		for (i = 0; i < iface->num_bss; i++) {
902281806Srpaulo			/* if bss is set, driver will call this function for
903281806Srpaulo			 * each bss individually. */
904281806Srpaulo			if (rx_mgmt->drv_priv &&
905281806Srpaulo			    (iface->bss[i]->drv_priv != rx_mgmt->drv_priv))
906281806Srpaulo				continue;
907281806Srpaulo
908281806Srpaulo			if (ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
909281806Srpaulo					    rx_mgmt->frame_len, &fi) > 0)
910281806Srpaulo				ret = 1;
911281806Srpaulo		}
912214501Srpaulo	} else
913281806Srpaulo		ret = ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len,
914281806Srpaulo				      &fi);
915252726Srpaulo
916252726Srpaulo	random_add_randomness(&fi, sizeof(fi));
917214501Srpaulo
918281806Srpaulo	return ret;
919252726Srpaulo}
920252726Srpaulo
921252726Srpaulo
922214501Srpaulostatic void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
923214501Srpaulo			       size_t len, u16 stype, int ok)
924214501Srpaulo{
925214501Srpaulo	struct ieee80211_hdr *hdr;
926337817Scy	struct hostapd_data *orig_hapd = hapd;
927289549Srpaulo
928214501Srpaulo	hdr = (struct ieee80211_hdr *) buf;
929214501Srpaulo	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
930337817Scy	if (!hapd)
931214501Srpaulo		return;
932337817Scy	if (hapd == HAPD_BROADCAST) {
933337817Scy		if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
934337817Scy		    buf[24] != WLAN_ACTION_PUBLIC)
935337817Scy			return;
936337817Scy		hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
937337817Scy		if (!hapd || hapd == HAPD_BROADCAST)
938337817Scy			return;
939337817Scy		/*
940337817Scy		 * Allow processing of TX status for a Public Action frame that
941337817Scy		 * used wildcard BBSID.
942337817Scy		 */
943337817Scy	}
944214501Srpaulo	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
945214501Srpaulo}
946214501Srpaulo
947214501Srpaulo#endif /* NEED_AP_MLME */
948214501Srpaulo
949214501Srpaulo
950214501Srpaulostatic int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
951214501Srpaulo{
952214501Srpaulo	struct sta_info *sta = ap_get_sta(hapd, addr);
953289549Srpaulo
954214501Srpaulo	if (sta)
955214501Srpaulo		return 0;
956214501Srpaulo
957214501Srpaulo	wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
958214501Srpaulo		   " - adding a new STA", MAC2STR(addr));
959214501Srpaulo	sta = ap_sta_add(hapd, addr);
960214501Srpaulo	if (sta) {
961214501Srpaulo		hostapd_new_assoc_sta(hapd, sta, 0);
962214501Srpaulo	} else {
963214501Srpaulo		wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
964214501Srpaulo			   MAC2STR(addr));
965214501Srpaulo		return -1;
966214501Srpaulo	}
967214501Srpaulo
968214501Srpaulo	return 0;
969214501Srpaulo}
970214501Srpaulo
971214501Srpaulo
972214501Srpaulostatic void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
973214501Srpaulo				   const u8 *data, size_t data_len)
974214501Srpaulo{
975214501Srpaulo	struct hostapd_iface *iface = hapd->iface;
976252726Srpaulo	struct sta_info *sta;
977214501Srpaulo	size_t j;
978214501Srpaulo
979214501Srpaulo	for (j = 0; j < iface->num_bss; j++) {
980289549Srpaulo		sta = ap_get_sta(iface->bss[j], src);
981289549Srpaulo		if (sta && sta->flags & WLAN_STA_ASSOC) {
982289549Srpaulo			hapd = iface->bss[j];
983289549Srpaulo			break;
984214501Srpaulo		}
985214501Srpaulo	}
986214501Srpaulo
987214501Srpaulo	ieee802_1x_receive(hapd, src, data, data_len);
988214501Srpaulo}
989214501Srpaulo
990337817Scy#endif /* HOSTAPD */
991214501Srpaulo
992337817Scy
993281806Srpaulostatic struct hostapd_channel_data * hostapd_get_mode_channel(
994281806Srpaulo	struct hostapd_iface *iface, unsigned int freq)
995281806Srpaulo{
996281806Srpaulo	int i;
997281806Srpaulo	struct hostapd_channel_data *chan;
998281806Srpaulo
999281806Srpaulo	for (i = 0; i < iface->current_mode->num_channels; i++) {
1000281806Srpaulo		chan = &iface->current_mode->channels[i];
1001281806Srpaulo		if ((unsigned int) chan->freq == freq)
1002281806Srpaulo			return chan;
1003281806Srpaulo	}
1004281806Srpaulo
1005281806Srpaulo	return NULL;
1006281806Srpaulo}
1007281806Srpaulo
1008281806Srpaulo
1009281806Srpaulostatic void hostapd_update_nf(struct hostapd_iface *iface,
1010281806Srpaulo			      struct hostapd_channel_data *chan,
1011281806Srpaulo			      struct freq_survey *survey)
1012281806Srpaulo{
1013281806Srpaulo	if (!iface->chans_surveyed) {
1014281806Srpaulo		chan->min_nf = survey->nf;
1015281806Srpaulo		iface->lowest_nf = survey->nf;
1016281806Srpaulo	} else {
1017281806Srpaulo		if (dl_list_empty(&chan->survey_list))
1018281806Srpaulo			chan->min_nf = survey->nf;
1019281806Srpaulo		else if (survey->nf < chan->min_nf)
1020281806Srpaulo			chan->min_nf = survey->nf;
1021281806Srpaulo		if (survey->nf < iface->lowest_nf)
1022281806Srpaulo			iface->lowest_nf = survey->nf;
1023281806Srpaulo	}
1024281806Srpaulo}
1025281806Srpaulo
1026281806Srpaulo
1027281806Srpaulostatic void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
1028281806Srpaulo					      struct survey_results *survey_res)
1029281806Srpaulo{
1030281806Srpaulo	struct hostapd_channel_data *chan;
1031281806Srpaulo	struct freq_survey *survey;
1032281806Srpaulo	u64 divisor, dividend;
1033281806Srpaulo
1034281806Srpaulo	survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
1035281806Srpaulo			       list);
1036281806Srpaulo	if (!survey || !survey->freq)
1037281806Srpaulo		return;
1038281806Srpaulo
1039281806Srpaulo	chan = hostapd_get_mode_channel(iface, survey->freq);
1040281806Srpaulo	if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
1041281806Srpaulo		return;
1042281806Srpaulo
1043289549Srpaulo	wpa_printf(MSG_DEBUG,
1044289549Srpaulo		   "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
1045281806Srpaulo		   survey->freq,
1046281806Srpaulo		   (unsigned long int) survey->channel_time,
1047281806Srpaulo		   (unsigned long int) survey->channel_time_busy);
1048281806Srpaulo
1049281806Srpaulo	if (survey->channel_time > iface->last_channel_time &&
1050281806Srpaulo	    survey->channel_time > survey->channel_time_busy) {
1051281806Srpaulo		dividend = survey->channel_time_busy -
1052281806Srpaulo			iface->last_channel_time_busy;
1053281806Srpaulo		divisor = survey->channel_time - iface->last_channel_time;
1054281806Srpaulo
1055281806Srpaulo		iface->channel_utilization = dividend * 255 / divisor;
1056281806Srpaulo		wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
1057281806Srpaulo			   iface->channel_utilization);
1058281806Srpaulo	}
1059281806Srpaulo	iface->last_channel_time = survey->channel_time;
1060281806Srpaulo	iface->last_channel_time_busy = survey->channel_time_busy;
1061281806Srpaulo}
1062281806Srpaulo
1063281806Srpaulo
1064337817Scyvoid hostapd_event_get_survey(struct hostapd_iface *iface,
1065337817Scy			      struct survey_results *survey_results)
1066281806Srpaulo{
1067281806Srpaulo	struct freq_survey *survey, *tmp;
1068281806Srpaulo	struct hostapd_channel_data *chan;
1069281806Srpaulo
1070281806Srpaulo	if (dl_list_empty(&survey_results->survey_list)) {
1071281806Srpaulo		wpa_printf(MSG_DEBUG, "No survey data received");
1072281806Srpaulo		return;
1073281806Srpaulo	}
1074281806Srpaulo
1075281806Srpaulo	if (survey_results->freq_filter) {
1076281806Srpaulo		hostapd_single_channel_get_survey(iface, survey_results);
1077281806Srpaulo		return;
1078281806Srpaulo	}
1079281806Srpaulo
1080281806Srpaulo	dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
1081281806Srpaulo			      struct freq_survey, list) {
1082281806Srpaulo		chan = hostapd_get_mode_channel(iface, survey->freq);
1083281806Srpaulo		if (!chan)
1084281806Srpaulo			continue;
1085281806Srpaulo		if (chan->flag & HOSTAPD_CHAN_DISABLED)
1086281806Srpaulo			continue;
1087281806Srpaulo
1088281806Srpaulo		dl_list_del(&survey->list);
1089281806Srpaulo		dl_list_add_tail(&chan->survey_list, &survey->list);
1090281806Srpaulo
1091281806Srpaulo		hostapd_update_nf(iface, chan, survey);
1092281806Srpaulo
1093281806Srpaulo		iface->chans_surveyed++;
1094281806Srpaulo	}
1095281806Srpaulo}
1096281806Srpaulo
1097281806Srpaulo
1098337817Scy#ifdef HOSTAPD
1099281806Srpaulo#ifdef NEED_AP_MLME
1100281806Srpaulo
1101281806Srpaulostatic void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
1102281806Srpaulo{
1103281806Srpaulo	wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
1104281806Srpaulo		   hapd->conf->iface);
1105281806Srpaulo
1106281806Srpaulo	if (hapd->csa_in_progress) {
1107281806Srpaulo		wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
1108281806Srpaulo			   hapd->conf->iface);
1109281806Srpaulo		hostapd_switch_channel_fallback(hapd->iface,
1110281806Srpaulo						&hapd->cs_freq_params);
1111281806Srpaulo	}
1112281806Srpaulo}
1113281806Srpaulo
1114281806Srpaulo
1115281806Srpaulostatic void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
1116281806Srpaulo					     struct dfs_event *radar)
1117281806Srpaulo{
1118281806Srpaulo	wpa_printf(MSG_DEBUG, "DFS radar detected on %d MHz", radar->freq);
1119281806Srpaulo	hostapd_dfs_radar_detected(hapd->iface, radar->freq, radar->ht_enabled,
1120281806Srpaulo				   radar->chan_offset, radar->chan_width,
1121281806Srpaulo				   radar->cf1, radar->cf2);
1122281806Srpaulo}
1123281806Srpaulo
1124281806Srpaulo
1125281806Srpaulostatic void hostapd_event_dfs_cac_finished(struct hostapd_data *hapd,
1126281806Srpaulo					   struct dfs_event *radar)
1127281806Srpaulo{
1128281806Srpaulo	wpa_printf(MSG_DEBUG, "DFS CAC finished on %d MHz", radar->freq);
1129281806Srpaulo	hostapd_dfs_complete_cac(hapd->iface, 1, radar->freq, radar->ht_enabled,
1130281806Srpaulo				 radar->chan_offset, radar->chan_width,
1131281806Srpaulo				 radar->cf1, radar->cf2);
1132281806Srpaulo}
1133281806Srpaulo
1134281806Srpaulo
1135281806Srpaulostatic void hostapd_event_dfs_cac_aborted(struct hostapd_data *hapd,
1136281806Srpaulo					  struct dfs_event *radar)
1137281806Srpaulo{
1138281806Srpaulo	wpa_printf(MSG_DEBUG, "DFS CAC aborted on %d MHz", radar->freq);
1139281806Srpaulo	hostapd_dfs_complete_cac(hapd->iface, 0, radar->freq, radar->ht_enabled,
1140281806Srpaulo				 radar->chan_offset, radar->chan_width,
1141281806Srpaulo				 radar->cf1, radar->cf2);
1142281806Srpaulo}
1143281806Srpaulo
1144281806Srpaulo
1145281806Srpaulostatic void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
1146281806Srpaulo					   struct dfs_event *radar)
1147281806Srpaulo{
1148281806Srpaulo	wpa_printf(MSG_DEBUG, "DFS NOP finished on %d MHz", radar->freq);
1149281806Srpaulo	hostapd_dfs_nop_finished(hapd->iface, radar->freq, radar->ht_enabled,
1150281806Srpaulo				 radar->chan_offset, radar->chan_width,
1151281806Srpaulo				 radar->cf1, radar->cf2);
1152281806Srpaulo}
1153281806Srpaulo
1154281806Srpaulo
1155281806Srpaulostatic void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
1156281806Srpaulo					  struct dfs_event *radar)
1157281806Srpaulo{
1158281806Srpaulo	wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
1159281806Srpaulo	hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
1160281806Srpaulo			      radar->chan_offset, radar->chan_width,
1161281806Srpaulo			      radar->cf1, radar->cf2);
1162281806Srpaulo}
1163281806Srpaulo
1164281806Srpaulo#endif /* NEED_AP_MLME */
1165281806Srpaulo
1166281806Srpaulo
1167214501Srpaulovoid wpa_supplicant_event(void *ctx, enum wpa_event_type event,
1168214501Srpaulo			  union wpa_event_data *data)
1169214501Srpaulo{
1170214501Srpaulo	struct hostapd_data *hapd = ctx;
1171252726Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG
1172252726Srpaulo	int level = MSG_DEBUG;
1173214501Srpaulo
1174252726Srpaulo	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
1175252726Srpaulo	    data->rx_mgmt.frame_len >= 24) {
1176252726Srpaulo		const struct ieee80211_hdr *hdr;
1177252726Srpaulo		u16 fc;
1178289549Srpaulo
1179252726Srpaulo		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
1180252726Srpaulo		fc = le_to_host16(hdr->frame_control);
1181252726Srpaulo		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
1182252726Srpaulo		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
1183252726Srpaulo			level = MSG_EXCESSIVE;
1184281806Srpaulo		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
1185281806Srpaulo		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
1186281806Srpaulo			level = MSG_EXCESSIVE;
1187252726Srpaulo	}
1188252726Srpaulo
1189252726Srpaulo	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
1190252726Srpaulo		event_to_string(event), event);
1191252726Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */
1192252726Srpaulo
1193214501Srpaulo	switch (event) {
1194214501Srpaulo	case EVENT_MICHAEL_MIC_FAILURE:
1195214501Srpaulo		michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
1196214501Srpaulo		break;
1197214501Srpaulo	case EVENT_SCAN_RESULTS:
1198214501Srpaulo		if (hapd->iface->scan_cb)
1199214501Srpaulo			hapd->iface->scan_cb(hapd->iface);
1200214501Srpaulo		break;
1201214501Srpaulo	case EVENT_WPS_BUTTON_PUSHED:
1202252726Srpaulo		hostapd_wps_button_pushed(hapd, NULL);
1203214501Srpaulo		break;
1204214501Srpaulo#ifdef NEED_AP_MLME
1205214501Srpaulo	case EVENT_TX_STATUS:
1206214501Srpaulo		switch (data->tx_status.type) {
1207214501Srpaulo		case WLAN_FC_TYPE_MGMT:
1208214501Srpaulo			hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
1209214501Srpaulo					   data->tx_status.data_len,
1210214501Srpaulo					   data->tx_status.stype,
1211214501Srpaulo					   data->tx_status.ack);
1212214501Srpaulo			break;
1213214501Srpaulo		case WLAN_FC_TYPE_DATA:
1214214501Srpaulo			hostapd_tx_status(hapd, data->tx_status.dst,
1215214501Srpaulo					  data->tx_status.data,
1216214501Srpaulo					  data->tx_status.data_len,
1217214501Srpaulo					  data->tx_status.ack);
1218214501Srpaulo			break;
1219214501Srpaulo		}
1220214501Srpaulo		break;
1221252726Srpaulo	case EVENT_EAPOL_TX_STATUS:
1222252726Srpaulo		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
1223252726Srpaulo					data->eapol_tx_status.data,
1224252726Srpaulo					data->eapol_tx_status.data_len,
1225252726Srpaulo					data->eapol_tx_status.ack);
1226252726Srpaulo		break;
1227252726Srpaulo	case EVENT_DRIVER_CLIENT_POLL_OK:
1228252726Srpaulo		hostapd_client_poll_ok(hapd, data->client_poll.addr);
1229252726Srpaulo		break;
1230214501Srpaulo	case EVENT_RX_FROM_UNKNOWN:
1231252726Srpaulo		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
1232252726Srpaulo					    data->rx_from_unknown.addr,
1233252726Srpaulo					    data->rx_from_unknown.wds);
1234214501Srpaulo		break;
1235281806Srpaulo#endif /* NEED_AP_MLME */
1236214501Srpaulo	case EVENT_RX_MGMT:
1237281806Srpaulo		if (!data->rx_mgmt.frame)
1238281806Srpaulo			break;
1239281806Srpaulo#ifdef NEED_AP_MLME
1240281806Srpaulo		if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
1241281806Srpaulo			break;
1242281806Srpaulo#endif /* NEED_AP_MLME */
1243281806Srpaulo		hostapd_action_rx(hapd, &data->rx_mgmt);
1244214501Srpaulo		break;
1245214501Srpaulo	case EVENT_RX_PROBE_REQ:
1246252726Srpaulo		if (data->rx_probe_req.sa == NULL ||
1247252726Srpaulo		    data->rx_probe_req.ie == NULL)
1248252726Srpaulo			break;
1249214501Srpaulo		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
1250252726Srpaulo				     data->rx_probe_req.da,
1251252726Srpaulo				     data->rx_probe_req.bssid,
1252214501Srpaulo				     data->rx_probe_req.ie,
1253252726Srpaulo				     data->rx_probe_req.ie_len,
1254252726Srpaulo				     data->rx_probe_req.ssi_signal);
1255214501Srpaulo		break;
1256214501Srpaulo	case EVENT_NEW_STA:
1257214501Srpaulo		hostapd_event_new_sta(hapd, data->new_sta.addr);
1258214501Srpaulo		break;
1259214501Srpaulo	case EVENT_EAPOL_RX:
1260214501Srpaulo		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
1261214501Srpaulo				       data->eapol_rx.data,
1262214501Srpaulo				       data->eapol_rx.data_len);
1263214501Srpaulo		break;
1264214501Srpaulo	case EVENT_ASSOC:
1265281806Srpaulo		if (!data)
1266281806Srpaulo			return;
1267214501Srpaulo		hostapd_notif_assoc(hapd, data->assoc_info.addr,
1268214501Srpaulo				    data->assoc_info.req_ies,
1269252726Srpaulo				    data->assoc_info.req_ies_len,
1270252726Srpaulo				    data->assoc_info.reassoc);
1271214501Srpaulo		break;
1272214501Srpaulo	case EVENT_DISASSOC:
1273214501Srpaulo		if (data)
1274214501Srpaulo			hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
1275214501Srpaulo		break;
1276214501Srpaulo	case EVENT_DEAUTH:
1277214501Srpaulo		if (data)
1278214501Srpaulo			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
1279214501Srpaulo		break;
1280252726Srpaulo	case EVENT_STATION_LOW_ACK:
1281252726Srpaulo		if (!data)
1282252726Srpaulo			break;
1283252726Srpaulo		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
1284252726Srpaulo		break;
1285252726Srpaulo	case EVENT_AUTH:
1286252726Srpaulo		hostapd_notif_auth(hapd, &data->auth);
1287252726Srpaulo		break;
1288252726Srpaulo	case EVENT_CH_SWITCH:
1289252726Srpaulo		if (!data)
1290252726Srpaulo			break;
1291252726Srpaulo		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
1292252726Srpaulo					data->ch_switch.ht_enabled,
1293281806Srpaulo					data->ch_switch.ch_offset,
1294281806Srpaulo					data->ch_switch.ch_width,
1295281806Srpaulo					data->ch_switch.cf1,
1296281806Srpaulo					data->ch_switch.cf2);
1297252726Srpaulo		break;
1298281806Srpaulo	case EVENT_CONNECT_FAILED_REASON:
1299281806Srpaulo		if (!data)
1300281806Srpaulo			break;
1301281806Srpaulo		hostapd_event_connect_failed_reason(
1302281806Srpaulo			hapd, data->connect_failed_reason.addr,
1303281806Srpaulo			data->connect_failed_reason.code);
1304281806Srpaulo		break;
1305281806Srpaulo	case EVENT_SURVEY:
1306337817Scy		hostapd_event_get_survey(hapd->iface, &data->survey_results);
1307281806Srpaulo		break;
1308281806Srpaulo#ifdef NEED_AP_MLME
1309281806Srpaulo	case EVENT_INTERFACE_UNAVAILABLE:
1310281806Srpaulo		hostapd_event_iface_unavailable(hapd);
1311281806Srpaulo		break;
1312281806Srpaulo	case EVENT_DFS_RADAR_DETECTED:
1313281806Srpaulo		if (!data)
1314281806Srpaulo			break;
1315281806Srpaulo		hostapd_event_dfs_radar_detected(hapd, &data->dfs_event);
1316281806Srpaulo		break;
1317281806Srpaulo	case EVENT_DFS_CAC_FINISHED:
1318281806Srpaulo		if (!data)
1319281806Srpaulo			break;
1320281806Srpaulo		hostapd_event_dfs_cac_finished(hapd, &data->dfs_event);
1321281806Srpaulo		break;
1322281806Srpaulo	case EVENT_DFS_CAC_ABORTED:
1323281806Srpaulo		if (!data)
1324281806Srpaulo			break;
1325281806Srpaulo		hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event);
1326281806Srpaulo		break;
1327281806Srpaulo	case EVENT_DFS_NOP_FINISHED:
1328281806Srpaulo		if (!data)
1329281806Srpaulo			break;
1330281806Srpaulo		hostapd_event_dfs_nop_finished(hapd, &data->dfs_event);
1331281806Srpaulo		break;
1332281806Srpaulo	case EVENT_CHANNEL_LIST_CHANGED:
1333281806Srpaulo		/* channel list changed (regulatory?), update channel list */
1334281806Srpaulo		/* TODO: check this. hostapd_get_hw_features() initializes
1335281806Srpaulo		 * too much stuff. */
1336281806Srpaulo		/* hostapd_get_hw_features(hapd->iface); */
1337281806Srpaulo		hostapd_channel_list_updated(
1338281806Srpaulo			hapd->iface, data->channel_list_changed.initiator);
1339281806Srpaulo		break;
1340281806Srpaulo	case EVENT_DFS_CAC_STARTED:
1341281806Srpaulo		if (!data)
1342281806Srpaulo			break;
1343281806Srpaulo		hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
1344281806Srpaulo		break;
1345281806Srpaulo#endif /* NEED_AP_MLME */
1346281806Srpaulo	case EVENT_INTERFACE_ENABLED:
1347281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
1348281806Srpaulo		if (hapd->disabled && hapd->started) {
1349281806Srpaulo			hapd->disabled = 0;
1350281806Srpaulo			/*
1351281806Srpaulo			 * Try to re-enable interface if the driver stopped it
1352281806Srpaulo			 * when the interface got disabled.
1353281806Srpaulo			 */
1354281806Srpaulo			wpa_auth_reconfig_group_keys(hapd->wpa_auth);
1355281806Srpaulo			hapd->reenable_beacon = 1;
1356281806Srpaulo			ieee802_11_set_beacon(hapd);
1357281806Srpaulo		}
1358281806Srpaulo		break;
1359281806Srpaulo	case EVENT_INTERFACE_DISABLED:
1360281806Srpaulo		hostapd_free_stas(hapd);
1361281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
1362281806Srpaulo		hapd->disabled = 1;
1363281806Srpaulo		break;
1364281806Srpaulo#ifdef CONFIG_ACS
1365281806Srpaulo	case EVENT_ACS_CHANNEL_SELECTED:
1366289549Srpaulo		hostapd_acs_channel_selected(hapd,
1367289549Srpaulo					     &data->acs_selected_channels);
1368281806Srpaulo		break;
1369281806Srpaulo#endif /* CONFIG_ACS */
1370214501Srpaulo	default:
1371214501Srpaulo		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
1372214501Srpaulo		break;
1373214501Srpaulo	}
1374214501Srpaulo}
1375214501Srpaulo
1376337817Scy
1377337817Scyvoid wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
1378337817Scy				 union wpa_event_data *data)
1379337817Scy{
1380337817Scy	struct hapd_interfaces *interfaces = ctx;
1381337817Scy	struct hostapd_data *hapd;
1382337817Scy
1383337817Scy	if (event != EVENT_INTERFACE_STATUS)
1384337817Scy		return;
1385337817Scy
1386337817Scy	hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
1387337817Scy	if (hapd && hapd->driver && hapd->driver->get_ifindex &&
1388337817Scy	    hapd->drv_priv) {
1389337817Scy		unsigned int ifindex;
1390337817Scy
1391337817Scy		ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
1392337817Scy		if (ifindex != data->interface_status.ifindex) {
1393337817Scy			wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1394337817Scy				"interface status ifindex %d mismatch (%d)",
1395337817Scy				ifindex, data->interface_status.ifindex);
1396337817Scy			return;
1397337817Scy		}
1398337817Scy	}
1399337817Scy	if (hapd)
1400337817Scy		wpa_supplicant_event(hapd, event, data);
1401337817Scy}
1402337817Scy
1403214501Srpaulo#endif /* HOSTAPD */
1404