1214501Srpaulo/*
2214501Srpaulo * hostapd / IEEE 802.11 Management
3214501Srpaulo * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5214501Srpaulo * This program is free software; you can redistribute it and/or modify
6214501Srpaulo * it under the terms of the GNU General Public License version 2 as
7214501Srpaulo * published by the Free Software Foundation.
8214501Srpaulo *
9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD
10214501Srpaulo * license.
11214501Srpaulo *
12214501Srpaulo * See README and COPYING for more details.
13214501Srpaulo */
14214501Srpaulo
15214501Srpaulo#include "utils/includes.h"
16214501Srpaulo
17214501Srpaulo#ifndef CONFIG_NATIVE_WINDOWS
18214501Srpaulo
19214501Srpaulo#include "utils/common.h"
20214501Srpaulo#include "utils/eloop.h"
21214501Srpaulo#include "crypto/crypto.h"
22214501Srpaulo#include "drivers/driver.h"
23214501Srpaulo#include "common/ieee802_11_defs.h"
24214501Srpaulo#include "common/ieee802_11_common.h"
25214501Srpaulo#include "common/wpa_ctrl.h"
26214501Srpaulo#include "radius/radius.h"
27214501Srpaulo#include "radius/radius_client.h"
28214501Srpaulo#include "wps/wps.h"
29214501Srpaulo#include "hostapd.h"
30214501Srpaulo#include "beacon.h"
31214501Srpaulo#include "ieee802_11_auth.h"
32214501Srpaulo#include "sta_info.h"
33214501Srpaulo#include "ieee802_1x.h"
34214501Srpaulo#include "wpa_auth.h"
35214501Srpaulo#include "wmm.h"
36214501Srpaulo#include "ap_list.h"
37214501Srpaulo#include "accounting.h"
38214501Srpaulo#include "ap_config.h"
39214501Srpaulo#include "ap_mlme.h"
40214501Srpaulo#include "ieee802_11.h"
41214501Srpaulo
42214501Srpaulo
43214501Srpaulou8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
44214501Srpaulo{
45214501Srpaulo	u8 *pos = eid;
46214501Srpaulo	int i, num, count;
47214501Srpaulo
48214501Srpaulo	if (hapd->iface->current_rates == NULL)
49214501Srpaulo		return eid;
50214501Srpaulo
51214501Srpaulo	*pos++ = WLAN_EID_SUPP_RATES;
52214501Srpaulo	num = hapd->iface->num_rates;
53214501Srpaulo	if (num > 8) {
54214501Srpaulo		/* rest of the rates are encoded in Extended supported
55214501Srpaulo		 * rates element */
56214501Srpaulo		num = 8;
57214501Srpaulo	}
58214501Srpaulo
59214501Srpaulo	*pos++ = num;
60214501Srpaulo	count = 0;
61214501Srpaulo	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
62214501Srpaulo	     i++) {
63214501Srpaulo		count++;
64214501Srpaulo		*pos = hapd->iface->current_rates[i].rate / 5;
65214501Srpaulo		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
66214501Srpaulo			*pos |= 0x80;
67214501Srpaulo		pos++;
68214501Srpaulo	}
69214501Srpaulo
70214501Srpaulo	return pos;
71214501Srpaulo}
72214501Srpaulo
73214501Srpaulo
74214501Srpaulou8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
75214501Srpaulo{
76214501Srpaulo	u8 *pos = eid;
77214501Srpaulo	int i, num, count;
78214501Srpaulo
79214501Srpaulo	if (hapd->iface->current_rates == NULL)
80214501Srpaulo		return eid;
81214501Srpaulo
82214501Srpaulo	num = hapd->iface->num_rates;
83214501Srpaulo	if (num <= 8)
84214501Srpaulo		return eid;
85214501Srpaulo	num -= 8;
86214501Srpaulo
87214501Srpaulo	*pos++ = WLAN_EID_EXT_SUPP_RATES;
88214501Srpaulo	*pos++ = num;
89214501Srpaulo	count = 0;
90214501Srpaulo	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
91214501Srpaulo	     i++) {
92214501Srpaulo		count++;
93214501Srpaulo		if (count <= 8)
94214501Srpaulo			continue; /* already in SuppRates IE */
95214501Srpaulo		*pos = hapd->iface->current_rates[i].rate / 5;
96214501Srpaulo		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
97214501Srpaulo			*pos |= 0x80;
98214501Srpaulo		pos++;
99214501Srpaulo	}
100214501Srpaulo
101214501Srpaulo	return pos;
102214501Srpaulo}
103214501Srpaulo
104214501Srpaulo
105214501Srpaulou16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
106214501Srpaulo			   int probe)
107214501Srpaulo{
108214501Srpaulo	int capab = WLAN_CAPABILITY_ESS;
109214501Srpaulo	int privacy;
110214501Srpaulo
111214501Srpaulo	if (hapd->iface->num_sta_no_short_preamble == 0 &&
112214501Srpaulo	    hapd->iconf->preamble == SHORT_PREAMBLE)
113214501Srpaulo		capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
114214501Srpaulo
115214501Srpaulo	privacy = hapd->conf->ssid.wep.keys_set;
116214501Srpaulo
117214501Srpaulo	if (hapd->conf->ieee802_1x &&
118214501Srpaulo	    (hapd->conf->default_wep_key_len ||
119214501Srpaulo	     hapd->conf->individual_wep_key_len))
120214501Srpaulo		privacy = 1;
121214501Srpaulo
122214501Srpaulo	if (hapd->conf->wpa)
123214501Srpaulo		privacy = 1;
124214501Srpaulo
125214501Srpaulo	if (sta) {
126214501Srpaulo		int policy, def_klen;
127214501Srpaulo		if (probe && sta->ssid_probe) {
128214501Srpaulo			policy = sta->ssid_probe->security_policy;
129214501Srpaulo			def_klen = sta->ssid_probe->wep.default_len;
130214501Srpaulo		} else {
131214501Srpaulo			policy = sta->ssid->security_policy;
132214501Srpaulo			def_klen = sta->ssid->wep.default_len;
133214501Srpaulo		}
134214501Srpaulo		privacy = policy != SECURITY_PLAINTEXT;
135214501Srpaulo		if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
136214501Srpaulo			privacy = 0;
137214501Srpaulo	}
138214501Srpaulo
139214501Srpaulo	if (privacy)
140214501Srpaulo		capab |= WLAN_CAPABILITY_PRIVACY;
141214501Srpaulo
142214501Srpaulo	if (hapd->iface->current_mode &&
143214501Srpaulo	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
144214501Srpaulo	    hapd->iface->num_sta_no_short_slot_time == 0)
145214501Srpaulo		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
146214501Srpaulo
147214501Srpaulo	return capab;
148214501Srpaulo}
149214501Srpaulo
150214501Srpaulo
151214501Srpaulo#ifdef CONFIG_IEEE80211W
152214501Srpaulostatic u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
153214501Srpaulo					    struct sta_info *sta, u8 *eid)
154214501Srpaulo{
155214501Srpaulo	u8 *pos = eid;
156214501Srpaulo	u32 timeout, tu;
157214501Srpaulo	struct os_time now, passed;
158214501Srpaulo
159214501Srpaulo	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
160214501Srpaulo	*pos++ = 5;
161214501Srpaulo	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
162214501Srpaulo	os_get_time(&now);
163214501Srpaulo	os_time_sub(&now, &sta->sa_query_start, &passed);
164214501Srpaulo	tu = (passed.sec * 1000000 + passed.usec) / 1024;
165214501Srpaulo	if (hapd->conf->assoc_sa_query_max_timeout > tu)
166214501Srpaulo		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
167214501Srpaulo	else
168214501Srpaulo		timeout = 0;
169214501Srpaulo	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
170214501Srpaulo		timeout++; /* add some extra time for local timers */
171214501Srpaulo	WPA_PUT_LE32(pos, timeout);
172214501Srpaulo	pos += 4;
173214501Srpaulo
174214501Srpaulo	return pos;
175214501Srpaulo}
176214501Srpaulo#endif /* CONFIG_IEEE80211W */
177214501Srpaulo
178214501Srpaulo
179214501Srpaulovoid ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
180214501Srpaulo{
181214501Srpaulo	int i;
182214501Srpaulo	if (len > HOSTAPD_MAX_SSID_LEN)
183214501Srpaulo		len = HOSTAPD_MAX_SSID_LEN;
184214501Srpaulo	for (i = 0; i < len; i++) {
185214501Srpaulo		if (ssid[i] >= 32 && ssid[i] < 127)
186214501Srpaulo			buf[i] = ssid[i];
187214501Srpaulo		else
188214501Srpaulo			buf[i] = '.';
189214501Srpaulo	}
190214501Srpaulo	buf[len] = '\0';
191214501Srpaulo}
192214501Srpaulo
193214501Srpaulo
194214501Srpaulostatic u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
195214501Srpaulo			   u16 auth_transaction, const u8 *challenge,
196214501Srpaulo			   int iswep)
197214501Srpaulo{
198214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
199214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
200214501Srpaulo		       "authentication (shared key, transaction %d)",
201214501Srpaulo		       auth_transaction);
202214501Srpaulo
203214501Srpaulo	if (auth_transaction == 1) {
204214501Srpaulo		if (!sta->challenge) {
205214501Srpaulo			/* Generate a pseudo-random challenge */
206214501Srpaulo			u8 key[8];
207214501Srpaulo			time_t now;
208214501Srpaulo			int r;
209214501Srpaulo			sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
210214501Srpaulo			if (sta->challenge == NULL)
211214501Srpaulo				return WLAN_STATUS_UNSPECIFIED_FAILURE;
212214501Srpaulo
213214501Srpaulo			now = time(NULL);
214214501Srpaulo			r = random();
215214501Srpaulo			os_memcpy(key, &now, 4);
216214501Srpaulo			os_memcpy(key + 4, &r, 4);
217214501Srpaulo			rc4_skip(key, sizeof(key), 0,
218214501Srpaulo				 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
219214501Srpaulo		}
220214501Srpaulo		return 0;
221214501Srpaulo	}
222214501Srpaulo
223214501Srpaulo	if (auth_transaction != 3)
224214501Srpaulo		return WLAN_STATUS_UNSPECIFIED_FAILURE;
225214501Srpaulo
226214501Srpaulo	/* Transaction 3 */
227214501Srpaulo	if (!iswep || !sta->challenge || !challenge ||
228214501Srpaulo	    os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) {
229214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
230214501Srpaulo			       HOSTAPD_LEVEL_INFO,
231214501Srpaulo			       "shared key authentication - invalid "
232214501Srpaulo			       "challenge-response");
233214501Srpaulo		return WLAN_STATUS_CHALLENGE_FAIL;
234214501Srpaulo	}
235214501Srpaulo
236214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
237214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
238214501Srpaulo		       "authentication OK (shared key)");
239214501Srpaulo#ifdef IEEE80211_REQUIRE_AUTH_ACK
240214501Srpaulo	/* Station will be marked authenticated if it ACKs the
241214501Srpaulo	 * authentication reply. */
242214501Srpaulo#else
243214501Srpaulo	sta->flags |= WLAN_STA_AUTH;
244214501Srpaulo	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
245214501Srpaulo#endif
246214501Srpaulo	os_free(sta->challenge);
247214501Srpaulo	sta->challenge = NULL;
248214501Srpaulo
249214501Srpaulo	return 0;
250214501Srpaulo}
251214501Srpaulo
252214501Srpaulo
253214501Srpaulostatic void send_auth_reply(struct hostapd_data *hapd,
254214501Srpaulo			    const u8 *dst, const u8 *bssid,
255214501Srpaulo			    u16 auth_alg, u16 auth_transaction, u16 resp,
256214501Srpaulo			    const u8 *ies, size_t ies_len)
257214501Srpaulo{
258214501Srpaulo	struct ieee80211_mgmt *reply;
259214501Srpaulo	u8 *buf;
260214501Srpaulo	size_t rlen;
261214501Srpaulo
262214501Srpaulo	rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
263214501Srpaulo	buf = os_zalloc(rlen);
264214501Srpaulo	if (buf == NULL)
265214501Srpaulo		return;
266214501Srpaulo
267214501Srpaulo	reply = (struct ieee80211_mgmt *) buf;
268214501Srpaulo	reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
269214501Srpaulo					    WLAN_FC_STYPE_AUTH);
270214501Srpaulo	os_memcpy(reply->da, dst, ETH_ALEN);
271214501Srpaulo	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
272214501Srpaulo	os_memcpy(reply->bssid, bssid, ETH_ALEN);
273214501Srpaulo
274214501Srpaulo	reply->u.auth.auth_alg = host_to_le16(auth_alg);
275214501Srpaulo	reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
276214501Srpaulo	reply->u.auth.status_code = host_to_le16(resp);
277214501Srpaulo
278214501Srpaulo	if (ies && ies_len)
279214501Srpaulo		os_memcpy(reply->u.auth.variable, ies, ies_len);
280214501Srpaulo
281214501Srpaulo	wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
282214501Srpaulo		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
283214501Srpaulo		   MAC2STR(dst), auth_alg, auth_transaction,
284214501Srpaulo		   resp, (unsigned long) ies_len);
285214501Srpaulo	if (hapd->drv.send_mgmt_frame(hapd, reply, rlen) < 0)
286214501Srpaulo		perror("send_auth_reply: send");
287214501Srpaulo
288214501Srpaulo	os_free(buf);
289214501Srpaulo}
290214501Srpaulo
291214501Srpaulo
292214501Srpaulo#ifdef CONFIG_IEEE80211R
293214501Srpaulostatic void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
294214501Srpaulo				  u16 auth_transaction, u16 status,
295214501Srpaulo				  const u8 *ies, size_t ies_len)
296214501Srpaulo{
297214501Srpaulo	struct hostapd_data *hapd = ctx;
298214501Srpaulo	struct sta_info *sta;
299214501Srpaulo
300214501Srpaulo	send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
301214501Srpaulo			status, ies, ies_len);
302214501Srpaulo
303214501Srpaulo	if (status != WLAN_STATUS_SUCCESS)
304214501Srpaulo		return;
305214501Srpaulo
306214501Srpaulo	sta = ap_get_sta(hapd, dst);
307214501Srpaulo	if (sta == NULL)
308214501Srpaulo		return;
309214501Srpaulo
310214501Srpaulo	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
311214501Srpaulo		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
312214501Srpaulo	sta->flags |= WLAN_STA_AUTH;
313214501Srpaulo	mlme_authenticate_indication(hapd, sta);
314214501Srpaulo}
315214501Srpaulo#endif /* CONFIG_IEEE80211R */
316214501Srpaulo
317214501Srpaulo
318214501Srpaulostatic void handle_auth(struct hostapd_data *hapd,
319214501Srpaulo			const struct ieee80211_mgmt *mgmt, size_t len)
320214501Srpaulo{
321214501Srpaulo	u16 auth_alg, auth_transaction, status_code;
322214501Srpaulo	u16 resp = WLAN_STATUS_SUCCESS;
323214501Srpaulo	struct sta_info *sta = NULL;
324214501Srpaulo	int res;
325214501Srpaulo	u16 fc;
326214501Srpaulo	const u8 *challenge = NULL;
327214501Srpaulo	u32 session_timeout, acct_interim_interval;
328214501Srpaulo	int vlan_id = 0;
329214501Srpaulo	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
330214501Srpaulo	size_t resp_ies_len = 0;
331214501Srpaulo
332214501Srpaulo	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
333214501Srpaulo		printf("handle_auth - too short payload (len=%lu)\n",
334214501Srpaulo		       (unsigned long) len);
335214501Srpaulo		return;
336214501Srpaulo	}
337214501Srpaulo
338214501Srpaulo	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
339214501Srpaulo	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
340214501Srpaulo	status_code = le_to_host16(mgmt->u.auth.status_code);
341214501Srpaulo	fc = le_to_host16(mgmt->frame_control);
342214501Srpaulo
343214501Srpaulo	if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
344214501Srpaulo	    2 + WLAN_AUTH_CHALLENGE_LEN &&
345214501Srpaulo	    mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
346214501Srpaulo	    mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
347214501Srpaulo		challenge = &mgmt->u.auth.variable[2];
348214501Srpaulo
349214501Srpaulo	wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
350214501Srpaulo		   "auth_transaction=%d status_code=%d wep=%d%s",
351214501Srpaulo		   MAC2STR(mgmt->sa), auth_alg, auth_transaction,
352214501Srpaulo		   status_code, !!(fc & WLAN_FC_ISWEP),
353214501Srpaulo		   challenge ? " challenge" : "");
354214501Srpaulo
355214501Srpaulo	if (hapd->tkip_countermeasures) {
356214501Srpaulo		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
357214501Srpaulo		goto fail;
358214501Srpaulo	}
359214501Srpaulo
360214501Srpaulo	if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
361214501Srpaulo	       auth_alg == WLAN_AUTH_OPEN) ||
362214501Srpaulo#ifdef CONFIG_IEEE80211R
363214501Srpaulo	      (hapd->conf->wpa &&
364214501Srpaulo	       (hapd->conf->wpa_key_mgmt &
365214501Srpaulo		(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
366214501Srpaulo	       auth_alg == WLAN_AUTH_FT) ||
367214501Srpaulo#endif /* CONFIG_IEEE80211R */
368214501Srpaulo	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
369214501Srpaulo	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
370214501Srpaulo		printf("Unsupported authentication algorithm (%d)\n",
371214501Srpaulo		       auth_alg);
372214501Srpaulo		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
373214501Srpaulo		goto fail;
374214501Srpaulo	}
375214501Srpaulo
376214501Srpaulo	if (!(auth_transaction == 1 ||
377214501Srpaulo	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
378214501Srpaulo		printf("Unknown authentication transaction number (%d)\n",
379214501Srpaulo		       auth_transaction);
380214501Srpaulo		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
381214501Srpaulo		goto fail;
382214501Srpaulo	}
383214501Srpaulo
384214501Srpaulo	if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
385214501Srpaulo		printf("Station " MACSTR " not allowed to authenticate.\n",
386214501Srpaulo		       MAC2STR(mgmt->sa));
387214501Srpaulo		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
388214501Srpaulo		goto fail;
389214501Srpaulo	}
390214501Srpaulo
391214501Srpaulo	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
392214501Srpaulo				      &session_timeout,
393214501Srpaulo				      &acct_interim_interval, &vlan_id);
394214501Srpaulo	if (res == HOSTAPD_ACL_REJECT) {
395214501Srpaulo		printf("Station " MACSTR " not allowed to authenticate.\n",
396214501Srpaulo		       MAC2STR(mgmt->sa));
397214501Srpaulo		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
398214501Srpaulo		goto fail;
399214501Srpaulo	}
400214501Srpaulo	if (res == HOSTAPD_ACL_PENDING) {
401214501Srpaulo		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
402214501Srpaulo			   " waiting for an external authentication",
403214501Srpaulo			   MAC2STR(mgmt->sa));
404214501Srpaulo		/* Authentication code will re-send the authentication frame
405214501Srpaulo		 * after it has received (and cached) information from the
406214501Srpaulo		 * external source. */
407214501Srpaulo		return;
408214501Srpaulo	}
409214501Srpaulo
410214501Srpaulo	sta = ap_sta_add(hapd, mgmt->sa);
411214501Srpaulo	if (!sta) {
412214501Srpaulo		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
413214501Srpaulo		goto fail;
414214501Srpaulo	}
415214501Srpaulo
416214501Srpaulo	if (vlan_id > 0) {
417214501Srpaulo		if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
418214501Srpaulo					       vlan_id) == NULL) {
419214501Srpaulo			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
420214501Srpaulo				       HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
421214501Srpaulo				       "%d received from RADIUS server",
422214501Srpaulo				       vlan_id);
423214501Srpaulo			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
424214501Srpaulo			goto fail;
425214501Srpaulo		}
426214501Srpaulo		sta->vlan_id = vlan_id;
427214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
428214501Srpaulo			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
429214501Srpaulo	}
430214501Srpaulo
431214501Srpaulo	sta->flags &= ~WLAN_STA_PREAUTH;
432214501Srpaulo	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
433214501Srpaulo
434214501Srpaulo	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
435214501Srpaulo		sta->acct_interim_interval = acct_interim_interval;
436214501Srpaulo	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
437214501Srpaulo		ap_sta_session_timeout(hapd, sta, session_timeout);
438214501Srpaulo	else
439214501Srpaulo		ap_sta_no_session_timeout(hapd, sta);
440214501Srpaulo
441214501Srpaulo	switch (auth_alg) {
442214501Srpaulo	case WLAN_AUTH_OPEN:
443214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
444214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
445214501Srpaulo			       "authentication OK (open system)");
446214501Srpaulo#ifdef IEEE80211_REQUIRE_AUTH_ACK
447214501Srpaulo		/* Station will be marked authenticated if it ACKs the
448214501Srpaulo		 * authentication reply. */
449214501Srpaulo#else
450214501Srpaulo		sta->flags |= WLAN_STA_AUTH;
451214501Srpaulo		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
452214501Srpaulo		sta->auth_alg = WLAN_AUTH_OPEN;
453214501Srpaulo		mlme_authenticate_indication(hapd, sta);
454214501Srpaulo#endif
455214501Srpaulo		break;
456214501Srpaulo	case WLAN_AUTH_SHARED_KEY:
457214501Srpaulo		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
458214501Srpaulo				       fc & WLAN_FC_ISWEP);
459214501Srpaulo		sta->auth_alg = WLAN_AUTH_SHARED_KEY;
460214501Srpaulo		mlme_authenticate_indication(hapd, sta);
461214501Srpaulo		if (sta->challenge && auth_transaction == 1) {
462214501Srpaulo			resp_ies[0] = WLAN_EID_CHALLENGE;
463214501Srpaulo			resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
464214501Srpaulo			os_memcpy(resp_ies + 2, sta->challenge,
465214501Srpaulo				  WLAN_AUTH_CHALLENGE_LEN);
466214501Srpaulo			resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
467214501Srpaulo		}
468214501Srpaulo		break;
469214501Srpaulo#ifdef CONFIG_IEEE80211R
470214501Srpaulo	case WLAN_AUTH_FT:
471214501Srpaulo		sta->auth_alg = WLAN_AUTH_FT;
472214501Srpaulo		if (sta->wpa_sm == NULL)
473214501Srpaulo			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
474214501Srpaulo							sta->addr);
475214501Srpaulo		if (sta->wpa_sm == NULL) {
476214501Srpaulo			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
477214501Srpaulo				   "state machine");
478214501Srpaulo			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
479214501Srpaulo			goto fail;
480214501Srpaulo		}
481214501Srpaulo		wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
482214501Srpaulo				    auth_transaction, mgmt->u.auth.variable,
483214501Srpaulo				    len - IEEE80211_HDRLEN -
484214501Srpaulo				    sizeof(mgmt->u.auth),
485214501Srpaulo				    handle_auth_ft_finish, hapd);
486214501Srpaulo		/* handle_auth_ft_finish() callback will complete auth. */
487214501Srpaulo		return;
488214501Srpaulo#endif /* CONFIG_IEEE80211R */
489214501Srpaulo	}
490214501Srpaulo
491214501Srpaulo fail:
492214501Srpaulo	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
493214501Srpaulo			auth_transaction + 1, resp, resp_ies, resp_ies_len);
494214501Srpaulo}
495214501Srpaulo
496214501Srpaulo
497214501Srpaulostatic int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
498214501Srpaulo{
499214501Srpaulo	int i, j = 32, aid;
500214501Srpaulo
501214501Srpaulo	/* get a unique AID */
502214501Srpaulo	if (sta->aid > 0) {
503214501Srpaulo		wpa_printf(MSG_DEBUG, "  old AID %d", sta->aid);
504214501Srpaulo		return 0;
505214501Srpaulo	}
506214501Srpaulo
507214501Srpaulo	for (i = 0; i < AID_WORDS; i++) {
508214501Srpaulo		if (hapd->sta_aid[i] == (u32) -1)
509214501Srpaulo			continue;
510214501Srpaulo		for (j = 0; j < 32; j++) {
511214501Srpaulo			if (!(hapd->sta_aid[i] & BIT(j)))
512214501Srpaulo				break;
513214501Srpaulo		}
514214501Srpaulo		if (j < 32)
515214501Srpaulo			break;
516214501Srpaulo	}
517214501Srpaulo	if (j == 32)
518214501Srpaulo		return -1;
519214501Srpaulo	aid = i * 32 + j + 1;
520214501Srpaulo	if (aid > 2007)
521214501Srpaulo		return -1;
522214501Srpaulo
523214501Srpaulo	sta->aid = aid;
524214501Srpaulo	hapd->sta_aid[i] |= BIT(j);
525214501Srpaulo	wpa_printf(MSG_DEBUG, "  new AID %d", sta->aid);
526214501Srpaulo	return 0;
527214501Srpaulo}
528214501Srpaulo
529214501Srpaulo
530214501Srpaulostatic u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
531214501Srpaulo		      const u8 *ssid_ie, size_t ssid_ie_len)
532214501Srpaulo{
533214501Srpaulo	if (ssid_ie == NULL)
534214501Srpaulo		return WLAN_STATUS_UNSPECIFIED_FAILURE;
535214501Srpaulo
536214501Srpaulo	if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
537214501Srpaulo	    os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
538214501Srpaulo		char ssid_txt[33];
539214501Srpaulo		ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len);
540214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
541214501Srpaulo			       HOSTAPD_LEVEL_INFO,
542214501Srpaulo			       "Station tried to associate with unknown SSID "
543214501Srpaulo			       "'%s'", ssid_txt);
544214501Srpaulo		return WLAN_STATUS_UNSPECIFIED_FAILURE;
545214501Srpaulo	}
546214501Srpaulo
547214501Srpaulo	return WLAN_STATUS_SUCCESS;
548214501Srpaulo}
549214501Srpaulo
550214501Srpaulo
551214501Srpaulostatic u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
552214501Srpaulo		     const u8 *wmm_ie, size_t wmm_ie_len)
553214501Srpaulo{
554214501Srpaulo	sta->flags &= ~WLAN_STA_WMM;
555214501Srpaulo	if (wmm_ie && hapd->conf->wmm_enabled) {
556214501Srpaulo		if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
557214501Srpaulo			hostapd_logger(hapd, sta->addr,
558214501Srpaulo				       HOSTAPD_MODULE_WPA,
559214501Srpaulo				       HOSTAPD_LEVEL_DEBUG,
560214501Srpaulo				       "invalid WMM element in association "
561214501Srpaulo				       "request");
562214501Srpaulo		else
563214501Srpaulo			sta->flags |= WLAN_STA_WMM;
564214501Srpaulo	}
565214501Srpaulo	return WLAN_STATUS_SUCCESS;
566214501Srpaulo}
567214501Srpaulo
568214501Srpaulo
569214501Srpaulostatic u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
570214501Srpaulo			   struct ieee802_11_elems *elems)
571214501Srpaulo{
572214501Srpaulo	if (!elems->supp_rates) {
573214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
574214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
575214501Srpaulo			       "No supported rates element in AssocReq");
576214501Srpaulo		return WLAN_STATUS_UNSPECIFIED_FAILURE;
577214501Srpaulo	}
578214501Srpaulo
579214501Srpaulo	if (elems->supp_rates_len > sizeof(sta->supported_rates)) {
580214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
581214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
582214501Srpaulo			       "Invalid supported rates element length %d",
583214501Srpaulo			       elems->supp_rates_len);
584214501Srpaulo		return WLAN_STATUS_UNSPECIFIED_FAILURE;
585214501Srpaulo	}
586214501Srpaulo
587214501Srpaulo	os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
588214501Srpaulo	os_memcpy(sta->supported_rates, elems->supp_rates,
589214501Srpaulo		  elems->supp_rates_len);
590214501Srpaulo	sta->supported_rates_len = elems->supp_rates_len;
591214501Srpaulo
592214501Srpaulo	if (elems->ext_supp_rates) {
593214501Srpaulo		if (elems->supp_rates_len + elems->ext_supp_rates_len >
594214501Srpaulo		    sizeof(sta->supported_rates)) {
595214501Srpaulo			hostapd_logger(hapd, sta->addr,
596214501Srpaulo				       HOSTAPD_MODULE_IEEE80211,
597214501Srpaulo				       HOSTAPD_LEVEL_DEBUG,
598214501Srpaulo				       "Invalid supported rates element length"
599214501Srpaulo				       " %d+%d", elems->supp_rates_len,
600214501Srpaulo				       elems->ext_supp_rates_len);
601214501Srpaulo			return WLAN_STATUS_UNSPECIFIED_FAILURE;
602214501Srpaulo		}
603214501Srpaulo
604214501Srpaulo		os_memcpy(sta->supported_rates + elems->supp_rates_len,
605214501Srpaulo			  elems->ext_supp_rates, elems->ext_supp_rates_len);
606214501Srpaulo		sta->supported_rates_len += elems->ext_supp_rates_len;
607214501Srpaulo	}
608214501Srpaulo
609214501Srpaulo	return WLAN_STATUS_SUCCESS;
610214501Srpaulo}
611214501Srpaulo
612214501Srpaulo
613214501Srpaulostatic u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
614214501Srpaulo			   const u8 *ies, size_t ies_len, int reassoc)
615214501Srpaulo{
616214501Srpaulo	struct ieee802_11_elems elems;
617214501Srpaulo	u16 resp;
618214501Srpaulo	const u8 *wpa_ie;
619214501Srpaulo	size_t wpa_ie_len;
620214501Srpaulo
621214501Srpaulo	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
622214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
623214501Srpaulo			       HOSTAPD_LEVEL_INFO, "Station sent an invalid "
624214501Srpaulo			       "association request");
625214501Srpaulo		return WLAN_STATUS_UNSPECIFIED_FAILURE;
626214501Srpaulo	}
627214501Srpaulo
628214501Srpaulo	resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
629214501Srpaulo	if (resp != WLAN_STATUS_SUCCESS)
630214501Srpaulo		return resp;
631214501Srpaulo	resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
632214501Srpaulo	if (resp != WLAN_STATUS_SUCCESS)
633214501Srpaulo		return resp;
634214501Srpaulo	resp = copy_supp_rates(hapd, sta, &elems);
635214501Srpaulo	if (resp != WLAN_STATUS_SUCCESS)
636214501Srpaulo		return resp;
637214501Srpaulo#ifdef CONFIG_IEEE80211N
638214501Srpaulo	resp = copy_sta_ht_capab(sta, elems.ht_capabilities,
639214501Srpaulo				 elems.ht_capabilities_len);
640214501Srpaulo	if (resp != WLAN_STATUS_SUCCESS)
641214501Srpaulo		return resp;
642214501Srpaulo#endif /* CONFIG_IEEE80211N */
643214501Srpaulo
644214501Srpaulo	if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
645214501Srpaulo		wpa_ie = elems.rsn_ie;
646214501Srpaulo		wpa_ie_len = elems.rsn_ie_len;
647214501Srpaulo	} else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
648214501Srpaulo		   elems.wpa_ie) {
649214501Srpaulo		wpa_ie = elems.wpa_ie;
650214501Srpaulo		wpa_ie_len = elems.wpa_ie_len;
651214501Srpaulo	} else {
652214501Srpaulo		wpa_ie = NULL;
653214501Srpaulo		wpa_ie_len = 0;
654214501Srpaulo	}
655214501Srpaulo
656214501Srpaulo#ifdef CONFIG_WPS
657214501Srpaulo	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
658214501Srpaulo	if (hapd->conf->wps_state && elems.wps_ie) {
659214501Srpaulo		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
660214501Srpaulo			   "Request - assume WPS is used");
661214501Srpaulo		sta->flags |= WLAN_STA_WPS;
662214501Srpaulo		wpabuf_free(sta->wps_ie);
663214501Srpaulo		sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
664214501Srpaulo							  WPS_IE_VENDOR_TYPE);
665214501Srpaulo		wpa_ie = NULL;
666214501Srpaulo		wpa_ie_len = 0;
667214501Srpaulo	} else if (hapd->conf->wps_state && wpa_ie == NULL) {
668214501Srpaulo		wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
669214501Srpaulo			   "(Re)Association Request - possible WPS use");
670214501Srpaulo		sta->flags |= WLAN_STA_MAYBE_WPS;
671214501Srpaulo	} else
672214501Srpaulo#endif /* CONFIG_WPS */
673214501Srpaulo	if (hapd->conf->wpa && wpa_ie == NULL) {
674214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
675214501Srpaulo			       HOSTAPD_LEVEL_INFO,
676214501Srpaulo			       "No WPA/RSN IE in association request");
677214501Srpaulo		return WLAN_STATUS_INVALID_IE;
678214501Srpaulo	}
679214501Srpaulo
680214501Srpaulo	if (hapd->conf->wpa && wpa_ie) {
681214501Srpaulo		int res;
682214501Srpaulo		wpa_ie -= 2;
683214501Srpaulo		wpa_ie_len += 2;
684214501Srpaulo		if (sta->wpa_sm == NULL)
685214501Srpaulo			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
686214501Srpaulo							sta->addr);
687214501Srpaulo		if (sta->wpa_sm == NULL) {
688214501Srpaulo			wpa_printf(MSG_WARNING, "Failed to initialize WPA "
689214501Srpaulo				   "state machine");
690214501Srpaulo			return WLAN_STATUS_UNSPECIFIED_FAILURE;
691214501Srpaulo		}
692214501Srpaulo		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
693214501Srpaulo					  wpa_ie, wpa_ie_len,
694214501Srpaulo					  elems.mdie, elems.mdie_len);
695214501Srpaulo		if (res == WPA_INVALID_GROUP)
696214501Srpaulo			resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
697214501Srpaulo		else if (res == WPA_INVALID_PAIRWISE)
698214501Srpaulo			resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
699214501Srpaulo		else if (res == WPA_INVALID_AKMP)
700214501Srpaulo			resp = WLAN_STATUS_AKMP_NOT_VALID;
701214501Srpaulo		else if (res == WPA_ALLOC_FAIL)
702214501Srpaulo			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
703214501Srpaulo#ifdef CONFIG_IEEE80211W
704214501Srpaulo		else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
705214501Srpaulo			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
706214501Srpaulo		else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
707214501Srpaulo			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
708214501Srpaulo#endif /* CONFIG_IEEE80211W */
709214501Srpaulo		else if (res == WPA_INVALID_MDIE)
710214501Srpaulo			resp = WLAN_STATUS_INVALID_MDIE;
711214501Srpaulo		else if (res != WPA_IE_OK)
712214501Srpaulo			resp = WLAN_STATUS_INVALID_IE;
713214501Srpaulo		if (resp != WLAN_STATUS_SUCCESS)
714214501Srpaulo			return resp;
715214501Srpaulo#ifdef CONFIG_IEEE80211W
716214501Srpaulo		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
717214501Srpaulo		    sta->sa_query_count > 0)
718214501Srpaulo			ap_check_sa_query_timeout(hapd, sta);
719214501Srpaulo		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
720214501Srpaulo		    (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
721214501Srpaulo			/*
722214501Srpaulo			 * STA has already been associated with MFP and SA
723214501Srpaulo			 * Query timeout has not been reached. Reject the
724214501Srpaulo			 * association attempt temporarily and start SA Query,
725214501Srpaulo			 * if one is not pending.
726214501Srpaulo			 */
727214501Srpaulo
728214501Srpaulo			if (sta->sa_query_count == 0)
729214501Srpaulo				ap_sta_start_sa_query(hapd, sta);
730214501Srpaulo
731214501Srpaulo			return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
732214501Srpaulo		}
733214501Srpaulo
734214501Srpaulo		if (wpa_auth_uses_mfp(sta->wpa_sm))
735214501Srpaulo			sta->flags |= WLAN_STA_MFP;
736214501Srpaulo		else
737214501Srpaulo			sta->flags &= ~WLAN_STA_MFP;
738214501Srpaulo#endif /* CONFIG_IEEE80211W */
739214501Srpaulo
740214501Srpaulo#ifdef CONFIG_IEEE80211R
741214501Srpaulo		if (sta->auth_alg == WLAN_AUTH_FT) {
742214501Srpaulo			if (!reassoc) {
743214501Srpaulo				wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
744214501Srpaulo					   "to use association (not "
745214501Srpaulo					   "re-association) with FT auth_alg",
746214501Srpaulo					   MAC2STR(sta->addr));
747214501Srpaulo				return WLAN_STATUS_UNSPECIFIED_FAILURE;
748214501Srpaulo			}
749214501Srpaulo
750214501Srpaulo			resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
751214501Srpaulo						       ies_len);
752214501Srpaulo			if (resp != WLAN_STATUS_SUCCESS)
753214501Srpaulo				return resp;
754214501Srpaulo		}
755214501Srpaulo#endif /* CONFIG_IEEE80211R */
756214501Srpaulo
757214501Srpaulo#ifdef CONFIG_IEEE80211N
758214501Srpaulo		if ((sta->flags & WLAN_STA_HT) &&
759214501Srpaulo		    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
760214501Srpaulo			hostapd_logger(hapd, sta->addr,
761214501Srpaulo				       HOSTAPD_MODULE_IEEE80211,
762214501Srpaulo				       HOSTAPD_LEVEL_INFO,
763214501Srpaulo				       "Station tried to use TKIP with HT "
764214501Srpaulo				       "association");
765214501Srpaulo			return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
766214501Srpaulo		}
767214501Srpaulo#endif /* CONFIG_IEEE80211N */
768214501Srpaulo	} else
769214501Srpaulo		wpa_auth_sta_no_wpa(sta->wpa_sm);
770214501Srpaulo
771214501Srpaulo	return WLAN_STATUS_SUCCESS;
772214501Srpaulo}
773214501Srpaulo
774214501Srpaulo
775214501Srpaulostatic void send_deauth(struct hostapd_data *hapd, const u8 *addr,
776214501Srpaulo			u16 reason_code)
777214501Srpaulo{
778214501Srpaulo	int send_len;
779214501Srpaulo	struct ieee80211_mgmt reply;
780214501Srpaulo
781214501Srpaulo	os_memset(&reply, 0, sizeof(reply));
782214501Srpaulo	reply.frame_control =
783214501Srpaulo		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
784214501Srpaulo	os_memcpy(reply.da, addr, ETH_ALEN);
785214501Srpaulo	os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
786214501Srpaulo	os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
787214501Srpaulo
788214501Srpaulo	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
789214501Srpaulo	reply.u.deauth.reason_code = host_to_le16(reason_code);
790214501Srpaulo
791214501Srpaulo	if (hapd->drv.send_mgmt_frame(hapd, &reply, send_len) < 0)
792214501Srpaulo		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
793214501Srpaulo			   strerror(errno));
794214501Srpaulo}
795214501Srpaulo
796214501Srpaulo
797214501Srpaulostatic void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
798214501Srpaulo			    u16 status_code, int reassoc, const u8 *ies,
799214501Srpaulo			    size_t ies_len)
800214501Srpaulo{
801214501Srpaulo	int send_len;
802214501Srpaulo	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
803214501Srpaulo	struct ieee80211_mgmt *reply;
804214501Srpaulo	u8 *p;
805214501Srpaulo
806214501Srpaulo	os_memset(buf, 0, sizeof(buf));
807214501Srpaulo	reply = (struct ieee80211_mgmt *) buf;
808214501Srpaulo	reply->frame_control =
809214501Srpaulo		IEEE80211_FC(WLAN_FC_TYPE_MGMT,
810214501Srpaulo			     (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
811214501Srpaulo			      WLAN_FC_STYPE_ASSOC_RESP));
812214501Srpaulo	os_memcpy(reply->da, sta->addr, ETH_ALEN);
813214501Srpaulo	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
814214501Srpaulo	os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
815214501Srpaulo
816214501Srpaulo	send_len = IEEE80211_HDRLEN;
817214501Srpaulo	send_len += sizeof(reply->u.assoc_resp);
818214501Srpaulo	reply->u.assoc_resp.capab_info =
819214501Srpaulo		host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
820214501Srpaulo	reply->u.assoc_resp.status_code = host_to_le16(status_code);
821214501Srpaulo	reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
822214501Srpaulo					       | BIT(14) | BIT(15));
823214501Srpaulo	/* Supported rates */
824214501Srpaulo	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
825214501Srpaulo	/* Extended supported rates */
826214501Srpaulo	p = hostapd_eid_ext_supp_rates(hapd, p);
827214501Srpaulo
828214501Srpaulo#ifdef CONFIG_IEEE80211R
829214501Srpaulo	if (status_code == WLAN_STATUS_SUCCESS) {
830214501Srpaulo		/* IEEE 802.11r: Mobility Domain Information, Fast BSS
831214501Srpaulo		 * Transition Information, RSN, [RIC Response] */
832214501Srpaulo		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
833214501Srpaulo						buf + sizeof(buf) - p,
834214501Srpaulo						sta->auth_alg, ies, ies_len);
835214501Srpaulo	}
836214501Srpaulo#endif /* CONFIG_IEEE80211R */
837214501Srpaulo
838214501Srpaulo#ifdef CONFIG_IEEE80211W
839214501Srpaulo	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
840214501Srpaulo		p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
841214501Srpaulo#endif /* CONFIG_IEEE80211W */
842214501Srpaulo
843214501Srpaulo#ifdef CONFIG_IEEE80211N
844214501Srpaulo	p = hostapd_eid_ht_capabilities(hapd, p);
845214501Srpaulo	p = hostapd_eid_ht_operation(hapd, p);
846214501Srpaulo#endif /* CONFIG_IEEE80211N */
847214501Srpaulo
848214501Srpaulo	if (sta->flags & WLAN_STA_WMM)
849214501Srpaulo		p = hostapd_eid_wmm(hapd, p);
850214501Srpaulo
851214501Srpaulo#ifdef CONFIG_WPS
852214501Srpaulo	if (sta->flags & WLAN_STA_WPS) {
853214501Srpaulo		struct wpabuf *wps = wps_build_assoc_resp_ie();
854214501Srpaulo		if (wps) {
855214501Srpaulo			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
856214501Srpaulo			p += wpabuf_len(wps);
857214501Srpaulo			wpabuf_free(wps);
858214501Srpaulo		}
859214501Srpaulo	}
860214501Srpaulo#endif /* CONFIG_WPS */
861214501Srpaulo
862214501Srpaulo	send_len += p - reply->u.assoc_resp.variable;
863214501Srpaulo
864214501Srpaulo	if (hapd->drv.send_mgmt_frame(hapd, reply, send_len) < 0)
865214501Srpaulo		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
866214501Srpaulo			   strerror(errno));
867214501Srpaulo}
868214501Srpaulo
869214501Srpaulo
870214501Srpaulostatic void handle_assoc(struct hostapd_data *hapd,
871214501Srpaulo			 const struct ieee80211_mgmt *mgmt, size_t len,
872214501Srpaulo			 int reassoc)
873214501Srpaulo{
874214501Srpaulo	u16 capab_info, listen_interval;
875214501Srpaulo	u16 resp = WLAN_STATUS_SUCCESS;
876214501Srpaulo	const u8 *pos;
877214501Srpaulo	int left, i;
878214501Srpaulo	struct sta_info *sta;
879214501Srpaulo
880214501Srpaulo	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
881214501Srpaulo				      sizeof(mgmt->u.assoc_req))) {
882214501Srpaulo		printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
883214501Srpaulo		       "\n", reassoc, (unsigned long) len);
884214501Srpaulo		return;
885214501Srpaulo	}
886214501Srpaulo
887214501Srpaulo	if (reassoc) {
888214501Srpaulo		capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
889214501Srpaulo		listen_interval = le_to_host16(
890214501Srpaulo			mgmt->u.reassoc_req.listen_interval);
891214501Srpaulo		wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
892214501Srpaulo			   " capab_info=0x%02x listen_interval=%d current_ap="
893214501Srpaulo			   MACSTR,
894214501Srpaulo			   MAC2STR(mgmt->sa), capab_info, listen_interval,
895214501Srpaulo			   MAC2STR(mgmt->u.reassoc_req.current_ap));
896214501Srpaulo		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
897214501Srpaulo		pos = mgmt->u.reassoc_req.variable;
898214501Srpaulo	} else {
899214501Srpaulo		capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
900214501Srpaulo		listen_interval = le_to_host16(
901214501Srpaulo			mgmt->u.assoc_req.listen_interval);
902214501Srpaulo		wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
903214501Srpaulo			   " capab_info=0x%02x listen_interval=%d",
904214501Srpaulo			   MAC2STR(mgmt->sa), capab_info, listen_interval);
905214501Srpaulo		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
906214501Srpaulo		pos = mgmt->u.assoc_req.variable;
907214501Srpaulo	}
908214501Srpaulo
909214501Srpaulo	sta = ap_get_sta(hapd, mgmt->sa);
910214501Srpaulo#ifdef CONFIG_IEEE80211R
911214501Srpaulo	if (sta && sta->auth_alg == WLAN_AUTH_FT &&
912214501Srpaulo	    (sta->flags & WLAN_STA_AUTH) == 0) {
913214501Srpaulo		wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
914214501Srpaulo			   "prior to authentication since it is using "
915214501Srpaulo			   "over-the-DS FT", MAC2STR(mgmt->sa));
916214501Srpaulo	} else
917214501Srpaulo#endif /* CONFIG_IEEE80211R */
918214501Srpaulo	if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
919214501Srpaulo		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
920214501Srpaulo			       HOSTAPD_LEVEL_INFO, "Station tried to "
921214501Srpaulo			       "associate before authentication "
922214501Srpaulo			       "(aid=%d flags=0x%x)",
923214501Srpaulo			       sta ? sta->aid : -1,
924214501Srpaulo			       sta ? sta->flags : 0);
925214501Srpaulo		send_deauth(hapd, mgmt->sa,
926214501Srpaulo			    WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
927214501Srpaulo		return;
928214501Srpaulo	}
929214501Srpaulo
930214501Srpaulo	if (hapd->tkip_countermeasures) {
931214501Srpaulo		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
932214501Srpaulo		goto fail;
933214501Srpaulo	}
934214501Srpaulo
935214501Srpaulo	if (listen_interval > hapd->conf->max_listen_interval) {
936214501Srpaulo		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
937214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
938214501Srpaulo			       "Too large Listen Interval (%d)",
939214501Srpaulo			       listen_interval);
940214501Srpaulo		resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
941214501Srpaulo		goto fail;
942214501Srpaulo	}
943214501Srpaulo
944214501Srpaulo	/* followed by SSID and Supported rates; and HT capabilities if 802.11n
945214501Srpaulo	 * is used */
946214501Srpaulo	resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
947214501Srpaulo	if (resp != WLAN_STATUS_SUCCESS)
948214501Srpaulo		goto fail;
949214501Srpaulo
950214501Srpaulo	if (hostapd_get_aid(hapd, sta) < 0) {
951214501Srpaulo		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
952214501Srpaulo			       HOSTAPD_LEVEL_INFO, "No room for more AIDs");
953214501Srpaulo		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
954214501Srpaulo		goto fail;
955214501Srpaulo	}
956214501Srpaulo
957214501Srpaulo	sta->capability = capab_info;
958214501Srpaulo	sta->listen_interval = listen_interval;
959214501Srpaulo
960214501Srpaulo	if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
961214501Srpaulo		sta->flags |= WLAN_STA_NONERP;
962214501Srpaulo	for (i = 0; i < sta->supported_rates_len; i++) {
963214501Srpaulo		if ((sta->supported_rates[i] & 0x7f) > 22) {
964214501Srpaulo			sta->flags &= ~WLAN_STA_NONERP;
965214501Srpaulo			break;
966214501Srpaulo		}
967214501Srpaulo	}
968214501Srpaulo	if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
969214501Srpaulo		sta->nonerp_set = 1;
970214501Srpaulo		hapd->iface->num_sta_non_erp++;
971214501Srpaulo		if (hapd->iface->num_sta_non_erp == 1)
972214501Srpaulo			ieee802_11_set_beacons(hapd->iface);
973214501Srpaulo	}
974214501Srpaulo
975214501Srpaulo	if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
976214501Srpaulo	    !sta->no_short_slot_time_set) {
977214501Srpaulo		sta->no_short_slot_time_set = 1;
978214501Srpaulo		hapd->iface->num_sta_no_short_slot_time++;
979214501Srpaulo		if (hapd->iface->current_mode->mode ==
980214501Srpaulo		    HOSTAPD_MODE_IEEE80211G &&
981214501Srpaulo		    hapd->iface->num_sta_no_short_slot_time == 1)
982214501Srpaulo			ieee802_11_set_beacons(hapd->iface);
983214501Srpaulo	}
984214501Srpaulo
985214501Srpaulo	if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
986214501Srpaulo		sta->flags |= WLAN_STA_SHORT_PREAMBLE;
987214501Srpaulo	else
988214501Srpaulo		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
989214501Srpaulo
990214501Srpaulo	if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
991214501Srpaulo	    !sta->no_short_preamble_set) {
992214501Srpaulo		sta->no_short_preamble_set = 1;
993214501Srpaulo		hapd->iface->num_sta_no_short_preamble++;
994214501Srpaulo		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
995214501Srpaulo		    && hapd->iface->num_sta_no_short_preamble == 1)
996214501Srpaulo			ieee802_11_set_beacons(hapd->iface);
997214501Srpaulo	}
998214501Srpaulo
999214501Srpaulo#ifdef CONFIG_IEEE80211N
1000214501Srpaulo	update_ht_state(hapd, sta);
1001214501Srpaulo#endif /* CONFIG_IEEE80211N */
1002214501Srpaulo
1003214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1004214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
1005214501Srpaulo		       "association OK (aid %d)", sta->aid);
1006214501Srpaulo	/* Station will be marked associated, after it acknowledges AssocResp
1007214501Srpaulo	 */
1008214501Srpaulo
1009214501Srpaulo#ifdef CONFIG_IEEE80211W
1010214501Srpaulo	if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
1011214501Srpaulo		wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
1012214501Srpaulo			   "SA Query procedure", reassoc ? "re" : "");
1013214501Srpaulo		/* TODO: Send a protected Disassociate frame to the STA using
1014214501Srpaulo		 * the old key and Reason Code "Previous Authentication no
1015214501Srpaulo		 * longer valid". Make sure this is only sent protected since
1016214501Srpaulo		 * unprotected frame would be received by the STA that is now
1017214501Srpaulo		 * trying to associate.
1018214501Srpaulo		 */
1019214501Srpaulo	}
1020214501Srpaulo#endif /* CONFIG_IEEE80211W */
1021214501Srpaulo
1022214501Srpaulo	if (reassoc) {
1023214501Srpaulo		os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
1024214501Srpaulo			  ETH_ALEN);
1025214501Srpaulo	}
1026214501Srpaulo
1027214501Srpaulo	if (sta->last_assoc_req)
1028214501Srpaulo		os_free(sta->last_assoc_req);
1029214501Srpaulo	sta->last_assoc_req = os_malloc(len);
1030214501Srpaulo	if (sta->last_assoc_req)
1031214501Srpaulo		os_memcpy(sta->last_assoc_req, mgmt, len);
1032214501Srpaulo
1033214501Srpaulo	/* Make sure that the previously registered inactivity timer will not
1034214501Srpaulo	 * remove the STA immediately. */
1035214501Srpaulo	sta->timeout_next = STA_NULLFUNC;
1036214501Srpaulo
1037214501Srpaulo fail:
1038214501Srpaulo	send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
1039214501Srpaulo}
1040214501Srpaulo
1041214501Srpaulo
1042214501Srpaulostatic void handle_disassoc(struct hostapd_data *hapd,
1043214501Srpaulo			    const struct ieee80211_mgmt *mgmt, size_t len)
1044214501Srpaulo{
1045214501Srpaulo	struct sta_info *sta;
1046214501Srpaulo
1047214501Srpaulo	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
1048214501Srpaulo		printf("handle_disassoc - too short payload (len=%lu)\n",
1049214501Srpaulo		       (unsigned long) len);
1050214501Srpaulo		return;
1051214501Srpaulo	}
1052214501Srpaulo
1053214501Srpaulo	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
1054214501Srpaulo		   MAC2STR(mgmt->sa),
1055214501Srpaulo		   le_to_host16(mgmt->u.disassoc.reason_code));
1056214501Srpaulo
1057214501Srpaulo	sta = ap_get_sta(hapd, mgmt->sa);
1058214501Srpaulo	if (sta == NULL) {
1059214501Srpaulo		printf("Station " MACSTR " trying to disassociate, but it "
1060214501Srpaulo		       "is not associated.\n", MAC2STR(mgmt->sa));
1061214501Srpaulo		return;
1062214501Srpaulo	}
1063214501Srpaulo
1064214501Srpaulo	sta->flags &= ~WLAN_STA_ASSOC;
1065214501Srpaulo	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
1066214501Srpaulo		MAC2STR(sta->addr));
1067214501Srpaulo	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
1068214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1069214501Srpaulo		       HOSTAPD_LEVEL_INFO, "disassociated");
1070214501Srpaulo	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
1071214501Srpaulo	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
1072214501Srpaulo	/* Stop Accounting and IEEE 802.1X sessions, but leave the STA
1073214501Srpaulo	 * authenticated. */
1074214501Srpaulo	accounting_sta_stop(hapd, sta);
1075214501Srpaulo	ieee802_1x_free_station(sta);
1076214501Srpaulo	hapd->drv.sta_remove(hapd, sta->addr);
1077214501Srpaulo
1078214501Srpaulo	if (sta->timeout_next == STA_NULLFUNC ||
1079214501Srpaulo	    sta->timeout_next == STA_DISASSOC) {
1080214501Srpaulo		sta->timeout_next = STA_DEAUTH;
1081214501Srpaulo		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
1082214501Srpaulo		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
1083214501Srpaulo				       hapd, sta);
1084214501Srpaulo	}
1085214501Srpaulo
1086214501Srpaulo	mlme_disassociate_indication(
1087214501Srpaulo		hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
1088214501Srpaulo}
1089214501Srpaulo
1090214501Srpaulo
1091214501Srpaulostatic void handle_deauth(struct hostapd_data *hapd,
1092214501Srpaulo			  const struct ieee80211_mgmt *mgmt, size_t len)
1093214501Srpaulo{
1094214501Srpaulo	struct sta_info *sta;
1095214501Srpaulo
1096214501Srpaulo	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
1097214501Srpaulo		printf("handle_deauth - too short payload (len=%lu)\n",
1098214501Srpaulo		       (unsigned long) len);
1099214501Srpaulo		return;
1100214501Srpaulo	}
1101214501Srpaulo
1102214501Srpaulo	wpa_printf(MSG_DEBUG, "deauthentication: STA=" MACSTR
1103214501Srpaulo		   " reason_code=%d",
1104214501Srpaulo		   MAC2STR(mgmt->sa),
1105214501Srpaulo		   le_to_host16(mgmt->u.deauth.reason_code));
1106214501Srpaulo
1107214501Srpaulo	sta = ap_get_sta(hapd, mgmt->sa);
1108214501Srpaulo	if (sta == NULL) {
1109214501Srpaulo		printf("Station " MACSTR " trying to deauthenticate, but it "
1110214501Srpaulo		       "is not authenticated.\n", MAC2STR(mgmt->sa));
1111214501Srpaulo		return;
1112214501Srpaulo	}
1113214501Srpaulo
1114214501Srpaulo	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
1115214501Srpaulo	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
1116214501Srpaulo		MAC2STR(sta->addr));
1117214501Srpaulo	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
1118214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1119214501Srpaulo		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
1120214501Srpaulo	mlme_deauthenticate_indication(
1121214501Srpaulo		hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
1122214501Srpaulo	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
1123214501Srpaulo	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
1124214501Srpaulo	ap_free_sta(hapd, sta);
1125214501Srpaulo}
1126214501Srpaulo
1127214501Srpaulo
1128214501Srpaulostatic void handle_beacon(struct hostapd_data *hapd,
1129214501Srpaulo			  const struct ieee80211_mgmt *mgmt, size_t len,
1130214501Srpaulo			  struct hostapd_frame_info *fi)
1131214501Srpaulo{
1132214501Srpaulo	struct ieee802_11_elems elems;
1133214501Srpaulo
1134214501Srpaulo	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
1135214501Srpaulo		printf("handle_beacon - too short payload (len=%lu)\n",
1136214501Srpaulo		       (unsigned long) len);
1137214501Srpaulo		return;
1138214501Srpaulo	}
1139214501Srpaulo
1140214501Srpaulo	(void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
1141214501Srpaulo				      len - (IEEE80211_HDRLEN +
1142214501Srpaulo					     sizeof(mgmt->u.beacon)), &elems,
1143214501Srpaulo				      0);
1144214501Srpaulo
1145214501Srpaulo	ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
1146214501Srpaulo}
1147214501Srpaulo
1148214501Srpaulo
1149214501Srpaulo#ifdef CONFIG_IEEE80211W
1150214501Srpaulo
1151214501Srpaulo/* MLME-SAQuery.request */
1152214501Srpaulovoid ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
1153214501Srpaulo				  const u8 *addr, const u8 *trans_id)
1154214501Srpaulo{
1155214501Srpaulo	struct ieee80211_mgmt mgmt;
1156214501Srpaulo	u8 *end;
1157214501Srpaulo
1158214501Srpaulo	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
1159214501Srpaulo		   MACSTR, MAC2STR(addr));
1160214501Srpaulo	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
1161214501Srpaulo		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
1162214501Srpaulo
1163214501Srpaulo	os_memset(&mgmt, 0, sizeof(mgmt));
1164214501Srpaulo	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
1165214501Srpaulo					  WLAN_FC_STYPE_ACTION);
1166214501Srpaulo	os_memcpy(mgmt.da, addr, ETH_ALEN);
1167214501Srpaulo	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
1168214501Srpaulo	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
1169214501Srpaulo	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
1170214501Srpaulo	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
1171214501Srpaulo	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
1172214501Srpaulo		  WLAN_SA_QUERY_TR_ID_LEN);
1173214501Srpaulo	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
1174214501Srpaulo	if (hapd->drv.send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt) < 0)
1175214501Srpaulo		perror("ieee802_11_send_sa_query_req: send");
1176214501Srpaulo}
1177214501Srpaulo
1178214501Srpaulo
1179214501Srpaulostatic void hostapd_sa_query_request(struct hostapd_data *hapd,
1180214501Srpaulo				     const struct ieee80211_mgmt *mgmt)
1181214501Srpaulo{
1182214501Srpaulo	struct sta_info *sta;
1183214501Srpaulo	struct ieee80211_mgmt resp;
1184214501Srpaulo	u8 *end;
1185214501Srpaulo
1186214501Srpaulo	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
1187214501Srpaulo		   MACSTR, MAC2STR(mgmt->sa));
1188214501Srpaulo	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
1189214501Srpaulo		    mgmt->u.action.u.sa_query_resp.trans_id,
1190214501Srpaulo		    WLAN_SA_QUERY_TR_ID_LEN);
1191214501Srpaulo
1192214501Srpaulo	sta = ap_get_sta(hapd, mgmt->sa);
1193214501Srpaulo	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
1194214501Srpaulo		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
1195214501Srpaulo			   "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
1196214501Srpaulo		return;
1197214501Srpaulo	}
1198214501Srpaulo
1199214501Srpaulo	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
1200214501Srpaulo		   MACSTR, MAC2STR(mgmt->sa));
1201214501Srpaulo
1202214501Srpaulo	os_memset(&resp, 0, sizeof(resp));
1203214501Srpaulo	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
1204214501Srpaulo					  WLAN_FC_STYPE_ACTION);
1205214501Srpaulo	os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
1206214501Srpaulo	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
1207214501Srpaulo	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
1208214501Srpaulo	resp.u.action.category = WLAN_ACTION_SA_QUERY;
1209214501Srpaulo	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
1210214501Srpaulo	os_memcpy(resp.u.action.u.sa_query_req.trans_id,
1211214501Srpaulo		  mgmt->u.action.u.sa_query_req.trans_id,
1212214501Srpaulo		  WLAN_SA_QUERY_TR_ID_LEN);
1213214501Srpaulo	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
1214214501Srpaulo	if (hapd->drv.send_mgmt_frame(hapd, &resp, end - (u8 *) &resp) < 0)
1215214501Srpaulo		perror("hostapd_sa_query_request: send");
1216214501Srpaulo}
1217214501Srpaulo
1218214501Srpaulo
1219214501Srpaulostatic void hostapd_sa_query_action(struct hostapd_data *hapd,
1220214501Srpaulo				    const struct ieee80211_mgmt *mgmt,
1221214501Srpaulo				    size_t len)
1222214501Srpaulo{
1223214501Srpaulo	struct sta_info *sta;
1224214501Srpaulo	const u8 *end;
1225214501Srpaulo	int i;
1226214501Srpaulo
1227214501Srpaulo	end = mgmt->u.action.u.sa_query_resp.trans_id +
1228214501Srpaulo		WLAN_SA_QUERY_TR_ID_LEN;
1229214501Srpaulo	if (((u8 *) mgmt) + len < end) {
1230214501Srpaulo		wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
1231214501Srpaulo			   "frame (len=%lu)", (unsigned long) len);
1232214501Srpaulo		return;
1233214501Srpaulo	}
1234214501Srpaulo
1235214501Srpaulo	if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
1236214501Srpaulo		hostapd_sa_query_request(hapd, mgmt);
1237214501Srpaulo		return;
1238214501Srpaulo	}
1239214501Srpaulo
1240214501Srpaulo	if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
1241214501Srpaulo		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
1242214501Srpaulo			   "Action %d", mgmt->u.action.u.sa_query_resp.action);
1243214501Srpaulo		return;
1244214501Srpaulo	}
1245214501Srpaulo
1246214501Srpaulo	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
1247214501Srpaulo		   MACSTR, MAC2STR(mgmt->sa));
1248214501Srpaulo	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
1249214501Srpaulo		    mgmt->u.action.u.sa_query_resp.trans_id,
1250214501Srpaulo		    WLAN_SA_QUERY_TR_ID_LEN);
1251214501Srpaulo
1252214501Srpaulo	/* MLME-SAQuery.confirm */
1253214501Srpaulo
1254214501Srpaulo	sta = ap_get_sta(hapd, mgmt->sa);
1255214501Srpaulo	if (sta == NULL || sta->sa_query_trans_id == NULL) {
1256214501Srpaulo		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
1257214501Srpaulo			   "pending SA Query request found");
1258214501Srpaulo		return;
1259214501Srpaulo	}
1260214501Srpaulo
1261214501Srpaulo	for (i = 0; i < sta->sa_query_count; i++) {
1262214501Srpaulo		if (os_memcmp(sta->sa_query_trans_id +
1263214501Srpaulo			      i * WLAN_SA_QUERY_TR_ID_LEN,
1264214501Srpaulo			      mgmt->u.action.u.sa_query_resp.trans_id,
1265214501Srpaulo			      WLAN_SA_QUERY_TR_ID_LEN) == 0)
1266214501Srpaulo			break;
1267214501Srpaulo	}
1268214501Srpaulo
1269214501Srpaulo	if (i >= sta->sa_query_count) {
1270214501Srpaulo		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
1271214501Srpaulo			   "transaction identifier found");
1272214501Srpaulo		return;
1273214501Srpaulo	}
1274214501Srpaulo
1275214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1276214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
1277214501Srpaulo		       "Reply to pending SA Query received");
1278214501Srpaulo	ap_sta_stop_sa_query(hapd, sta);
1279214501Srpaulo}
1280214501Srpaulo
1281214501Srpaulo
1282214501Srpaulostatic int robust_action_frame(u8 category)
1283214501Srpaulo{
1284214501Srpaulo	return category != WLAN_ACTION_PUBLIC &&
1285214501Srpaulo		category != WLAN_ACTION_HT;
1286214501Srpaulo}
1287214501Srpaulo#endif /* CONFIG_IEEE80211W */
1288214501Srpaulo
1289214501Srpaulo
1290214501Srpaulostatic void handle_action(struct hostapd_data *hapd,
1291214501Srpaulo			  const struct ieee80211_mgmt *mgmt, size_t len)
1292214501Srpaulo{
1293214501Srpaulo	struct sta_info *sta;
1294214501Srpaulo
1295214501Srpaulo	if (len < IEEE80211_HDRLEN + 1) {
1296214501Srpaulo		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
1297214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
1298214501Srpaulo			       "handle_action - too short payload (len=%lu)",
1299214501Srpaulo			       (unsigned long) len);
1300214501Srpaulo		return;
1301214501Srpaulo	}
1302214501Srpaulo
1303214501Srpaulo	sta = ap_get_sta(hapd, mgmt->sa);
1304214501Srpaulo#ifdef CONFIG_IEEE80211W
1305214501Srpaulo	if (sta && (sta->flags & WLAN_STA_MFP) &&
1306214501Srpaulo	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
1307214501Srpaulo	      robust_action_frame(mgmt->u.action.category))) {
1308214501Srpaulo		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
1309214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
1310214501Srpaulo			       "Dropped unprotected Robust Action frame from "
1311214501Srpaulo			       "an MFP STA");
1312214501Srpaulo		return;
1313214501Srpaulo	}
1314214501Srpaulo#endif /* CONFIG_IEEE80211W */
1315214501Srpaulo
1316214501Srpaulo	switch (mgmt->u.action.category) {
1317214501Srpaulo#ifdef CONFIG_IEEE80211R
1318214501Srpaulo	case WLAN_ACTION_FT:
1319214501Srpaulo	{
1320214501Srpaulo		if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
1321214501Srpaulo			wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
1322214501Srpaulo				   "frame from unassociated STA " MACSTR,
1323214501Srpaulo				   MAC2STR(mgmt->sa));
1324214501Srpaulo			return;
1325214501Srpaulo		}
1326214501Srpaulo
1327214501Srpaulo		if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
1328214501Srpaulo				     len - IEEE80211_HDRLEN))
1329214501Srpaulo			break;
1330214501Srpaulo
1331214501Srpaulo		return;
1332214501Srpaulo	}
1333214501Srpaulo#endif /* CONFIG_IEEE80211R */
1334214501Srpaulo	case WLAN_ACTION_WMM:
1335214501Srpaulo		hostapd_wmm_action(hapd, mgmt, len);
1336214501Srpaulo		return;
1337214501Srpaulo#ifdef CONFIG_IEEE80211W
1338214501Srpaulo	case WLAN_ACTION_SA_QUERY:
1339214501Srpaulo		hostapd_sa_query_action(hapd, mgmt, len);
1340214501Srpaulo		return;
1341214501Srpaulo#endif /* CONFIG_IEEE80211W */
1342214501Srpaulo	case WLAN_ACTION_PUBLIC:
1343214501Srpaulo		if (hapd->public_action_cb) {
1344214501Srpaulo			hapd->public_action_cb(hapd->public_action_cb_ctx,
1345214501Srpaulo					       (u8 *) mgmt, len,
1346214501Srpaulo					       hapd->iface->freq);
1347214501Srpaulo			return;
1348214501Srpaulo		}
1349214501Srpaulo		break;
1350214501Srpaulo	}
1351214501Srpaulo
1352214501Srpaulo	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
1353214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
1354214501Srpaulo		       "handle_action - unknown action category %d or invalid "
1355214501Srpaulo		       "frame",
1356214501Srpaulo		       mgmt->u.action.category);
1357214501Srpaulo	if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
1358214501Srpaulo	    !(mgmt->sa[0] & 0x01)) {
1359214501Srpaulo		struct ieee80211_mgmt *resp;
1360214501Srpaulo
1361214501Srpaulo		/*
1362214501Srpaulo		 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
1363214501Srpaulo		 * Return the Action frame to the source without change
1364214501Srpaulo		 * except that MSB of the Category set to 1.
1365214501Srpaulo		 */
1366214501Srpaulo		wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
1367214501Srpaulo			   "frame back to sender");
1368214501Srpaulo		resp = os_malloc(len);
1369214501Srpaulo		if (resp == NULL)
1370214501Srpaulo			return;
1371214501Srpaulo		os_memcpy(resp, mgmt, len);
1372214501Srpaulo		os_memcpy(resp->da, resp->sa, ETH_ALEN);
1373214501Srpaulo		os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
1374214501Srpaulo		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
1375214501Srpaulo		resp->u.action.category |= 0x80;
1376214501Srpaulo
1377214501Srpaulo		hapd->drv.send_mgmt_frame(hapd, resp, len);
1378214501Srpaulo		os_free(resp);
1379214501Srpaulo	}
1380214501Srpaulo}
1381214501Srpaulo
1382214501Srpaulo
1383214501Srpaulo/**
1384214501Srpaulo * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
1385214501Srpaulo * @hapd: hostapd BSS data structure (the BSS to which the management frame was
1386214501Srpaulo * sent to)
1387214501Srpaulo * @buf: management frame data (starting from IEEE 802.11 header)
1388214501Srpaulo * @len: length of frame data in octets
1389214501Srpaulo * @fi: meta data about received frame (signal level, etc.)
1390214501Srpaulo *
1391214501Srpaulo * Process all incoming IEEE 802.11 management frames. This will be called for
1392214501Srpaulo * each frame received from the kernel driver through wlan#ap interface. In
1393214501Srpaulo * addition, it can be called to re-inserted pending frames (e.g., when using
1394214501Srpaulo * external RADIUS server as an MAC ACL).
1395214501Srpaulo */
1396214501Srpaulovoid ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
1397214501Srpaulo		     struct hostapd_frame_info *fi)
1398214501Srpaulo{
1399214501Srpaulo	struct ieee80211_mgmt *mgmt;
1400214501Srpaulo	int broadcast;
1401214501Srpaulo	u16 fc, stype;
1402214501Srpaulo
1403214501Srpaulo	mgmt = (struct ieee80211_mgmt *) buf;
1404214501Srpaulo	fc = le_to_host16(mgmt->frame_control);
1405214501Srpaulo	stype = WLAN_FC_GET_STYPE(fc);
1406214501Srpaulo
1407214501Srpaulo	if (stype == WLAN_FC_STYPE_BEACON) {
1408214501Srpaulo		handle_beacon(hapd, mgmt, len, fi);
1409214501Srpaulo		return;
1410214501Srpaulo	}
1411214501Srpaulo
1412214501Srpaulo	broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
1413214501Srpaulo		mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
1414214501Srpaulo		mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
1415214501Srpaulo
1416214501Srpaulo	if (!broadcast &&
1417214501Srpaulo	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
1418214501Srpaulo		printf("MGMT: BSSID=" MACSTR " not our address\n",
1419214501Srpaulo		       MAC2STR(mgmt->bssid));
1420214501Srpaulo		return;
1421214501Srpaulo	}
1422214501Srpaulo
1423214501Srpaulo
1424214501Srpaulo	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
1425214501Srpaulo		handle_probe_req(hapd, mgmt, len);
1426214501Srpaulo		return;
1427214501Srpaulo	}
1428214501Srpaulo
1429214501Srpaulo	if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
1430214501Srpaulo		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
1431214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
1432214501Srpaulo			       "MGMT: DA=" MACSTR " not our address",
1433214501Srpaulo			       MAC2STR(mgmt->da));
1434214501Srpaulo		return;
1435214501Srpaulo	}
1436214501Srpaulo
1437214501Srpaulo	switch (stype) {
1438214501Srpaulo	case WLAN_FC_STYPE_AUTH:
1439214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::auth");
1440214501Srpaulo		handle_auth(hapd, mgmt, len);
1441214501Srpaulo		break;
1442214501Srpaulo	case WLAN_FC_STYPE_ASSOC_REQ:
1443214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
1444214501Srpaulo		handle_assoc(hapd, mgmt, len, 0);
1445214501Srpaulo		break;
1446214501Srpaulo	case WLAN_FC_STYPE_REASSOC_REQ:
1447214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
1448214501Srpaulo		handle_assoc(hapd, mgmt, len, 1);
1449214501Srpaulo		break;
1450214501Srpaulo	case WLAN_FC_STYPE_DISASSOC:
1451214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::disassoc");
1452214501Srpaulo		handle_disassoc(hapd, mgmt, len);
1453214501Srpaulo		break;
1454214501Srpaulo	case WLAN_FC_STYPE_DEAUTH:
1455214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::deauth");
1456214501Srpaulo		handle_deauth(hapd, mgmt, len);
1457214501Srpaulo		break;
1458214501Srpaulo	case WLAN_FC_STYPE_ACTION:
1459214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::action");
1460214501Srpaulo		handle_action(hapd, mgmt, len);
1461214501Srpaulo		break;
1462214501Srpaulo	default:
1463214501Srpaulo		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
1464214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
1465214501Srpaulo			       "unknown mgmt frame subtype %d", stype);
1466214501Srpaulo		break;
1467214501Srpaulo	}
1468214501Srpaulo}
1469214501Srpaulo
1470214501Srpaulo
1471214501Srpaulostatic void handle_auth_cb(struct hostapd_data *hapd,
1472214501Srpaulo			   const struct ieee80211_mgmt *mgmt,
1473214501Srpaulo			   size_t len, int ok)
1474214501Srpaulo{
1475214501Srpaulo	u16 auth_alg, auth_transaction, status_code;
1476214501Srpaulo	struct sta_info *sta;
1477214501Srpaulo
1478214501Srpaulo	if (!ok) {
1479214501Srpaulo		hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
1480214501Srpaulo			       HOSTAPD_LEVEL_NOTICE,
1481214501Srpaulo			       "did not acknowledge authentication response");
1482214501Srpaulo		return;
1483214501Srpaulo	}
1484214501Srpaulo
1485214501Srpaulo	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
1486214501Srpaulo		printf("handle_auth_cb - too short payload (len=%lu)\n",
1487214501Srpaulo		       (unsigned long) len);
1488214501Srpaulo		return;
1489214501Srpaulo	}
1490214501Srpaulo
1491214501Srpaulo	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
1492214501Srpaulo	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
1493214501Srpaulo	status_code = le_to_host16(mgmt->u.auth.status_code);
1494214501Srpaulo
1495214501Srpaulo	sta = ap_get_sta(hapd, mgmt->da);
1496214501Srpaulo	if (!sta) {
1497214501Srpaulo		printf("handle_auth_cb: STA " MACSTR " not found\n",
1498214501Srpaulo		       MAC2STR(mgmt->da));
1499214501Srpaulo		return;
1500214501Srpaulo	}
1501214501Srpaulo
1502214501Srpaulo	if (status_code == WLAN_STATUS_SUCCESS &&
1503214501Srpaulo	    ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
1504214501Srpaulo	     (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
1505214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1506214501Srpaulo			       HOSTAPD_LEVEL_INFO, "authenticated");
1507214501Srpaulo		sta->flags |= WLAN_STA_AUTH;
1508214501Srpaulo	}
1509214501Srpaulo}
1510214501Srpaulo
1511214501Srpaulo
1512214501Srpaulostatic void handle_assoc_cb(struct hostapd_data *hapd,
1513214501Srpaulo			    const struct ieee80211_mgmt *mgmt,
1514214501Srpaulo			    size_t len, int reassoc, int ok)
1515214501Srpaulo{
1516214501Srpaulo	u16 status;
1517214501Srpaulo	struct sta_info *sta;
1518214501Srpaulo	int new_assoc = 1;
1519214501Srpaulo	struct ieee80211_ht_capabilities ht_cap;
1520214501Srpaulo
1521214501Srpaulo	if (!ok) {
1522214501Srpaulo		hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
1523214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
1524214501Srpaulo			       "did not acknowledge association response");
1525214501Srpaulo		return;
1526214501Srpaulo	}
1527214501Srpaulo
1528214501Srpaulo	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
1529214501Srpaulo				      sizeof(mgmt->u.assoc_resp))) {
1530214501Srpaulo		printf("handle_assoc_cb(reassoc=%d) - too short payload "
1531214501Srpaulo		       "(len=%lu)\n", reassoc, (unsigned long) len);
1532214501Srpaulo		return;
1533214501Srpaulo	}
1534214501Srpaulo
1535214501Srpaulo	if (reassoc)
1536214501Srpaulo		status = le_to_host16(mgmt->u.reassoc_resp.status_code);
1537214501Srpaulo	else
1538214501Srpaulo		status = le_to_host16(mgmt->u.assoc_resp.status_code);
1539214501Srpaulo
1540214501Srpaulo	sta = ap_get_sta(hapd, mgmt->da);
1541214501Srpaulo	if (!sta) {
1542214501Srpaulo		printf("handle_assoc_cb: STA " MACSTR " not found\n",
1543214501Srpaulo		       MAC2STR(mgmt->da));
1544214501Srpaulo		return;
1545214501Srpaulo	}
1546214501Srpaulo
1547214501Srpaulo	if (status != WLAN_STATUS_SUCCESS)
1548214501Srpaulo		goto fail;
1549214501Srpaulo
1550214501Srpaulo	/* Stop previous accounting session, if one is started, and allocate
1551214501Srpaulo	 * new session id for the new session. */
1552214501Srpaulo	accounting_sta_stop(hapd, sta);
1553214501Srpaulo
1554214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1555214501Srpaulo		       HOSTAPD_LEVEL_INFO,
1556214501Srpaulo		       "associated (aid %d)",
1557214501Srpaulo		       sta->aid);
1558214501Srpaulo
1559214501Srpaulo	if (sta->flags & WLAN_STA_ASSOC)
1560214501Srpaulo		new_assoc = 0;
1561214501Srpaulo	sta->flags |= WLAN_STA_ASSOC;
1562214501Srpaulo	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
1563214501Srpaulo	    sta->auth_alg == WLAN_AUTH_FT) {
1564214501Srpaulo		/*
1565214501Srpaulo		 * Open, static WEP, or FT protocol; no separate authorization
1566214501Srpaulo		 * step.
1567214501Srpaulo		 */
1568214501Srpaulo		sta->flags |= WLAN_STA_AUTHORIZED;
1569214501Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO,
1570214501Srpaulo			AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
1571214501Srpaulo	}
1572214501Srpaulo
1573214501Srpaulo	if (reassoc)
1574214501Srpaulo		mlme_reassociate_indication(hapd, sta);
1575214501Srpaulo	else
1576214501Srpaulo		mlme_associate_indication(hapd, sta);
1577214501Srpaulo
1578214501Srpaulo#ifdef CONFIG_IEEE80211W
1579214501Srpaulo	sta->sa_query_timed_out = 0;
1580214501Srpaulo#endif /* CONFIG_IEEE80211W */
1581214501Srpaulo
1582214501Srpaulo	/*
1583214501Srpaulo	 * Remove the STA entry in order to make sure the STA PS state gets
1584214501Srpaulo	 * cleared and configuration gets updated in case of reassociation back
1585214501Srpaulo	 * to the same AP.
1586214501Srpaulo	 */
1587214501Srpaulo	hapd->drv.sta_remove(hapd, sta->addr);
1588214501Srpaulo
1589214501Srpaulo#ifdef CONFIG_IEEE80211N
1590214501Srpaulo	if (sta->flags & WLAN_STA_HT)
1591214501Srpaulo		hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
1592214501Srpaulo#endif /* CONFIG_IEEE80211N */
1593214501Srpaulo
1594214501Srpaulo	if (hapd->drv.sta_add(hapd, sta->addr, sta->aid, sta->capability,
1595214501Srpaulo			      sta->supported_rates, sta->supported_rates_len,
1596214501Srpaulo			      sta->listen_interval,
1597214501Srpaulo			      sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) {
1598214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1599214501Srpaulo			       HOSTAPD_LEVEL_NOTICE,
1600214501Srpaulo			       "Could not add STA to kernel driver");
1601214501Srpaulo	}
1602214501Srpaulo
1603214501Srpaulo	if (sta->eapol_sm == NULL) {
1604214501Srpaulo		/*
1605214501Srpaulo		 * This STA does not use RADIUS server for EAP authentication,
1606214501Srpaulo		 * so bind it to the selected VLAN interface now, since the
1607214501Srpaulo		 * interface selection is not going to change anymore.
1608214501Srpaulo		 */
1609214501Srpaulo		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
1610214501Srpaulo			goto fail;
1611214501Srpaulo	} else if (sta->vlan_id) {
1612214501Srpaulo		/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
1613214501Srpaulo		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
1614214501Srpaulo			goto fail;
1615214501Srpaulo	}
1616214501Srpaulo
1617214501Srpaulo	hapd->drv.set_sta_flags(hapd, sta);
1618214501Srpaulo
1619214501Srpaulo	if (sta->auth_alg == WLAN_AUTH_FT)
1620214501Srpaulo		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
1621214501Srpaulo	else
1622214501Srpaulo		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
1623214501Srpaulo	hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
1624214501Srpaulo
1625214501Srpaulo	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
1626214501Srpaulo
1627214501Srpaulo fail:
1628214501Srpaulo	/* Copy of the association request is not needed anymore */
1629214501Srpaulo	if (sta->last_assoc_req) {
1630214501Srpaulo		os_free(sta->last_assoc_req);
1631214501Srpaulo		sta->last_assoc_req = NULL;
1632214501Srpaulo	}
1633214501Srpaulo}
1634214501Srpaulo
1635214501Srpaulo
1636214501Srpaulo/**
1637214501Srpaulo * ieee802_11_mgmt_cb - Process management frame TX status callback
1638214501Srpaulo * @hapd: hostapd BSS data structure (the BSS from which the management frame
1639214501Srpaulo * was sent from)
1640214501Srpaulo * @buf: management frame data (starting from IEEE 802.11 header)
1641214501Srpaulo * @len: length of frame data in octets
1642214501Srpaulo * @stype: management frame subtype from frame control field
1643214501Srpaulo * @ok: Whether the frame was ACK'ed
1644214501Srpaulo */
1645214501Srpaulovoid ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
1646214501Srpaulo			u16 stype, int ok)
1647214501Srpaulo{
1648214501Srpaulo	const struct ieee80211_mgmt *mgmt;
1649214501Srpaulo	mgmt = (const struct ieee80211_mgmt *) buf;
1650214501Srpaulo
1651214501Srpaulo	switch (stype) {
1652214501Srpaulo	case WLAN_FC_STYPE_AUTH:
1653214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::auth cb");
1654214501Srpaulo		handle_auth_cb(hapd, mgmt, len, ok);
1655214501Srpaulo		break;
1656214501Srpaulo	case WLAN_FC_STYPE_ASSOC_RESP:
1657214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
1658214501Srpaulo		handle_assoc_cb(hapd, mgmt, len, 0, ok);
1659214501Srpaulo		break;
1660214501Srpaulo	case WLAN_FC_STYPE_REASSOC_RESP:
1661214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
1662214501Srpaulo		handle_assoc_cb(hapd, mgmt, len, 1, ok);
1663214501Srpaulo		break;
1664214501Srpaulo	case WLAN_FC_STYPE_PROBE_RESP:
1665214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::proberesp cb");
1666214501Srpaulo		break;
1667214501Srpaulo	case WLAN_FC_STYPE_DEAUTH:
1668214501Srpaulo		/* ignore */
1669214501Srpaulo		break;
1670214501Srpaulo	case WLAN_FC_STYPE_ACTION:
1671214501Srpaulo		wpa_printf(MSG_DEBUG, "mgmt::action cb");
1672214501Srpaulo		break;
1673214501Srpaulo	default:
1674214501Srpaulo		printf("unknown mgmt cb frame subtype %d\n", stype);
1675214501Srpaulo		break;
1676214501Srpaulo	}
1677214501Srpaulo}
1678214501Srpaulo
1679214501Srpaulo
1680214501Srpauloint ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
1681214501Srpaulo{
1682214501Srpaulo	/* TODO */
1683214501Srpaulo	return 0;
1684214501Srpaulo}
1685214501Srpaulo
1686214501Srpaulo
1687214501Srpauloint ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
1688214501Srpaulo			   char *buf, size_t buflen)
1689214501Srpaulo{
1690214501Srpaulo	/* TODO */
1691214501Srpaulo	return 0;
1692214501Srpaulo}
1693214501Srpaulo
1694214501Srpaulo
1695214501Srpaulovoid hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
1696214501Srpaulo		       const u8 *buf, size_t len, int ack)
1697214501Srpaulo{
1698214501Srpaulo	struct sta_info *sta;
1699214501Srpaulo	struct hostapd_iface *iface = hapd->iface;
1700214501Srpaulo
1701214501Srpaulo	sta = ap_get_sta(hapd, addr);
1702214501Srpaulo	if (sta == NULL && iface->num_bss > 1) {
1703214501Srpaulo		size_t j;
1704214501Srpaulo		for (j = 0; j < iface->num_bss; j++) {
1705214501Srpaulo			hapd = iface->bss[j];
1706214501Srpaulo			sta = ap_get_sta(hapd, addr);
1707214501Srpaulo			if (sta)
1708214501Srpaulo				break;
1709214501Srpaulo		}
1710214501Srpaulo	}
1711214501Srpaulo	if (sta == NULL)
1712214501Srpaulo		return;
1713214501Srpaulo	if (sta->flags & WLAN_STA_PENDING_POLL) {
1714214501Srpaulo		wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
1715214501Srpaulo			   "activity poll", MAC2STR(sta->addr),
1716214501Srpaulo			   ack ? "ACKed" : "did not ACK");
1717214501Srpaulo		if (ack)
1718214501Srpaulo			sta->flags &= ~WLAN_STA_PENDING_POLL;
1719214501Srpaulo	}
1720214501Srpaulo
1721214501Srpaulo	ieee802_1x_tx_status(hapd, sta, buf, len, ack);
1722214501Srpaulo}
1723214501Srpaulo
1724214501Srpaulo
1725214501Srpaulovoid ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
1726214501Srpaulo				int wds)
1727214501Srpaulo{
1728214501Srpaulo	struct sta_info *sta;
1729214501Srpaulo
1730214501Srpaulo	sta = ap_get_sta(hapd, src);
1731214501Srpaulo	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
1732214501Srpaulo		if (wds && !(sta->flags & WLAN_STA_WDS)) {
1733214501Srpaulo			wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
1734214501Srpaulo				   "STA " MACSTR " (aid %u)",
1735214501Srpaulo				   MAC2STR(sta->addr), sta->aid);
1736214501Srpaulo			sta->flags |= WLAN_STA_WDS;
1737214501Srpaulo			hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 1);
1738214501Srpaulo		}
1739214501Srpaulo		return;
1740214501Srpaulo	}
1741214501Srpaulo
1742214501Srpaulo	wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
1743214501Srpaulo		   MACSTR, MAC2STR(src));
1744214501Srpaulo	if (sta && (sta->flags & WLAN_STA_AUTH))
1745214501Srpaulo		hapd->drv.sta_disassoc(
1746214501Srpaulo			hapd, src,
1747214501Srpaulo			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
1748214501Srpaulo	else
1749214501Srpaulo		hapd->drv.sta_deauth(
1750214501Srpaulo			hapd, src,
1751214501Srpaulo			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
1752214501Srpaulo}
1753214501Srpaulo
1754214501Srpaulo
1755214501Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */
1756