blob: 2178d65ae0befd19cb665949607270f695bf90b2 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / Station table
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07003 * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "utils/includes.h"
10
11#include "utils/common.h"
12#include "utils/eloop.h"
13#include "common/ieee802_11_defs.h"
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080014#include "common/wpa_ctrl.h"
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -080015#include "common/sae.h"
Hai Shalom021b0b52019-04-10 11:17:58 -070016#include "common/dpp.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070017#include "radius/radius.h"
18#include "radius/radius_client.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#include "p2p/p2p.h"
Dmitry Shmidtd80a4012015-11-05 16:35:40 -080020#include "fst/fst.h"
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070021#include "crypto/crypto.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022#include "hostapd.h"
23#include "accounting.h"
24#include "ieee802_1x.h"
25#include "ieee802_11.h"
Dmitry Shmidtd5e49232012-12-03 15:08:10 -080026#include "ieee802_11_auth.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070027#include "wpa_auth.h"
28#include "preauth_auth.h"
29#include "ap_config.h"
30#include "beacon.h"
31#include "ap_mlme.h"
32#include "vlan_init.h"
33#include "p2p_hostapd.h"
34#include "ap_drv_ops.h"
Dmitry Shmidt04949592012-07-19 12:16:46 -070035#include "gas_serv.h"
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080036#include "wnm_ap.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080037#include "mbo_ap.h"
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080038#include "ndisc_snoop.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070039#include "sta_info.h"
Dmitry Shmidt57c2d392016-02-23 13:40:19 -080040#include "vlan.h"
Dmitry Shmidt29333592017-01-09 12:27:11 -080041#include "wps_hostapd.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070042
43static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
44 struct sta_info *sta);
45static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -080046static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080047static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
48static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080050static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
Dmitry Shmidt29333592017-01-09 12:27:11 -080051static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070052
53int ap_for_each_sta(struct hostapd_data *hapd,
54 int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
55 void *ctx),
56 void *ctx)
57{
58 struct sta_info *sta;
59
60 for (sta = hapd->sta_list; sta; sta = sta->next) {
61 if (cb(hapd, sta, ctx))
62 return 1;
63 }
64
65 return 0;
66}
67
68
69struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
70{
71 struct sta_info *s;
72
73 s = hapd->sta_hash[STA_HASH(sta)];
74 while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
75 s = s->hnext;
76 return s;
77}
78
79
Dmitry Shmidt391c59f2013-09-03 12:16:28 -070080#ifdef CONFIG_P2P
81struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr)
82{
83 struct sta_info *sta;
84
85 for (sta = hapd->sta_list; sta; sta = sta->next) {
86 const u8 *p2p_dev_addr;
87
88 if (sta->p2p_ie == NULL)
89 continue;
90
91 p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
92 if (p2p_dev_addr == NULL)
93 continue;
94
Sunil Ravib0ac25f2024-07-12 01:42:03 +000095 if (ether_addr_equal(p2p_dev_addr, addr))
Dmitry Shmidt391c59f2013-09-03 12:16:28 -070096 return sta;
97 }
98
99 return NULL;
100}
101#endif /* CONFIG_P2P */
102
103
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700104static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
105{
106 struct sta_info *tmp;
107
108 if (hapd->sta_list == sta) {
109 hapd->sta_list = sta->next;
110 return;
111 }
112
113 tmp = hapd->sta_list;
114 while (tmp != NULL && tmp->next != sta)
115 tmp = tmp->next;
116 if (tmp == NULL) {
117 wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
118 "list.", MAC2STR(sta->addr));
119 } else
120 tmp->next = sta->next;
121}
122
123
124void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
125{
126 sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
127 hapd->sta_hash[STA_HASH(sta->addr)] = sta;
128}
129
130
131static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
132{
133 struct sta_info *s;
134
135 s = hapd->sta_hash[STA_HASH(sta->addr)];
136 if (s == NULL) return;
137 if (os_memcmp(s->addr, sta->addr, 6) == 0) {
138 hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
139 return;
140 }
141
142 while (s->hnext != NULL &&
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000143 !ether_addr_equal(s->hnext->addr, sta->addr))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700144 s = s->hnext;
145 if (s->hnext != NULL)
146 s->hnext = s->hnext->hnext;
147 else
148 wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
149 " from hash table", MAC2STR(sta->addr));
150}
151
152
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800153void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
154{
155 sta_ip6addr_del(hapd, sta);
156}
157
158
Hai Shalom60840252021-02-19 19:02:11 -0800159#ifdef CONFIG_PASN
160
161void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
162{
163 if (sta->pasn) {
164 wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR,
165 MAC2STR(sta->addr));
166
167 if (sta->pasn->ecdh)
168 crypto_ecdh_deinit(sta->pasn->ecdh);
169
170 wpabuf_free(sta->pasn->secret);
171 sta->pasn->secret = NULL;
172
173#ifdef CONFIG_SAE
174 sae_clear_data(&sta->pasn->sae);
175#endif /* CONFIG_SAE */
176
177#ifdef CONFIG_FILS
178 /* In practice this pointer should be NULL */
179 wpabuf_free(sta->pasn->fils.erp_resp);
180 sta->pasn->fils.erp_resp = NULL;
181#endif /* CONFIG_FILS */
182
Sunil Ravi88611412024-06-28 17:34:56 +0000183 bin_clear_free(sta->pasn, sizeof(*sta->pasn));
Hai Shalom60840252021-02-19 19:02:11 -0800184 sta->pasn = NULL;
185 }
186}
187
188#endif /* CONFIG_PASN */
189
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700190void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
191{
192 int set_beacon = 0;
193
194 accounting_sta_stop(hapd, sta);
195
196 /* just in case */
197 ap_sta_set_authorized(hapd, sta, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -0700198 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700199
Sunil Ravi640215c2023-06-28 23:08:09 +0000200 if ((sta->flags & WLAN_STA_WDS) ||
201 (sta->flags & WLAN_STA_MULTI_AP &&
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000202 (hapd->conf->multi_ap & BACKHAUL_BSS) &&
Sunil Ravi640215c2023-06-28 23:08:09 +0000203 !(sta->flags & WLAN_STA_WPS)))
Dmitry Shmidtc2ebb4b2013-07-24 12:57:51 -0700204 hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700205
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800206 if (sta->ipaddr)
207 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
208 ap_sta_ip6addr_del(hapd, sta);
209
Dmitry Shmidta38abf92014-03-06 13:38:44 -0800210 if (!hapd->iface->driver_ap_teardown &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800211 !(sta->flags & WLAN_STA_PREAUTH)) {
Sunil Ravi88611412024-06-28 17:34:56 +0000212 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800213 sta->added_unassoc = 0;
214 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700215
216 ap_sta_hash_del(hapd, sta);
217 ap_sta_list_del(hapd, sta);
218
219 if (sta->aid > 0)
220 hapd->sta_aid[(sta->aid - 1) / 32] &=
221 ~BIT((sta->aid - 1) % 32);
222
223 hapd->num_sta--;
224 if (sta->nonerp_set) {
225 sta->nonerp_set = 0;
226 hapd->iface->num_sta_non_erp--;
227 if (hapd->iface->num_sta_non_erp == 0)
228 set_beacon++;
229 }
230
231 if (sta->no_short_slot_time_set) {
232 sta->no_short_slot_time_set = 0;
233 hapd->iface->num_sta_no_short_slot_time--;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700234 if (hapd->iface->current_mode &&
235 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700236 && hapd->iface->num_sta_no_short_slot_time == 0)
237 set_beacon++;
238 }
239
240 if (sta->no_short_preamble_set) {
241 sta->no_short_preamble_set = 0;
242 hapd->iface->num_sta_no_short_preamble--;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700243 if (hapd->iface->current_mode &&
244 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700245 && hapd->iface->num_sta_no_short_preamble == 0)
246 set_beacon++;
247 }
248
249 if (sta->no_ht_gf_set) {
250 sta->no_ht_gf_set = 0;
251 hapd->iface->num_sta_ht_no_gf--;
252 }
253
254 if (sta->no_ht_set) {
255 sta->no_ht_set = 0;
256 hapd->iface->num_sta_no_ht--;
257 }
258
259 if (sta->ht_20mhz_set) {
260 sta->ht_20mhz_set = 0;
261 hapd->iface->num_sta_ht_20mhz--;
262 }
263
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700264#ifdef CONFIG_TAXONOMY
265 wpabuf_free(sta->probe_ie_taxonomy);
266 sta->probe_ie_taxonomy = NULL;
267 wpabuf_free(sta->assoc_ie_taxonomy);
268 sta->assoc_ie_taxonomy = NULL;
269#endif /* CONFIG_TAXONOMY */
270
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700271 ht40_intolerant_remove(hapd->iface, sta);
Dmitry Shmidt7832adb2014-04-29 10:53:02 -0700272
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700273#ifdef CONFIG_P2P
274 if (sta->no_p2p_set) {
275 sta->no_p2p_set = 0;
276 hapd->num_sta_no_p2p--;
277 if (hapd->num_sta_no_p2p == 0)
278 hostapd_p2p_non_p2p_sta_disconnected(hapd);
279 }
280#endif /* CONFIG_P2P */
281
Hai Shalomfdcde762020-04-02 11:19:20 -0700282#ifdef NEED_AP_MLME
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700283 if (hostapd_ht_operation_update(hapd->iface) > 0)
284 set_beacon++;
Hai Shalomfdcde762020-04-02 11:19:20 -0700285#endif /* NEED_AP_MLME */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700286
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800287#ifdef CONFIG_MESH
288 if (hapd->mesh_sta_free_cb)
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800289 hapd->mesh_sta_free_cb(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800290#endif /* CONFIG_MESH */
291
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700292 if (set_beacon)
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000293 ieee802_11_update_beacons(hapd->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700294
Dmitry Shmidt04949592012-07-19 12:16:46 -0700295 wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
296 __func__, MAC2STR(sta->addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700297 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
298 eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800299 eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800300 ap_sta_clear_disconnect_timeouts(hapd, sta);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800301 sae_clear_retransmit_timer(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700302
Dmitry Shmidtde47be72016-01-07 12:52:55 -0800303 ieee802_1x_free_station(hapd, sta);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000304
305#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000306 if (!ap_sta_is_mld(hapd, sta) ||
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000307 hapd->mld_link_id == sta->mld_assoc_link_id)
308 wpa_auth_sta_deinit(sta->wpa_sm);
309#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700310 wpa_auth_sta_deinit(sta->wpa_sm);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000311#endif /* CONFIG_IEEE80211BE */
312
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700313 rsn_preauth_free_station(hapd, sta);
314#ifndef CONFIG_NO_RADIUS
Dmitry Shmidt96571392013-10-14 12:54:46 -0700315 if (hapd->radius)
316 radius_client_flush_auth(hapd->radius, sta->addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700317#endif /* CONFIG_NO_RADIUS */
318
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800319#ifndef CONFIG_NO_VLAN
320 /*
321 * sta->wpa_sm->group needs to be released before so that
322 * vlan_remove_dynamic() can check that no stations are left on the
323 * AP_VLAN netdev.
324 */
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800325 if (sta->vlan_id)
326 vlan_remove_dynamic(hapd, sta->vlan_id);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800327 if (sta->vlan_id_bound) {
328 /*
329 * Need to remove the STA entry before potentially removing the
330 * VLAN.
331 */
332 if (hapd->iface->driver_ap_teardown &&
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800333 !(sta->flags & WLAN_STA_PREAUTH)) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800334 hostapd_drv_sta_remove(hapd, sta->addr);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800335 sta->added_unassoc = 0;
336 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800337 vlan_remove_dynamic(hapd, sta->vlan_id_bound);
338 }
339#endif /* CONFIG_NO_VLAN */
340
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700341 os_free(sta->challenge);
342
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700343 os_free(sta->sa_query_trans_id);
344 eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700345
346#ifdef CONFIG_P2P
347 p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
348#endif /* CONFIG_P2P */
349
Dmitry Shmidt04949592012-07-19 12:16:46 -0700350#ifdef CONFIG_INTERWORKING
351 if (sta->gas_dialog) {
352 int i;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000353
Dmitry Shmidt04949592012-07-19 12:16:46 -0700354 for (i = 0; i < GAS_DIALOG_MAX; i++)
355 gas_serv_dialog_clear(&sta->gas_dialog[i]);
356 os_free(sta->gas_dialog);
357 }
358#endif /* CONFIG_INTERWORKING */
359
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700360 wpabuf_free(sta->wps_ie);
361 wpabuf_free(sta->p2p_ie);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800362 wpabuf_free(sta->hs20_ie);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700363 wpabuf_free(sta->roaming_consortium);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800364#ifdef CONFIG_FST
365 wpabuf_free(sta->mb_ies);
366#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700367
368 os_free(sta->ht_capabilities);
Dmitry Shmidt292b0c32013-11-22 12:54:42 -0800369 os_free(sta->vht_capabilities);
Hai Shalom74f70d42019-02-11 14:42:39 -0800370 os_free(sta->vht_operation);
Hai Shalom81f62d82019-07-22 12:10:00 -0700371 os_free(sta->he_capab);
Hai Shalom4fbc08f2020-05-18 12:37:00 -0700372 os_free(sta->he_6ghz_capab);
Sunil Ravia04bd252022-05-02 22:54:18 -0700373 os_free(sta->eht_capab);
Dmitry Shmidtd5e49232012-12-03 15:08:10 -0800374 hostapd_free_psk_list(sta->psk);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700375 os_free(sta->identity);
376 os_free(sta->radius_cui);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800377 os_free(sta->remediation_url);
Roshan Pius3a1667e2018-07-03 15:17:14 -0700378 os_free(sta->t_c_url);
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800379 wpabuf_free(sta->hs20_deauth_req);
380 os_free(sta->hs20_session_info_url);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700381
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800382#ifdef CONFIG_SAE
383 sae_clear_data(sta->sae);
384 os_free(sta->sae);
385#endif /* CONFIG_SAE */
386
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800387 mbo_ap_sta_free(sta);
Dmitry Shmidt9c175262016-03-03 10:20:07 -0800388 os_free(sta->supp_op_classes);
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800389
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800390#ifdef CONFIG_FILS
391 os_free(sta->fils_pending_assoc_req);
392 wpabuf_free(sta->fils_hlp_resp);
393 wpabuf_free(sta->hlp_dhcp_discover);
394 eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700395#ifdef CONFIG_FILS_SK_PFS
396 crypto_ecdh_deinit(sta->fils_ecdh);
397 wpabuf_clear_free(sta->fils_dh_ss);
398 wpabuf_free(sta->fils_g_sta);
399#endif /* CONFIG_FILS_SK_PFS */
Dmitry Shmidtebd93af2017-02-21 13:40:44 -0800400#endif /* CONFIG_FILS */
401
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700402#ifdef CONFIG_OWE
403 bin_clear_free(sta->owe_pmk, sta->owe_pmk_len);
404 crypto_ecdh_deinit(sta->owe_ecdh);
405#endif /* CONFIG_OWE */
406
Hai Shalom021b0b52019-04-10 11:17:58 -0700407#ifdef CONFIG_DPP2
408 dpp_pfs_free(sta->dpp_pfs);
409 sta->dpp_pfs = NULL;
410#endif /* CONFIG_DPP2 */
411
Roshan Pius3a1667e2018-07-03 15:17:14 -0700412 os_free(sta->ext_capability);
413
414#ifdef CONFIG_WNM_AP
415 eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
416#endif /* CONFIG_WNM_AP */
417
Hai Shalom60840252021-02-19 19:02:11 -0800418#ifdef CONFIG_PASN
419 ap_free_sta_pasn(hapd, sta);
420#endif /* CONFIG_PASN */
421
Roshan Pius3a1667e2018-07-03 15:17:14 -0700422 os_free(sta->ifname_wds);
423
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000424#ifdef CONFIG_IEEE80211BE
425 ap_sta_free_sta_profile(&sta->mld_info);
426#endif /* CONFIG_IEEE80211BE */
427
Hai Shalomfdcde762020-04-02 11:19:20 -0700428#ifdef CONFIG_TESTING_OPTIONS
429 os_free(sta->sae_postponed_commit);
Sunil Ravia04bd252022-05-02 22:54:18 -0700430 forced_memzero(sta->last_tk, WPA_TK_MAX_LEN);
Hai Shalomfdcde762020-04-02 11:19:20 -0700431#endif /* CONFIG_TESTING_OPTIONS */
432
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700433 os_free(sta);
434}
435
436
437void hostapd_free_stas(struct hostapd_data *hapd)
438{
439 struct sta_info *sta, *prev;
440
441 sta = hapd->sta_list;
442
443 while (sta) {
444 prev = sta;
445 if (sta->flags & WLAN_STA_AUTH) {
446 mlme_deauthenticate_indication(
447 hapd, sta, WLAN_REASON_UNSPECIFIED);
448 }
449 sta = sta->next;
450 wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
451 MAC2STR(prev->addr));
452 ap_free_sta(hapd, prev);
453 }
454}
455
456
457/**
458 * ap_handle_timer - Per STA timer handler
459 * @eloop_ctx: struct hostapd_data *
460 * @timeout_ctx: struct sta_info *
461 *
462 * This function is called to check station activity and to remove inactive
463 * stations.
464 */
465void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
466{
467 struct hostapd_data *hapd = eloop_ctx;
468 struct sta_info *sta = timeout_ctx;
469 unsigned long next_time = 0;
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700470 int reason;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700471
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800472 wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
473 hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
Dmitry Shmidt04949592012-07-19 12:16:46 -0700474 sta->timeout_next);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700475 if (sta->timeout_next == STA_REMOVE) {
476 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
477 HOSTAPD_LEVEL_INFO, "deauthenticated due to "
478 "local deauth request");
479 ap_free_sta(hapd, sta);
480 return;
481 }
482
483 if ((sta->flags & WLAN_STA_ASSOC) &&
484 (sta->timeout_next == STA_NULLFUNC ||
485 sta->timeout_next == STA_DISASSOC)) {
486 int inactive_sec;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700487 /*
488 * Add random value to timeout so that we don't end up bouncing
489 * all stations at the same time if we have lots of associated
490 * stations that are idle (but keep re-associating).
491 */
492 int fuzz = os_random() % 20;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700493 inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
494 if (inactive_sec == -1) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800495 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
496 "Check inactivity: Could not "
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800497 "get station info from kernel driver for "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700498 MACSTR, MAC2STR(sta->addr));
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -0800499 /*
500 * The driver may not support this functionality.
501 * Anyway, try again after the next inactivity timeout,
502 * but do not disconnect the station now.
503 */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700504 next_time = hapd->conf->ap_max_inactivity + fuzz;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800505 } else if (inactive_sec == -ENOENT) {
506 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
507 "Station " MACSTR " has lost its driver entry",
508 MAC2STR(sta->addr));
509
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800510 /* Avoid sending client probe on removed client */
511 sta->timeout_next = STA_DISASSOC;
512 goto skip_poll;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800513 } else if (inactive_sec < hapd->conf->ap_max_inactivity) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700514 /* station activity detected; reset timeout state */
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800515 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
516 "Station " MACSTR " has been active %is ago",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700517 MAC2STR(sta->addr), inactive_sec);
518 sta->timeout_next = STA_NULLFUNC;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700519 next_time = hapd->conf->ap_max_inactivity + fuzz -
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700520 inactive_sec;
521 } else {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800522 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
523 "Station " MACSTR " has been "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700524 "inactive too long: %d sec, max allowed: %d",
525 MAC2STR(sta->addr), inactive_sec,
526 hapd->conf->ap_max_inactivity);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800527
528 if (hapd->conf->skip_inactivity_poll)
529 sta->timeout_next = STA_DISASSOC;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530 }
531 }
532
533 if ((sta->flags & WLAN_STA_ASSOC) &&
534 sta->timeout_next == STA_DISASSOC &&
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800535 !(sta->flags & WLAN_STA_PENDING_POLL) &&
536 !hapd->conf->skip_inactivity_poll) {
537 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
538 " has ACKed data poll", MAC2STR(sta->addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700539 /* data nullfunc frame poll did not produce TX errors; assume
540 * station ACKed it */
541 sta->timeout_next = STA_NULLFUNC;
542 next_time = hapd->conf->ap_max_inactivity;
543 }
544
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800545skip_poll:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700546 if (next_time) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700547 wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
548 "for " MACSTR " (%lu seconds)",
549 __func__, MAC2STR(sta->addr), next_time);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700550 eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
551 sta);
552 return;
553 }
554
555 if (sta->timeout_next == STA_NULLFUNC &&
556 (sta->flags & WLAN_STA_ASSOC)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800557 wpa_printf(MSG_DEBUG, " Polling STA");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700558 sta->flags |= WLAN_STA_PENDING_POLL;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800559 hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
560 sta->flags & WLAN_STA_WMM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700561 } else if (sta->timeout_next != STA_REMOVE) {
562 int deauth = sta->timeout_next == STA_DEAUTH;
563
Hai Shalom74f70d42019-02-11 14:42:39 -0800564 if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) {
565 /* Cannot disassociate not-associated STA, so move
566 * directly to deauthentication. */
567 sta->timeout_next = STA_DEAUTH;
568 deauth = 1;
569 }
570
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800571 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
572 "Timeout, sending %s info to STA " MACSTR,
573 deauth ? "deauthentication" : "disassociation",
574 MAC2STR(sta->addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700575
576 if (deauth) {
577 hostapd_drv_sta_deauth(
578 hapd, sta->addr,
579 WLAN_REASON_PREV_AUTH_NOT_VALID);
580 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700581 reason = (sta->timeout_next == STA_DISASSOC) ?
582 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
583 WLAN_REASON_PREV_AUTH_NOT_VALID;
584
585 hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700586 }
587 }
588
589 switch (sta->timeout_next) {
590 case STA_NULLFUNC:
591 sta->timeout_next = STA_DISASSOC;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700592 wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
593 "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
594 __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700595 eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
596 hapd, sta);
597 break;
598 case STA_DISASSOC:
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700599 case STA_DISASSOC_FROM_CLI:
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800600 ap_sta_set_authorized(hapd, sta, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700601 sta->flags &= ~WLAN_STA_ASSOC;
Hai Shalomfdcde762020-04-02 11:19:20 -0700602 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700603 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
604 if (!sta->acct_terminate_cause)
605 sta->acct_terminate_cause =
606 RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
607 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -0800608 ieee802_1x_free_station(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700609 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
610 HOSTAPD_LEVEL_INFO, "disassociated due to "
611 "inactivity");
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700612 reason = (sta->timeout_next == STA_DISASSOC) ?
613 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY :
614 WLAN_REASON_PREV_AUTH_NOT_VALID;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700615 sta->timeout_next = STA_DEAUTH;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700616 wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
617 "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
618 __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700619 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
620 hapd, sta);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -0700621 mlme_disassociate_indication(hapd, sta, reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700622 break;
623 case STA_DEAUTH:
624 case STA_REMOVE:
625 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
626 HOSTAPD_LEVEL_INFO, "deauthenticated due to "
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800627 "inactivity (timer DEAUTH/REMOVE)");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700628 if (!sta->acct_terminate_cause)
629 sta->acct_terminate_cause =
630 RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
631 mlme_deauthenticate_indication(
632 hapd, sta,
633 WLAN_REASON_PREV_AUTH_NOT_VALID);
634 ap_free_sta(hapd, sta);
635 break;
636 }
637}
638
639
640static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
641{
642 struct hostapd_data *hapd = eloop_ctx;
643 struct sta_info *sta = timeout_ctx;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700644
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800645 wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR,
646 hapd->conf->iface, MAC2STR(sta->addr));
Hai Shalomfdcde762020-04-02 11:19:20 -0700647 if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC |
648 WLAN_STA_AUTHORIZED))) {
Dmitry Shmidt04949592012-07-19 12:16:46 -0700649 if (sta->flags & WLAN_STA_GAS) {
650 wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
651 "entry " MACSTR, MAC2STR(sta->addr));
652 ap_free_sta(hapd, sta);
653 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700654 return;
Dmitry Shmidt04949592012-07-19 12:16:46 -0700655 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700656
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700657 hostapd_drv_sta_deauth(hapd, sta->addr,
658 WLAN_REASON_PREV_AUTH_NOT_VALID);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700659 mlme_deauthenticate_indication(hapd, sta,
660 WLAN_REASON_PREV_AUTH_NOT_VALID);
661 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
662 HOSTAPD_LEVEL_INFO, "deauthenticated due to "
663 "session timeout");
664 sta->acct_terminate_cause =
665 RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700666 ap_free_sta(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700667}
668
669
Dmitry Shmidt54605472013-11-08 11:10:19 -0800670void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
671 u32 session_timeout)
672{
673 if (eloop_replenish_timeout(session_timeout, 0,
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -0800674 ap_handle_session_timer, hapd, sta) == 1) {
Dmitry Shmidt54605472013-11-08 11:10:19 -0800675 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
676 HOSTAPD_LEVEL_DEBUG, "setting session timeout "
677 "to %d seconds", session_timeout);
678 }
679}
680
681
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700682void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
683 u32 session_timeout)
684{
685 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
686 HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
687 "seconds", session_timeout);
688 eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
689 eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
690 hapd, sta);
691}
692
693
694void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
695{
696 eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
697}
698
699
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800700static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx)
701{
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700702#ifdef CONFIG_WNM_AP
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800703 struct hostapd_data *hapd = eloop_ctx;
704 struct sta_info *sta = timeout_ctx;
705
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800706 wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for "
707 MACSTR, hapd->conf->iface, MAC2STR(sta->addr));
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800708 if (sta->hs20_session_info_url == NULL)
709 return;
710
711 wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url,
712 sta->hs20_disassoc_timer);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700713#endif /* CONFIG_WNM_AP */
Dmitry Shmidtf21452a2014-02-26 10:55:25 -0800714}
715
716
717void ap_sta_session_warning_timeout(struct hostapd_data *hapd,
718 struct sta_info *sta, int warning_time)
719{
720 eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
721 eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer,
722 hapd, sta);
723}
724
725
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700726struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
727{
728 struct sta_info *sta;
Hai Shalom81f62d82019-07-22 12:10:00 -0700729 int i;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700730
731 sta = ap_get_sta(hapd, addr);
732 if (sta)
733 return sta;
734
735 wpa_printf(MSG_DEBUG, " New STA");
736 if (hapd->num_sta >= hapd->conf->max_num_sta) {
737 /* FIX: might try to remove some old STAs first? */
738 wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
739 hapd->num_sta, hapd->conf->max_num_sta);
740 return NULL;
741 }
742
743 sta = os_zalloc(sizeof(struct sta_info));
744 if (sta == NULL) {
745 wpa_printf(MSG_ERROR, "malloc failed");
746 return NULL;
747 }
748 sta->acct_interim_interval = hapd->conf->acct_interim_interval;
Dmitry Shmidtb97e4282016-02-08 10:16:07 -0800749 if (accounting_sta_get_id(hapd, sta) < 0) {
750 os_free(sta);
751 return NULL;
752 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700753
Hai Shalom81f62d82019-07-22 12:10:00 -0700754 for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
755 if (!hapd->iface->basic_rates)
756 break;
757 if (hapd->iface->basic_rates[i] < 0)
758 break;
759 sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5;
760 }
761 sta->supported_rates_len = i;
762
Dmitry Shmidt01904cf2013-12-05 11:08:35 -0800763 if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
764 wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
765 "for " MACSTR " (%d seconds - ap_max_inactivity)",
766 __func__, MAC2STR(addr),
767 hapd->conf->ap_max_inactivity);
768 eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
769 ap_handle_timer, hapd, sta);
770 }
771
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700772 /* initialize STA info data */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700773 os_memcpy(sta->addr, addr, ETH_ALEN);
774 sta->next = hapd->sta_list;
775 hapd->sta_list = sta;
776 hapd->num_sta++;
777 ap_sta_hash_add(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700778 ap_sta_remove_in_other_bss(hapd, sta);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800779 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
780 dl_list_init(&sta->ip6addr);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700781
Dmitry Shmidtaca489e2016-09-28 15:44:14 -0700782#ifdef CONFIG_TAXONOMY
783 sta_track_claim_taxonomy_info(hapd->iface, addr,
784 &sta->probe_ie_taxonomy);
785#endif /* CONFIG_TAXONOMY */
786
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700787 return sta;
788}
789
790
791static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
792{
793 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
794
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800795 if (sta->ipaddr)
796 hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
797 ap_sta_ip6addr_del(hapd, sta);
798
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800799 wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver",
800 hapd->conf->iface, MAC2STR(sta->addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700801 if (hostapd_drv_sta_remove(hapd, sta->addr) &&
802 sta->flags & WLAN_STA_ASSOC) {
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800803 wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR
804 " from kernel driver",
805 hapd->conf->iface, MAC2STR(sta->addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700806 return -1;
807 }
Dmitry Shmidt57c2d392016-02-23 13:40:19 -0800808 sta->added_unassoc = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700809 return 0;
810}
811
812
813static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
814 struct sta_info *sta)
815{
816 struct hostapd_iface *iface = hapd->iface;
817 size_t i;
818
819 for (i = 0; i < iface->num_bss; i++) {
820 struct hostapd_data *bss = iface->bss[i];
821 struct sta_info *sta2;
822 /* bss should always be set during operation, but it may be
823 * NULL during reconfiguration. Assume the STA is not
824 * associated to another BSS in that case to avoid NULL pointer
825 * dereferences. */
826 if (bss == hapd || bss == NULL)
827 continue;
828 sta2 = ap_get_sta(bss, sta->addr);
829 if (!sta2)
830 continue;
831
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800832 wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR
833 " association from another BSS %s",
834 hapd->conf->iface, MAC2STR(sta2->addr),
835 bss->conf->iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700836 ap_sta_disconnect(bss, sta2, sta2->addr,
837 WLAN_REASON_PREV_AUTH_NOT_VALID);
838 }
839}
840
841
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800842static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
843{
844 struct hostapd_data *hapd = eloop_ctx;
845 struct sta_info *sta = timeout_ctx;
846
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800847 wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR,
848 hapd->conf->iface, MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800849 ap_sta_remove(hapd, sta);
850 mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
851}
852
853
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000854static void ap_sta_disconnect_common(struct hostapd_data *hapd,
855 struct sta_info *sta, unsigned int timeout)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700856{
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800857 sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000858
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800859 ap_sta_set_authorized(hapd, sta, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -0700860 hostapd_set_sta_flags(hapd, sta);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000861
862 wpa_printf(MSG_DEBUG,
863 "reschedule ap_handle_timer timeout (%u sec) for " MACSTR,
864 MAC2STR(sta->addr), timeout);
865
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700866 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000867 eloop_register_timeout(timeout, 0, ap_handle_timer, hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700868 accounting_sta_stop(hapd, sta);
Dmitry Shmidtde47be72016-01-07 12:52:55 -0800869 ieee802_1x_free_station(hapd, sta);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000870#ifdef CONFIG_IEEE80211BE
871 if (!hapd->conf->mld_ap ||
872 hapd->mld_link_id == sta->mld_assoc_link_id)
873 wpa_auth_sta_deinit(sta->wpa_sm);
874#else
Hai Shalom81f62d82019-07-22 12:10:00 -0700875 wpa_auth_sta_deinit(sta->wpa_sm);
Sunil Ravi2a14cf12023-11-21 00:54:38 +0000876#endif /* CONFIG_IEEE80211BE */
877
Hai Shalom81f62d82019-07-22 12:10:00 -0700878 sta->wpa_sm = NULL;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000879}
880
881
882static void ap_sta_handle_disassociate(struct hostapd_data *hapd,
883 struct sta_info *sta, u16 reason)
884{
885 wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
886 hapd->conf->iface, MAC2STR(sta->addr));
887
888 if (hapd->iface->current_mode &&
889 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
890 /* Skip deauthentication in DMG/IEEE 802.11ad */
891 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
892 WLAN_STA_ASSOC_REQ_OK);
893 sta->timeout_next = STA_REMOVE;
894 } else {
895 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
896 sta->timeout_next = STA_DEAUTH;
897 }
898
899 ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700900
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800901 sta->disassoc_reason = reason;
902 sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
903 eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
904 eloop_register_timeout(hapd->iface->drv_flags &
905 WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
906 ap_sta_disassoc_cb_timeout, hapd, sta);
907}
908
909
910static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
911{
912 struct hostapd_data *hapd = eloop_ctx;
913 struct sta_info *sta = timeout_ctx;
914
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -0800915 wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR,
916 hapd->conf->iface, MAC2STR(sta->addr));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800917 ap_sta_remove(hapd, sta);
918 mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700919}
920
921
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000922static void ap_sta_handle_deauthenticate(struct hostapd_data *hapd,
923 struct sta_info *sta, u16 reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700924{
Dmitry Shmidt29333592017-01-09 12:27:11 -0800925 if (hapd->iface->current_mode &&
926 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
927 /* Deauthentication is not used in DMG/IEEE 802.11ad;
928 * disassociate the STA instead. */
929 ap_sta_disassociate(hapd, sta, reason);
930 return;
931 }
932
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700933 wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
934 hapd->conf->iface, MAC2STR(sta->addr));
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000935
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800936 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000937
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700938 sta->timeout_next = STA_REMOVE;
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000939 ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700940
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800941 sta->deauth_reason = reason;
942 sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
943 eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
944 eloop_register_timeout(hapd->iface->drv_flags &
945 WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
946 ap_sta_deauth_cb_timeout, hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700947}
948
949
Sunil Ravib0ac25f2024-07-12 01:42:03 +0000950static bool ap_sta_ml_disconnect(struct hostapd_data *hapd,
951 struct sta_info *sta, u16 reason,
952 bool disassoc)
953{
954#ifdef CONFIG_IEEE80211BE
955 struct hostapd_data *assoc_hapd, *tmp_hapd;
956 struct sta_info *assoc_sta;
957 unsigned int i, link_id;
958 struct hapd_interfaces *interfaces;
959
960 if (!hostapd_is_mld_ap(hapd))
961 return false;
962
963 /*
964 * Get the station on which the association was performed, as it holds
965 * the information about all the other links.
966 */
967 assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd);
968 if (!assoc_sta)
969 return false;
970 interfaces = assoc_hapd->iface->interfaces;
971
972 for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
973 for (i = 0; i < interfaces->count; i++) {
974 struct sta_info *tmp_sta;
975
976 if (!assoc_sta->mld_info.links[link_id].valid)
977 continue;
978
979 tmp_hapd = interfaces->iface[i]->bss[0];
980
981 if (!tmp_hapd->conf->mld_ap ||
982 assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id)
983 continue;
984
985 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
986 tmp_sta = tmp_sta->next) {
987 /*
988 * Handle the station on which the association
989 * was done only after all other link station
990 * are removed. Since there is a only a single
991 * station per hapd with the same association
992 * link simply break;
993 */
994 if (tmp_sta == assoc_sta)
995 break;
996
997 if (tmp_sta->mld_assoc_link_id !=
998 assoc_sta->mld_assoc_link_id ||
999 tmp_sta->aid != assoc_sta->aid)
1000 continue;
1001
1002 if (disassoc)
1003 ap_sta_handle_disassociate(tmp_hapd,
1004 tmp_sta,
1005 reason);
1006 else
1007 ap_sta_handle_deauthenticate(tmp_hapd,
1008 tmp_sta,
1009 reason);
1010
1011 break;
1012 }
1013 }
1014 }
1015
1016 /* Disconnect the station on which the association was performed. */
1017 if (disassoc)
1018 ap_sta_handle_disassociate(assoc_hapd, assoc_sta, reason);
1019 else
1020 ap_sta_handle_deauthenticate(assoc_hapd, assoc_sta, reason);
1021
1022 return true;
1023#else /* CONFIG_IEEE80211BE */
1024 return false;
1025#endif /* CONFIG_IEEE80211BE */
1026}
1027
1028
1029void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
1030 u16 reason)
1031{
1032 if (ap_sta_ml_disconnect(hapd, sta, reason, true))
1033 return;
1034
1035 ap_sta_handle_disassociate(hapd, sta, reason);
1036}
1037
1038
1039void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
1040 u16 reason)
1041{
1042 if (ap_sta_ml_disconnect(hapd, sta, reason, false))
1043 return;
1044
1045 ap_sta_handle_deauthenticate(hapd, sta, reason);
1046}
1047
1048
Dmitry Shmidt04949592012-07-19 12:16:46 -07001049#ifdef CONFIG_WPS
1050int ap_sta_wps_cancel(struct hostapd_data *hapd,
1051 struct sta_info *sta, void *ctx)
1052{
1053 if (sta && (sta->flags & WLAN_STA_WPS)) {
1054 ap_sta_deauthenticate(hapd, sta,
1055 WLAN_REASON_PREV_AUTH_NOT_VALID);
1056 wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
1057 __func__, MAC2STR(sta->addr));
1058 return 1;
1059 }
1060
1061 return 0;
1062}
1063#endif /* CONFIG_WPS */
1064
1065
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001066static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd)
1067{
1068 struct hostapd_vlan *vlan;
1069 int vlan_id = MAX_VLAN_ID + 2;
1070
1071retry:
1072 for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
1073 if (vlan->vlan_id == vlan_id) {
1074 vlan_id++;
1075 goto retry;
1076 }
1077 }
1078 return vlan_id;
1079}
1080
1081
1082int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
1083 struct vlan_description *vlan_desc)
1084{
1085 struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
1086 int old_vlan_id, vlan_id = 0, ret = 0;
1087
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001088 /* Check if there is something to do */
1089 if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) {
1090 /* This sta is lacking its own vif */
1091 } else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED &&
1092 !hapd->conf->ssid.per_sta_vif && sta->vlan_id) {
1093 /* sta->vlan_id needs to be reset */
1094 } else if (!vlan_compare(vlan_desc, sta->vlan_desc)) {
1095 return 0; /* nothing to change */
1096 }
1097
1098 /* Now the real VLAN changed or the STA just needs its own vif */
1099 if (hapd->conf->ssid.per_sta_vif) {
1100 /* Assign a new vif, always */
1101 /* find a free vlan_id sufficiently big */
1102 vlan_id = ap_sta_get_free_vlan_id(hapd);
1103 /* Get wildcard VLAN */
1104 for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
1105 if (vlan->vlan_id == VLAN_ID_WILDCARD)
1106 break;
1107 }
1108 if (!vlan) {
1109 hostapd_logger(hapd, sta->addr,
1110 HOSTAPD_MODULE_IEEE80211,
1111 HOSTAPD_LEVEL_DEBUG,
1112 "per_sta_vif missing wildcard");
1113 vlan_id = 0;
1114 ret = -1;
1115 goto done;
1116 }
1117 } else if (vlan_desc && vlan_desc->notempty) {
1118 for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
1119 if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
1120 break;
1121 if (vlan->vlan_id == VLAN_ID_WILDCARD)
1122 wildcard_vlan = vlan;
1123 }
1124 if (vlan) {
1125 vlan_id = vlan->vlan_id;
1126 } else if (wildcard_vlan) {
1127 vlan = wildcard_vlan;
1128 vlan_id = vlan_desc->untagged;
1129 if (vlan_desc->tagged[0]) {
1130 /* Tagged VLAN configuration */
1131 vlan_id = ap_sta_get_free_vlan_id(hapd);
1132 }
1133 } else {
1134 hostapd_logger(hapd, sta->addr,
1135 HOSTAPD_MODULE_IEEE80211,
1136 HOSTAPD_LEVEL_DEBUG,
1137 "missing vlan and wildcard for vlan=%d%s",
1138 vlan_desc->untagged,
1139 vlan_desc->tagged[0] ? "+" : "");
1140 vlan_id = 0;
1141 ret = -1;
1142 goto done;
1143 }
1144 }
1145
1146 if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
1147 vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
1148 if (vlan == NULL) {
1149 hostapd_logger(hapd, sta->addr,
1150 HOSTAPD_MODULE_IEEE80211,
1151 HOSTAPD_LEVEL_DEBUG,
1152 "could not add dynamic VLAN interface for vlan=%d%s",
1153 vlan_desc ? vlan_desc->untagged : -1,
1154 (vlan_desc && vlan_desc->tagged[0]) ?
1155 "+" : "");
1156 vlan_id = 0;
1157 ret = -1;
1158 goto done;
1159 }
1160
1161 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1162 HOSTAPD_LEVEL_DEBUG,
1163 "added new dynamic VLAN interface '%s'",
1164 vlan->ifname);
1165 } else if (vlan && vlan->dynamic_vlan > 0) {
1166 vlan->dynamic_vlan++;
1167 hostapd_logger(hapd, sta->addr,
1168 HOSTAPD_MODULE_IEEE80211,
1169 HOSTAPD_LEVEL_DEBUG,
1170 "updated existing dynamic VLAN interface '%s'",
1171 vlan->ifname);
1172 }
1173done:
1174 old_vlan_id = sta->vlan_id;
1175 sta->vlan_id = vlan_id;
1176 sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
1177
1178 if (vlan_id != old_vlan_id && old_vlan_id)
1179 vlan_remove_dynamic(hapd, old_vlan_id);
1180
1181 return ret;
1182}
1183
1184
Dmitry Shmidt83474442015-04-15 13:47:09 -07001185int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001186{
1187#ifndef CONFIG_NO_VLAN
1188 const char *iface;
1189 struct hostapd_vlan *vlan = NULL;
1190 int ret;
Dmitry Shmidt83474442015-04-15 13:47:09 -07001191 int old_vlanid = sta->vlan_id_bound;
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001192 int mld_link_id = -1;
1193
1194#ifdef CONFIG_IEEE80211BE
1195 if (hapd->conf->mld_ap)
1196 mld_link_id = hapd->mld_link_id;
1197#endif /* CONFIG_IEEE80211BE */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001198
Hai Shalomfdcde762020-04-02 11:19:20 -07001199 if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) {
1200 wpa_printf(MSG_DEBUG,
1201 "Do not override WDS VLAN assignment for STA "
1202 MACSTR, MAC2STR(sta->addr));
1203 return 0;
1204 }
1205
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001206 iface = hapd->conf->iface;
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -07001207 if (hapd->conf->ssid.vlan[0])
1208 iface = hapd->conf->ssid.vlan;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001209
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001210 if (sta->vlan_id > 0) {
1211 for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07001212 if (vlan->vlan_id == sta->vlan_id)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001213 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001214 }
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -07001215 if (vlan)
1216 iface = vlan->ifname;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001217 }
1218
Dmitry Shmidt83474442015-04-15 13:47:09 -07001219 /*
1220 * Do not increment ref counters if the VLAN ID remains same, but do
1221 * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
1222 * have been called before.
1223 */
1224 if (sta->vlan_id == old_vlanid)
1225 goto skip_counting;
1226
Hai Shalomfdcde762020-04-02 11:19:20 -07001227 if (sta->vlan_id > 0 && !vlan &&
1228 !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001229 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1230 HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
1231 "binding station to (vlan_id=%d)",
1232 sta->vlan_id);
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001233 ret = -1;
1234 goto done;
Dmitry Shmidt57c2d392016-02-23 13:40:19 -08001235 } else if (vlan && vlan->dynamic_vlan > 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001236 vlan->dynamic_vlan++;
1237 hostapd_logger(hapd, sta->addr,
1238 HOSTAPD_MODULE_IEEE80211,
1239 HOSTAPD_LEVEL_DEBUG,
1240 "updated existing dynamic VLAN interface '%s'",
1241 iface);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001242 }
1243
Dmitry Shmidt83474442015-04-15 13:47:09 -07001244 /* ref counters have been increased, so mark the station */
1245 sta->vlan_id_bound = sta->vlan_id;
1246
1247skip_counting:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001248 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1249 HOSTAPD_LEVEL_DEBUG, "binding station to interface "
1250 "'%s'", iface);
1251
1252 if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
1253 wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
1254
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001255 ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id,
1256 mld_link_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001257 if (ret < 0) {
1258 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1259 HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
1260 "entry to vlan_id=%d", sta->vlan_id);
1261 }
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001262
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001263 /* During 1x reauth, if the vlan id changes, then remove the old id. */
Dmitry Shmidt83474442015-04-15 13:47:09 -07001264 if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001265 vlan_remove_dynamic(hapd, old_vlanid);
Dmitry Shmidt83474442015-04-15 13:47:09 -07001266done:
Dmitry Shmidt216983b2015-02-06 10:50:36 -08001267
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001268 return ret;
1269#else /* CONFIG_NO_VLAN */
1270 return 0;
1271#endif /* CONFIG_NO_VLAN */
1272}
1273
1274
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001275int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
1276{
1277 u32 tu;
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001278 struct os_reltime now, passed;
1279 os_get_reltime(&now);
1280 os_reltime_sub(&now, &sta->sa_query_start, &passed);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001281 tu = (passed.sec * 1000000 + passed.usec) / 1024;
1282 if (hapd->conf->assoc_sa_query_max_timeout < tu) {
1283 hostapd_logger(hapd, sta->addr,
1284 HOSTAPD_MODULE_IEEE80211,
1285 HOSTAPD_LEVEL_DEBUG,
1286 "association SA Query timed out");
1287 sta->sa_query_timed_out = 1;
1288 os_free(sta->sa_query_trans_id);
1289 sta->sa_query_trans_id = NULL;
1290 sta->sa_query_count = 0;
1291 eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
1292 return 1;
1293 }
1294
1295 return 0;
1296}
1297
1298
1299static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
1300{
1301 struct hostapd_data *hapd = eloop_ctx;
1302 struct sta_info *sta = timeout_ctx;
1303 unsigned int timeout, sec, usec;
1304 u8 *trans_id, *nbuf;
1305
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08001306 wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR
1307 " (count=%d)",
1308 hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count);
1309
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001310 if (sta->sa_query_count > 0 &&
1311 ap_check_sa_query_timeout(hapd, sta))
1312 return;
Hai Shalomfdcde762020-04-02 11:19:20 -07001313 if (sta->sa_query_count >= 1000)
1314 return;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001315
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001316 nbuf = os_realloc_array(sta->sa_query_trans_id,
1317 sta->sa_query_count + 1,
1318 WLAN_SA_QUERY_TR_ID_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001319 if (nbuf == NULL)
1320 return;
1321 if (sta->sa_query_count == 0) {
1322 /* Starting a new SA Query procedure */
Dmitry Shmidt04f534e2013-12-09 15:50:16 -08001323 os_get_reltime(&sta->sa_query_start);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001324 }
1325 trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
1326 sta->sa_query_trans_id = nbuf;
1327 sta->sa_query_count++;
1328
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001329 if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
1330 /*
1331 * We don't really care which ID is used here, so simply
1332 * hardcode this if the mostly theoretical os_get_random()
1333 * failure happens.
1334 */
1335 trans_id[0] = 0x12;
1336 trans_id[1] = 0x34;
1337 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001338
1339 timeout = hapd->conf->assoc_sa_query_retry_timeout;
1340 sec = ((timeout / 1000) * 1024) / 1000;
1341 usec = (timeout % 1000) * 1024;
1342 eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
1343
1344 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
1345 HOSTAPD_LEVEL_DEBUG,
1346 "association SA Query attempt %d", sta->sa_query_count);
1347
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001348 ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001349}
1350
1351
1352void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
1353{
1354 ap_sa_query_timer(hapd, sta);
1355}
1356
1357
1358void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
1359{
1360 eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
1361 os_free(sta->sa_query_trans_id);
1362 sta->sa_query_trans_id = NULL;
1363 sta->sa_query_count = 0;
1364}
1365
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001366
Hai Shalom74f70d42019-02-11 14:42:39 -08001367const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
1368 struct sta_info *sta)
1369{
1370 struct hostapd_wpa_psk *psk;
1371 struct hostapd_ssid *ssid;
1372 const u8 *pmk;
1373 int pmk_len;
1374
1375 ssid = &hapd->conf->ssid;
1376
1377 pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len);
1378 if (!pmk || pmk_len != PMK_LEN)
1379 return NULL;
1380
1381 for (psk = ssid->wpa_psk; psk; psk = psk->next)
1382 if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
1383 break;
Hai Shalom74f70d42019-02-11 14:42:39 -08001384 if (!psk || !psk->keyid[0])
1385 return NULL;
1386
1387 return psk->keyid;
1388}
1389
1390
Sunil Ravi77d572f2023-01-17 23:58:31 +00001391const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
1392 struct sta_info *sta)
1393{
1394 return wpa_auth_get_dpp_pkhash(sta->wpa_sm);
1395}
1396
1397
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001398bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta,
1399 int authorized)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001400{
1401 if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001402 return false;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001403
Sunil Ravi640215c2023-06-28 23:08:09 +00001404 if (authorized) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001405 int mld_assoc_link_id = -1;
1406
1407#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001408 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001409 if (sta->mld_assoc_link_id == hapd->mld_link_id)
1410 mld_assoc_link_id = sta->mld_assoc_link_id;
1411 else
1412 mld_assoc_link_id = -2;
1413 }
1414#endif /* CONFIG_IEEE80211BE */
1415 if (mld_assoc_link_id != -2)
1416 hostapd_prune_associations(hapd, sta->addr,
1417 mld_assoc_link_id);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001418 sta->flags |= WLAN_STA_AUTHORIZED;
Sunil Ravi640215c2023-06-28 23:08:09 +00001419 } else {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001420 sta->flags &= ~WLAN_STA_AUTHORIZED;
Sunil Ravi640215c2023-06-28 23:08:09 +00001421 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001422
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001423 return true;
1424}
1425
1426
1427void ap_sta_set_authorized_event(struct hostapd_data *hapd,
1428 struct sta_info *sta, int authorized)
1429{
1430 const u8 *dev_addr = NULL;
1431 char buf[100];
1432#ifdef CONFIG_P2P
1433 u8 addr[ETH_ALEN];
1434 u8 ip_addr_buf[4];
1435#endif /* CONFIG_P2P */
1436 u8 *ip_ptr = NULL;
1437
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001438#ifdef CONFIG_P2P
Dmitry Shmidt04949592012-07-19 12:16:46 -07001439 if (hapd->p2p_group == NULL) {
1440 if (sta->p2p_ie != NULL &&
1441 p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
1442 dev_addr = addr;
1443 } else
1444 dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001445
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001446 if (dev_addr)
1447 os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR,
1448 MAC2STR(sta->addr), MAC2STR(dev_addr));
1449 else
Dmitry Shmidt661b4f72014-09-29 14:58:27 -07001450#endif /* CONFIG_P2P */
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001451 os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
1452
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001453 if (authorized) {
Sunil Ravi77d572f2023-01-17 23:58:31 +00001454 const u8 *dpp_pkhash;
Hai Shalom74f70d42019-02-11 14:42:39 -08001455 const char *keyid;
Sunil Ravi77d572f2023-01-17 23:58:31 +00001456 char dpp_pkhash_buf[100];
Hai Shalom74f70d42019-02-11 14:42:39 -08001457 char keyid_buf[100];
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001458 char ip_addr[100];
Hai Shalom74f70d42019-02-11 14:42:39 -08001459
Sunil Ravi77d572f2023-01-17 23:58:31 +00001460 dpp_pkhash_buf[0] = '\0';
Hai Shalom74f70d42019-02-11 14:42:39 -08001461 keyid_buf[0] = '\0';
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001462 ip_addr[0] = '\0';
1463#ifdef CONFIG_P2P
1464 if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) {
1465 os_snprintf(ip_addr, sizeof(ip_addr),
1466 " ip_addr=%u.%u.%u.%u",
1467 ip_addr_buf[0], ip_addr_buf[1],
1468 ip_addr_buf[2], ip_addr_buf[3]);
Sunil Ravid8128a22023-11-06 23:53:58 +00001469 ip_ptr = ip_addr_buf;
Dmitry Shmidtcf32e602014-01-28 10:57:39 -08001470 }
1471#endif /* CONFIG_P2P */
1472
Hai Shalom74f70d42019-02-11 14:42:39 -08001473 keyid = ap_sta_wpa_get_keyid(hapd, sta);
1474 if (keyid) {
1475 os_snprintf(keyid_buf, sizeof(keyid_buf),
1476 " keyid=%s", keyid);
1477 }
1478
Sunil Ravi77d572f2023-01-17 23:58:31 +00001479 dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
1480 if (dpp_pkhash) {
1481 const char *prefix = " dpp_pkhash=";
1482 size_t plen = os_strlen(prefix);
1483
1484 os_strlcpy(dpp_pkhash_buf, prefix,
1485 sizeof(dpp_pkhash_buf));
1486 wpa_snprintf_hex(&dpp_pkhash_buf[plen],
1487 sizeof(dpp_pkhash_buf) - plen,
1488 dpp_pkhash, SHA256_MAC_LEN);
1489 }
1490
1491 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s",
1492 buf, ip_addr, keyid_buf, dpp_pkhash_buf);
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001493
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001494 if (hapd->msg_ctx_parent &&
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001495 hapd->msg_ctx_parent != hapd->msg_ctx)
1496 wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
Sunil Ravi77d572f2023-01-17 23:58:31 +00001497 AP_STA_CONNECTED "%s%s%s%s",
1498 buf, ip_addr, keyid_buf,
1499 dpp_pkhash_buf);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001500 } else {
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001501 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
1502
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001503 if (hapd->msg_ctx_parent &&
Dmitry Shmidtb6e9aaf2013-05-20 14:49:44 -07001504 hapd->msg_ctx_parent != hapd->msg_ctx)
1505 wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
1506 AP_STA_DISCONNECTED "%s", buf);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001507 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001508
Sunil Ravid8128a22023-11-06 23:53:58 +00001509 if (hapd->sta_authorized_cb)
1510 hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
1511 sta->addr, authorized, dev_addr,
1512 ip_ptr);
1513
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001514#ifdef CONFIG_FST
1515 if (hapd->iface->fst) {
1516 if (authorized)
1517 fst_notify_peer_connected(hapd->iface->fst, sta->addr);
1518 else
1519 fst_notify_peer_disconnected(hapd->iface->fst,
1520 sta->addr);
1521 }
1522#endif /* CONFIG_FST */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001523}
1524
1525
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001526void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
1527 int authorized)
1528{
1529 if (!ap_sta_set_authorized_flag(hapd, sta, authorized))
1530 return;
1531 ap_sta_set_authorized_event(hapd, sta, authorized);
1532}
1533
1534
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001535void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
1536 const u8 *addr, u16 reason)
1537{
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08001538 if (sta)
1539 wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u",
1540 hapd->conf->iface, __func__, MAC2STR(sta->addr),
1541 reason);
1542 else if (addr)
1543 wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u",
1544 hapd->conf->iface, __func__, MAC2STR(addr),
1545 reason);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001546
1547 if (sta == NULL && addr)
1548 sta = ap_get_sta(hapd, addr);
1549
1550 if (addr)
1551 hostapd_drv_sta_deauth(hapd, addr, reason);
1552
1553 if (sta == NULL)
1554 return;
1555 ap_sta_set_authorized(hapd, sta, 0);
Hai Shalomfdcde762020-04-02 11:19:20 -07001556 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
1557 hostapd_set_sta_flags(hapd, sta);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001558 wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
1559 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08001560 wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
Dmitry Shmidt04949592012-07-19 12:16:46 -07001561 "for " MACSTR " (%d seconds - "
1562 "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08001563 hapd->conf->iface, __func__, MAC2STR(sta->addr),
Dmitry Shmidt04949592012-07-19 12:16:46 -07001564 AP_MAX_INACTIVITY_AFTER_DEAUTH);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001565 eloop_cancel_timeout(ap_handle_timer, hapd, sta);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001566 eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
1567 ap_handle_timer, hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001568 sta->timeout_next = STA_REMOVE;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001569
Dmitry Shmidt29333592017-01-09 12:27:11 -08001570 if (hapd->iface->current_mode &&
1571 hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
1572 /* Deauthentication is not used in DMG/IEEE 802.11ad;
1573 * disassociate the STA instead. */
1574 sta->disassoc_reason = reason;
1575 sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
1576 eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
1577 eloop_register_timeout(hapd->iface->drv_flags &
1578 WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
1579 2 : 0, 0, ap_sta_disassoc_cb_timeout,
1580 hapd, sta);
1581 return;
1582 }
1583
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001584 sta->deauth_reason = reason;
1585 sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
1586 eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
1587 eloop_register_timeout(hapd->iface->drv_flags &
1588 WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
1589 ap_sta_deauth_cb_timeout, hapd, sta);
1590}
1591
1592
1593void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
1594{
1595 if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
1596 wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
1597 return;
1598 }
1599 sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
1600 eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
1601 ap_sta_deauth_cb_timeout(hapd, sta);
1602}
1603
1604
1605void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
1606{
1607 if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
1608 wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
1609 return;
1610 }
1611 sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
1612 eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
1613 ap_sta_disassoc_cb_timeout(hapd, sta);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001614}
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001615
1616
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08001617void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
1618 struct sta_info *sta)
1619{
1620 if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0)
1621 wpa_printf(MSG_DEBUG,
1622 "%s: Removed ap_sta_deauth_cb_timeout timeout for "
1623 MACSTR,
1624 hapd->conf->iface, MAC2STR(sta->addr));
1625 if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0)
1626 wpa_printf(MSG_DEBUG,
1627 "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
1628 MACSTR,
1629 hapd->conf->iface, MAC2STR(sta->addr));
Dmitry Shmidt29333592017-01-09 12:27:11 -08001630 if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
1631 {
1632 wpa_printf(MSG_DEBUG,
1633 "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
1634 MACSTR,
1635 hapd->conf->iface, MAC2STR(sta->addr));
1636 if (sta->flags & WLAN_STA_WPS)
1637 hostapd_wps_eap_completed(hapd);
1638 }
Dmitry Shmidt1d6bf422016-01-19 15:51:35 -08001639}
1640
1641
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001642int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
1643{
1644 int res;
1645
1646 buf[0] = '\0';
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001647 res = os_snprintf(buf, buflen,
Sunil Ravia04bd252022-05-02 22:54:18 -07001648 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001649 (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
1650 (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
1651 (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
1652 (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
1653 ""),
1654 (flags & WLAN_STA_SHORT_PREAMBLE ?
1655 "[SHORT_PREAMBLE]" : ""),
1656 (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
1657 (flags & WLAN_STA_WMM ? "[WMM]" : ""),
1658 (flags & WLAN_STA_MFP ? "[MFP]" : ""),
1659 (flags & WLAN_STA_WPS ? "[WPS]" : ""),
1660 (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
1661 (flags & WLAN_STA_WDS ? "[WDS]" : ""),
1662 (flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
1663 (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
1664 (flags & WLAN_STA_GAS ? "[GAS]" : ""),
Roshan Pius3a1667e2018-07-03 15:17:14 -07001665 (flags & WLAN_STA_HT ? "[HT]" : ""),
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001666 (flags & WLAN_STA_VHT ? "[VHT]" : ""),
Hai Shalomc3565922019-10-28 11:58:20 -07001667 (flags & WLAN_STA_HE ? "[HE]" : ""),
Sunil Ravia04bd252022-05-02 22:54:18 -07001668 (flags & WLAN_STA_EHT ? "[EHT]" : ""),
Hai Shalom4fbc08f2020-05-18 12:37:00 -07001669 (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001670 (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001671 (flags & WLAN_STA_WNM_SLEEP_MODE ?
1672 "[WNM_SLEEP_MODE]" : ""));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001673 if (os_snprintf_error(buflen, res))
1674 res = -1;
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08001675
1676 return res;
1677}
Dmitry Shmidt29333592017-01-09 12:27:11 -08001678
1679
1680static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
1681{
1682 struct hostapd_data *hapd = eloop_ctx;
1683 struct sta_info *sta = timeout_ctx;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001684 u16 reason;
Dmitry Shmidt29333592017-01-09 12:27:11 -08001685
1686 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1687 "IEEE 802.1X: Scheduled disconnection of " MACSTR
1688 " after EAP-Failure", MAC2STR(sta->addr));
1689
Roshan Pius3a1667e2018-07-03 15:17:14 -07001690 reason = sta->disconnect_reason_code;
1691 if (!reason)
1692 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED;
1693 ap_sta_disconnect(hapd, sta, sta->addr, reason);
Dmitry Shmidt29333592017-01-09 12:27:11 -08001694 if (sta->flags & WLAN_STA_WPS)
1695 hostapd_wps_eap_completed(hapd);
1696}
1697
1698
1699void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
Sunil Ravi640215c2023-06-28 23:08:09 +00001700 struct sta_info *sta,
1701 unsigned timeout)
Dmitry Shmidt29333592017-01-09 12:27:11 -08001702{
1703 wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
1704 "IEEE 802.1X: Force disconnection of " MACSTR
Sunil Ravi640215c2023-06-28 23:08:09 +00001705 " after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout);
Dmitry Shmidt29333592017-01-09 12:27:11 -08001706
1707 /*
1708 * Add a small sleep to increase likelihood of previously requested
1709 * EAP-Failure TX getting out before this should the driver reorder
1710 * operations.
1711 */
1712 eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
Sunil Ravi640215c2023-06-28 23:08:09 +00001713 eloop_register_timeout(0, timeout * 1000,
1714 ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
Dmitry Shmidt29333592017-01-09 12:27:11 -08001715}
1716
1717
1718int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
1719 struct sta_info *sta)
1720{
1721 return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
1722 hapd, sta);
1723}
Hai Shalomb755a2a2020-04-23 21:49:02 -07001724
1725
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001726#ifdef CONFIG_IEEE80211BE
1727static void ap_sta_remove_link_sta(struct hostapd_data *hapd,
1728 struct sta_info *sta)
1729{
1730 struct hostapd_data *tmp_hapd;
1731 unsigned int i, j;
1732
1733 for_each_mld_link(tmp_hapd, i, j, hapd->iface->interfaces,
1734 hapd->conf->mld_id) {
1735 struct sta_info *tmp_sta;
1736
1737 if (hapd == tmp_hapd)
1738 continue;
1739
1740 for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
1741 tmp_sta = tmp_sta->next) {
1742 if (tmp_sta == sta ||
1743 !ether_addr_equal(tmp_sta->addr, sta->addr))
1744 continue;
1745
1746 ap_free_sta(tmp_hapd, tmp_sta);
1747 break;
1748 }
1749 }
1750}
1751#endif /* CONFIG_IEEE80211BE */
1752
1753
Hai Shalomb755a2a2020-04-23 21:49:02 -07001754int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
1755{
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001756 const u8 *mld_link_addr = NULL;
1757 bool mld_link_sta = false;
1758
Hai Shalomb755a2a2020-04-23 21:49:02 -07001759 /*
1760 * If a station that is already associated to the AP, is trying to
1761 * authenticate again, remove the STA entry, in order to make sure the
1762 * STA PS state gets cleared and configuration gets updated. To handle
1763 * this, station's added_unassoc flag is cleared once the station has
1764 * completed association.
1765 */
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001766
1767#ifdef CONFIG_IEEE80211BE
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001768 if (ap_sta_is_mld(hapd, sta)) {
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001769 u8 mld_link_id = hapd->mld_link_id;
1770
1771 mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
1772 mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001773
1774 /*
1775 * In case the AP is affiliated with an AP MLD, we need to
1776 * remove the station from all relevant links/APs.
1777 */
1778 ap_sta_remove_link_sta(hapd, sta);
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001779 }
1780#endif /* CONFIG_IEEE80211BE */
1781
Hai Shalomb755a2a2020-04-23 21:49:02 -07001782 ap_sta_set_authorized(hapd, sta, 0);
1783 hostapd_drv_sta_remove(hapd, sta->addr);
1784 sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
1785
1786 if (hostapd_sta_add(hapd, sta->addr, 0, 0,
1787 sta->supported_rates,
1788 sta->supported_rates_len,
Sunil Ravia04bd252022-05-02 22:54:18 -07001789 0, NULL, NULL, NULL, 0, NULL, 0, NULL,
Sunil Ravi2a14cf12023-11-21 00:54:38 +00001790 sta->flags, 0, 0, 0, 0,
1791 mld_link_addr, mld_link_sta)) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07001792 hostapd_logger(hapd, sta->addr,
1793 HOSTAPD_MODULE_IEEE80211,
1794 HOSTAPD_LEVEL_NOTICE,
1795 "Could not add STA to kernel driver");
1796 return -1;
1797 }
1798
1799 sta->added_unassoc = 1;
1800 return 0;
1801}
Sunil Ravib0ac25f2024-07-12 01:42:03 +00001802
1803
1804#ifdef CONFIG_IEEE80211BE
1805void ap_sta_free_sta_profile(struct mld_info *info)
1806{
1807 int i;
1808
1809 if (!info)
1810 return;
1811
1812 for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
1813 os_free(info->links[i].resp_sta_profile);
1814 info->links[i].resp_sta_profile = NULL;
1815 }
1816}
1817#endif /* CONFIG_IEEE80211BE */