1214501Srpaulo/*
2214501Srpaulo * hostapd / Station table
3281806Srpaulo * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "utils/includes.h"
10214501Srpaulo
11214501Srpaulo#include "utils/common.h"
12214501Srpaulo#include "utils/eloop.h"
13214501Srpaulo#include "common/ieee802_11_defs.h"
14252726Srpaulo#include "common/wpa_ctrl.h"
15281806Srpaulo#include "common/sae.h"
16214501Srpaulo#include "radius/radius.h"
17214501Srpaulo#include "radius/radius_client.h"
18252726Srpaulo#include "p2p/p2p.h"
19289549Srpaulo#include "fst/fst.h"
20214501Srpaulo#include "hostapd.h"
21214501Srpaulo#include "accounting.h"
22214501Srpaulo#include "ieee802_1x.h"
23214501Srpaulo#include "ieee802_11.h"
24252726Srpaulo#include "ieee802_11_auth.h"
25214501Srpaulo#include "wpa_auth.h"
26214501Srpaulo#include "preauth_auth.h"
27214501Srpaulo#include "ap_config.h"
28214501Srpaulo#include "beacon.h"
29214501Srpaulo#include "ap_mlme.h"
30214501Srpaulo#include "vlan_init.h"
31252726Srpaulo#include "p2p_hostapd.h"
32252726Srpaulo#include "ap_drv_ops.h"
33252726Srpaulo#include "gas_serv.h"
34281806Srpaulo#include "wnm_ap.h"
35281806Srpaulo#include "ndisc_snoop.h"
36214501Srpaulo#include "sta_info.h"
37214501Srpaulo
38214501Srpaulostatic void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
39214501Srpaulo				       struct sta_info *sta);
40214501Srpaulostatic void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
41281806Srpaulostatic void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
42252726Srpaulostatic void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
43252726Srpaulostatic void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
44214501Srpaulo#ifdef CONFIG_IEEE80211W
45214501Srpaulostatic void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
46214501Srpaulo#endif /* CONFIG_IEEE80211W */
47252726Srpaulostatic int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
48214501Srpaulo
49214501Srpauloint ap_for_each_sta(struct hostapd_data *hapd,
50214501Srpaulo		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
51214501Srpaulo			      void *ctx),
52214501Srpaulo		    void *ctx)
53214501Srpaulo{
54214501Srpaulo	struct sta_info *sta;
55214501Srpaulo
56214501Srpaulo	for (sta = hapd->sta_list; sta; sta = sta->next) {
57214501Srpaulo		if (cb(hapd, sta, ctx))
58214501Srpaulo			return 1;
59214501Srpaulo	}
60214501Srpaulo
61214501Srpaulo	return 0;
62214501Srpaulo}
63214501Srpaulo
64214501Srpaulo
65214501Srpaulostruct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
66214501Srpaulo{
67214501Srpaulo	struct sta_info *s;
68214501Srpaulo
69214501Srpaulo	s = hapd->sta_hash[STA_HASH(sta)];
70214501Srpaulo	while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
71214501Srpaulo		s = s->hnext;
72214501Srpaulo	return s;
73214501Srpaulo}
74214501Srpaulo
75214501Srpaulo
76281806Srpaulo#ifdef CONFIG_P2P
77281806Srpaulostruct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
78281806Srpaulo{
79281806Srpaulo	struct sta_info *sta;
80281806Srpaulo
81281806Srpaulo	for (sta = hapd->sta_list; sta; sta = sta->next) {
82281806Srpaulo		const u8 *p2p_dev_addr;
83281806Srpaulo
84281806Srpaulo		if (sta->p2p_ie == NULL)
85281806Srpaulo			continue;
86281806Srpaulo
87281806Srpaulo		p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
88281806Srpaulo		if (p2p_dev_addr == NULL)
89281806Srpaulo			continue;
90281806Srpaulo
91281806Srpaulo		if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
92281806Srpaulo			return sta;
93281806Srpaulo	}
94281806Srpaulo
95281806Srpaulo	return NULL;
96281806Srpaulo}
97281806Srpaulo#endif /* CONFIG_P2P */
98281806Srpaulo
99281806Srpaulo
100214501Srpaulostatic void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
101214501Srpaulo{
102214501Srpaulo	struct sta_info *tmp;
103214501Srpaulo
104214501Srpaulo	if (hapd->sta_list == sta) {
105214501Srpaulo		hapd->sta_list = sta->next;
106214501Srpaulo		return;
107214501Srpaulo	}
108214501Srpaulo
109214501Srpaulo	tmp = hapd->sta_list;
110214501Srpaulo	while (tmp != NULL && tmp->next != sta)
111214501Srpaulo		tmp = tmp->next;
112214501Srpaulo	if (tmp == NULL) {
113214501Srpaulo		wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
114214501Srpaulo			   "list.", MAC2STR(sta->addr));
115214501Srpaulo	} else
116214501Srpaulo		tmp->next = sta->next;
117214501Srpaulo}
118214501Srpaulo
119214501Srpaulo
120214501Srpaulovoid ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
121214501Srpaulo{
122214501Srpaulo	sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
123214501Srpaulo	hapd->sta_hash[STA_HASH(sta->addr)] = sta;
124214501Srpaulo}
125214501Srpaulo
126214501Srpaulo
127214501Srpaulostatic void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
128214501Srpaulo{
129214501Srpaulo	struct sta_info *s;
130214501Srpaulo
131214501Srpaulo	s = hapd->sta_hash[STA_HASH(sta->addr)];
132214501Srpaulo	if (s == NULL) return;
133214501Srpaulo	if (os_memcmp(s->addr, sta->addr, 6) == 0) {
134214501Srpaulo		hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
135214501Srpaulo		return;
136214501Srpaulo	}
137214501Srpaulo
138214501Srpaulo	while (s->hnext != NULL &&
139214501Srpaulo	       os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
140214501Srpaulo		s = s->hnext;
141214501Srpaulo	if (s->hnext != NULL)
142214501Srpaulo		s->hnext = s->hnext->hnext;
143214501Srpaulo	else
144214501Srpaulo		wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
145214501Srpaulo			   " from hash table", MAC2STR(sta->addr));
146214501Srpaulo}
147214501Srpaulo
148214501Srpaulo
149281806Srpaulovoid ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
150281806Srpaulo{
151281806Srpaulo	sta_ip6addr_del(hapd, sta);
152281806Srpaulo}
153281806Srpaulo
154281806Srpaulo
155214501Srpaulovoid ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
156214501Srpaulo{
157214501Srpaulo	int set_beacon = 0;
158214501Srpaulo
159214501Srpaulo	accounting_sta_stop(hapd, sta);
160214501Srpaulo
161252726Srpaulo	/* just in case */
162252726Srpaulo	ap_sta_set_authorized(hapd, sta, 0);
163252726Srpaulo
164214501Srpaulo	if (sta->flags & WLAN_STA_WDS)
165281806Srpaulo		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
166214501Srpaulo
167281806Srpaulo	if (sta->ipaddr)
168281806Srpaulo		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
169281806Srpaulo	ap_sta_ip6addr_del(hapd, sta);
170281806Srpaulo
171281806Srpaulo	if (!hapd->iface->driver_ap_teardown &&
172281806Srpaulo	    !(sta->flags & WLAN_STA_PREAUTH))
173252726Srpaulo		hostapd_drv_sta_remove(hapd, sta->addr);
174214501Srpaulo
175289549Srpaulo#ifndef CONFIG_NO_VLAN
176289549Srpaulo	if (sta->vlan_id_bound) {
177289549Srpaulo		/*
178289549Srpaulo		 * Need to remove the STA entry before potentially removing the
179289549Srpaulo		 * VLAN.
180289549Srpaulo		 */
181289549Srpaulo		if (hapd->iface->driver_ap_teardown &&
182289549Srpaulo		    !(sta->flags & WLAN_STA_PREAUTH))
183289549Srpaulo			hostapd_drv_sta_remove(hapd, sta->addr);
184289549Srpaulo		vlan_remove_dynamic(hapd, sta->vlan_id_bound);
185289549Srpaulo	}
186289549Srpaulo#endif /* CONFIG_NO_VLAN */
187289549Srpaulo
188214501Srpaulo	ap_sta_hash_del(hapd, sta);
189214501Srpaulo	ap_sta_list_del(hapd, sta);
190214501Srpaulo
191214501Srpaulo	if (sta->aid > 0)
192214501Srpaulo		hapd->sta_aid[(sta->aid - 1) / 32] &=
193214501Srpaulo			~BIT((sta->aid - 1) % 32);
194214501Srpaulo
195214501Srpaulo	hapd->num_sta--;
196214501Srpaulo	if (sta->nonerp_set) {
197214501Srpaulo		sta->nonerp_set = 0;
198214501Srpaulo		hapd->iface->num_sta_non_erp--;
199214501Srpaulo		if (hapd->iface->num_sta_non_erp == 0)
200214501Srpaulo			set_beacon++;
201214501Srpaulo	}
202214501Srpaulo
203214501Srpaulo	if (sta->no_short_slot_time_set) {
204214501Srpaulo		sta->no_short_slot_time_set = 0;
205214501Srpaulo		hapd->iface->num_sta_no_short_slot_time--;
206214501Srpaulo		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
207214501Srpaulo		    && hapd->iface->num_sta_no_short_slot_time == 0)
208214501Srpaulo			set_beacon++;
209214501Srpaulo	}
210214501Srpaulo
211214501Srpaulo	if (sta->no_short_preamble_set) {
212214501Srpaulo		sta->no_short_preamble_set = 0;
213214501Srpaulo		hapd->iface->num_sta_no_short_preamble--;
214214501Srpaulo		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
215214501Srpaulo		    && hapd->iface->num_sta_no_short_preamble == 0)
216214501Srpaulo			set_beacon++;
217214501Srpaulo	}
218214501Srpaulo
219214501Srpaulo	if (sta->no_ht_gf_set) {
220214501Srpaulo		sta->no_ht_gf_set = 0;
221214501Srpaulo		hapd->iface->num_sta_ht_no_gf--;
222214501Srpaulo	}
223214501Srpaulo
224214501Srpaulo	if (sta->no_ht_set) {
225214501Srpaulo		sta->no_ht_set = 0;
226214501Srpaulo		hapd->iface->num_sta_no_ht--;
227214501Srpaulo	}
228214501Srpaulo
229214501Srpaulo	if (sta->ht_20mhz_set) {
230214501Srpaulo		sta->ht_20mhz_set = 0;
231214501Srpaulo		hapd->iface->num_sta_ht_20mhz--;
232214501Srpaulo	}
233214501Srpaulo
234281806Srpaulo#ifdef CONFIG_IEEE80211N
235281806Srpaulo	ht40_intolerant_remove(hapd->iface, sta);
236281806Srpaulo#endif /* CONFIG_IEEE80211N */
237281806Srpaulo
238252726Srpaulo#ifdef CONFIG_P2P
239252726Srpaulo	if (sta->no_p2p_set) {
240252726Srpaulo		sta->no_p2p_set = 0;
241252726Srpaulo		hapd->num_sta_no_p2p--;
242252726Srpaulo		if (hapd->num_sta_no_p2p == 0)
243252726Srpaulo			hostapd_p2p_non_p2p_sta_disconnected(hapd);
244252726Srpaulo	}
245252726Srpaulo#endif /* CONFIG_P2P */
246252726Srpaulo
247214501Srpaulo#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
248214501Srpaulo	if (hostapd_ht_operation_update(hapd->iface) > 0)
249214501Srpaulo		set_beacon++;
250214501Srpaulo#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
251214501Srpaulo
252281806Srpaulo#ifdef CONFIG_MESH
253281806Srpaulo	if (hapd->mesh_sta_free_cb)
254281806Srpaulo		hapd->mesh_sta_free_cb(sta);
255281806Srpaulo#endif /* CONFIG_MESH */
256281806Srpaulo
257214501Srpaulo	if (set_beacon)
258214501Srpaulo		ieee802_11_set_beacons(hapd->iface);
259214501Srpaulo
260252726Srpaulo	wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
261252726Srpaulo		   __func__, MAC2STR(sta->addr));
262214501Srpaulo	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
263214501Srpaulo	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
264281806Srpaulo	eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
265252726Srpaulo	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
266252726Srpaulo	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
267281806Srpaulo	sae_clear_retransmit_timer(hapd, sta);
268214501Srpaulo
269214501Srpaulo	ieee802_1x_free_station(sta);
270214501Srpaulo	wpa_auth_sta_deinit(sta->wpa_sm);
271214501Srpaulo	rsn_preauth_free_station(hapd, sta);
272214501Srpaulo#ifndef CONFIG_NO_RADIUS
273281806Srpaulo	if (hapd->radius)
274281806Srpaulo		radius_client_flush_auth(hapd->radius, sta->addr);
275214501Srpaulo#endif /* CONFIG_NO_RADIUS */
276214501Srpaulo
277214501Srpaulo	os_free(sta->challenge);
278214501Srpaulo
279214501Srpaulo#ifdef CONFIG_IEEE80211W
280214501Srpaulo	os_free(sta->sa_query_trans_id);
281214501Srpaulo	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
282214501Srpaulo#endif /* CONFIG_IEEE80211W */
283214501Srpaulo
284252726Srpaulo#ifdef CONFIG_P2P
285252726Srpaulo	p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
286252726Srpaulo#endif /* CONFIG_P2P */
287252726Srpaulo
288252726Srpaulo#ifdef CONFIG_INTERWORKING
289252726Srpaulo	if (sta->gas_dialog) {
290252726Srpaulo		int i;
291252726Srpaulo		for (i = 0; i < GAS_DIALOG_MAX; i++)
292252726Srpaulo			gas_serv_dialog_clear(&sta->gas_dialog[i]);
293252726Srpaulo		os_free(sta->gas_dialog);
294252726Srpaulo	}
295252726Srpaulo#endif /* CONFIG_INTERWORKING */
296252726Srpaulo
297214501Srpaulo	wpabuf_free(sta->wps_ie);
298252726Srpaulo	wpabuf_free(sta->p2p_ie);
299252726Srpaulo	wpabuf_free(sta->hs20_ie);
300289549Srpaulo#ifdef CONFIG_FST
301289549Srpaulo	wpabuf_free(sta->mb_ies);
302289549Srpaulo#endif /* CONFIG_FST */
303214501Srpaulo
304214501Srpaulo	os_free(sta->ht_capabilities);
305281806Srpaulo	os_free(sta->vht_capabilities);
306252726Srpaulo	hostapd_free_psk_list(sta->psk);
307252726Srpaulo	os_free(sta->identity);
308252726Srpaulo	os_free(sta->radius_cui);
309281806Srpaulo	os_free(sta->remediation_url);
310281806Srpaulo	wpabuf_free(sta->hs20_deauth_req);
311281806Srpaulo	os_free(sta->hs20_session_info_url);
312214501Srpaulo
313281806Srpaulo#ifdef CONFIG_SAE
314281806Srpaulo	sae_clear_data(sta->sae);
315281806Srpaulo	os_free(sta->sae);
316281806Srpaulo#endif /* CONFIG_SAE */
317281806Srpaulo
318214501Srpaulo	os_free(sta);
319214501Srpaulo}
320214501Srpaulo
321214501Srpaulo
322214501Srpaulovoid hostapd_free_stas(struct hostapd_data *hapd)
323214501Srpaulo{
324214501Srpaulo	struct sta_info *sta, *prev;
325214501Srpaulo
326214501Srpaulo	sta = hapd->sta_list;
327214501Srpaulo
328214501Srpaulo	while (sta) {
329214501Srpaulo		prev = sta;
330214501Srpaulo		if (sta->flags & WLAN_STA_AUTH) {
331214501Srpaulo			mlme_deauthenticate_indication(
332214501Srpaulo				hapd, sta, WLAN_REASON_UNSPECIFIED);
333214501Srpaulo		}
334214501Srpaulo		sta = sta->next;
335214501Srpaulo		wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
336214501Srpaulo			   MAC2STR(prev->addr));
337214501Srpaulo		ap_free_sta(hapd, prev);
338214501Srpaulo	}
339214501Srpaulo}
340214501Srpaulo
341214501Srpaulo
342214501Srpaulo/**
343214501Srpaulo * ap_handle_timer - Per STA timer handler
344214501Srpaulo * @eloop_ctx: struct hostapd_data *
345214501Srpaulo * @timeout_ctx: struct sta_info *
346214501Srpaulo *
347214501Srpaulo * This function is called to check station activity and to remove inactive
348214501Srpaulo * stations.
349214501Srpaulo */
350214501Srpaulovoid ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
351214501Srpaulo{
352214501Srpaulo	struct hostapd_data *hapd = eloop_ctx;
353214501Srpaulo	struct sta_info *sta = timeout_ctx;
354214501Srpaulo	unsigned long next_time = 0;
355281806Srpaulo	int reason;
356214501Srpaulo
357252726Srpaulo	wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
358252726Srpaulo		   __func__, MAC2STR(sta->addr), sta->flags,
359252726Srpaulo		   sta->timeout_next);
360214501Srpaulo	if (sta->timeout_next == STA_REMOVE) {
361214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
362214501Srpaulo			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
363214501Srpaulo			       "local deauth request");
364214501Srpaulo		ap_free_sta(hapd, sta);
365214501Srpaulo		return;
366214501Srpaulo	}
367214501Srpaulo
368214501Srpaulo	if ((sta->flags & WLAN_STA_ASSOC) &&
369214501Srpaulo	    (sta->timeout_next == STA_NULLFUNC ||
370214501Srpaulo	     sta->timeout_next == STA_DISASSOC)) {
371214501Srpaulo		int inactive_sec;
372252726Srpaulo		/*
373252726Srpaulo		 * Add random value to timeout so that we don't end up bouncing
374252726Srpaulo		 * all stations at the same time if we have lots of associated
375252726Srpaulo		 * stations that are idle (but keep re-associating).
376252726Srpaulo		 */
377252726Srpaulo		int fuzz = os_random() % 20;
378252726Srpaulo		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
379214501Srpaulo		if (inactive_sec == -1) {
380252726Srpaulo			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
381252726Srpaulo				"Check inactivity: Could not "
382252726Srpaulo				"get station info from kernel driver for "
383252726Srpaulo				MACSTR, MAC2STR(sta->addr));
384252726Srpaulo			/*
385252726Srpaulo			 * The driver may not support this functionality.
386252726Srpaulo			 * Anyway, try again after the next inactivity timeout,
387252726Srpaulo			 * but do not disconnect the station now.
388252726Srpaulo			 */
389252726Srpaulo			next_time = hapd->conf->ap_max_inactivity + fuzz;
390281806Srpaulo		} else if (inactive_sec == -ENOENT) {
391281806Srpaulo			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
392281806Srpaulo				"Station " MACSTR " has lost its driver entry",
393281806Srpaulo				MAC2STR(sta->addr));
394281806Srpaulo
395281806Srpaulo			/* Avoid sending client probe on removed client */
396281806Srpaulo			sta->timeout_next = STA_DISASSOC;
397281806Srpaulo			goto skip_poll;
398281806Srpaulo		} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
399214501Srpaulo			/* station activity detected; reset timeout state */
400252726Srpaulo			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
401252726Srpaulo				"Station " MACSTR " has been active %is ago",
402252726Srpaulo				MAC2STR(sta->addr), inactive_sec);
403214501Srpaulo			sta->timeout_next = STA_NULLFUNC;
404252726Srpaulo			next_time = hapd->conf->ap_max_inactivity + fuzz -
405214501Srpaulo				inactive_sec;
406252726Srpaulo		} else {
407252726Srpaulo			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
408252726Srpaulo				"Station " MACSTR " has been "
409252726Srpaulo				"inactive too long: %d sec, max allowed: %d",
410252726Srpaulo				MAC2STR(sta->addr), inactive_sec,
411252726Srpaulo				hapd->conf->ap_max_inactivity);
412252726Srpaulo
413252726Srpaulo			if (hapd->conf->skip_inactivity_poll)
414252726Srpaulo				sta->timeout_next = STA_DISASSOC;
415214501Srpaulo		}
416214501Srpaulo	}
417214501Srpaulo
418214501Srpaulo	if ((sta->flags & WLAN_STA_ASSOC) &&
419214501Srpaulo	    sta->timeout_next == STA_DISASSOC &&
420252726Srpaulo	    !(sta->flags & WLAN_STA_PENDING_POLL) &&
421252726Srpaulo	    !hapd->conf->skip_inactivity_poll) {
422252726Srpaulo		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
423252726Srpaulo			" has ACKed data poll", MAC2STR(sta->addr));
424214501Srpaulo		/* data nullfunc frame poll did not produce TX errors; assume
425214501Srpaulo		 * station ACKed it */
426214501Srpaulo		sta->timeout_next = STA_NULLFUNC;
427214501Srpaulo		next_time = hapd->conf->ap_max_inactivity;
428214501Srpaulo	}
429214501Srpaulo
430281806Srpauloskip_poll:
431214501Srpaulo	if (next_time) {
432252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
433252726Srpaulo			   "for " MACSTR " (%lu seconds)",
434252726Srpaulo			   __func__, MAC2STR(sta->addr), next_time);
435214501Srpaulo		eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
436214501Srpaulo				       sta);
437214501Srpaulo		return;
438214501Srpaulo	}
439214501Srpaulo
440214501Srpaulo	if (sta->timeout_next == STA_NULLFUNC &&
441214501Srpaulo	    (sta->flags & WLAN_STA_ASSOC)) {
442252726Srpaulo		wpa_printf(MSG_DEBUG, "  Polling STA");
443214501Srpaulo		sta->flags |= WLAN_STA_PENDING_POLL;
444252726Srpaulo		hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
445252726Srpaulo					sta->flags & WLAN_STA_WMM);
446214501Srpaulo	} else if (sta->timeout_next != STA_REMOVE) {
447214501Srpaulo		int deauth = sta->timeout_next == STA_DEAUTH;
448214501Srpaulo
449252726Srpaulo		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
450252726Srpaulo			"Timeout, sending %s info to STA " MACSTR,
451252726Srpaulo			deauth ? "deauthentication" : "disassociation",
452252726Srpaulo			MAC2STR(sta->addr));
453214501Srpaulo
454214501Srpaulo		if (deauth) {
455252726Srpaulo			hostapd_drv_sta_deauth(
456252726Srpaulo				hapd, sta->addr,
457252726Srpaulo				WLAN_REASON_PREV_AUTH_NOT_VALID);
458214501Srpaulo		} else {
459281806Srpaulo			reason = (sta->timeout_next == STA_DISASSOC) ?
460281806Srpaulo				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
461281806Srpaulo				WLAN_REASON_PREV_AUTH_NOT_VALID;
462281806Srpaulo
463281806Srpaulo			hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
464214501Srpaulo		}
465214501Srpaulo	}
466214501Srpaulo
467214501Srpaulo	switch (sta->timeout_next) {
468214501Srpaulo	case STA_NULLFUNC:
469214501Srpaulo		sta->timeout_next = STA_DISASSOC;
470252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
471252726Srpaulo			   "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
472252726Srpaulo			   __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
473214501Srpaulo		eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
474214501Srpaulo				       hapd, sta);
475214501Srpaulo		break;
476214501Srpaulo	case STA_DISASSOC:
477281806Srpaulo	case STA_DISASSOC_FROM_CLI:
478252726Srpaulo		ap_sta_set_authorized(hapd, sta, 0);
479214501Srpaulo		sta->flags &= ~WLAN_STA_ASSOC;
480214501Srpaulo		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
481214501Srpaulo		if (!sta->acct_terminate_cause)
482214501Srpaulo			sta->acct_terminate_cause =
483214501Srpaulo				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
484214501Srpaulo		accounting_sta_stop(hapd, sta);
485214501Srpaulo		ieee802_1x_free_station(sta);
486214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
487214501Srpaulo			       HOSTAPD_LEVEL_INFO, "disassociated due to "
488214501Srpaulo			       "inactivity");
489281806Srpaulo		reason = (sta->timeout_next == STA_DISASSOC) ?
490281806Srpaulo			WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
491281806Srpaulo			WLAN_REASON_PREV_AUTH_NOT_VALID;
492214501Srpaulo		sta->timeout_next = STA_DEAUTH;
493252726Srpaulo		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
494252726Srpaulo			   "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
495252726Srpaulo			   __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
496214501Srpaulo		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
497214501Srpaulo				       hapd, sta);
498281806Srpaulo		mlme_disassociate_indication(hapd, sta, reason);
499214501Srpaulo		break;
500214501Srpaulo	case STA_DEAUTH:
501214501Srpaulo	case STA_REMOVE:
502214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
503214501Srpaulo			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
504252726Srpaulo			       "inactivity (timer DEAUTH/REMOVE)");
505214501Srpaulo		if (!sta->acct_terminate_cause)
506214501Srpaulo			sta->acct_terminate_cause =
507214501Srpaulo				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
508214501Srpaulo		mlme_deauthenticate_indication(
509214501Srpaulo			hapd, sta,
510214501Srpaulo			WLAN_REASON_PREV_AUTH_NOT_VALID);
511214501Srpaulo		ap_free_sta(hapd, sta);
512214501Srpaulo		break;
513214501Srpaulo	}
514214501Srpaulo}
515214501Srpaulo
516214501Srpaulo
517214501Srpaulostatic void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
518214501Srpaulo{
519214501Srpaulo	struct hostapd_data *hapd = eloop_ctx;
520214501Srpaulo	struct sta_info *sta = timeout_ctx;
521214501Srpaulo
522252726Srpaulo	if (!(sta->flags & WLAN_STA_AUTH)) {
523252726Srpaulo		if (sta->flags & WLAN_STA_GAS) {
524252726Srpaulo			wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
525252726Srpaulo				   "entry " MACSTR, MAC2STR(sta->addr));
526252726Srpaulo			ap_free_sta(hapd, sta);
527252726Srpaulo		}
528214501Srpaulo		return;
529252726Srpaulo	}
530214501Srpaulo
531281806Srpaulo	hostapd_drv_sta_deauth(hapd, sta->addr,
532281806Srpaulo			       WLAN_REASON_PREV_AUTH_NOT_VALID);
533214501Srpaulo	mlme_deauthenticate_indication(hapd, sta,
534214501Srpaulo				       WLAN_REASON_PREV_AUTH_NOT_VALID);
535214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
536214501Srpaulo		       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
537214501Srpaulo		       "session timeout");
538214501Srpaulo	sta->acct_terminate_cause =
539214501Srpaulo		RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
540214501Srpaulo	ap_free_sta(hapd, sta);
541214501Srpaulo}
542214501Srpaulo
543214501Srpaulo
544281806Srpaulovoid ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
545281806Srpaulo			      u32 session_timeout)
546281806Srpaulo{
547281806Srpaulo	if (eloop_replenish_timeout(session_timeout, 0,
548281806Srpaulo				    ap_handle_session_timer, hapd, sta) == 1) {
549281806Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
550281806Srpaulo			       HOSTAPD_LEVEL_DEBUG, "setting session timeout "
551281806Srpaulo			       "to %d seconds", session_timeout);
552281806Srpaulo	}
553281806Srpaulo}
554281806Srpaulo
555281806Srpaulo
556214501Srpaulovoid ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
557214501Srpaulo			    u32 session_timeout)
558214501Srpaulo{
559214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
560214501Srpaulo		       HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
561214501Srpaulo		       "seconds", session_timeout);
562214501Srpaulo	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
563214501Srpaulo	eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
564214501Srpaulo			       hapd, sta);
565214501Srpaulo}
566214501Srpaulo
567214501Srpaulo
568214501Srpaulovoid ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
569214501Srpaulo{
570214501Srpaulo	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
571214501Srpaulo}
572214501Srpaulo
573214501Srpaulo
574281806Srpaulostatic void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
575281806Srpaulo{
576281806Srpaulo#ifdef CONFIG_WNM
577281806Srpaulo	struct hostapd_data *hapd = eloop_ctx;
578281806Srpaulo	struct sta_info *sta = timeout_ctx;
579281806Srpaulo
580281806Srpaulo	wpa_printf(MSG_DEBUG, "WNM: Session warning time reached for " MACSTR,
581281806Srpaulo		   MAC2STR(sta->addr));
582281806Srpaulo	if (sta->hs20_session_info_url == NULL)
583281806Srpaulo		return;
584281806Srpaulo
585281806Srpaulo	wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
586281806Srpaulo				       sta->hs20_disassoc_timer);
587281806Srpaulo#endif /* CONFIG_WNM */
588281806Srpaulo}
589281806Srpaulo
590281806Srpaulo
591281806Srpaulovoid ap_sta_session_warning_timeout(struct hostapd_data *hapd,
592281806Srpaulo				    struct sta_info *sta, int warning_time)
593281806Srpaulo{
594281806Srpaulo	eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
595281806Srpaulo	eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer,
596281806Srpaulo			       hapd, sta);
597281806Srpaulo}
598281806Srpaulo
599281806Srpaulo
600214501Srpaulostruct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
601214501Srpaulo{
602214501Srpaulo	struct sta_info *sta;
603214501Srpaulo
604214501Srpaulo	sta = ap_get_sta(hapd, addr);
605214501Srpaulo	if (sta)
606214501Srpaulo		return sta;
607214501Srpaulo
608214501Srpaulo	wpa_printf(MSG_DEBUG, "  New STA");
609214501Srpaulo	if (hapd->num_sta >= hapd->conf->max_num_sta) {
610214501Srpaulo		/* FIX: might try to remove some old STAs first? */
611214501Srpaulo		wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
612214501Srpaulo			   hapd->num_sta, hapd->conf->max_num_sta);
613214501Srpaulo		return NULL;
614214501Srpaulo	}
615214501Srpaulo
616214501Srpaulo	sta = os_zalloc(sizeof(struct sta_info));
617214501Srpaulo	if (sta == NULL) {
618214501Srpaulo		wpa_printf(MSG_ERROR, "malloc failed");
619214501Srpaulo		return NULL;
620214501Srpaulo	}
621214501Srpaulo	sta->acct_interim_interval = hapd->conf->acct_interim_interval;
622252726Srpaulo	accounting_sta_get_id(hapd, sta);
623214501Srpaulo
624281806Srpaulo	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
625281806Srpaulo		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
626281806Srpaulo			   "for " MACSTR " (%d seconds - ap_max_inactivity)",
627281806Srpaulo			   __func__, MAC2STR(addr),
628281806Srpaulo			   hapd->conf->ap_max_inactivity);
629281806Srpaulo		eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
630281806Srpaulo				       ap_handle_timer, hapd, sta);
631281806Srpaulo	}
632281806Srpaulo
633214501Srpaulo	/* initialize STA info data */
634214501Srpaulo	os_memcpy(sta->addr, addr, ETH_ALEN);
635214501Srpaulo	sta->next = hapd->sta_list;
636214501Srpaulo	hapd->sta_list = sta;
637214501Srpaulo	hapd->num_sta++;
638214501Srpaulo	ap_sta_hash_add(hapd, sta);
639214501Srpaulo	ap_sta_remove_in_other_bss(hapd, sta);
640281806Srpaulo	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
641281806Srpaulo	dl_list_init(&sta->ip6addr);
642214501Srpaulo
643214501Srpaulo	return sta;
644214501Srpaulo}
645214501Srpaulo
646214501Srpaulo
647214501Srpaulostatic int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
648214501Srpaulo{
649214501Srpaulo	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
650214501Srpaulo
651281806Srpaulo	if (sta->ipaddr)
652281806Srpaulo		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
653281806Srpaulo	ap_sta_ip6addr_del(hapd, sta);
654281806Srpaulo
655214501Srpaulo	wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
656214501Srpaulo		   MAC2STR(sta->addr));
657252726Srpaulo	if (hostapd_drv_sta_remove(hapd, sta->addr) &&
658214501Srpaulo	    sta->flags & WLAN_STA_ASSOC) {
659214501Srpaulo		wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
660214501Srpaulo			   " from kernel driver.", MAC2STR(sta->addr));
661214501Srpaulo		return -1;
662214501Srpaulo	}
663214501Srpaulo	return 0;
664214501Srpaulo}
665214501Srpaulo
666214501Srpaulo
667214501Srpaulostatic void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
668214501Srpaulo				       struct sta_info *sta)
669214501Srpaulo{
670214501Srpaulo	struct hostapd_iface *iface = hapd->iface;
671214501Srpaulo	size_t i;
672214501Srpaulo
673214501Srpaulo	for (i = 0; i < iface->num_bss; i++) {
674214501Srpaulo		struct hostapd_data *bss = iface->bss[i];
675214501Srpaulo		struct sta_info *sta2;
676214501Srpaulo		/* bss should always be set during operation, but it may be
677214501Srpaulo		 * NULL during reconfiguration. Assume the STA is not
678214501Srpaulo		 * associated to another BSS in that case to avoid NULL pointer
679214501Srpaulo		 * dereferences. */
680214501Srpaulo		if (bss == hapd || bss == NULL)
681214501Srpaulo			continue;
682214501Srpaulo		sta2 = ap_get_sta(bss, sta->addr);
683214501Srpaulo		if (!sta2)
684214501Srpaulo			continue;
685214501Srpaulo
686214501Srpaulo		ap_sta_disconnect(bss, sta2, sta2->addr,
687214501Srpaulo				  WLAN_REASON_PREV_AUTH_NOT_VALID);
688214501Srpaulo	}
689214501Srpaulo}
690214501Srpaulo
691214501Srpaulo
692252726Srpaulostatic void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
693252726Srpaulo{
694252726Srpaulo	struct hostapd_data *hapd = eloop_ctx;
695252726Srpaulo	struct sta_info *sta = timeout_ctx;
696252726Srpaulo
697252726Srpaulo	ap_sta_remove(hapd, sta);
698252726Srpaulo	mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
699252726Srpaulo}
700252726Srpaulo
701252726Srpaulo
702214501Srpaulovoid ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
703214501Srpaulo			 u16 reason)
704214501Srpaulo{
705214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
706214501Srpaulo		   hapd->conf->iface, MAC2STR(sta->addr));
707281806Srpaulo	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
708281806Srpaulo	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
709252726Srpaulo	ap_sta_set_authorized(hapd, sta, 0);
710214501Srpaulo	sta->timeout_next = STA_DEAUTH;
711252726Srpaulo	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
712252726Srpaulo		   "for " MACSTR " (%d seconds - "
713252726Srpaulo		   "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
714252726Srpaulo		   __func__, MAC2STR(sta->addr),
715252726Srpaulo		   AP_MAX_INACTIVITY_AFTER_DISASSOC);
716214501Srpaulo	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
717214501Srpaulo	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
718214501Srpaulo			       ap_handle_timer, hapd, sta);
719214501Srpaulo	accounting_sta_stop(hapd, sta);
720214501Srpaulo	ieee802_1x_free_station(sta);
721214501Srpaulo
722252726Srpaulo	sta->disassoc_reason = reason;
723252726Srpaulo	sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
724252726Srpaulo	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
725252726Srpaulo	eloop_register_timeout(hapd->iface->drv_flags &
726252726Srpaulo			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
727252726Srpaulo			       ap_sta_disassoc_cb_timeout, hapd, sta);
728214501Srpaulo}
729214501Srpaulo
730214501Srpaulo
731252726Srpaulostatic void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
732252726Srpaulo{
733252726Srpaulo	struct hostapd_data *hapd = eloop_ctx;
734252726Srpaulo	struct sta_info *sta = timeout_ctx;
735252726Srpaulo
736252726Srpaulo	ap_sta_remove(hapd, sta);
737252726Srpaulo	mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
738252726Srpaulo}
739252726Srpaulo
740252726Srpaulo
741214501Srpaulovoid ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
742214501Srpaulo			   u16 reason)
743214501Srpaulo{
744214501Srpaulo	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
745214501Srpaulo		   hapd->conf->iface, MAC2STR(sta->addr));
746281806Srpaulo	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
747281806Srpaulo	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
748252726Srpaulo	ap_sta_set_authorized(hapd, sta, 0);
749214501Srpaulo	sta->timeout_next = STA_REMOVE;
750252726Srpaulo	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
751252726Srpaulo		   "for " MACSTR " (%d seconds - "
752252726Srpaulo		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
753252726Srpaulo		   __func__, MAC2STR(sta->addr),
754252726Srpaulo		   AP_MAX_INACTIVITY_AFTER_DEAUTH);
755214501Srpaulo	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
756214501Srpaulo	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
757214501Srpaulo			       ap_handle_timer, hapd, sta);
758214501Srpaulo	accounting_sta_stop(hapd, sta);
759214501Srpaulo	ieee802_1x_free_station(sta);
760214501Srpaulo
761252726Srpaulo	sta->deauth_reason = reason;
762252726Srpaulo	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
763252726Srpaulo	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
764252726Srpaulo	eloop_register_timeout(hapd->iface->drv_flags &
765252726Srpaulo			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
766252726Srpaulo			       ap_sta_deauth_cb_timeout, hapd, sta);
767214501Srpaulo}
768214501Srpaulo
769214501Srpaulo
770252726Srpaulo#ifdef CONFIG_WPS
771252726Srpauloint ap_sta_wps_cancel(struct hostapd_data *hapd,
772252726Srpaulo		      struct sta_info *sta, void *ctx)
773252726Srpaulo{
774252726Srpaulo	if (sta && (sta->flags & WLAN_STA_WPS)) {
775252726Srpaulo		ap_sta_deauthenticate(hapd, sta,
776252726Srpaulo				      WLAN_REASON_PREV_AUTH_NOT_VALID);
777252726Srpaulo		wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
778252726Srpaulo			   __func__, MAC2STR(sta->addr));
779252726Srpaulo		return 1;
780252726Srpaulo	}
781252726Srpaulo
782252726Srpaulo	return 0;
783252726Srpaulo}
784252726Srpaulo#endif /* CONFIG_WPS */
785252726Srpaulo
786252726Srpaulo
787289549Srpauloint ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
788214501Srpaulo{
789214501Srpaulo#ifndef CONFIG_NO_VLAN
790214501Srpaulo	const char *iface;
791214501Srpaulo	struct hostapd_vlan *vlan = NULL;
792214501Srpaulo	int ret;
793289549Srpaulo	int old_vlanid = sta->vlan_id_bound;
794214501Srpaulo
795214501Srpaulo	iface = hapd->conf->iface;
796289549Srpaulo	if (hapd->conf->ssid.vlan[0])
797289549Srpaulo		iface = hapd->conf->ssid.vlan;
798214501Srpaulo
799289549Srpaulo	if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
800214501Srpaulo		sta->vlan_id = 0;
801214501Srpaulo	else if (sta->vlan_id > 0) {
802281806Srpaulo		struct hostapd_vlan *wildcard_vlan = NULL;
803214501Srpaulo		vlan = hapd->conf->vlan;
804214501Srpaulo		while (vlan) {
805281806Srpaulo			if (vlan->vlan_id == sta->vlan_id)
806214501Srpaulo				break;
807281806Srpaulo			if (vlan->vlan_id == VLAN_ID_WILDCARD)
808281806Srpaulo				wildcard_vlan = vlan;
809214501Srpaulo			vlan = vlan->next;
810214501Srpaulo		}
811281806Srpaulo		if (!vlan)
812281806Srpaulo			vlan = wildcard_vlan;
813281806Srpaulo		if (vlan)
814281806Srpaulo			iface = vlan->ifname;
815214501Srpaulo	}
816214501Srpaulo
817289549Srpaulo	/*
818289549Srpaulo	 * Do not increment ref counters if the VLAN ID remains same, but do
819289549Srpaulo	 * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
820289549Srpaulo	 * have been called before.
821289549Srpaulo	 */
822289549Srpaulo	if (sta->vlan_id == old_vlanid)
823289549Srpaulo		goto skip_counting;
824289549Srpaulo
825214501Srpaulo	if (sta->vlan_id > 0 && vlan == NULL) {
826214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
827214501Srpaulo			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
828214501Srpaulo			       "binding station to (vlan_id=%d)",
829214501Srpaulo			       sta->vlan_id);
830281806Srpaulo		ret = -1;
831281806Srpaulo		goto done;
832214501Srpaulo	} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
833214501Srpaulo		vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
834214501Srpaulo		if (vlan == NULL) {
835214501Srpaulo			hostapd_logger(hapd, sta->addr,
836214501Srpaulo				       HOSTAPD_MODULE_IEEE80211,
837214501Srpaulo				       HOSTAPD_LEVEL_DEBUG, "could not add "
838214501Srpaulo				       "dynamic VLAN interface for vlan_id=%d",
839214501Srpaulo				       sta->vlan_id);
840281806Srpaulo			ret = -1;
841281806Srpaulo			goto done;
842214501Srpaulo		}
843214501Srpaulo
844214501Srpaulo		iface = vlan->ifname;
845289549Srpaulo		if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
846214501Srpaulo			hostapd_logger(hapd, sta->addr,
847214501Srpaulo				       HOSTAPD_MODULE_IEEE80211,
848214501Srpaulo				       HOSTAPD_LEVEL_DEBUG, "could not "
849214501Srpaulo				       "configure encryption for dynamic VLAN "
850214501Srpaulo				       "interface for vlan_id=%d",
851214501Srpaulo				       sta->vlan_id);
852214501Srpaulo		}
853214501Srpaulo
854214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
855214501Srpaulo			       HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
856214501Srpaulo			       "interface '%s'", iface);
857214501Srpaulo	} else if (vlan && vlan->vlan_id == sta->vlan_id) {
858289549Srpaulo		if (vlan->dynamic_vlan > 0) {
859214501Srpaulo			vlan->dynamic_vlan++;
860214501Srpaulo			hostapd_logger(hapd, sta->addr,
861214501Srpaulo				       HOSTAPD_MODULE_IEEE80211,
862214501Srpaulo				       HOSTAPD_LEVEL_DEBUG, "updated existing "
863214501Srpaulo				       "dynamic VLAN interface '%s'", iface);
864214501Srpaulo		}
865214501Srpaulo
866214501Srpaulo		/*
867214501Srpaulo		 * Update encryption configuration for statically generated
868214501Srpaulo		 * VLAN interface. This is only used for static WEP
869214501Srpaulo		 * configuration for the case where hostapd did not yet know
870214501Srpaulo		 * which keys are to be used when the interface was added.
871214501Srpaulo		 */
872289549Srpaulo		if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
873214501Srpaulo			hostapd_logger(hapd, sta->addr,
874214501Srpaulo				       HOSTAPD_MODULE_IEEE80211,
875214501Srpaulo				       HOSTAPD_LEVEL_DEBUG, "could not "
876214501Srpaulo				       "configure encryption for VLAN "
877214501Srpaulo				       "interface for vlan_id=%d",
878214501Srpaulo				       sta->vlan_id);
879214501Srpaulo		}
880214501Srpaulo	}
881214501Srpaulo
882289549Srpaulo	/* ref counters have been increased, so mark the station */
883289549Srpaulo	sta->vlan_id_bound = sta->vlan_id;
884289549Srpaulo
885289549Srpauloskip_counting:
886214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
887214501Srpaulo		       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
888214501Srpaulo		       "'%s'", iface);
889214501Srpaulo
890214501Srpaulo	if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
891214501Srpaulo		wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
892214501Srpaulo
893252726Srpaulo	ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
894214501Srpaulo	if (ret < 0) {
895214501Srpaulo		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
896214501Srpaulo			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
897214501Srpaulo			       "entry to vlan_id=%d", sta->vlan_id);
898214501Srpaulo	}
899281806Srpaulo
900281806Srpaulo	/* During 1x reauth, if the vlan id changes, then remove the old id. */
901289549Srpaulo	if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
902281806Srpaulo		vlan_remove_dynamic(hapd, old_vlanid);
903289549Srpaulodone:
904281806Srpaulo
905214501Srpaulo	return ret;
906214501Srpaulo#else /* CONFIG_NO_VLAN */
907214501Srpaulo	return 0;
908214501Srpaulo#endif /* CONFIG_NO_VLAN */
909214501Srpaulo}
910214501Srpaulo
911214501Srpaulo
912214501Srpaulo#ifdef CONFIG_IEEE80211W
913214501Srpaulo
914214501Srpauloint ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
915214501Srpaulo{
916214501Srpaulo	u32 tu;
917281806Srpaulo	struct os_reltime now, passed;
918281806Srpaulo	os_get_reltime(&now);
919281806Srpaulo	os_reltime_sub(&now, &sta->sa_query_start, &passed);
920214501Srpaulo	tu = (passed.sec * 1000000 + passed.usec) / 1024;
921214501Srpaulo	if (hapd->conf->assoc_sa_query_max_timeout < tu) {
922214501Srpaulo		hostapd_logger(hapd, sta->addr,
923214501Srpaulo			       HOSTAPD_MODULE_IEEE80211,
924214501Srpaulo			       HOSTAPD_LEVEL_DEBUG,
925214501Srpaulo			       "association SA Query timed out");
926214501Srpaulo		sta->sa_query_timed_out = 1;
927214501Srpaulo		os_free(sta->sa_query_trans_id);
928214501Srpaulo		sta->sa_query_trans_id = NULL;
929214501Srpaulo		sta->sa_query_count = 0;
930214501Srpaulo		eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
931214501Srpaulo		return 1;
932214501Srpaulo	}
933214501Srpaulo
934214501Srpaulo	return 0;
935214501Srpaulo}
936214501Srpaulo
937214501Srpaulo
938214501Srpaulostatic void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
939214501Srpaulo{
940214501Srpaulo	struct hostapd_data *hapd = eloop_ctx;
941214501Srpaulo	struct sta_info *sta = timeout_ctx;
942214501Srpaulo	unsigned int timeout, sec, usec;
943214501Srpaulo	u8 *trans_id, *nbuf;
944214501Srpaulo
945214501Srpaulo	if (sta->sa_query_count > 0 &&
946214501Srpaulo	    ap_check_sa_query_timeout(hapd, sta))
947214501Srpaulo		return;
948214501Srpaulo
949252726Srpaulo	nbuf = os_realloc_array(sta->sa_query_trans_id,
950252726Srpaulo				sta->sa_query_count + 1,
951252726Srpaulo				WLAN_SA_QUERY_TR_ID_LEN);
952214501Srpaulo	if (nbuf == NULL)
953214501Srpaulo		return;
954214501Srpaulo	if (sta->sa_query_count == 0) {
955214501Srpaulo		/* Starting a new SA Query procedure */
956281806Srpaulo		os_get_reltime(&sta->sa_query_start);
957214501Srpaulo	}
958214501Srpaulo	trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
959214501Srpaulo	sta->sa_query_trans_id = nbuf;
960214501Srpaulo	sta->sa_query_count++;
961214501Srpaulo
962281806Srpaulo	if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
963281806Srpaulo		/*
964281806Srpaulo		 * We don't really care which ID is used here, so simply
965281806Srpaulo		 * hardcode this if the mostly theoretical os_get_random()
966281806Srpaulo		 * failure happens.
967281806Srpaulo		 */
968281806Srpaulo		trans_id[0] = 0x12;
969281806Srpaulo		trans_id[1] = 0x34;
970281806Srpaulo	}
971214501Srpaulo
972214501Srpaulo	timeout = hapd->conf->assoc_sa_query_retry_timeout;
973214501Srpaulo	sec = ((timeout / 1000) * 1024) / 1000;
974214501Srpaulo	usec = (timeout % 1000) * 1024;
975214501Srpaulo	eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
976214501Srpaulo
977214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
978214501Srpaulo		       HOSTAPD_LEVEL_DEBUG,
979214501Srpaulo		       "association SA Query attempt %d", sta->sa_query_count);
980214501Srpaulo
981214501Srpaulo	ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
982214501Srpaulo}
983214501Srpaulo
984214501Srpaulo
985214501Srpaulovoid ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
986214501Srpaulo{
987214501Srpaulo	ap_sa_query_timer(hapd, sta);
988214501Srpaulo}
989214501Srpaulo
990214501Srpaulo
991214501Srpaulovoid ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
992214501Srpaulo{
993214501Srpaulo	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
994214501Srpaulo	os_free(sta->sa_query_trans_id);
995214501Srpaulo	sta->sa_query_trans_id = NULL;
996214501Srpaulo	sta->sa_query_count = 0;
997214501Srpaulo}
998214501Srpaulo
999214501Srpaulo#endif /* CONFIG_IEEE80211W */
1000214501Srpaulo
1001214501Srpaulo
1002252726Srpaulovoid ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
1003252726Srpaulo			   int authorized)
1004252726Srpaulo{
1005252726Srpaulo	const u8 *dev_addr = NULL;
1006281806Srpaulo	char buf[100];
1007252726Srpaulo#ifdef CONFIG_P2P
1008252726Srpaulo	u8 addr[ETH_ALEN];
1009281806Srpaulo	u8 ip_addr_buf[4];
1010252726Srpaulo#endif /* CONFIG_P2P */
1011252726Srpaulo
1012252726Srpaulo	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
1013252726Srpaulo		return;
1014252726Srpaulo
1015281806Srpaulo	if (authorized)
1016281806Srpaulo		sta->flags |= WLAN_STA_AUTHORIZED;
1017281806Srpaulo	else
1018281806Srpaulo		sta->flags &= ~WLAN_STA_AUTHORIZED;
1019281806Srpaulo
1020252726Srpaulo#ifdef CONFIG_P2P
1021252726Srpaulo	if (hapd->p2p_group == NULL) {
1022252726Srpaulo		if (sta->p2p_ie != NULL &&
1023252726Srpaulo		    p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
1024252726Srpaulo			dev_addr = addr;
1025252726Srpaulo	} else
1026252726Srpaulo		dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
1027281806Srpaulo
1028281806Srpaulo	if (dev_addr)
1029281806Srpaulo		os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
1030281806Srpaulo			    MAC2STR(sta->addr), MAC2STR(dev_addr));
1031281806Srpaulo	else
1032252726Srpaulo#endif /* CONFIG_P2P */
1033281806Srpaulo		os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
1034252726Srpaulo
1035281806Srpaulo	if (hapd->sta_authorized_cb)
1036281806Srpaulo		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
1037281806Srpaulo					sta->addr, authorized, dev_addr);
1038281806Srpaulo
1039252726Srpaulo	if (authorized) {
1040281806Srpaulo		char ip_addr[100];
1041281806Srpaulo		ip_addr[0] = '\0';
1042281806Srpaulo#ifdef CONFIG_P2P
1043281806Srpaulo		if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
1044281806Srpaulo			os_snprintf(ip_addr, sizeof(ip_addr),
1045281806Srpaulo				    " ip_addr=%u.%u.%u.%u",
1046281806Srpaulo				    ip_addr_buf[0], ip_addr_buf[1],
1047281806Srpaulo				    ip_addr_buf[2], ip_addr_buf[3]);
1048281806Srpaulo		}
1049281806Srpaulo#endif /* CONFIG_P2P */
1050281806Srpaulo
1051281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s",
1052281806Srpaulo			buf, ip_addr);
1053281806Srpaulo
1054252726Srpaulo		if (hapd->msg_ctx_parent &&
1055281806Srpaulo		    hapd->msg_ctx_parent != hapd->msg_ctx)
1056281806Srpaulo			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
1057281806Srpaulo					  AP_STA_CONNECTED "%s%s",
1058281806Srpaulo					  buf, ip_addr);
1059281806Srpaulo	} else {
1060281806Srpaulo		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
1061252726Srpaulo
1062252726Srpaulo		if (hapd->msg_ctx_parent &&
1063281806Srpaulo		    hapd->msg_ctx_parent != hapd->msg_ctx)
1064281806Srpaulo			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
1065281806Srpaulo					  AP_STA_DISCONNECTED "%s", buf);
1066252726Srpaulo	}
1067289549Srpaulo
1068289549Srpaulo#ifdef CONFIG_FST
1069289549Srpaulo	if (hapd->iface->fst) {
1070289549Srpaulo		if (authorized)
1071289549Srpaulo			fst_notify_peer_connected(hapd->iface->fst, sta->addr);
1072289549Srpaulo		else
1073289549Srpaulo			fst_notify_peer_disconnected(hapd->iface->fst,
1074289549Srpaulo						     sta->addr);
1075289549Srpaulo	}
1076289549Srpaulo#endif /* CONFIG_FST */
1077252726Srpaulo}
1078252726Srpaulo
1079252726Srpaulo
1080214501Srpaulovoid ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
1081214501Srpaulo		       const u8 *addr, u16 reason)
1082214501Srpaulo{
1083214501Srpaulo
1084214501Srpaulo	if (sta == NULL && addr)
1085214501Srpaulo		sta = ap_get_sta(hapd, addr);
1086214501Srpaulo
1087214501Srpaulo	if (addr)
1088252726Srpaulo		hostapd_drv_sta_deauth(hapd, addr, reason);
1089214501Srpaulo
1090214501Srpaulo	if (sta == NULL)
1091214501Srpaulo		return;
1092252726Srpaulo	ap_sta_set_authorized(hapd, sta, 0);
1093252726Srpaulo	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
1094252726Srpaulo	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
1095252726Srpaulo	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
1096252726Srpaulo	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
1097252726Srpaulo		   "for " MACSTR " (%d seconds - "
1098252726Srpaulo		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
1099252726Srpaulo		   __func__, MAC2STR(sta->addr),
1100252726Srpaulo		   AP_MAX_INACTIVITY_AFTER_DEAUTH);
1101214501Srpaulo	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
1102252726Srpaulo	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
1103252726Srpaulo			       ap_handle_timer, hapd, sta);
1104214501Srpaulo	sta->timeout_next = STA_REMOVE;
1105252726Srpaulo
1106252726Srpaulo	sta->deauth_reason = reason;
1107252726Srpaulo	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
1108252726Srpaulo	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
1109252726Srpaulo	eloop_register_timeout(hapd->iface->drv_flags &
1110252726Srpaulo			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
1111252726Srpaulo			       ap_sta_deauth_cb_timeout, hapd, sta);
1112214501Srpaulo}
1113252726Srpaulo
1114252726Srpaulo
1115252726Srpaulovoid ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
1116252726Srpaulo{
1117252726Srpaulo	if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
1118252726Srpaulo		wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
1119252726Srpaulo		return;
1120252726Srpaulo	}
1121252726Srpaulo	sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
1122252726Srpaulo	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
1123252726Srpaulo	ap_sta_deauth_cb_timeout(hapd, sta);
1124252726Srpaulo}
1125252726Srpaulo
1126252726Srpaulo
1127252726Srpaulovoid ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
1128252726Srpaulo{
1129252726Srpaulo	if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
1130252726Srpaulo		wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
1131252726Srpaulo		return;
1132252726Srpaulo	}
1133252726Srpaulo	sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
1134252726Srpaulo	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
1135252726Srpaulo	ap_sta_disassoc_cb_timeout(hapd, sta);
1136252726Srpaulo}
1137281806Srpaulo
1138281806Srpaulo
1139281806Srpauloint ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
1140281806Srpaulo{
1141281806Srpaulo	int res;
1142281806Srpaulo
1143281806Srpaulo	buf[0] = '\0';
1144281806Srpaulo	res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1145281806Srpaulo			  (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
1146281806Srpaulo			  (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
1147281806Srpaulo			  (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
1148281806Srpaulo			  (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
1149281806Srpaulo			   ""),
1150281806Srpaulo			  (flags & WLAN_STA_SHORT_PREAMBLE ?
1151281806Srpaulo			   "[SHORT_PREAMBLE]" : ""),
1152281806Srpaulo			  (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
1153281806Srpaulo			  (flags & WLAN_STA_WMM ? "[WMM]" : ""),
1154281806Srpaulo			  (flags & WLAN_STA_MFP ? "[MFP]" : ""),
1155281806Srpaulo			  (flags & WLAN_STA_WPS ? "[WPS]" : ""),
1156281806Srpaulo			  (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
1157281806Srpaulo			  (flags & WLAN_STA_WDS ? "[WDS]" : ""),
1158281806Srpaulo			  (flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
1159281806Srpaulo			  (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
1160281806Srpaulo			  (flags & WLAN_STA_GAS ? "[GAS]" : ""),
1161281806Srpaulo			  (flags & WLAN_STA_VHT ? "[VHT]" : ""),
1162281806Srpaulo			  (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
1163281806Srpaulo			  (flags & WLAN_STA_WNM_SLEEP_MODE ?
1164281806Srpaulo			   "[WNM_SLEEP_MODE]" : ""));
1165281806Srpaulo	if (os_snprintf_error(buflen, res))
1166281806Srpaulo		res = -1;
1167281806Srpaulo
1168281806Srpaulo	return res;
1169281806Srpaulo}
1170