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