drv_callbacks.c revision d5e4923d04122f81300fa68fb07d64ede28fd44d
17da6ac33a9de82be52e22846d5f22d502452854cDianne Hackborn/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * hostapd / Callback functions for driver wrappers
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
44eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller *
54eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller * This software may be distributed under the terms of the BSD license.
64eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller * See README for more details.
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
84eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/includes.h"
104eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller
114eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller#include "utils/common.h"
124eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller#include "radius/radius.h"
134eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller#include "drivers/driver.h"
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "common/ieee802_11_defs.h"
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "common/ieee802_11_common.h"
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "crypto/random.h"
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "p2p/p2p.h"
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "wps/wps.h"
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "wnm_ap.h"
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "hostapd.h"
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "ieee802_11.h"
222f0b17573d4324832f7a20402a3d2b5920bc4866Dianne Hackborn#include "sta_info.h"
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "accounting.h"
240aae2d4e0075fd699cf40b26dca0eb2c3b3e37d2Dianne Hackborn#include "tkip_countermeasures.h"
25ac8dea12c17aa047e03a358110aeb60401d36aa2Dianne Hackborn#include "ieee802_1x.h"
26c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov#include "wpa_auth.h"
27f752202bee88e31ce765483ba2efa6999ae9c9adAdam Cohen#include "wps_hostapd.h"
2838e29a61d0c87fe3e391d24e2eb11dd1800d107dDianne Hackborn#include "ap_drv_ops.h"
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "ap_config.h"
301cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov#include "hw_features.h"
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			const u8 *req_ies, size_t req_ies_len, int reassoc)
356ec402b5ae33c8927694d8522b4cc6a5c8ba974eJeff Brown{
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	struct sta_info *sta;
37a41ca77fabe1c7ad12ebb9b69b9e786c07d49fa0Jeff Brown	int new_assoc, res;
388d60866e2100db70ecf0502c14768a384514d7e9Jeff Brown	struct ieee802_11_elems elems;
391cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov	const u8 *ie;
401cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov	size_t ielen;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#ifdef CONFIG_IEEE80211R
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	u8 *p = buf;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif /* CONFIG_IEEE80211R */
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	u16 reason = WLAN_REASON_UNSPECIFIED;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	u16 status = WLAN_STATUS_SUCCESS;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	if (addr == NULL) {
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		/*
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 * This could potentially happen with unexpected event from the
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 * driver wrapper. This was seen at least in one case where the
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 * driver ended up being set to station mode while hostapd was
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 * running, so better make sure we stop processing such an
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 * event here.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 */
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			   "no address");
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		return -1;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	random_add_randomness(addr, ETH_ALEN);
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
62ac8dea12c17aa047e03a358110aeb60401d36aa2Dianne Hackborn	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
6343aa15912891930833edfc101615a9c881de54a1Jeff Brown		       HOSTAPD_LEVEL_INFO, "associated");
6459c009776dae5ccbdfb93d7151ff2065ca049dc3Craig Mautner
65dde331cebd87982faded6818ad5f9927ff994c96Dianne Hackborn	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
66dde331cebd87982faded6818ad5f9927ff994c96Dianne Hackborn	if (elems.wps_ie) {
677916ac65dc492e4e1431879875c77d7121fbf82eDianne Hackborn		ie = elems.wps_ie - 2;
68f87d19621dc2a30232bba1f51862a0b671eb9729Dianne Hackborn		ielen = elems.wps_ie_len + 2;
69f87d19621dc2a30232bba1f51862a0b671eb9729Dianne Hackborn		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
7081e56d535c853d73ff537357da5b935f51cb779dDianne Hackborn	} else if (elems.rsn_ie) {
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		ie = elems.rsn_ie - 2;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		ielen = elems.rsn_ie_len + 2;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	} else if (elems.wpa_ie) {
75e4fbd6235c8d1c5b0ed4883ec275dd3fc9c919fbDianne Hackborn		ie = elems.wpa_ie - 2;
76e4fbd6235c8d1c5b0ed4883ec275dd3fc9c919fbDianne Hackborn		ielen = elems.wpa_ie_len + 2;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
785962b12bedc4a1d0354816c1cd6b06ba04f6d807Craig Mautner	} else {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		ie = NULL;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		ielen = 0;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			   "(Re)AssocReq");
837da6ac33a9de82be52e22846d5f22d502452854cDianne Hackborn	}
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8584375876fcef73c5fa9c3de205c7db908ee14e15Dianne Hackborn	sta = ap_get_sta(hapd, addr);
8684375876fcef73c5fa9c3de205c7db908ee14e15Dianne Hackborn	if (sta) {
87eabfb3a36e9469c5e219f92b39b7200104319185Dianne Hackborn		accounting_sta_stop(hapd, sta);
88eabfb3a36e9469c5e219f92b39b7200104319185Dianne Hackborn
898078d8c8a282ca81344febe7256f63b1e805e3aaDianne Hackborn		/*
90832cb229cd748505c90f74ae8154fc3557d61a73Michael Jurka		 * Make sure that the previously registered inactivity timer
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 * will not remove the STA immediately.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		 */
932f0b17573d4324832f7a20402a3d2b5920bc4866Dianne Hackborn		sta->timeout_next = STA_NULLFUNC;
947eec10e6c99c30d5ee061fec08ac89ad4254ac32Dianne Hackborn	} else {
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		sta = ap_sta_add(hapd, addr);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (sta == NULL) {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			hostapd_drv_sta_disassoc(hapd, addr,
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project						 WLAN_REASON_DISASSOC_AP_BUSY);
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return -1;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
104e36d6e277e49475076b7872d36ea6a5c5b996e9dDianne Hackborn#ifdef CONFIG_P2P
105e36d6e277e49475076b7872d36ea6a5c5b996e9dDianne Hackborn	if (elems.p2p) {
106e36d6e277e49475076b7872d36ea6a5c5b996e9dDianne Hackborn		wpabuf_free(sta->p2p_ie);
107e36d6e277e49475076b7872d36ea6a5c5b996e9dDianne Hackborn		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
108e36d6e277e49475076b7872d36ea6a5c5b996e9dDianne Hackborn							  P2P_IE_VENDOR_TYPE);
109e36d6e277e49475076b7872d36ea6a5c5b996e9dDianne Hackborn	}
1104eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller#endif /* CONFIG_P2P */
1119d9ece3c1e16001b63244459cdf4b428f4272d2eDianne Hackborn
1129d9ece3c1e16001b63244459cdf4b428f4272d2eDianne Hackborn#ifdef CONFIG_HS20
1139d9ece3c1e16001b63244459cdf4b428f4272d2eDianne Hackborn	wpabuf_free(sta->hs20_ie);
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	if (elems.hs20 && elems.hs20_len > 4) {
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project						 elems.hs20_len - 4);
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	} else
118520d8bc1d840966b5519195aaa514597a662c053Mike Lockwood		sta->hs20_ie = NULL;
119520d8bc1d840966b5519195aaa514597a662c053Mike Lockwood#endif /* CONFIG_HS20 */
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12190c52de28691ca0bbbf7c039ef20f85ce46882ccDianne Hackborn	if (hapd->conf->wpa) {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (ie == NULL || ielen == 0) {
123ffa424800d0338b8b894aef2ea1e3e3344cbda7aDianne Hackborn#ifdef CONFIG_WPS
1244eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			if (hapd->conf->wps_state) {
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				wpa_printf(MSG_DEBUG, "STA did not include "
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project					   "WPA/RSN IE in (Re)Association "
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project					   "Request - possible WPS use");
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				sta->flags |= WLAN_STA_MAYBE_WPS;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				goto skip_wpa_check;
1304eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			}
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif /* CONFIG_WPS */
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1336804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
1346804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick			return -1;
1356804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick		}
1366804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick#ifdef CONFIG_WPS
1376804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
1386804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
1396804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick			struct wpabuf *wps;
1406804433b0af50f33a338307ae8ddb50bc49e886bBrad Fitzpatrick			sta->flags |= WLAN_STA_WPS;
141c1a968a8ed45181312f7d4bcdbba0cc8ddc201baBrad Fitzpatrick			wps = ieee802_11_vendor_ie_concat(ie, ielen,
142c1a968a8ed45181312f7d4bcdbba0cc8ddc201baBrad Fitzpatrick							  WPS_IE_VENDOR_TYPE);
143c1a968a8ed45181312f7d4bcdbba0cc8ddc201baBrad Fitzpatrick			if (wps) {
144c1a968a8ed45181312f7d4bcdbba0cc8ddc201baBrad Fitzpatrick				if (wps_is_20(wps)) {
145c1a968a8ed45181312f7d4bcdbba0cc8ddc201baBrad Fitzpatrick					wpa_printf(MSG_DEBUG, "WPS: STA "
146c1a968a8ed45181312f7d4bcdbba0cc8ddc201baBrad Fitzpatrick						   "supports WPS 2.0");
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project					sta->flags |= WLAN_STA_WPS2;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				}
14901a98ddbdfbaf1f0d2bc602537e6e314364902a3Jeff Brown				wpabuf_free(wps);
15001a98ddbdfbaf1f0d2bc602537e6e314364902a3Jeff Brown			}
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			goto skip_wpa_check;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif /* CONFIG_WPS */
154f87d19621dc2a30232bba1f51862a0b671eb9729Dianne Hackborn
155f87d19621dc2a30232bba1f51862a0b671eb9729Dianne Hackborn		if (sta->wpa_sm == NULL)
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
157f87d19621dc2a30232bba1f51862a0b671eb9729Dianne Hackborn							sta->addr);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (sta->wpa_sm == NULL) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				   "machine");
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return -1;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
1644eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller					  ie, ielen,
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project					  elems.mdie, elems.mdie_len);
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (res != WPA_IE_OK) {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project				   "rejected? (res %u)", res);
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
170b73617de462579f7c12c25a4c2747c576f00f6a2Daniel Sandler			if (res == WPA_INVALID_GROUP) {
171dfee59afb3e4cdcde38f6338f9360655de76da92Adam Powell				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
172dfee59afb3e4cdcde38f6338f9360655de76da92Adam Powell				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
173dfee59afb3e4cdcde38f6338f9360655de76da92Adam Powell			} else if (res == WPA_INVALID_PAIRWISE) {
174dfee59afb3e4cdcde38f6338f9360655de76da92Adam Powell				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
175dfee59afb3e4cdcde38f6338f9360655de76da92Adam Powell				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
176dfee59afb3e4cdcde38f6338f9360655de76da92Adam Powell			} else if (res == WPA_INVALID_AKMP) {
177dfee59afb3e4cdcde38f6338f9360655de76da92Adam Powell				reason = WLAN_REASON_AKMP_NOT_VALID;
1784eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				status = WLAN_STATUS_AKMP_NOT_VALID;
1794eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			}
1804eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller#ifdef CONFIG_IEEE80211W
1814eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
1824eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				reason = WLAN_REASON_INVALID_IE;
1834eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				status = WLAN_STATUS_INVALID_IE;
1844eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
1854eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
1864eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
1874eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			}
1884eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller#endif /* CONFIG_IEEE80211W */
1894eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			else {
1904eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				reason = WLAN_REASON_INVALID_IE;
1914eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				status = WLAN_STATUS_INVALID_IE;
1924eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			}
1934eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			goto fail;
1944eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller		}
1954eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller#ifdef CONFIG_IEEE80211W
196664644d9e012aa2a28ac96f305b1ce6499ec8806Joe Onorato		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
197664644d9e012aa2a28ac96f305b1ce6499ec8806Joe Onorato		    sta->sa_query_count > 0)
198664644d9e012aa2a28ac96f305b1ce6499ec8806Joe Onorato			ap_check_sa_query_timeout(hapd, sta);
199664644d9e012aa2a28ac96f305b1ce6499ec8806Joe Onorato		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
200664644d9e012aa2a28ac96f305b1ce6499ec8806Joe Onorato		    (sta->auth_alg != WLAN_AUTH_FT)) {
2011a84fd1fb7a51f3fe4f8865e1cdd09f3490f696cJeff Brown			/*
2021a84fd1fb7a51f3fe4f8865e1cdd09f3490f696cJeff Brown			 * STA has already been associated with MFP and SA
20338e29a61d0c87fe3e391d24e2eb11dd1800d107dDianne Hackborn			 * Query timeout has not been reached. Reject the
204c38c9be031ddad5cf551b55458889f11e01dc5b2Jeff Brown			 * association attempt temporarily and start SA Query,
20529aae6f36e565b8f2a99f2193597b964bb800ee8Dianne Hackborn			 * if one is not pending.
206c38c9be031ddad5cf551b55458889f11e01dc5b2Jeff Brown			 */
2070c4ccff36930ff4f0292b94ad51e164c9fa060a3Daniel Sandler
2080c4ccff36930ff4f0292b94ad51e164c9fa060a3Daniel Sandler			if (sta->sa_query_count == 0)
2090c4ccff36930ff4f0292b94ad51e164c9fa060a3Daniel Sandler				ap_sta_start_sa_query(hapd, sta);
2100c4ccff36930ff4f0292b94ad51e164c9fa060a3Daniel Sandler
2110c4ccff36930ff4f0292b94ad51e164c9fa060a3Daniel Sandler#ifdef CONFIG_IEEE80211R
21293c518e4f8abd98f87cda1712b30a5a86cfa60ddJim Miller			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
21393c518e4f8abd98f87cda1712b30a5a86cfa60ddJim Miller
214f752202bee88e31ce765483ba2efa6999ae9c9adAdam Cohen			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
21593c518e4f8abd98f87cda1712b30a5a86cfa60ddJim Miller
216f752202bee88e31ce765483ba2efa6999ae9c9adAdam Cohen			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
217c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov					  p - buf);
218c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov#endif /* CONFIG_IEEE80211R */
219c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov			return 0;
220c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov		}
221c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov
222c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov		if (wpa_auth_uses_mfp(sta->wpa_sm))
223c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov			sta->flags |= WLAN_STA_MFP;
224c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov		else
225c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov			sta->flags &= ~WLAN_STA_MFP;
226c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov#endif /* CONFIG_IEEE80211W */
227c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov
228c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov#ifdef CONFIG_IEEE80211R
229c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov		if (sta->auth_alg == WLAN_AUTH_FT) {
230c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov			status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
231c9c9a48e7bafae63cb35a9aa69255e80aba83988Svetoslav Ganov							 req_ies_len);
2321cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			if (status != WLAN_STATUS_SUCCESS) {
2331cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov				if (status == WLAN_STATUS_INVALID_PMKID)
2341cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov					reason = WLAN_REASON_INVALID_IE;
2351cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov				if (status == WLAN_STATUS_INVALID_MDIE)
2361cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov					reason = WLAN_REASON_INVALID_IE;
2371cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov				if (status == WLAN_STATUS_INVALID_FTIE)
2381cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov					reason = WLAN_REASON_INVALID_IE;
2391cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov				goto fail;
2401cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			}
2411cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov		}
2421cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov#endif /* CONFIG_IEEE80211R */
2431cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov	} else if (hapd->conf->wps_state) {
2441cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov#ifdef CONFIG_WPS
2451cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov		struct wpabuf *wps;
2461cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov		if (req_ies)
2471cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
2481cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov							  WPS_IE_VENDOR_TYPE);
2491cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov		else
2501cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			wps = NULL;
2511cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov#ifdef CONFIG_WPS_STRICT
2521cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov		if (wps && wps_validate_assoc_req(wps) < 0) {
2531cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			reason = WLAN_REASON_INVALID_IE;
2541cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			status = WLAN_STATUS_INVALID_IE;
2551cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			wpabuf_free(wps);
2561cf70bbf96930662cab0e699d70b62865766ff52Svetoslav Ganov			goto fail;
257bfec0a8616bc197ee3b7b71be6fed1939d0c3c4dJim Miller		}
258bfec0a8616bc197ee3b7b71be6fed1939d0c3c4dJim Miller#endif /* CONFIG_WPS_STRICT */
259bfec0a8616bc197ee3b7b71be6fed1939d0c3c4dJim Miller		if (wps) {
260bfec0a8616bc197ee3b7b71be6fed1939d0c3c4dJim Miller			sta->flags |= WLAN_STA_WPS;
261bfec0a8616bc197ee3b7b71be6fed1939d0c3c4dJim Miller			if (wps_is_20(wps)) {
2624eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				wpa_printf(MSG_DEBUG, "WPS: STA supports "
2634eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller					   "WPS 2.0");
2644eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller				sta->flags |= WLAN_STA_WPS2;
2654eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			}
2664eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller		} else
2674eeb4f664ac6b5901a8e874dcf70c0382295f792Jim Miller			sta->flags |= WLAN_STA_MAYBE_WPS;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		wpabuf_free(wps);
269#endif /* CONFIG_WPS */
270	}
271#ifdef CONFIG_WPS
272skip_wpa_check:
273#endif /* CONFIG_WPS */
274
275#ifdef CONFIG_IEEE80211R
276	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
277					sta->auth_alg, req_ies, req_ies_len);
278
279	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
280#else /* CONFIG_IEEE80211R */
281	/* Keep compiler silent about unused variables */
282	if (status) {
283	}
284#endif /* CONFIG_IEEE80211R */
285
286	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
287	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
288
289	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
290		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
291	else
292		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
293
294	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
295
296	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
297
298#ifdef CONFIG_P2P
299	if (req_ies) {
300		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
301				      req_ies, req_ies_len);
302	}
303#endif /* CONFIG_P2P */
304
305	return 0;
306
307fail:
308#ifdef CONFIG_IEEE80211R
309	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
310#endif /* CONFIG_IEEE80211R */
311	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
312	ap_free_sta(hapd, sta);
313	return -1;
314}
315
316
317void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
318{
319	struct sta_info *sta;
320
321	if (addr == NULL) {
322		/*
323		 * This could potentially happen with unexpected event from the
324		 * driver wrapper. This was seen at least in one case where the
325		 * driver ended up reporting a station mode event while hostapd
326		 * was running, so better make sure we stop processing such an
327		 * event here.
328		 */
329		wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
330			   "with no address");
331		return;
332	}
333
334	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
335		       HOSTAPD_LEVEL_INFO, "disassociated");
336
337	sta = ap_get_sta(hapd, addr);
338	if (sta == NULL) {
339		wpa_printf(MSG_DEBUG, "Disassociation notification for "
340			   "unknown STA " MACSTR, MAC2STR(addr));
341		return;
342	}
343
344	ap_sta_set_authorized(hapd, sta, 0);
345	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
346	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
347	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
348	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
349	ap_free_sta(hapd, sta);
350}
351
352
353void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
354{
355	struct sta_info *sta = ap_get_sta(hapd, addr);
356
357	if (!sta || !hapd->conf->disassoc_low_ack)
358		return;
359
360	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
361		       HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
362		       "missing ACKs");
363	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
364	if (sta)
365		ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
366}
367
368
369void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
370			     int offset)
371{
372#ifdef NEED_AP_MLME
373	int channel;
374
375	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
376		       HOSTAPD_LEVEL_INFO, "driver had channel switch: "
377		       "freq=%d, ht=%d, offset=%d", freq, ht, offset);
378
379	hapd->iface->freq = freq;
380
381	channel = hostapd_hw_get_channel(hapd, freq);
382	if (!channel) {
383		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
384			       HOSTAPD_LEVEL_WARNING, "driver switched to "
385			       "bad channel!");
386		return;
387	}
388
389	hapd->iconf->channel = channel;
390	hapd->iconf->ieee80211n = ht;
391	hapd->iconf->secondary_channel = offset;
392#endif /* NEED_AP_MLME */
393}
394
395
396int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
397			 const u8 *bssid, const u8 *ie, size_t ie_len,
398			 int ssi_signal)
399{
400	size_t i;
401	int ret = 0;
402
403	if (sa == NULL || ie == NULL)
404		return -1;
405
406	random_add_randomness(sa, ETH_ALEN);
407	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
408		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
409					    sa, da, bssid, ie, ie_len,
410					    ssi_signal) > 0) {
411			ret = 1;
412			break;
413		}
414	}
415	return ret;
416}
417
418
419#ifdef HOSTAPD
420
421#ifdef CONFIG_IEEE80211R
422static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
423					  const u8 *bssid,
424					  u16 auth_transaction, u16 status,
425					  const u8 *ies, size_t ies_len)
426{
427	struct hostapd_data *hapd = ctx;
428	struct sta_info *sta;
429
430	sta = ap_get_sta(hapd, dst);
431	if (sta == NULL)
432		return;
433
434	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
435		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
436	sta->flags |= WLAN_STA_AUTH;
437
438	hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
439}
440#endif /* CONFIG_IEEE80211R */
441
442
443static void hostapd_notif_auth(struct hostapd_data *hapd,
444			       struct auth_info *rx_auth)
445{
446	struct sta_info *sta;
447	u16 status = WLAN_STATUS_SUCCESS;
448	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
449	size_t resp_ies_len = 0;
450
451	sta = ap_get_sta(hapd, rx_auth->peer);
452	if (!sta) {
453		sta = ap_sta_add(hapd, rx_auth->peer);
454		if (sta == NULL) {
455			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
456			goto fail;
457		}
458	}
459	sta->flags &= ~WLAN_STA_PREAUTH;
460	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
461#ifdef CONFIG_IEEE80211R
462	if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
463		sta->auth_alg = WLAN_AUTH_FT;
464		if (sta->wpa_sm == NULL)
465			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
466							sta->addr);
467		if (sta->wpa_sm == NULL) {
468			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
469				   "state machine");
470			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
471			goto fail;
472		}
473		wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
474				    rx_auth->auth_transaction, rx_auth->ies,
475				    rx_auth->ies_len,
476				    hostapd_notify_auth_ft_finish, hapd);
477		return;
478	}
479#endif /* CONFIG_IEEE80211R */
480fail:
481	hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
482			 status, resp_ies, resp_ies_len);
483}
484
485
486static void hostapd_action_rx(struct hostapd_data *hapd,
487			      struct rx_action *action)
488{
489	struct sta_info *sta;
490
491        wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
492		   action->category, (int) action->len);
493
494	sta = ap_get_sta(hapd, action->sa);
495	if (sta == NULL) {
496		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
497		return;
498	}
499#ifdef CONFIG_IEEE80211R
500	if (action->category == WLAN_ACTION_FT) {
501		wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
502			   __func__, (int) action->len);
503		wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
504	}
505#endif /* CONFIG_IEEE80211R */
506#ifdef CONFIG_IEEE80211W
507	if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
508		wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
509			   __func__, (int) action->len);
510		ieee802_11_sa_query_action(hapd, action->sa,
511					   *(action->data + 1),
512					   action->data + 2);
513	}
514#endif /* CONFIG_IEEE80211W */
515#ifdef CONFIG_IEEE80211V
516	if (action->category == WLAN_ACTION_WNM) {
517		wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
518			   __func__, (int) action->len);
519		ieee802_11_rx_wnm_action_ap(hapd, action);
520	}
521#endif /* CONFIG_IEEE80211V */
522}
523
524
525#ifdef NEED_AP_MLME
526
527#define HAPD_BROADCAST ((struct hostapd_data *) -1)
528
529static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
530					    const u8 *bssid)
531{
532	size_t i;
533
534	if (bssid == NULL)
535		return NULL;
536	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
537	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
538		return HAPD_BROADCAST;
539
540	for (i = 0; i < iface->num_bss; i++) {
541		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
542			return iface->bss[i];
543	}
544
545	return NULL;
546}
547
548
549static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
550					const u8 *bssid, const u8 *addr,
551					int wds)
552{
553	hapd = get_hapd_bssid(hapd->iface, bssid);
554	if (hapd == NULL || hapd == HAPD_BROADCAST)
555		return;
556
557	ieee802_11_rx_from_unknown(hapd, addr, wds);
558}
559
560
561static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
562{
563	struct hostapd_iface *iface = hapd->iface;
564	const struct ieee80211_hdr *hdr;
565	const u8 *bssid;
566	struct hostapd_frame_info fi;
567
568	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
569	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
570	if (bssid == NULL)
571		return;
572
573	hapd = get_hapd_bssid(iface, bssid);
574	if (hapd == NULL) {
575		u16 fc;
576		fc = le_to_host16(hdr->frame_control);
577
578		/*
579		 * Drop frames to unknown BSSIDs except for Beacon frames which
580		 * could be used to update neighbor information.
581		 */
582		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
583		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
584			hapd = iface->bss[0];
585		else
586			return;
587	}
588
589	os_memset(&fi, 0, sizeof(fi));
590	fi.datarate = rx_mgmt->datarate;
591	fi.ssi_signal = rx_mgmt->ssi_signal;
592
593	if (hapd == HAPD_BROADCAST) {
594		size_t i;
595		for (i = 0; i < iface->num_bss; i++)
596			ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
597					rx_mgmt->frame_len, &fi);
598	} else
599		ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
600
601	random_add_randomness(&fi, sizeof(fi));
602}
603
604
605static void hostapd_rx_action(struct hostapd_data *hapd,
606			      struct rx_action *rx_action)
607{
608	struct rx_mgmt rx_mgmt;
609	u8 *buf;
610	struct ieee80211_hdr *hdr;
611
612	wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
613		   " BSSID=" MACSTR " category=%u",
614		   MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
615		   MAC2STR(rx_action->bssid), rx_action->category);
616	wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
617		    rx_action->data, rx_action->len);
618
619	buf = os_zalloc(24 + 1 + rx_action->len);
620	if (buf == NULL)
621		return;
622	hdr = (struct ieee80211_hdr *) buf;
623	hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
624					  WLAN_FC_STYPE_ACTION);
625	if (rx_action->category == WLAN_ACTION_SA_QUERY) {
626		/*
627		 * Assume frame was protected; it would have been dropped if
628		 * not.
629		 */
630		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
631	}
632	os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
633	os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
634	os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
635	buf[24] = rx_action->category;
636	os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
637	os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
638	rx_mgmt.frame = buf;
639	rx_mgmt.frame_len = 24 + 1 + rx_action->len;
640	hostapd_mgmt_rx(hapd, &rx_mgmt);
641	os_free(buf);
642}
643
644
645static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
646			       size_t len, u16 stype, int ok)
647{
648	struct ieee80211_hdr *hdr;
649	hdr = (struct ieee80211_hdr *) buf;
650	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
651	if (hapd == NULL || hapd == HAPD_BROADCAST)
652		return;
653	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
654}
655
656#endif /* NEED_AP_MLME */
657
658
659static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
660{
661	struct sta_info *sta = ap_get_sta(hapd, addr);
662	if (sta)
663		return 0;
664
665	wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
666		   " - adding a new STA", MAC2STR(addr));
667	sta = ap_sta_add(hapd, addr);
668	if (sta) {
669		hostapd_new_assoc_sta(hapd, sta, 0);
670	} else {
671		wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
672			   MAC2STR(addr));
673		return -1;
674	}
675
676	return 0;
677}
678
679
680static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
681				   const u8 *data, size_t data_len)
682{
683	struct hostapd_iface *iface = hapd->iface;
684	struct sta_info *sta;
685	size_t j;
686
687	for (j = 0; j < iface->num_bss; j++) {
688		if ((sta = ap_get_sta(iface->bss[j], src))) {
689			if (sta->flags & WLAN_STA_ASSOC) {
690				hapd = iface->bss[j];
691				break;
692			}
693		}
694	}
695
696	ieee802_1x_receive(hapd, src, data, data_len);
697}
698
699
700void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
701			  union wpa_event_data *data)
702{
703	struct hostapd_data *hapd = ctx;
704#ifndef CONFIG_NO_STDOUT_DEBUG
705	int level = MSG_DEBUG;
706
707	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
708	    data->rx_mgmt.frame_len >= 24) {
709		const struct ieee80211_hdr *hdr;
710		u16 fc;
711		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
712		fc = le_to_host16(hdr->frame_control);
713		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
714		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
715			level = MSG_EXCESSIVE;
716	}
717
718	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
719		event_to_string(event), event);
720#endif /* CONFIG_NO_STDOUT_DEBUG */
721
722	switch (event) {
723	case EVENT_MICHAEL_MIC_FAILURE:
724		michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
725		break;
726	case EVENT_SCAN_RESULTS:
727		if (hapd->iface->scan_cb)
728			hapd->iface->scan_cb(hapd->iface);
729		break;
730#ifdef CONFIG_IEEE80211R
731	case EVENT_FT_RRB_RX:
732		wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
733			      data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
734		break;
735#endif /* CONFIG_IEEE80211R */
736	case EVENT_WPS_BUTTON_PUSHED:
737		hostapd_wps_button_pushed(hapd, NULL);
738		break;
739#ifdef NEED_AP_MLME
740	case EVENT_TX_STATUS:
741		switch (data->tx_status.type) {
742		case WLAN_FC_TYPE_MGMT:
743			hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
744					   data->tx_status.data_len,
745					   data->tx_status.stype,
746					   data->tx_status.ack);
747			break;
748		case WLAN_FC_TYPE_DATA:
749			hostapd_tx_status(hapd, data->tx_status.dst,
750					  data->tx_status.data,
751					  data->tx_status.data_len,
752					  data->tx_status.ack);
753			break;
754		}
755		break;
756	case EVENT_EAPOL_TX_STATUS:
757		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
758					data->eapol_tx_status.data,
759					data->eapol_tx_status.data_len,
760					data->eapol_tx_status.ack);
761		break;
762	case EVENT_DRIVER_CLIENT_POLL_OK:
763		hostapd_client_poll_ok(hapd, data->client_poll.addr);
764		break;
765	case EVENT_RX_FROM_UNKNOWN:
766		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
767					    data->rx_from_unknown.addr,
768					    data->rx_from_unknown.wds);
769		break;
770	case EVENT_RX_MGMT:
771		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
772		break;
773#endif /* NEED_AP_MLME */
774	case EVENT_RX_PROBE_REQ:
775		if (data->rx_probe_req.sa == NULL ||
776		    data->rx_probe_req.ie == NULL)
777			break;
778		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
779				     data->rx_probe_req.da,
780				     data->rx_probe_req.bssid,
781				     data->rx_probe_req.ie,
782				     data->rx_probe_req.ie_len,
783				     data->rx_probe_req.ssi_signal);
784		break;
785	case EVENT_NEW_STA:
786		hostapd_event_new_sta(hapd, data->new_sta.addr);
787		break;
788	case EVENT_EAPOL_RX:
789		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
790				       data->eapol_rx.data,
791				       data->eapol_rx.data_len);
792		break;
793	case EVENT_ASSOC:
794		hostapd_notif_assoc(hapd, data->assoc_info.addr,
795				    data->assoc_info.req_ies,
796				    data->assoc_info.req_ies_len,
797				    data->assoc_info.reassoc);
798		break;
799	case EVENT_DISASSOC:
800		if (data)
801			hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
802		break;
803	case EVENT_DEAUTH:
804		if (data)
805			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
806		break;
807	case EVENT_STATION_LOW_ACK:
808		if (!data)
809			break;
810		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
811		break;
812	case EVENT_RX_ACTION:
813		if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
814		    data->rx_action.bssid == NULL)
815			break;
816#ifdef NEED_AP_MLME
817		hostapd_rx_action(hapd, &data->rx_action);
818#endif /* NEED_AP_MLME */
819		hostapd_action_rx(hapd, &data->rx_action);
820		break;
821	case EVENT_AUTH:
822		hostapd_notif_auth(hapd, &data->auth);
823		break;
824	case EVENT_CH_SWITCH:
825		if (!data)
826			break;
827		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
828					data->ch_switch.ht_enabled,
829					data->ch_switch.ch_offset);
830		break;
831	default:
832		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
833		break;
834	}
835}
836
837#endif /* HOSTAPD */
838