xref: /freebsd/contrib/wpa/src/ap/sta_info.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * hostapd / Station table
385732ac8SCy Schubert  * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "utils/includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "utils/common.h"
12e28a4053SRui Paulo #include "utils/eloop.h"
13e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
14f05cddf9SRui Paulo #include "common/wpa_ctrl.h"
155b9c547cSRui Paulo #include "common/sae.h"
164bc52338SCy Schubert #include "common/dpp.h"
17e28a4053SRui Paulo #include "radius/radius.h"
18e28a4053SRui Paulo #include "radius/radius_client.h"
19f05cddf9SRui Paulo #include "p2p/p2p.h"
20325151a3SRui Paulo #include "fst/fst.h"
2185732ac8SCy Schubert #include "crypto/crypto.h"
22e28a4053SRui Paulo #include "hostapd.h"
23e28a4053SRui Paulo #include "accounting.h"
24e28a4053SRui Paulo #include "ieee802_1x.h"
25e28a4053SRui Paulo #include "ieee802_11.h"
26f05cddf9SRui Paulo #include "ieee802_11_auth.h"
27e28a4053SRui Paulo #include "wpa_auth.h"
28e28a4053SRui Paulo #include "preauth_auth.h"
29e28a4053SRui Paulo #include "ap_config.h"
30e28a4053SRui Paulo #include "beacon.h"
31e28a4053SRui Paulo #include "ap_mlme.h"
32e28a4053SRui Paulo #include "vlan_init.h"
33f05cddf9SRui Paulo #include "p2p_hostapd.h"
34f05cddf9SRui Paulo #include "ap_drv_ops.h"
35f05cddf9SRui Paulo #include "gas_serv.h"
365b9c547cSRui Paulo #include "wnm_ap.h"
37780fb4a2SCy Schubert #include "mbo_ap.h"
385b9c547cSRui Paulo #include "ndisc_snoop.h"
39e28a4053SRui Paulo #include "sta_info.h"
40780fb4a2SCy Schubert #include "vlan.h"
4185732ac8SCy Schubert #include "wps_hostapd.h"
42e28a4053SRui Paulo 
43e28a4053SRui Paulo static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
44e28a4053SRui Paulo 				       struct sta_info *sta);
45e28a4053SRui Paulo static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
465b9c547cSRui Paulo static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
47f05cddf9SRui Paulo static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
48f05cddf9SRui Paulo static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
49e28a4053SRui Paulo static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
50f05cddf9SRui Paulo static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
5185732ac8SCy Schubert static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
52e28a4053SRui Paulo 
53e28a4053SRui Paulo int ap_for_each_sta(struct hostapd_data *hapd,
54e28a4053SRui Paulo 		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
55e28a4053SRui Paulo 			      void *ctx),
56e28a4053SRui Paulo 		    void *ctx)
57e28a4053SRui Paulo {
58e28a4053SRui Paulo 	struct sta_info *sta;
59e28a4053SRui Paulo 
60e28a4053SRui Paulo 	for (sta = hapd->sta_list; sta; sta = sta->next) {
61e28a4053SRui Paulo 		if (cb(hapd, sta, ctx))
62e28a4053SRui Paulo 			return 1;
63e28a4053SRui Paulo 	}
64e28a4053SRui Paulo 
65e28a4053SRui Paulo 	return 0;
66e28a4053SRui Paulo }
67e28a4053SRui Paulo 
68e28a4053SRui Paulo 
69e28a4053SRui Paulo struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
70e28a4053SRui Paulo {
71e28a4053SRui Paulo 	struct sta_info *s;
72e28a4053SRui Paulo 
73e28a4053SRui Paulo 	s = hapd->sta_hash[STA_HASH(sta)];
74e28a4053SRui Paulo 	while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
75e28a4053SRui Paulo 		s = s->hnext;
76e28a4053SRui Paulo 	return s;
77e28a4053SRui Paulo }
78e28a4053SRui Paulo 
79e28a4053SRui Paulo 
805b9c547cSRui Paulo #ifdef CONFIG_P2P
815b9c547cSRui Paulo struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
825b9c547cSRui Paulo {
835b9c547cSRui Paulo 	struct sta_info *sta;
845b9c547cSRui Paulo 
855b9c547cSRui Paulo 	for (sta = hapd->sta_list; sta; sta = sta->next) {
865b9c547cSRui Paulo 		const u8 *p2p_dev_addr;
875b9c547cSRui Paulo 
885b9c547cSRui Paulo 		if (sta->p2p_ie == NULL)
895b9c547cSRui Paulo 			continue;
905b9c547cSRui Paulo 
915b9c547cSRui Paulo 		p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
925b9c547cSRui Paulo 		if (p2p_dev_addr == NULL)
935b9c547cSRui Paulo 			continue;
945b9c547cSRui Paulo 
955b9c547cSRui Paulo 		if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0)
965b9c547cSRui Paulo 			return sta;
975b9c547cSRui Paulo 	}
985b9c547cSRui Paulo 
995b9c547cSRui Paulo 	return NULL;
1005b9c547cSRui Paulo }
1015b9c547cSRui Paulo #endif /* CONFIG_P2P */
1025b9c547cSRui Paulo 
1035b9c547cSRui Paulo 
104e28a4053SRui Paulo static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
105e28a4053SRui Paulo {
106e28a4053SRui Paulo 	struct sta_info *tmp;
107e28a4053SRui Paulo 
108e28a4053SRui Paulo 	if (hapd->sta_list == sta) {
109e28a4053SRui Paulo 		hapd->sta_list = sta->next;
110e28a4053SRui Paulo 		return;
111e28a4053SRui Paulo 	}
112e28a4053SRui Paulo 
113e28a4053SRui Paulo 	tmp = hapd->sta_list;
114e28a4053SRui Paulo 	while (tmp != NULL && tmp->next != sta)
115e28a4053SRui Paulo 		tmp = tmp->next;
116e28a4053SRui Paulo 	if (tmp == NULL) {
117e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
118e28a4053SRui Paulo 			   "list.", MAC2STR(sta->addr));
119e28a4053SRui Paulo 	} else
120e28a4053SRui Paulo 		tmp->next = sta->next;
121e28a4053SRui Paulo }
122e28a4053SRui Paulo 
123e28a4053SRui Paulo 
124e28a4053SRui Paulo void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
125e28a4053SRui Paulo {
126e28a4053SRui Paulo 	sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
127e28a4053SRui Paulo 	hapd->sta_hash[STA_HASH(sta->addr)] = sta;
128e28a4053SRui Paulo }
129e28a4053SRui Paulo 
130e28a4053SRui Paulo 
131e28a4053SRui Paulo static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
132e28a4053SRui Paulo {
133e28a4053SRui Paulo 	struct sta_info *s;
134e28a4053SRui Paulo 
135e28a4053SRui Paulo 	s = hapd->sta_hash[STA_HASH(sta->addr)];
136e28a4053SRui Paulo 	if (s == NULL) return;
137e28a4053SRui Paulo 	if (os_memcmp(s->addr, sta->addr, 6) == 0) {
138e28a4053SRui Paulo 		hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
139e28a4053SRui Paulo 		return;
140e28a4053SRui Paulo 	}
141e28a4053SRui Paulo 
142e28a4053SRui Paulo 	while (s->hnext != NULL &&
143e28a4053SRui Paulo 	       os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
144e28a4053SRui Paulo 		s = s->hnext;
145e28a4053SRui Paulo 	if (s->hnext != NULL)
146e28a4053SRui Paulo 		s->hnext = s->hnext->hnext;
147e28a4053SRui Paulo 	else
148e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
149e28a4053SRui Paulo 			   " from hash table", MAC2STR(sta->addr));
150e28a4053SRui Paulo }
151e28a4053SRui Paulo 
152e28a4053SRui Paulo 
1535b9c547cSRui Paulo void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
1545b9c547cSRui Paulo {
1555b9c547cSRui Paulo 	sta_ip6addr_del(hapd, sta);
1565b9c547cSRui Paulo }
1575b9c547cSRui Paulo 
1585b9c547cSRui Paulo 
159*c1d255d3SCy Schubert #ifdef CONFIG_PASN
160*c1d255d3SCy Schubert 
161*c1d255d3SCy Schubert void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
162*c1d255d3SCy Schubert {
163*c1d255d3SCy Schubert 	if (sta->pasn) {
164*c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR,
165*c1d255d3SCy Schubert 			   MAC2STR(sta->addr));
166*c1d255d3SCy Schubert 
167*c1d255d3SCy Schubert 		if (sta->pasn->ecdh)
168*c1d255d3SCy Schubert 			crypto_ecdh_deinit(sta->pasn->ecdh);
169*c1d255d3SCy Schubert 
170*c1d255d3SCy Schubert 		wpabuf_free(sta->pasn->secret);
171*c1d255d3SCy Schubert 		sta->pasn->secret = NULL;
172*c1d255d3SCy Schubert 
173*c1d255d3SCy Schubert #ifdef CONFIG_SAE
174*c1d255d3SCy Schubert 		sae_clear_data(&sta->pasn->sae);
175*c1d255d3SCy Schubert #endif /* CONFIG_SAE */
176*c1d255d3SCy Schubert 
177*c1d255d3SCy Schubert #ifdef CONFIG_FILS
178*c1d255d3SCy Schubert 		/* In practice this pointer should be NULL */
179*c1d255d3SCy Schubert 		wpabuf_free(sta->pasn->fils.erp_resp);
180*c1d255d3SCy Schubert 		sta->pasn->fils.erp_resp = NULL;
181*c1d255d3SCy Schubert #endif /* CONFIG_FILS */
182*c1d255d3SCy Schubert 
183*c1d255d3SCy Schubert 		bin_clear_free(sta->pasn, sizeof(*sta->pasn));
184*c1d255d3SCy Schubert 		sta->pasn = NULL;
185*c1d255d3SCy Schubert 	}
186*c1d255d3SCy Schubert }
187*c1d255d3SCy Schubert 
188*c1d255d3SCy Schubert #endif /* CONFIG_PASN */
189*c1d255d3SCy Schubert 
190e28a4053SRui Paulo void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
191e28a4053SRui Paulo {
192e28a4053SRui Paulo 	int set_beacon = 0;
193e28a4053SRui Paulo 
194e28a4053SRui Paulo 	accounting_sta_stop(hapd, sta);
195e28a4053SRui Paulo 
196f05cddf9SRui Paulo 	/* just in case */
197f05cddf9SRui Paulo 	ap_sta_set_authorized(hapd, sta, 0);
198*c1d255d3SCy Schubert 	hostapd_set_sta_flags(hapd, sta);
199f05cddf9SRui Paulo 
2004bc52338SCy Schubert 	if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP))
2015b9c547cSRui Paulo 		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
202e28a4053SRui Paulo 
2035b9c547cSRui Paulo 	if (sta->ipaddr)
2045b9c547cSRui Paulo 		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
2055b9c547cSRui Paulo 	ap_sta_ip6addr_del(hapd, sta);
2065b9c547cSRui Paulo 
2075b9c547cSRui Paulo 	if (!hapd->iface->driver_ap_teardown &&
208780fb4a2SCy Schubert 	    !(sta->flags & WLAN_STA_PREAUTH)) {
209f05cddf9SRui Paulo 		hostapd_drv_sta_remove(hapd, sta->addr);
210780fb4a2SCy Schubert 		sta->added_unassoc = 0;
211325151a3SRui Paulo 	}
212325151a3SRui Paulo 
213e28a4053SRui Paulo 	ap_sta_hash_del(hapd, sta);
214e28a4053SRui Paulo 	ap_sta_list_del(hapd, sta);
215e28a4053SRui Paulo 
216e28a4053SRui Paulo 	if (sta->aid > 0)
217e28a4053SRui Paulo 		hapd->sta_aid[(sta->aid - 1) / 32] &=
218e28a4053SRui Paulo 			~BIT((sta->aid - 1) % 32);
219e28a4053SRui Paulo 
220e28a4053SRui Paulo 	hapd->num_sta--;
221e28a4053SRui Paulo 	if (sta->nonerp_set) {
222e28a4053SRui Paulo 		sta->nonerp_set = 0;
223e28a4053SRui Paulo 		hapd->iface->num_sta_non_erp--;
224e28a4053SRui Paulo 		if (hapd->iface->num_sta_non_erp == 0)
225e28a4053SRui Paulo 			set_beacon++;
226e28a4053SRui Paulo 	}
227e28a4053SRui Paulo 
228e28a4053SRui Paulo 	if (sta->no_short_slot_time_set) {
229e28a4053SRui Paulo 		sta->no_short_slot_time_set = 0;
230e28a4053SRui Paulo 		hapd->iface->num_sta_no_short_slot_time--;
23185732ac8SCy Schubert 		if (hapd->iface->current_mode &&
23285732ac8SCy Schubert 		    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
233e28a4053SRui Paulo 		    && hapd->iface->num_sta_no_short_slot_time == 0)
234e28a4053SRui Paulo 			set_beacon++;
235e28a4053SRui Paulo 	}
236e28a4053SRui Paulo 
237e28a4053SRui Paulo 	if (sta->no_short_preamble_set) {
238e28a4053SRui Paulo 		sta->no_short_preamble_set = 0;
239e28a4053SRui Paulo 		hapd->iface->num_sta_no_short_preamble--;
24085732ac8SCy Schubert 		if (hapd->iface->current_mode &&
24185732ac8SCy Schubert 		    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
242e28a4053SRui Paulo 		    && hapd->iface->num_sta_no_short_preamble == 0)
243e28a4053SRui Paulo 			set_beacon++;
244e28a4053SRui Paulo 	}
245e28a4053SRui Paulo 
246e28a4053SRui Paulo 	if (sta->no_ht_gf_set) {
247e28a4053SRui Paulo 		sta->no_ht_gf_set = 0;
248e28a4053SRui Paulo 		hapd->iface->num_sta_ht_no_gf--;
249e28a4053SRui Paulo 	}
250e28a4053SRui Paulo 
251e28a4053SRui Paulo 	if (sta->no_ht_set) {
252e28a4053SRui Paulo 		sta->no_ht_set = 0;
253e28a4053SRui Paulo 		hapd->iface->num_sta_no_ht--;
254e28a4053SRui Paulo 	}
255e28a4053SRui Paulo 
256e28a4053SRui Paulo 	if (sta->ht_20mhz_set) {
257e28a4053SRui Paulo 		sta->ht_20mhz_set = 0;
258e28a4053SRui Paulo 		hapd->iface->num_sta_ht_20mhz--;
259e28a4053SRui Paulo 	}
260e28a4053SRui Paulo 
261780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY
262780fb4a2SCy Schubert 	wpabuf_free(sta->probe_ie_taxonomy);
263780fb4a2SCy Schubert 	sta->probe_ie_taxonomy = NULL;
264780fb4a2SCy Schubert 	wpabuf_free(sta->assoc_ie_taxonomy);
265780fb4a2SCy Schubert 	sta->assoc_ie_taxonomy = NULL;
266780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */
267780fb4a2SCy Schubert 
2685b9c547cSRui Paulo 	ht40_intolerant_remove(hapd->iface, sta);
2695b9c547cSRui Paulo 
270f05cddf9SRui Paulo #ifdef CONFIG_P2P
271f05cddf9SRui Paulo 	if (sta->no_p2p_set) {
272f05cddf9SRui Paulo 		sta->no_p2p_set = 0;
273f05cddf9SRui Paulo 		hapd->num_sta_no_p2p--;
274f05cddf9SRui Paulo 		if (hapd->num_sta_no_p2p == 0)
275f05cddf9SRui Paulo 			hostapd_p2p_non_p2p_sta_disconnected(hapd);
276f05cddf9SRui Paulo 	}
277f05cddf9SRui Paulo #endif /* CONFIG_P2P */
278f05cddf9SRui Paulo 
279*c1d255d3SCy Schubert #ifdef NEED_AP_MLME
280e28a4053SRui Paulo 	if (hostapd_ht_operation_update(hapd->iface) > 0)
281e28a4053SRui Paulo 		set_beacon++;
282*c1d255d3SCy Schubert #endif /* NEED_AP_MLME */
283e28a4053SRui Paulo 
2845b9c547cSRui Paulo #ifdef CONFIG_MESH
2855b9c547cSRui Paulo 	if (hapd->mesh_sta_free_cb)
286780fb4a2SCy Schubert 		hapd->mesh_sta_free_cb(hapd, sta);
2875b9c547cSRui Paulo #endif /* CONFIG_MESH */
2885b9c547cSRui Paulo 
289e28a4053SRui Paulo 	if (set_beacon)
290e28a4053SRui Paulo 		ieee802_11_set_beacons(hapd->iface);
291e28a4053SRui Paulo 
292f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
293f05cddf9SRui Paulo 		   __func__, MAC2STR(sta->addr));
294e28a4053SRui Paulo 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
295e28a4053SRui Paulo 	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
2965b9c547cSRui Paulo 	eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
297780fb4a2SCy Schubert 	ap_sta_clear_disconnect_timeouts(hapd, sta);
2985b9c547cSRui Paulo 	sae_clear_retransmit_timer(hapd, sta);
299e28a4053SRui Paulo 
300780fb4a2SCy Schubert 	ieee802_1x_free_station(hapd, sta);
301e28a4053SRui Paulo 	wpa_auth_sta_deinit(sta->wpa_sm);
302e28a4053SRui Paulo 	rsn_preauth_free_station(hapd, sta);
303e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
3045b9c547cSRui Paulo 	if (hapd->radius)
305e28a4053SRui Paulo 		radius_client_flush_auth(hapd->radius, sta->addr);
306e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
307e28a4053SRui Paulo 
308780fb4a2SCy Schubert #ifndef CONFIG_NO_VLAN
309780fb4a2SCy Schubert 	/*
310780fb4a2SCy Schubert 	 * sta->wpa_sm->group needs to be released before so that
311780fb4a2SCy Schubert 	 * vlan_remove_dynamic() can check that no stations are left on the
312780fb4a2SCy Schubert 	 * AP_VLAN netdev.
313780fb4a2SCy Schubert 	 */
314780fb4a2SCy Schubert 	if (sta->vlan_id)
315780fb4a2SCy Schubert 		vlan_remove_dynamic(hapd, sta->vlan_id);
316780fb4a2SCy Schubert 	if (sta->vlan_id_bound) {
317780fb4a2SCy Schubert 		/*
318780fb4a2SCy Schubert 		 * Need to remove the STA entry before potentially removing the
319780fb4a2SCy Schubert 		 * VLAN.
320780fb4a2SCy Schubert 		 */
321780fb4a2SCy Schubert 		if (hapd->iface->driver_ap_teardown &&
322780fb4a2SCy Schubert 		    !(sta->flags & WLAN_STA_PREAUTH)) {
323780fb4a2SCy Schubert 			hostapd_drv_sta_remove(hapd, sta->addr);
324780fb4a2SCy Schubert 			sta->added_unassoc = 0;
325780fb4a2SCy Schubert 		}
326780fb4a2SCy Schubert 		vlan_remove_dynamic(hapd, sta->vlan_id_bound);
327780fb4a2SCy Schubert 	}
328780fb4a2SCy Schubert #endif /* CONFIG_NO_VLAN */
329780fb4a2SCy Schubert 
330e28a4053SRui Paulo 	os_free(sta->challenge);
331e28a4053SRui Paulo 
332e28a4053SRui Paulo 	os_free(sta->sa_query_trans_id);
333e28a4053SRui Paulo 	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
334e28a4053SRui Paulo 
335f05cddf9SRui Paulo #ifdef CONFIG_P2P
336f05cddf9SRui Paulo 	p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
337f05cddf9SRui Paulo #endif /* CONFIG_P2P */
338f05cddf9SRui Paulo 
339f05cddf9SRui Paulo #ifdef CONFIG_INTERWORKING
340f05cddf9SRui Paulo 	if (sta->gas_dialog) {
341f05cddf9SRui Paulo 		int i;
342f05cddf9SRui Paulo 		for (i = 0; i < GAS_DIALOG_MAX; i++)
343f05cddf9SRui Paulo 			gas_serv_dialog_clear(&sta->gas_dialog[i]);
344f05cddf9SRui Paulo 		os_free(sta->gas_dialog);
345f05cddf9SRui Paulo 	}
346f05cddf9SRui Paulo #endif /* CONFIG_INTERWORKING */
347f05cddf9SRui Paulo 
348e28a4053SRui Paulo 	wpabuf_free(sta->wps_ie);
349f05cddf9SRui Paulo 	wpabuf_free(sta->p2p_ie);
350f05cddf9SRui Paulo 	wpabuf_free(sta->hs20_ie);
35185732ac8SCy Schubert 	wpabuf_free(sta->roaming_consortium);
352325151a3SRui Paulo #ifdef CONFIG_FST
353325151a3SRui Paulo 	wpabuf_free(sta->mb_ies);
354325151a3SRui Paulo #endif /* CONFIG_FST */
355e28a4053SRui Paulo 
356e28a4053SRui Paulo 	os_free(sta->ht_capabilities);
3575b9c547cSRui Paulo 	os_free(sta->vht_capabilities);
3584bc52338SCy Schubert 	os_free(sta->vht_operation);
359206b73d0SCy Schubert 	os_free(sta->he_capab);
360*c1d255d3SCy Schubert 	os_free(sta->he_6ghz_capab);
361f05cddf9SRui Paulo 	hostapd_free_psk_list(sta->psk);
362f05cddf9SRui Paulo 	os_free(sta->identity);
363f05cddf9SRui Paulo 	os_free(sta->radius_cui);
3645b9c547cSRui Paulo 	os_free(sta->remediation_url);
36585732ac8SCy Schubert 	os_free(sta->t_c_url);
3665b9c547cSRui Paulo 	wpabuf_free(sta->hs20_deauth_req);
3675b9c547cSRui Paulo 	os_free(sta->hs20_session_info_url);
3685b9c547cSRui Paulo 
3695b9c547cSRui Paulo #ifdef CONFIG_SAE
3705b9c547cSRui Paulo 	sae_clear_data(sta->sae);
3715b9c547cSRui Paulo 	os_free(sta->sae);
3725b9c547cSRui Paulo #endif /* CONFIG_SAE */
373e28a4053SRui Paulo 
374780fb4a2SCy Schubert 	mbo_ap_sta_free(sta);
375780fb4a2SCy Schubert 	os_free(sta->supp_op_classes);
376780fb4a2SCy Schubert 
37785732ac8SCy Schubert #ifdef CONFIG_FILS
37885732ac8SCy Schubert 	os_free(sta->fils_pending_assoc_req);
37985732ac8SCy Schubert 	wpabuf_free(sta->fils_hlp_resp);
38085732ac8SCy Schubert 	wpabuf_free(sta->hlp_dhcp_discover);
38185732ac8SCy Schubert 	eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
38285732ac8SCy Schubert #ifdef CONFIG_FILS_SK_PFS
38385732ac8SCy Schubert 	crypto_ecdh_deinit(sta->fils_ecdh);
38485732ac8SCy Schubert 	wpabuf_clear_free(sta->fils_dh_ss);
38585732ac8SCy Schubert 	wpabuf_free(sta->fils_g_sta);
38685732ac8SCy Schubert #endif /* CONFIG_FILS_SK_PFS */
38785732ac8SCy Schubert #endif /* CONFIG_FILS */
38885732ac8SCy Schubert 
38985732ac8SCy Schubert #ifdef CONFIG_OWE
39085732ac8SCy Schubert 	bin_clear_free(sta->owe_pmk, sta->owe_pmk_len);
39185732ac8SCy Schubert 	crypto_ecdh_deinit(sta->owe_ecdh);
39285732ac8SCy Schubert #endif /* CONFIG_OWE */
39385732ac8SCy Schubert 
3944bc52338SCy Schubert #ifdef CONFIG_DPP2
3954bc52338SCy Schubert 	dpp_pfs_free(sta->dpp_pfs);
3964bc52338SCy Schubert 	sta->dpp_pfs = NULL;
3974bc52338SCy Schubert #endif /* CONFIG_DPP2 */
3984bc52338SCy Schubert 
39985732ac8SCy Schubert 	os_free(sta->ext_capability);
40085732ac8SCy Schubert 
40185732ac8SCy Schubert #ifdef CONFIG_WNM_AP
40285732ac8SCy Schubert 	eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
40385732ac8SCy Schubert #endif /* CONFIG_WNM_AP */
40485732ac8SCy Schubert 
405*c1d255d3SCy Schubert #ifdef CONFIG_PASN
406*c1d255d3SCy Schubert 	ap_free_sta_pasn(hapd, sta);
407*c1d255d3SCy Schubert #endif /* CONFIG_PASN */
408*c1d255d3SCy Schubert 
40985732ac8SCy Schubert 	os_free(sta->ifname_wds);
41085732ac8SCy Schubert 
411*c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
412*c1d255d3SCy Schubert 	os_free(sta->sae_postponed_commit);
413*c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
414*c1d255d3SCy Schubert 
415e28a4053SRui Paulo 	os_free(sta);
416e28a4053SRui Paulo }
417e28a4053SRui Paulo 
418e28a4053SRui Paulo 
419e28a4053SRui Paulo void hostapd_free_stas(struct hostapd_data *hapd)
420e28a4053SRui Paulo {
421e28a4053SRui Paulo 	struct sta_info *sta, *prev;
422e28a4053SRui Paulo 
423e28a4053SRui Paulo 	sta = hapd->sta_list;
424e28a4053SRui Paulo 
425e28a4053SRui Paulo 	while (sta) {
426e28a4053SRui Paulo 		prev = sta;
427e28a4053SRui Paulo 		if (sta->flags & WLAN_STA_AUTH) {
428e28a4053SRui Paulo 			mlme_deauthenticate_indication(
429e28a4053SRui Paulo 				hapd, sta, WLAN_REASON_UNSPECIFIED);
430e28a4053SRui Paulo 		}
431e28a4053SRui Paulo 		sta = sta->next;
432e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
433e28a4053SRui Paulo 			   MAC2STR(prev->addr));
434e28a4053SRui Paulo 		ap_free_sta(hapd, prev);
435e28a4053SRui Paulo 	}
436e28a4053SRui Paulo }
437e28a4053SRui Paulo 
438e28a4053SRui Paulo 
439e28a4053SRui Paulo /**
440e28a4053SRui Paulo  * ap_handle_timer - Per STA timer handler
441e28a4053SRui Paulo  * @eloop_ctx: struct hostapd_data *
442e28a4053SRui Paulo  * @timeout_ctx: struct sta_info *
443e28a4053SRui Paulo  *
444e28a4053SRui Paulo  * This function is called to check station activity and to remove inactive
445e28a4053SRui Paulo  * stations.
446e28a4053SRui Paulo  */
447e28a4053SRui Paulo void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
448e28a4053SRui Paulo {
449e28a4053SRui Paulo 	struct hostapd_data *hapd = eloop_ctx;
450e28a4053SRui Paulo 	struct sta_info *sta = timeout_ctx;
451e28a4053SRui Paulo 	unsigned long next_time = 0;
4525b9c547cSRui Paulo 	int reason;
453e28a4053SRui Paulo 
454780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
455780fb4a2SCy Schubert 		   hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
456f05cddf9SRui Paulo 		   sta->timeout_next);
457e28a4053SRui Paulo 	if (sta->timeout_next == STA_REMOVE) {
458e28a4053SRui Paulo 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
459e28a4053SRui Paulo 			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
460e28a4053SRui Paulo 			       "local deauth request");
461e28a4053SRui Paulo 		ap_free_sta(hapd, sta);
462e28a4053SRui Paulo 		return;
463e28a4053SRui Paulo 	}
464e28a4053SRui Paulo 
465e28a4053SRui Paulo 	if ((sta->flags & WLAN_STA_ASSOC) &&
466e28a4053SRui Paulo 	    (sta->timeout_next == STA_NULLFUNC ||
467e28a4053SRui Paulo 	     sta->timeout_next == STA_DISASSOC)) {
468e28a4053SRui Paulo 		int inactive_sec;
469f05cddf9SRui Paulo 		/*
470f05cddf9SRui Paulo 		 * Add random value to timeout so that we don't end up bouncing
471f05cddf9SRui Paulo 		 * all stations at the same time if we have lots of associated
472f05cddf9SRui Paulo 		 * stations that are idle (but keep re-associating).
473f05cddf9SRui Paulo 		 */
474f05cddf9SRui Paulo 		int fuzz = os_random() % 20;
475f05cddf9SRui Paulo 		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
476e28a4053SRui Paulo 		if (inactive_sec == -1) {
477f05cddf9SRui Paulo 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
478f05cddf9SRui Paulo 				"Check inactivity: Could not "
479f05cddf9SRui Paulo 				"get station info from kernel driver for "
480f05cddf9SRui Paulo 				MACSTR, MAC2STR(sta->addr));
481f05cddf9SRui Paulo 			/*
482f05cddf9SRui Paulo 			 * The driver may not support this functionality.
483f05cddf9SRui Paulo 			 * Anyway, try again after the next inactivity timeout,
484f05cddf9SRui Paulo 			 * but do not disconnect the station now.
485f05cddf9SRui Paulo 			 */
486f05cddf9SRui Paulo 			next_time = hapd->conf->ap_max_inactivity + fuzz;
4875b9c547cSRui Paulo 		} else if (inactive_sec == -ENOENT) {
4885b9c547cSRui Paulo 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
4895b9c547cSRui Paulo 				"Station " MACSTR " has lost its driver entry",
4905b9c547cSRui Paulo 				MAC2STR(sta->addr));
4915b9c547cSRui Paulo 
4925b9c547cSRui Paulo 			/* Avoid sending client probe on removed client */
4935b9c547cSRui Paulo 			sta->timeout_next = STA_DISASSOC;
4945b9c547cSRui Paulo 			goto skip_poll;
4955b9c547cSRui Paulo 		} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
496e28a4053SRui Paulo 			/* station activity detected; reset timeout state */
497f05cddf9SRui Paulo 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
498f05cddf9SRui Paulo 				"Station " MACSTR " has been active %is ago",
499f05cddf9SRui Paulo 				MAC2STR(sta->addr), inactive_sec);
500e28a4053SRui Paulo 			sta->timeout_next = STA_NULLFUNC;
501f05cddf9SRui Paulo 			next_time = hapd->conf->ap_max_inactivity + fuzz -
502e28a4053SRui Paulo 				inactive_sec;
503f05cddf9SRui Paulo 		} else {
504f05cddf9SRui Paulo 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
505f05cddf9SRui Paulo 				"Station " MACSTR " has been "
506f05cddf9SRui Paulo 				"inactive too long: %d sec, max allowed: %d",
507f05cddf9SRui Paulo 				MAC2STR(sta->addr), inactive_sec,
508f05cddf9SRui Paulo 				hapd->conf->ap_max_inactivity);
509f05cddf9SRui Paulo 
510f05cddf9SRui Paulo 			if (hapd->conf->skip_inactivity_poll)
511f05cddf9SRui Paulo 				sta->timeout_next = STA_DISASSOC;
512e28a4053SRui Paulo 		}
513e28a4053SRui Paulo 	}
514e28a4053SRui Paulo 
515e28a4053SRui Paulo 	if ((sta->flags & WLAN_STA_ASSOC) &&
516e28a4053SRui Paulo 	    sta->timeout_next == STA_DISASSOC &&
517f05cddf9SRui Paulo 	    !(sta->flags & WLAN_STA_PENDING_POLL) &&
518f05cddf9SRui Paulo 	    !hapd->conf->skip_inactivity_poll) {
519f05cddf9SRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
520f05cddf9SRui Paulo 			" has ACKed data poll", MAC2STR(sta->addr));
521e28a4053SRui Paulo 		/* data nullfunc frame poll did not produce TX errors; assume
522e28a4053SRui Paulo 		 * station ACKed it */
523e28a4053SRui Paulo 		sta->timeout_next = STA_NULLFUNC;
524e28a4053SRui Paulo 		next_time = hapd->conf->ap_max_inactivity;
525e28a4053SRui Paulo 	}
526e28a4053SRui Paulo 
5275b9c547cSRui Paulo skip_poll:
528e28a4053SRui Paulo 	if (next_time) {
529f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
530f05cddf9SRui Paulo 			   "for " MACSTR " (%lu seconds)",
531f05cddf9SRui Paulo 			   __func__, MAC2STR(sta->addr), next_time);
532e28a4053SRui Paulo 		eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
533e28a4053SRui Paulo 				       sta);
534e28a4053SRui Paulo 		return;
535e28a4053SRui Paulo 	}
536e28a4053SRui Paulo 
537e28a4053SRui Paulo 	if (sta->timeout_next == STA_NULLFUNC &&
538e28a4053SRui Paulo 	    (sta->flags & WLAN_STA_ASSOC)) {
539f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "  Polling STA");
540e28a4053SRui Paulo 		sta->flags |= WLAN_STA_PENDING_POLL;
541f05cddf9SRui Paulo 		hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
542f05cddf9SRui Paulo 					sta->flags & WLAN_STA_WMM);
543e28a4053SRui Paulo 	} else if (sta->timeout_next != STA_REMOVE) {
544e28a4053SRui Paulo 		int deauth = sta->timeout_next == STA_DEAUTH;
545e28a4053SRui Paulo 
5464bc52338SCy Schubert 		if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) {
5474bc52338SCy Schubert 			/* Cannot disassociate not-associated STA, so move
5484bc52338SCy Schubert 			 * directly to deauthentication. */
5494bc52338SCy Schubert 			sta->timeout_next = STA_DEAUTH;
5504bc52338SCy Schubert 			deauth = 1;
5514bc52338SCy Schubert 		}
5524bc52338SCy Schubert 
553f05cddf9SRui Paulo 		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
554f05cddf9SRui Paulo 			"Timeout, sending %s info to STA " MACSTR,
555e28a4053SRui Paulo 			deauth ? "deauthentication" : "disassociation",
556e28a4053SRui Paulo 			MAC2STR(sta->addr));
557e28a4053SRui Paulo 
558e28a4053SRui Paulo 		if (deauth) {
559f05cddf9SRui Paulo 			hostapd_drv_sta_deauth(
560f05cddf9SRui Paulo 				hapd, sta->addr,
561e28a4053SRui Paulo 				WLAN_REASON_PREV_AUTH_NOT_VALID);
562e28a4053SRui Paulo 		} else {
5635b9c547cSRui Paulo 			reason = (sta->timeout_next == STA_DISASSOC) ?
5645b9c547cSRui Paulo 				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
5655b9c547cSRui Paulo 				WLAN_REASON_PREV_AUTH_NOT_VALID;
5665b9c547cSRui Paulo 
5675b9c547cSRui Paulo 			hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
568e28a4053SRui Paulo 		}
569e28a4053SRui Paulo 	}
570e28a4053SRui Paulo 
571e28a4053SRui Paulo 	switch (sta->timeout_next) {
572e28a4053SRui Paulo 	case STA_NULLFUNC:
573e28a4053SRui Paulo 		sta->timeout_next = STA_DISASSOC;
574f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
575f05cddf9SRui Paulo 			   "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
576f05cddf9SRui Paulo 			   __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
577e28a4053SRui Paulo 		eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
578e28a4053SRui Paulo 				       hapd, sta);
579e28a4053SRui Paulo 		break;
580e28a4053SRui Paulo 	case STA_DISASSOC:
5815b9c547cSRui Paulo 	case STA_DISASSOC_FROM_CLI:
582f05cddf9SRui Paulo 		ap_sta_set_authorized(hapd, sta, 0);
583e28a4053SRui Paulo 		sta->flags &= ~WLAN_STA_ASSOC;
584*c1d255d3SCy Schubert 		hostapd_set_sta_flags(hapd, sta);
585e28a4053SRui Paulo 		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
586e28a4053SRui Paulo 		if (!sta->acct_terminate_cause)
587e28a4053SRui Paulo 			sta->acct_terminate_cause =
588e28a4053SRui Paulo 				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
589e28a4053SRui Paulo 		accounting_sta_stop(hapd, sta);
590780fb4a2SCy Schubert 		ieee802_1x_free_station(hapd, sta);
591e28a4053SRui Paulo 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
592e28a4053SRui Paulo 			       HOSTAPD_LEVEL_INFO, "disassociated due to "
593e28a4053SRui Paulo 			       "inactivity");
5945b9c547cSRui Paulo 		reason = (sta->timeout_next == STA_DISASSOC) ?
5955b9c547cSRui Paulo 			WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
5965b9c547cSRui Paulo 			WLAN_REASON_PREV_AUTH_NOT_VALID;
597e28a4053SRui Paulo 		sta->timeout_next = STA_DEAUTH;
598f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
599f05cddf9SRui Paulo 			   "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
600f05cddf9SRui Paulo 			   __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
601e28a4053SRui Paulo 		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
602e28a4053SRui Paulo 				       hapd, sta);
6035b9c547cSRui Paulo 		mlme_disassociate_indication(hapd, sta, reason);
604e28a4053SRui Paulo 		break;
605e28a4053SRui Paulo 	case STA_DEAUTH:
606e28a4053SRui Paulo 	case STA_REMOVE:
607e28a4053SRui Paulo 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
608e28a4053SRui Paulo 			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
609f05cddf9SRui Paulo 			       "inactivity (timer DEAUTH/REMOVE)");
610e28a4053SRui Paulo 		if (!sta->acct_terminate_cause)
611e28a4053SRui Paulo 			sta->acct_terminate_cause =
612e28a4053SRui Paulo 				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
613e28a4053SRui Paulo 		mlme_deauthenticate_indication(
614e28a4053SRui Paulo 			hapd, sta,
615e28a4053SRui Paulo 			WLAN_REASON_PREV_AUTH_NOT_VALID);
616e28a4053SRui Paulo 		ap_free_sta(hapd, sta);
617e28a4053SRui Paulo 		break;
618e28a4053SRui Paulo 	}
619e28a4053SRui Paulo }
620e28a4053SRui Paulo 
621e28a4053SRui Paulo 
622e28a4053SRui Paulo static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
623e28a4053SRui Paulo {
624e28a4053SRui Paulo 	struct hostapd_data *hapd = eloop_ctx;
625e28a4053SRui Paulo 	struct sta_info *sta = timeout_ctx;
626e28a4053SRui Paulo 
627780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
628780fb4a2SCy Schubert 		   hapd->conf->iface, MAC2STR(sta->addr));
629*c1d255d3SCy Schubert 	if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
630*c1d255d3SCy Schubert 			    WLAN_STA_AUTHORIZED))) {
631f05cddf9SRui Paulo 		if (sta->flags & WLAN_STA_GAS) {
632f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
633f05cddf9SRui Paulo 				   "entry " MACSTR, MAC2STR(sta->addr));
634f05cddf9SRui Paulo 			ap_free_sta(hapd, sta);
635f05cddf9SRui Paulo 		}
636e28a4053SRui Paulo 		return;
637f05cddf9SRui Paulo 	}
638e28a4053SRui Paulo 
6395b9c547cSRui Paulo 	hostapd_drv_sta_deauth(hapd, sta->addr,
6405b9c547cSRui Paulo 			       WLAN_REASON_PREV_AUTH_NOT_VALID);
641e28a4053SRui Paulo 	mlme_deauthenticate_indication(hapd, sta,
642e28a4053SRui Paulo 				       WLAN_REASON_PREV_AUTH_NOT_VALID);
643e28a4053SRui Paulo 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
644e28a4053SRui Paulo 		       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
645e28a4053SRui Paulo 		       "session timeout");
646e28a4053SRui Paulo 	sta->acct_terminate_cause =
647e28a4053SRui Paulo 		RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
648e28a4053SRui Paulo 	ap_free_sta(hapd, sta);
6495b9c547cSRui Paulo }
6505b9c547cSRui Paulo 
6515b9c547cSRui Paulo 
6525b9c547cSRui Paulo void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
6535b9c547cSRui Paulo 			      u32 session_timeout)
6545b9c547cSRui Paulo {
6555b9c547cSRui Paulo 	if (eloop_replenish_timeout(session_timeout, 0,
6565b9c547cSRui Paulo 				    ap_handle_session_timer, hapd, sta) == 1) {
6575b9c547cSRui Paulo 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
6585b9c547cSRui Paulo 			       HOSTAPD_LEVEL_DEBUG, "setting session timeout "
6595b9c547cSRui Paulo 			       "to %d seconds", session_timeout);
6605b9c547cSRui Paulo 	}
661e28a4053SRui Paulo }
662e28a4053SRui Paulo 
663e28a4053SRui Paulo 
664e28a4053SRui Paulo void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
665e28a4053SRui Paulo 			    u32 session_timeout)
666e28a4053SRui Paulo {
667e28a4053SRui Paulo 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
668e28a4053SRui Paulo 		       HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
669e28a4053SRui Paulo 		       "seconds", session_timeout);
670e28a4053SRui Paulo 	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
671e28a4053SRui Paulo 	eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
672e28a4053SRui Paulo 			       hapd, sta);
673e28a4053SRui Paulo }
674e28a4053SRui Paulo 
675e28a4053SRui Paulo 
676e28a4053SRui Paulo void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
677e28a4053SRui Paulo {
678e28a4053SRui Paulo 	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
679e28a4053SRui Paulo }
680e28a4053SRui Paulo 
681e28a4053SRui Paulo 
6825b9c547cSRui Paulo static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
6835b9c547cSRui Paulo {
68485732ac8SCy Schubert #ifdef CONFIG_WNM_AP
6855b9c547cSRui Paulo 	struct hostapd_data *hapd = eloop_ctx;
6865b9c547cSRui Paulo 	struct sta_info *sta = timeout_ctx;
6875b9c547cSRui Paulo 
688780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
689780fb4a2SCy Schubert 		   MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
6905b9c547cSRui Paulo 	if (sta->hs20_session_info_url == NULL)
6915b9c547cSRui Paulo 		return;
6925b9c547cSRui Paulo 
6935b9c547cSRui Paulo 	wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
6945b9c547cSRui Paulo 				       sta->hs20_disassoc_timer);
69585732ac8SCy Schubert #endif /* CONFIG_WNM_AP */
6965b9c547cSRui Paulo }
6975b9c547cSRui Paulo 
6985b9c547cSRui Paulo 
6995b9c547cSRui Paulo void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
7005b9c547cSRui Paulo 				    struct sta_info *sta, int warning_time)
7015b9c547cSRui Paulo {
7025b9c547cSRui Paulo 	eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
7035b9c547cSRui Paulo 	eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer,
7045b9c547cSRui Paulo 			       hapd, sta);
7055b9c547cSRui Paulo }
7065b9c547cSRui Paulo 
7075b9c547cSRui Paulo 
708e28a4053SRui Paulo struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
709e28a4053SRui Paulo {
710e28a4053SRui Paulo 	struct sta_info *sta;
711206b73d0SCy Schubert 	int i;
712e28a4053SRui Paulo 
713e28a4053SRui Paulo 	sta = ap_get_sta(hapd, addr);
714e28a4053SRui Paulo 	if (sta)
715e28a4053SRui Paulo 		return sta;
716e28a4053SRui Paulo 
717e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "  New STA");
718e28a4053SRui Paulo 	if (hapd->num_sta >= hapd->conf->max_num_sta) {
719e28a4053SRui Paulo 		/* FIX: might try to remove some old STAs first? */
720e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
721e28a4053SRui Paulo 			   hapd->num_sta, hapd->conf->max_num_sta);
722e28a4053SRui Paulo 		return NULL;
723e28a4053SRui Paulo 	}
724e28a4053SRui Paulo 
725e28a4053SRui Paulo 	sta = os_zalloc(sizeof(struct sta_info));
726e28a4053SRui Paulo 	if (sta == NULL) {
727e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "malloc failed");
728e28a4053SRui Paulo 		return NULL;
729e28a4053SRui Paulo 	}
730e28a4053SRui Paulo 	sta->acct_interim_interval = hapd->conf->acct_interim_interval;
731780fb4a2SCy Schubert 	if (accounting_sta_get_id(hapd, sta) < 0) {
732780fb4a2SCy Schubert 		os_free(sta);
733780fb4a2SCy Schubert 		return NULL;
734780fb4a2SCy Schubert 	}
735e28a4053SRui Paulo 
736206b73d0SCy Schubert 	for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
737206b73d0SCy Schubert 		if (!hapd->iface->basic_rates)
738206b73d0SCy Schubert 			break;
739206b73d0SCy Schubert 		if (hapd->iface->basic_rates[i] < 0)
740206b73d0SCy Schubert 			break;
741206b73d0SCy Schubert 		sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5;
742206b73d0SCy Schubert 	}
743206b73d0SCy Schubert 	sta->supported_rates_len = i;
744206b73d0SCy Schubert 
7455b9c547cSRui Paulo 	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
746f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
747f05cddf9SRui Paulo 			   "for " MACSTR " (%d seconds - ap_max_inactivity)",
748f05cddf9SRui Paulo 			   __func__, MAC2STR(addr),
749f05cddf9SRui Paulo 			   hapd->conf->ap_max_inactivity);
750e28a4053SRui Paulo 		eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
751e28a4053SRui Paulo 				       ap_handle_timer, hapd, sta);
7525b9c547cSRui Paulo 	}
7535b9c547cSRui Paulo 
7545b9c547cSRui Paulo 	/* initialize STA info data */
755e28a4053SRui Paulo 	os_memcpy(sta->addr, addr, ETH_ALEN);
756e28a4053SRui Paulo 	sta->next = hapd->sta_list;
757e28a4053SRui Paulo 	hapd->sta_list = sta;
758e28a4053SRui Paulo 	hapd->num_sta++;
759e28a4053SRui Paulo 	ap_sta_hash_add(hapd, sta);
760e28a4053SRui Paulo 	ap_sta_remove_in_other_bss(hapd, sta);
7615b9c547cSRui Paulo 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
7625b9c547cSRui Paulo 	dl_list_init(&sta->ip6addr);
763e28a4053SRui Paulo 
764780fb4a2SCy Schubert #ifdef CONFIG_TAXONOMY
765780fb4a2SCy Schubert 	sta_track_claim_taxonomy_info(hapd->iface, addr,
766780fb4a2SCy Schubert 				      &sta->probe_ie_taxonomy);
767780fb4a2SCy Schubert #endif /* CONFIG_TAXONOMY */
768780fb4a2SCy Schubert 
769e28a4053SRui Paulo 	return sta;
770e28a4053SRui Paulo }
771e28a4053SRui Paulo 
772e28a4053SRui Paulo 
773e28a4053SRui Paulo static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
774e28a4053SRui Paulo {
775e28a4053SRui Paulo 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
776e28a4053SRui Paulo 
7775b9c547cSRui Paulo 	if (sta->ipaddr)
7785b9c547cSRui Paulo 		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
7795b9c547cSRui Paulo 	ap_sta_ip6addr_del(hapd, sta);
7805b9c547cSRui Paulo 
781780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
782780fb4a2SCy Schubert 		   hapd->conf->iface, MAC2STR(sta->addr));
783f05cddf9SRui Paulo 	if (hostapd_drv_sta_remove(hapd, sta->addr) &&
784e28a4053SRui Paulo 	    sta->flags & WLAN_STA_ASSOC) {
785780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
786780fb4a2SCy Schubert 			   " from kernel driver",
787780fb4a2SCy Schubert 			   hapd->conf->iface, MAC2STR(sta->addr));
788e28a4053SRui Paulo 		return -1;
789e28a4053SRui Paulo 	}
790780fb4a2SCy Schubert 	sta->added_unassoc = 0;
791e28a4053SRui Paulo 	return 0;
792e28a4053SRui Paulo }
793e28a4053SRui Paulo 
794e28a4053SRui Paulo 
795e28a4053SRui Paulo static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
796e28a4053SRui Paulo 				       struct sta_info *sta)
797e28a4053SRui Paulo {
798e28a4053SRui Paulo 	struct hostapd_iface *iface = hapd->iface;
799e28a4053SRui Paulo 	size_t i;
800e28a4053SRui Paulo 
801e28a4053SRui Paulo 	for (i = 0; i < iface->num_bss; i++) {
802e28a4053SRui Paulo 		struct hostapd_data *bss = iface->bss[i];
803e28a4053SRui Paulo 		struct sta_info *sta2;
804e28a4053SRui Paulo 		/* bss should always be set during operation, but it may be
805e28a4053SRui Paulo 		 * NULL during reconfiguration. Assume the STA is not
806e28a4053SRui Paulo 		 * associated to another BSS in that case to avoid NULL pointer
807e28a4053SRui Paulo 		 * dereferences. */
808e28a4053SRui Paulo 		if (bss == hapd || bss == NULL)
809e28a4053SRui Paulo 			continue;
810e28a4053SRui Paulo 		sta2 = ap_get_sta(bss, sta->addr);
811e28a4053SRui Paulo 		if (!sta2)
812e28a4053SRui Paulo 			continue;
813e28a4053SRui Paulo 
814780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
815780fb4a2SCy Schubert 			   " association from another BSS %s",
816780fb4a2SCy Schubert 			   hapd->conf->iface, MAC2STR(sta2->addr),
817780fb4a2SCy Schubert 			   bss->conf->iface);
818e28a4053SRui Paulo 		ap_sta_disconnect(bss, sta2, sta2->addr,
819e28a4053SRui Paulo 				  WLAN_REASON_PREV_AUTH_NOT_VALID);
820e28a4053SRui Paulo 	}
821e28a4053SRui Paulo }
822e28a4053SRui Paulo 
823e28a4053SRui Paulo 
824f05cddf9SRui Paulo static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
825f05cddf9SRui Paulo {
826f05cddf9SRui Paulo 	struct hostapd_data *hapd = eloop_ctx;
827f05cddf9SRui Paulo 	struct sta_info *sta = timeout_ctx;
828f05cddf9SRui Paulo 
829780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
830780fb4a2SCy Schubert 		   hapd->conf->iface, MAC2STR(sta->addr));
831f05cddf9SRui Paulo 	ap_sta_remove(hapd, sta);
832f05cddf9SRui Paulo 	mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
833f05cddf9SRui Paulo }
834f05cddf9SRui Paulo 
835f05cddf9SRui Paulo 
836e28a4053SRui Paulo void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
837e28a4053SRui Paulo 			 u16 reason)
838e28a4053SRui Paulo {
839e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
840e28a4053SRui Paulo 		   hapd->conf->iface, MAC2STR(sta->addr));
8415b9c547cSRui Paulo 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
84285732ac8SCy Schubert 	if (hapd->iface->current_mode &&
84385732ac8SCy Schubert 	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
84485732ac8SCy Schubert 		/* Skip deauthentication in DMG/IEEE 802.11ad */
84585732ac8SCy Schubert 		sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
84685732ac8SCy Schubert 				WLAN_STA_ASSOC_REQ_OK);
84785732ac8SCy Schubert 		sta->timeout_next = STA_REMOVE;
84885732ac8SCy Schubert 	} else {
8495b9c547cSRui Paulo 		sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
850e28a4053SRui Paulo 		sta->timeout_next = STA_DEAUTH;
85185732ac8SCy Schubert 	}
85285732ac8SCy Schubert 	ap_sta_set_authorized(hapd, sta, 0);
853*c1d255d3SCy Schubert 	hostapd_set_sta_flags(hapd, sta);
854f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
855f05cddf9SRui Paulo 		   "for " MACSTR " (%d seconds - "
856f05cddf9SRui Paulo 		   "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
857f05cddf9SRui Paulo 		   __func__, MAC2STR(sta->addr),
858f05cddf9SRui Paulo 		   AP_MAX_INACTIVITY_AFTER_DISASSOC);
859e28a4053SRui Paulo 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
860e28a4053SRui Paulo 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
861e28a4053SRui Paulo 			       ap_handle_timer, hapd, sta);
862e28a4053SRui Paulo 	accounting_sta_stop(hapd, sta);
863780fb4a2SCy Schubert 	ieee802_1x_free_station(hapd, sta);
8644bc52338SCy Schubert 	wpa_auth_sta_deinit(sta->wpa_sm);
8654bc52338SCy Schubert 	sta->wpa_sm = NULL;
866e28a4053SRui Paulo 
867f05cddf9SRui Paulo 	sta->disassoc_reason = reason;
868f05cddf9SRui Paulo 	sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
869f05cddf9SRui Paulo 	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
870f05cddf9SRui Paulo 	eloop_register_timeout(hapd->iface->drv_flags &
871f05cddf9SRui Paulo 			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
872f05cddf9SRui Paulo 			       ap_sta_disassoc_cb_timeout, hapd, sta);
873f05cddf9SRui Paulo }
874f05cddf9SRui Paulo 
875f05cddf9SRui Paulo 
876f05cddf9SRui Paulo static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
877f05cddf9SRui Paulo {
878f05cddf9SRui Paulo 	struct hostapd_data *hapd = eloop_ctx;
879f05cddf9SRui Paulo 	struct sta_info *sta = timeout_ctx;
880f05cddf9SRui Paulo 
881780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
882780fb4a2SCy Schubert 		   hapd->conf->iface, MAC2STR(sta->addr));
883f05cddf9SRui Paulo 	ap_sta_remove(hapd, sta);
884f05cddf9SRui Paulo 	mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
885e28a4053SRui Paulo }
886e28a4053SRui Paulo 
887e28a4053SRui Paulo 
888e28a4053SRui Paulo void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
889e28a4053SRui Paulo 			   u16 reason)
890e28a4053SRui Paulo {
89185732ac8SCy Schubert 	if (hapd->iface->current_mode &&
89285732ac8SCy Schubert 	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
89385732ac8SCy Schubert 		/* Deauthentication is not used in DMG/IEEE 802.11ad;
89485732ac8SCy Schubert 		 * disassociate the STA instead. */
89585732ac8SCy Schubert 		ap_sta_disassociate(hapd, sta, reason);
89685732ac8SCy Schubert 		return;
89785732ac8SCy Schubert 	}
89885732ac8SCy Schubert 
899e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
900e28a4053SRui Paulo 		   hapd->conf->iface, MAC2STR(sta->addr));
9015b9c547cSRui Paulo 	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
9025b9c547cSRui Paulo 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
903f05cddf9SRui Paulo 	ap_sta_set_authorized(hapd, sta, 0);
904*c1d255d3SCy Schubert 	hostapd_set_sta_flags(hapd, sta);
905e28a4053SRui Paulo 	sta->timeout_next = STA_REMOVE;
906f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
907f05cddf9SRui Paulo 		   "for " MACSTR " (%d seconds - "
908f05cddf9SRui Paulo 		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
909f05cddf9SRui Paulo 		   __func__, MAC2STR(sta->addr),
910f05cddf9SRui Paulo 		   AP_MAX_INACTIVITY_AFTER_DEAUTH);
911e28a4053SRui Paulo 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
912e28a4053SRui Paulo 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
913e28a4053SRui Paulo 			       ap_handle_timer, hapd, sta);
914e28a4053SRui Paulo 	accounting_sta_stop(hapd, sta);
915780fb4a2SCy Schubert 	ieee802_1x_free_station(hapd, sta);
916e28a4053SRui Paulo 
917f05cddf9SRui Paulo 	sta->deauth_reason = reason;
918f05cddf9SRui Paulo 	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
919f05cddf9SRui Paulo 	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
920f05cddf9SRui Paulo 	eloop_register_timeout(hapd->iface->drv_flags &
921f05cddf9SRui Paulo 			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
922f05cddf9SRui Paulo 			       ap_sta_deauth_cb_timeout, hapd, sta);
923e28a4053SRui Paulo }
924e28a4053SRui Paulo 
925e28a4053SRui Paulo 
926f05cddf9SRui Paulo #ifdef CONFIG_WPS
927f05cddf9SRui Paulo int ap_sta_wps_cancel(struct hostapd_data *hapd,
928f05cddf9SRui Paulo 		      struct sta_info *sta, void *ctx)
929f05cddf9SRui Paulo {
930f05cddf9SRui Paulo 	if (sta && (sta->flags & WLAN_STA_WPS)) {
931f05cddf9SRui Paulo 		ap_sta_deauthenticate(hapd, sta,
932f05cddf9SRui Paulo 				      WLAN_REASON_PREV_AUTH_NOT_VALID);
933f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
934f05cddf9SRui Paulo 			   __func__, MAC2STR(sta->addr));
935f05cddf9SRui Paulo 		return 1;
936f05cddf9SRui Paulo 	}
937f05cddf9SRui Paulo 
938f05cddf9SRui Paulo 	return 0;
939f05cddf9SRui Paulo }
940f05cddf9SRui Paulo #endif /* CONFIG_WPS */
941f05cddf9SRui Paulo 
942f05cddf9SRui Paulo 
943780fb4a2SCy Schubert static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
944780fb4a2SCy Schubert {
945780fb4a2SCy Schubert 	struct hostapd_vlan *vlan;
946780fb4a2SCy Schubert 	int vlan_id = MAX_VLAN_ID + 2;
947780fb4a2SCy Schubert 
948780fb4a2SCy Schubert retry:
949780fb4a2SCy Schubert 	for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
950780fb4a2SCy Schubert 		if (vlan->vlan_id == vlan_id) {
951780fb4a2SCy Schubert 			vlan_id++;
952780fb4a2SCy Schubert 			goto retry;
953780fb4a2SCy Schubert 		}
954780fb4a2SCy Schubert 	}
955780fb4a2SCy Schubert 	return vlan_id;
956780fb4a2SCy Schubert }
957780fb4a2SCy Schubert 
958780fb4a2SCy Schubert 
959780fb4a2SCy Schubert int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
960780fb4a2SCy Schubert 		    struct vlan_description *vlan_desc)
961780fb4a2SCy Schubert {
962780fb4a2SCy Schubert 	struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
963780fb4a2SCy Schubert 	int old_vlan_id, vlan_id = 0, ret = 0;
964780fb4a2SCy Schubert 
965780fb4a2SCy Schubert 	/* Check if there is something to do */
966780fb4a2SCy Schubert 	if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
967780fb4a2SCy Schubert 		/* This sta is lacking its own vif */
968780fb4a2SCy Schubert 	} else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
969780fb4a2SCy Schubert 		   !hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
970780fb4a2SCy Schubert 		/* sta->vlan_id needs to be reset */
971780fb4a2SCy Schubert 	} else if (!vlan_compare(vlan_desc, sta->vlan_desc)) {
972780fb4a2SCy Schubert 		return 0; /* nothing to change */
973780fb4a2SCy Schubert 	}
974780fb4a2SCy Schubert 
975780fb4a2SCy Schubert 	/* Now the real VLAN changed or the STA just needs its own vif */
976780fb4a2SCy Schubert 	if (hapd->conf->ssid.per_sta_vif) {
977780fb4a2SCy Schubert 		/* Assign a new vif, always */
978780fb4a2SCy Schubert 		/* find a free vlan_id sufficiently big */
979780fb4a2SCy Schubert 		vlan_id = ap_sta_get_free_vlan_id(hapd);
980780fb4a2SCy Schubert 		/* Get wildcard VLAN */
981780fb4a2SCy Schubert 		for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
982780fb4a2SCy Schubert 			if (vlan->vlan_id == VLAN_ID_WILDCARD)
983780fb4a2SCy Schubert 				break;
984780fb4a2SCy Schubert 		}
985780fb4a2SCy Schubert 		if (!vlan) {
986780fb4a2SCy Schubert 			hostapd_logger(hapd, sta->addr,
987780fb4a2SCy Schubert 				       HOSTAPD_MODULE_IEEE80211,
988780fb4a2SCy Schubert 				       HOSTAPD_LEVEL_DEBUG,
989780fb4a2SCy Schubert 				       "per_sta_vif missing wildcard");
990780fb4a2SCy Schubert 			vlan_id = 0;
991780fb4a2SCy Schubert 			ret = -1;
992780fb4a2SCy Schubert 			goto done;
993780fb4a2SCy Schubert 		}
994780fb4a2SCy Schubert 	} else if (vlan_desc && vlan_desc->notempty) {
995780fb4a2SCy Schubert 		for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
996780fb4a2SCy Schubert 			if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
997780fb4a2SCy Schubert 				break;
998780fb4a2SCy Schubert 			if (vlan->vlan_id == VLAN_ID_WILDCARD)
999780fb4a2SCy Schubert 				wildcard_vlan = vlan;
1000780fb4a2SCy Schubert 		}
1001780fb4a2SCy Schubert 		if (vlan) {
1002780fb4a2SCy Schubert 			vlan_id = vlan->vlan_id;
1003780fb4a2SCy Schubert 		} else if (wildcard_vlan) {
1004780fb4a2SCy Schubert 			vlan = wildcard_vlan;
1005780fb4a2SCy Schubert 			vlan_id = vlan_desc->untagged;
1006780fb4a2SCy Schubert 			if (vlan_desc->tagged[0]) {
1007780fb4a2SCy Schubert 				/* Tagged VLAN configuration */
1008780fb4a2SCy Schubert 				vlan_id = ap_sta_get_free_vlan_id(hapd);
1009780fb4a2SCy Schubert 			}
1010780fb4a2SCy Schubert 		} else {
1011780fb4a2SCy Schubert 			hostapd_logger(hapd, sta->addr,
1012780fb4a2SCy Schubert 				       HOSTAPD_MODULE_IEEE80211,
1013780fb4a2SCy Schubert 				       HOSTAPD_LEVEL_DEBUG,
1014780fb4a2SCy Schubert 				       "missing vlan and wildcard for vlan=%d%s",
1015780fb4a2SCy Schubert 				       vlan_desc->untagged,
1016780fb4a2SCy Schubert 				       vlan_desc->tagged[0] ? "+" : "");
1017780fb4a2SCy Schubert 			vlan_id = 0;
1018780fb4a2SCy Schubert 			ret = -1;
1019780fb4a2SCy Schubert 			goto done;
1020780fb4a2SCy Schubert 		}
1021780fb4a2SCy Schubert 	}
1022780fb4a2SCy Schubert 
1023780fb4a2SCy Schubert 	if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
1024780fb4a2SCy Schubert 		vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
1025780fb4a2SCy Schubert 		if (vlan == NULL) {
1026780fb4a2SCy Schubert 			hostapd_logger(hapd, sta->addr,
1027780fb4a2SCy Schubert 				       HOSTAPD_MODULE_IEEE80211,
1028780fb4a2SCy Schubert 				       HOSTAPD_LEVEL_DEBUG,
1029780fb4a2SCy Schubert 				       "could not add dynamic VLAN interface for vlan=%d%s",
1030780fb4a2SCy Schubert 				       vlan_desc ? vlan_desc->untagged : -1,
1031780fb4a2SCy Schubert 				       (vlan_desc && vlan_desc->tagged[0]) ?
1032780fb4a2SCy Schubert 				       "+" : "");
1033780fb4a2SCy Schubert 			vlan_id = 0;
1034780fb4a2SCy Schubert 			ret = -1;
1035780fb4a2SCy Schubert 			goto done;
1036780fb4a2SCy Schubert 		}
1037780fb4a2SCy Schubert 
1038780fb4a2SCy Schubert 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1039780fb4a2SCy Schubert 			       HOSTAPD_LEVEL_DEBUG,
1040780fb4a2SCy Schubert 			       "added new dynamic VLAN interface '%s'",
1041780fb4a2SCy Schubert 			       vlan->ifname);
1042780fb4a2SCy Schubert 	} else if (vlan && vlan->dynamic_vlan > 0) {
1043780fb4a2SCy Schubert 		vlan->dynamic_vlan++;
1044780fb4a2SCy Schubert 		hostapd_logger(hapd, sta->addr,
1045780fb4a2SCy Schubert 			       HOSTAPD_MODULE_IEEE80211,
1046780fb4a2SCy Schubert 			       HOSTAPD_LEVEL_DEBUG,
1047780fb4a2SCy Schubert 			       "updated existing dynamic VLAN interface '%s'",
1048780fb4a2SCy Schubert 			       vlan->ifname);
1049780fb4a2SCy Schubert 	}
1050780fb4a2SCy Schubert done:
1051780fb4a2SCy Schubert 	old_vlan_id = sta->vlan_id;
1052780fb4a2SCy Schubert 	sta->vlan_id = vlan_id;
1053780fb4a2SCy Schubert 	sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
1054780fb4a2SCy Schubert 
1055780fb4a2SCy Schubert 	if (vlan_id != old_vlan_id && old_vlan_id)
1056780fb4a2SCy Schubert 		vlan_remove_dynamic(hapd, old_vlan_id);
1057780fb4a2SCy Schubert 
1058780fb4a2SCy Schubert 	return ret;
1059780fb4a2SCy Schubert }
1060780fb4a2SCy Schubert 
1061780fb4a2SCy Schubert 
1062325151a3SRui Paulo int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
1063e28a4053SRui Paulo {
1064e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN
1065e28a4053SRui Paulo 	const char *iface;
1066e28a4053SRui Paulo 	struct hostapd_vlan *vlan = NULL;
1067e28a4053SRui Paulo 	int ret;
1068325151a3SRui Paulo 	int old_vlanid = sta->vlan_id_bound;
1069e28a4053SRui Paulo 
1070*c1d255d3SCy Schubert 	if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
1071*c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1072*c1d255d3SCy Schubert 			   "Do not override WDS VLAN assignment for STA "
1073*c1d255d3SCy Schubert 			   MACSTR, MAC2STR(sta->addr));
1074*c1d255d3SCy Schubert 		return 0;
1075*c1d255d3SCy Schubert 	}
1076*c1d255d3SCy Schubert 
1077e28a4053SRui Paulo 	iface = hapd->conf->iface;
1078325151a3SRui Paulo 	if (hapd->conf->ssid.vlan[0])
1079325151a3SRui Paulo 		iface = hapd->conf->ssid.vlan;
1080e28a4053SRui Paulo 
1081780fb4a2SCy Schubert 	if (sta->vlan_id > 0) {
1082780fb4a2SCy Schubert 		for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
10835b9c547cSRui Paulo 			if (vlan->vlan_id == sta->vlan_id)
1084e28a4053SRui Paulo 				break;
1085e28a4053SRui Paulo 		}
10865b9c547cSRui Paulo 		if (vlan)
10875b9c547cSRui Paulo 			iface = vlan->ifname;
1088e28a4053SRui Paulo 	}
1089e28a4053SRui Paulo 
1090325151a3SRui Paulo 	/*
1091325151a3SRui Paulo 	 * Do not increment ref counters if the VLAN ID remains same, but do
1092325151a3SRui Paulo 	 * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
1093325151a3SRui Paulo 	 * have been called before.
1094325151a3SRui Paulo 	 */
1095325151a3SRui Paulo 	if (sta->vlan_id == old_vlanid)
1096325151a3SRui Paulo 		goto skip_counting;
1097325151a3SRui Paulo 
1098*c1d255d3SCy Schubert 	if (sta->vlan_id > 0 && !vlan &&
1099*c1d255d3SCy Schubert 	    !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
1100e28a4053SRui Paulo 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1101e28a4053SRui Paulo 			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
1102e28a4053SRui Paulo 			       "binding station to (vlan_id=%d)",
1103e28a4053SRui Paulo 			       sta->vlan_id);
11045b9c547cSRui Paulo 		ret = -1;
11055b9c547cSRui Paulo 		goto done;
1106780fb4a2SCy Schubert 	} else if (vlan && vlan->dynamic_vlan > 0) {
1107e28a4053SRui Paulo 		vlan->dynamic_vlan++;
1108e28a4053SRui Paulo 		hostapd_logger(hapd, sta->addr,
1109e28a4053SRui Paulo 			       HOSTAPD_MODULE_IEEE80211,
1110780fb4a2SCy Schubert 			       HOSTAPD_LEVEL_DEBUG,
1111780fb4a2SCy Schubert 			       "updated existing dynamic VLAN interface '%s'",
1112780fb4a2SCy Schubert 			       iface);
1113e28a4053SRui Paulo 	}
1114e28a4053SRui Paulo 
1115325151a3SRui Paulo 	/* ref counters have been increased, so mark the station */
1116325151a3SRui Paulo 	sta->vlan_id_bound = sta->vlan_id;
1117325151a3SRui Paulo 
1118325151a3SRui Paulo skip_counting:
1119e28a4053SRui Paulo 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1120e28a4053SRui Paulo 		       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
1121e28a4053SRui Paulo 		       "'%s'", iface);
1122e28a4053SRui Paulo 
1123e28a4053SRui Paulo 	if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
1124e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
1125e28a4053SRui Paulo 
1126f05cddf9SRui Paulo 	ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
1127e28a4053SRui Paulo 	if (ret < 0) {
1128e28a4053SRui Paulo 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1129e28a4053SRui Paulo 			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
1130e28a4053SRui Paulo 			       "entry to vlan_id=%d", sta->vlan_id);
1131e28a4053SRui Paulo 	}
11325b9c547cSRui Paulo 
11335b9c547cSRui Paulo 	/* During 1x reauth, if the vlan id changes, then remove the old id. */
1134325151a3SRui Paulo 	if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
11355b9c547cSRui Paulo 		vlan_remove_dynamic(hapd, old_vlanid);
1136325151a3SRui Paulo done:
11375b9c547cSRui Paulo 
1138e28a4053SRui Paulo 	return ret;
1139e28a4053SRui Paulo #else /* CONFIG_NO_VLAN */
1140e28a4053SRui Paulo 	return 0;
1141e28a4053SRui Paulo #endif /* CONFIG_NO_VLAN */
1142e28a4053SRui Paulo }
1143e28a4053SRui Paulo 
1144e28a4053SRui Paulo 
1145e28a4053SRui Paulo int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
1146e28a4053SRui Paulo {
1147e28a4053SRui Paulo 	u32 tu;
11485b9c547cSRui Paulo 	struct os_reltime now, passed;
11495b9c547cSRui Paulo 	os_get_reltime(&now);
11505b9c547cSRui Paulo 	os_reltime_sub(&now, &sta->sa_query_start, &passed);
1151e28a4053SRui Paulo 	tu = (passed.sec * 1000000 + passed.usec) / 1024;
1152e28a4053SRui Paulo 	if (hapd->conf->assoc_sa_query_max_timeout < tu) {
1153e28a4053SRui Paulo 		hostapd_logger(hapd, sta->addr,
1154e28a4053SRui Paulo 			       HOSTAPD_MODULE_IEEE80211,
1155e28a4053SRui Paulo 			       HOSTAPD_LEVEL_DEBUG,
1156e28a4053SRui Paulo 			       "association SA Query timed out");
1157e28a4053SRui Paulo 		sta->sa_query_timed_out = 1;
1158e28a4053SRui Paulo 		os_free(sta->sa_query_trans_id);
1159e28a4053SRui Paulo 		sta->sa_query_trans_id = NULL;
1160e28a4053SRui Paulo 		sta->sa_query_count = 0;
1161e28a4053SRui Paulo 		eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
1162e28a4053SRui Paulo 		return 1;
1163e28a4053SRui Paulo 	}
1164e28a4053SRui Paulo 
1165e28a4053SRui Paulo 	return 0;
1166e28a4053SRui Paulo }
1167e28a4053SRui Paulo 
1168e28a4053SRui Paulo 
1169e28a4053SRui Paulo static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
1170e28a4053SRui Paulo {
1171e28a4053SRui Paulo 	struct hostapd_data *hapd = eloop_ctx;
1172e28a4053SRui Paulo 	struct sta_info *sta = timeout_ctx;
1173e28a4053SRui Paulo 	unsigned int timeout, sec, usec;
1174e28a4053SRui Paulo 	u8 *trans_id, *nbuf;
1175e28a4053SRui Paulo 
1176780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
1177780fb4a2SCy Schubert 		   " (count=%d)",
1178780fb4a2SCy Schubert 		   hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
1179780fb4a2SCy Schubert 
1180e28a4053SRui Paulo 	if (sta->sa_query_count > 0 &&
1181e28a4053SRui Paulo 	    ap_check_sa_query_timeout(hapd, sta))
1182e28a4053SRui Paulo 		return;
1183*c1d255d3SCy Schubert 	if (sta->sa_query_count >= 1000)
1184*c1d255d3SCy Schubert 		return;
1185e28a4053SRui Paulo 
1186f05cddf9SRui Paulo 	nbuf = os_realloc_array(sta->sa_query_trans_id,
1187f05cddf9SRui Paulo 				sta->sa_query_count + 1,
1188f05cddf9SRui Paulo 				WLAN_SA_QUERY_TR_ID_LEN);
1189e28a4053SRui Paulo 	if (nbuf == NULL)
1190e28a4053SRui Paulo 		return;
1191e28a4053SRui Paulo 	if (sta->sa_query_count == 0) {
1192e28a4053SRui Paulo 		/* Starting a new SA Query procedure */
11935b9c547cSRui Paulo 		os_get_reltime(&sta->sa_query_start);
1194e28a4053SRui Paulo 	}
1195e28a4053SRui Paulo 	trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
1196e28a4053SRui Paulo 	sta->sa_query_trans_id = nbuf;
1197e28a4053SRui Paulo 	sta->sa_query_count++;
1198e28a4053SRui Paulo 
11995b9c547cSRui Paulo 	if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
12005b9c547cSRui Paulo 		/*
12015b9c547cSRui Paulo 		 * We don't really care which ID is used here, so simply
12025b9c547cSRui Paulo 		 * hardcode this if the mostly theoretical os_get_random()
12035b9c547cSRui Paulo 		 * failure happens.
12045b9c547cSRui Paulo 		 */
12055b9c547cSRui Paulo 		trans_id[0] = 0x12;
12065b9c547cSRui Paulo 		trans_id[1] = 0x34;
12075b9c547cSRui Paulo 	}
1208e28a4053SRui Paulo 
1209e28a4053SRui Paulo 	timeout = hapd->conf->assoc_sa_query_retry_timeout;
1210e28a4053SRui Paulo 	sec = ((timeout / 1000) * 1024) / 1000;
1211e28a4053SRui Paulo 	usec = (timeout % 1000) * 1024;
1212e28a4053SRui Paulo 	eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
1213e28a4053SRui Paulo 
1214e28a4053SRui Paulo 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1215e28a4053SRui Paulo 		       HOSTAPD_LEVEL_DEBUG,
1216e28a4053SRui Paulo 		       "association SA Query attempt %d", sta->sa_query_count);
1217e28a4053SRui Paulo 
1218e28a4053SRui Paulo 	ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
1219e28a4053SRui Paulo }
1220e28a4053SRui Paulo 
1221e28a4053SRui Paulo 
1222e28a4053SRui Paulo void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
1223e28a4053SRui Paulo {
1224e28a4053SRui Paulo 	ap_sa_query_timer(hapd, sta);
1225e28a4053SRui Paulo }
1226e28a4053SRui Paulo 
1227e28a4053SRui Paulo 
1228e28a4053SRui Paulo void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
1229e28a4053SRui Paulo {
1230e28a4053SRui Paulo 	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
1231e28a4053SRui Paulo 	os_free(sta->sa_query_trans_id);
1232e28a4053SRui Paulo 	sta->sa_query_trans_id = NULL;
1233e28a4053SRui Paulo 	sta->sa_query_count = 0;
1234e28a4053SRui Paulo }
1235e28a4053SRui Paulo 
1236e28a4053SRui Paulo 
12374bc52338SCy Schubert const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
12384bc52338SCy Schubert 				  struct sta_info *sta)
12394bc52338SCy Schubert {
12404bc52338SCy Schubert 	struct hostapd_wpa_psk *psk;
12414bc52338SCy Schubert 	struct hostapd_ssid *ssid;
12424bc52338SCy Schubert 	const u8 *pmk;
12434bc52338SCy Schubert 	int pmk_len;
12444bc52338SCy Schubert 
12454bc52338SCy Schubert 	ssid = &hapd->conf->ssid;
12464bc52338SCy Schubert 
12474bc52338SCy Schubert 	pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
12484bc52338SCy Schubert 	if (!pmk || pmk_len != PMK_LEN)
12494bc52338SCy Schubert 		return NULL;
12504bc52338SCy Schubert 
12514bc52338SCy Schubert 	for (psk = ssid->wpa_psk; psk; psk = psk->next)
12524bc52338SCy Schubert 		if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
12534bc52338SCy Schubert 			break;
12544bc52338SCy Schubert 	if (!psk)
12554bc52338SCy Schubert 		return NULL;
12564bc52338SCy Schubert 	if (!psk || !psk->keyid[0])
12574bc52338SCy Schubert 		return NULL;
12584bc52338SCy Schubert 
12594bc52338SCy Schubert 	return psk->keyid;
12604bc52338SCy Schubert }
12614bc52338SCy Schubert 
12624bc52338SCy Schubert 
1263f05cddf9SRui Paulo void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
1264f05cddf9SRui Paulo 			   int authorized)
1265f05cddf9SRui Paulo {
1266f05cddf9SRui Paulo 	const u8 *dev_addr = NULL;
12675b9c547cSRui Paulo 	char buf[100];
1268f05cddf9SRui Paulo #ifdef CONFIG_P2P
1269f05cddf9SRui Paulo 	u8 addr[ETH_ALEN];
12705b9c547cSRui Paulo 	u8 ip_addr_buf[4];
1271f05cddf9SRui Paulo #endif /* CONFIG_P2P */
1272f05cddf9SRui Paulo 
1273f05cddf9SRui Paulo 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
1274f05cddf9SRui Paulo 		return;
1275f05cddf9SRui Paulo 
12765b9c547cSRui Paulo 	if (authorized)
12775b9c547cSRui Paulo 		sta->flags |= WLAN_STA_AUTHORIZED;
12785b9c547cSRui Paulo 	else
12795b9c547cSRui Paulo 		sta->flags &= ~WLAN_STA_AUTHORIZED;
12805b9c547cSRui Paulo 
1281f05cddf9SRui Paulo #ifdef CONFIG_P2P
1282f05cddf9SRui Paulo 	if (hapd->p2p_group == NULL) {
1283f05cddf9SRui Paulo 		if (sta->p2p_ie != NULL &&
1284f05cddf9SRui Paulo 		    p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
1285f05cddf9SRui Paulo 			dev_addr = addr;
1286f05cddf9SRui Paulo 	} else
1287f05cddf9SRui Paulo 		dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
12885b9c547cSRui Paulo 
12895b9c547cSRui Paulo 	if (dev_addr)
12905b9c547cSRui Paulo 		os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
12915b9c547cSRui Paulo 			    MAC2STR(sta->addr), MAC2STR(dev_addr));
12925b9c547cSRui Paulo 	else
1293f05cddf9SRui Paulo #endif /* CONFIG_P2P */
12945b9c547cSRui Paulo 		os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
1295f05cddf9SRui Paulo 
1296f05cddf9SRui Paulo 	if (hapd->sta_authorized_cb)
1297f05cddf9SRui Paulo 		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
1298f05cddf9SRui Paulo 					sta->addr, authorized, dev_addr);
12995b9c547cSRui Paulo 
13005b9c547cSRui Paulo 	if (authorized) {
13014bc52338SCy Schubert 		const char *keyid;
13024bc52338SCy Schubert 		char keyid_buf[100];
13035b9c547cSRui Paulo 		char ip_addr[100];
13044bc52338SCy Schubert 
13054bc52338SCy Schubert 		keyid_buf[0] = '\0';
13065b9c547cSRui Paulo 		ip_addr[0] = '\0';
13075b9c547cSRui Paulo #ifdef CONFIG_P2P
13085b9c547cSRui Paulo 		if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
13095b9c547cSRui Paulo 			os_snprintf(ip_addr, sizeof(ip_addr),
13105b9c547cSRui Paulo 				    " ip_addr=%u.%u.%u.%u",
13115b9c547cSRui Paulo 				    ip_addr_buf[0], ip_addr_buf[1],
13125b9c547cSRui Paulo 				    ip_addr_buf[2], ip_addr_buf[3]);
13135b9c547cSRui Paulo 		}
13145b9c547cSRui Paulo #endif /* CONFIG_P2P */
13155b9c547cSRui Paulo 
13164bc52338SCy Schubert 		keyid = ap_sta_wpa_get_keyid(hapd, sta);
13174bc52338SCy Schubert 		if (keyid) {
13184bc52338SCy Schubert 			os_snprintf(keyid_buf, sizeof(keyid_buf),
13194bc52338SCy Schubert 				    " keyid=%s", keyid);
13204bc52338SCy Schubert 		}
13214bc52338SCy Schubert 
13224bc52338SCy Schubert 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
13234bc52338SCy Schubert 			buf, ip_addr, keyid_buf);
13245b9c547cSRui Paulo 
13255b9c547cSRui Paulo 		if (hapd->msg_ctx_parent &&
13265b9c547cSRui Paulo 		    hapd->msg_ctx_parent != hapd->msg_ctx)
13275b9c547cSRui Paulo 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
13284bc52338SCy Schubert 					  AP_STA_CONNECTED "%s%s%s",
13294bc52338SCy Schubert 					  buf, ip_addr, keyid_buf);
13305b9c547cSRui Paulo 	} else {
13315b9c547cSRui Paulo 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
13325b9c547cSRui Paulo 
13335b9c547cSRui Paulo 		if (hapd->msg_ctx_parent &&
13345b9c547cSRui Paulo 		    hapd->msg_ctx_parent != hapd->msg_ctx)
13355b9c547cSRui Paulo 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
13365b9c547cSRui Paulo 					  AP_STA_DISCONNECTED "%s", buf);
13375b9c547cSRui Paulo 	}
1338325151a3SRui Paulo 
1339325151a3SRui Paulo #ifdef CONFIG_FST
1340325151a3SRui Paulo 	if (hapd->iface->fst) {
1341325151a3SRui Paulo 		if (authorized)
1342325151a3SRui Paulo 			fst_notify_peer_connected(hapd->iface->fst, sta->addr);
1343325151a3SRui Paulo 		else
1344325151a3SRui Paulo 			fst_notify_peer_disconnected(hapd->iface->fst,
1345325151a3SRui Paulo 						     sta->addr);
1346325151a3SRui Paulo 	}
1347325151a3SRui Paulo #endif /* CONFIG_FST */
1348f05cddf9SRui Paulo }
1349f05cddf9SRui Paulo 
1350f05cddf9SRui Paulo 
1351e28a4053SRui Paulo void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
1352e28a4053SRui Paulo 		       const u8 *addr, u16 reason)
1353e28a4053SRui Paulo {
1354780fb4a2SCy Schubert 	if (sta)
1355780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
1356780fb4a2SCy Schubert 			   hapd->conf->iface, __func__, MAC2STR(sta->addr),
1357780fb4a2SCy Schubert 			   reason);
1358780fb4a2SCy Schubert 	else if (addr)
1359780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
1360780fb4a2SCy Schubert 			   hapd->conf->iface, __func__, MAC2STR(addr),
1361780fb4a2SCy Schubert 			   reason);
1362e28a4053SRui Paulo 
1363e28a4053SRui Paulo 	if (sta == NULL && addr)
1364e28a4053SRui Paulo 		sta = ap_get_sta(hapd, addr);
1365e28a4053SRui Paulo 
1366e28a4053SRui Paulo 	if (addr)
1367f05cddf9SRui Paulo 		hostapd_drv_sta_deauth(hapd, addr, reason);
1368e28a4053SRui Paulo 
1369e28a4053SRui Paulo 	if (sta == NULL)
1370e28a4053SRui Paulo 		return;
1371f05cddf9SRui Paulo 	ap_sta_set_authorized(hapd, sta, 0);
1372*c1d255d3SCy Schubert 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
1373*c1d255d3SCy Schubert 	hostapd_set_sta_flags(hapd, sta);
1374f05cddf9SRui Paulo 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
1375f05cddf9SRui Paulo 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
1376780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
1377f05cddf9SRui Paulo 		   "for " MACSTR " (%d seconds - "
1378f05cddf9SRui Paulo 		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
1379780fb4a2SCy Schubert 		   hapd->conf->iface, __func__, MAC2STR(sta->addr),
1380f05cddf9SRui Paulo 		   AP_MAX_INACTIVITY_AFTER_DEAUTH);
1381e28a4053SRui Paulo 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
1382f05cddf9SRui Paulo 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
1383f05cddf9SRui Paulo 			       ap_handle_timer, hapd, sta);
1384e28a4053SRui Paulo 	sta->timeout_next = STA_REMOVE;
1385f05cddf9SRui Paulo 
138685732ac8SCy Schubert 	if (hapd->iface->current_mode &&
138785732ac8SCy Schubert 	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
138885732ac8SCy Schubert 		/* Deauthentication is not used in DMG/IEEE 802.11ad;
138985732ac8SCy Schubert 		 * disassociate the STA instead. */
139085732ac8SCy Schubert 		sta->disassoc_reason = reason;
139185732ac8SCy Schubert 		sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
139285732ac8SCy Schubert 		eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
139385732ac8SCy Schubert 		eloop_register_timeout(hapd->iface->drv_flags &
139485732ac8SCy Schubert 				       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
139585732ac8SCy Schubert 				       2 : 0, 0, ap_sta_disassoc_cb_timeout,
139685732ac8SCy Schubert 				       hapd, sta);
139785732ac8SCy Schubert 		return;
139885732ac8SCy Schubert 	}
139985732ac8SCy Schubert 
1400f05cddf9SRui Paulo 	sta->deauth_reason = reason;
1401f05cddf9SRui Paulo 	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
1402f05cddf9SRui Paulo 	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
1403f05cddf9SRui Paulo 	eloop_register_timeout(hapd->iface->drv_flags &
1404f05cddf9SRui Paulo 			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
1405f05cddf9SRui Paulo 			       ap_sta_deauth_cb_timeout, hapd, sta);
1406f05cddf9SRui Paulo }
1407f05cddf9SRui Paulo 
1408f05cddf9SRui Paulo 
1409f05cddf9SRui Paulo void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
1410f05cddf9SRui Paulo {
1411f05cddf9SRui Paulo 	if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
1412f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
1413f05cddf9SRui Paulo 		return;
1414f05cddf9SRui Paulo 	}
1415f05cddf9SRui Paulo 	sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
1416f05cddf9SRui Paulo 	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
1417f05cddf9SRui Paulo 	ap_sta_deauth_cb_timeout(hapd, sta);
1418f05cddf9SRui Paulo }
1419f05cddf9SRui Paulo 
1420f05cddf9SRui Paulo 
1421f05cddf9SRui Paulo void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
1422f05cddf9SRui Paulo {
1423f05cddf9SRui Paulo 	if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
1424f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
1425f05cddf9SRui Paulo 		return;
1426f05cddf9SRui Paulo 	}
1427f05cddf9SRui Paulo 	sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
1428f05cddf9SRui Paulo 	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
1429f05cddf9SRui Paulo 	ap_sta_disassoc_cb_timeout(hapd, sta);
1430e28a4053SRui Paulo }
14315b9c547cSRui Paulo 
14325b9c547cSRui Paulo 
1433780fb4a2SCy Schubert void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
1434780fb4a2SCy Schubert 				      struct sta_info *sta)
1435780fb4a2SCy Schubert {
1436780fb4a2SCy Schubert 	if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
1437780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
1438780fb4a2SCy Schubert 			   "%s: Removed ap_sta_deauth_cb_timeout timeout for "
1439780fb4a2SCy Schubert 			   MACSTR,
1440780fb4a2SCy Schubert 			   hapd->conf->iface, MAC2STR(sta->addr));
1441780fb4a2SCy Schubert 	if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
1442780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
1443780fb4a2SCy Schubert 			   "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
1444780fb4a2SCy Schubert 			   MACSTR,
1445780fb4a2SCy Schubert 			   hapd->conf->iface, MAC2STR(sta->addr));
144685732ac8SCy Schubert 	if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
144785732ac8SCy Schubert 	{
144885732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
144985732ac8SCy Schubert 			   "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
145085732ac8SCy Schubert 			   MACSTR,
145185732ac8SCy Schubert 			   hapd->conf->iface, MAC2STR(sta->addr));
145285732ac8SCy Schubert 		if (sta->flags & WLAN_STA_WPS)
145385732ac8SCy Schubert 			hostapd_wps_eap_completed(hapd);
145485732ac8SCy Schubert 	}
1455780fb4a2SCy Schubert }
1456780fb4a2SCy Schubert 
1457780fb4a2SCy Schubert 
14585b9c547cSRui Paulo int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
14595b9c547cSRui Paulo {
14605b9c547cSRui Paulo 	int res;
14615b9c547cSRui Paulo 
14625b9c547cSRui Paulo 	buf[0] = '\0';
1463*c1d255d3SCy Schubert 	res = os_snprintf(buf, buflen,
1464*c1d255d3SCy Schubert 			  "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
14655b9c547cSRui Paulo 			  (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
14665b9c547cSRui Paulo 			  (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
14675b9c547cSRui Paulo 			  (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
14685b9c547cSRui Paulo 			  (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
14695b9c547cSRui Paulo 			   ""),
14705b9c547cSRui Paulo 			  (flags & WLAN_STA_SHORT_PREAMBLE ?
14715b9c547cSRui Paulo 			   "[SHORT_PREAMBLE]" : ""),
14725b9c547cSRui Paulo 			  (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
14735b9c547cSRui Paulo 			  (flags & WLAN_STA_WMM ? "[WMM]" : ""),
14745b9c547cSRui Paulo 			  (flags & WLAN_STA_MFP ? "[MFP]" : ""),
14755b9c547cSRui Paulo 			  (flags & WLAN_STA_WPS ? "[WPS]" : ""),
14765b9c547cSRui Paulo 			  (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
14775b9c547cSRui Paulo 			  (flags & WLAN_STA_WDS ? "[WDS]" : ""),
14785b9c547cSRui Paulo 			  (flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
14795b9c547cSRui Paulo 			  (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
14805b9c547cSRui Paulo 			  (flags & WLAN_STA_GAS ? "[GAS]" : ""),
148185732ac8SCy Schubert 			  (flags & WLAN_STA_HT ? "[HT]" : ""),
14825b9c547cSRui Paulo 			  (flags & WLAN_STA_VHT ? "[VHT]" : ""),
1483*c1d255d3SCy Schubert 			  (flags & WLAN_STA_HE ? "[HE]" : ""),
1484*c1d255d3SCy Schubert 			  (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
14855b9c547cSRui Paulo 			  (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
14865b9c547cSRui Paulo 			  (flags & WLAN_STA_WNM_SLEEP_MODE ?
14875b9c547cSRui Paulo 			   "[WNM_SLEEP_MODE]" : ""));
14885b9c547cSRui Paulo 	if (os_snprintf_error(buflen, res))
14895b9c547cSRui Paulo 		res = -1;
14905b9c547cSRui Paulo 
14915b9c547cSRui Paulo 	return res;
14925b9c547cSRui Paulo }
149385732ac8SCy Schubert 
149485732ac8SCy Schubert 
149585732ac8SCy Schubert static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
149685732ac8SCy Schubert {
149785732ac8SCy Schubert 	struct hostapd_data *hapd = eloop_ctx;
149885732ac8SCy Schubert 	struct sta_info *sta = timeout_ctx;
149985732ac8SCy Schubert 	u16 reason;
150085732ac8SCy Schubert 
150185732ac8SCy Schubert 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
150285732ac8SCy Schubert 		"IEEE 802.1X: Scheduled disconnection of " MACSTR
150385732ac8SCy Schubert 		" after EAP-Failure", MAC2STR(sta->addr));
150485732ac8SCy Schubert 
150585732ac8SCy Schubert 	reason = sta->disconnect_reason_code;
150685732ac8SCy Schubert 	if (!reason)
150785732ac8SCy Schubert 		reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
150885732ac8SCy Schubert 	ap_sta_disconnect(hapd, sta, sta->addr, reason);
150985732ac8SCy Schubert 	if (sta->flags & WLAN_STA_WPS)
151085732ac8SCy Schubert 		hostapd_wps_eap_completed(hapd);
151185732ac8SCy Schubert }
151285732ac8SCy Schubert 
151385732ac8SCy Schubert 
151485732ac8SCy Schubert void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
151585732ac8SCy Schubert 					    struct sta_info *sta)
151685732ac8SCy Schubert {
151785732ac8SCy Schubert 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
151885732ac8SCy Schubert 		"IEEE 802.1X: Force disconnection of " MACSTR
151985732ac8SCy Schubert 		" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
152085732ac8SCy Schubert 
152185732ac8SCy Schubert 	/*
152285732ac8SCy Schubert 	 * Add a small sleep to increase likelihood of previously requested
152385732ac8SCy Schubert 	 * EAP-Failure TX getting out before this should the driver reorder
152485732ac8SCy Schubert 	 * operations.
152585732ac8SCy Schubert 	 */
152685732ac8SCy Schubert 	eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
152785732ac8SCy Schubert 	eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
152885732ac8SCy Schubert 			       hapd, sta);
152985732ac8SCy Schubert }
153085732ac8SCy Schubert 
153185732ac8SCy Schubert 
153285732ac8SCy Schubert int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
153385732ac8SCy Schubert 						   struct sta_info *sta)
153485732ac8SCy Schubert {
153585732ac8SCy Schubert 	return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
153685732ac8SCy Schubert 					   hapd, sta);
153785732ac8SCy Schubert }
1538*c1d255d3SCy Schubert 
1539*c1d255d3SCy Schubert 
1540*c1d255d3SCy Schubert int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
1541*c1d255d3SCy Schubert {
1542*c1d255d3SCy Schubert 	/*
1543*c1d255d3SCy Schubert 	 * If a station that is already associated to the AP, is trying to
1544*c1d255d3SCy Schubert 	 * authenticate again, remove the STA entry, in order to make sure the
1545*c1d255d3SCy Schubert 	 * STA PS state gets cleared and configuration gets updated. To handle
1546*c1d255d3SCy Schubert 	 * this, station's added_unassoc flag is cleared once the station has
1547*c1d255d3SCy Schubert 	 * completed association.
1548*c1d255d3SCy Schubert 	 */
1549*c1d255d3SCy Schubert 	ap_sta_set_authorized(hapd, sta, 0);
1550*c1d255d3SCy Schubert 	hostapd_drv_sta_remove(hapd, sta->addr);
1551*c1d255d3SCy Schubert 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
1552*c1d255d3SCy Schubert 
1553*c1d255d3SCy Schubert 	if (hostapd_sta_add(hapd, sta->addr, 0, 0,
1554*c1d255d3SCy Schubert 			    sta->supported_rates,
1555*c1d255d3SCy Schubert 			    sta->supported_rates_len,
1556*c1d255d3SCy Schubert 			    0, NULL, NULL, NULL, 0, NULL,
1557*c1d255d3SCy Schubert 			    sta->flags, 0, 0, 0, 0)) {
1558*c1d255d3SCy Schubert 		hostapd_logger(hapd, sta->addr,
1559*c1d255d3SCy Schubert 			       HOSTAPD_MODULE_IEEE80211,
1560*c1d255d3SCy Schubert 			       HOSTAPD_LEVEL_NOTICE,
1561*c1d255d3SCy Schubert 			       "Could not add STA to kernel driver");
1562*c1d255d3SCy Schubert 		return -1;
1563*c1d255d3SCy Schubert 	}
1564*c1d255d3SCy Schubert 
1565*c1d255d3SCy Schubert 	sta->added_unassoc = 1;
1566*c1d255d3SCy Schubert 	return 0;
1567*c1d255d3SCy Schubert }
1568