/src/hostap/src/ap/sta_info.c
Line | Count | Source |
1 | | /* |
2 | | * hostapd / Station table |
3 | | * Copyright (c) 2002-2017, Jouni Malinen <j@w1.fi> |
4 | | * |
5 | | * This software may be distributed under the terms of the BSD license. |
6 | | * See README for more details. |
7 | | */ |
8 | | |
9 | | #include "utils/includes.h" |
10 | | |
11 | | #include "utils/common.h" |
12 | | #include "utils/eloop.h" |
13 | | #include "common/ieee802_11_defs.h" |
14 | | #include "common/wpa_ctrl.h" |
15 | | #include "common/sae.h" |
16 | | #include "common/dpp.h" |
17 | | #include "radius/radius.h" |
18 | | #include "radius/radius_client.h" |
19 | | #include "p2p/p2p.h" |
20 | | #include "fst/fst.h" |
21 | | #include "crypto/crypto.h" |
22 | | #include "hostapd.h" |
23 | | #include "accounting.h" |
24 | | #include "ieee802_1x.h" |
25 | | #include "ieee802_11.h" |
26 | | #include "ieee802_11_auth.h" |
27 | | #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" |
35 | | #include "gas_serv.h" |
36 | | #include "wnm_ap.h" |
37 | | #include "mbo_ap.h" |
38 | | #include "ndisc_snoop.h" |
39 | | #include "sta_info.h" |
40 | | #include "vlan.h" |
41 | | #include "wps_hostapd.h" |
42 | | |
43 | | static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, |
44 | | struct sta_info *sta); |
45 | | static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx); |
46 | | static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx); |
47 | | static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx); |
48 | | static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx); |
49 | | static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx); |
50 | | static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta); |
51 | | static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx); |
52 | | |
53 | | int 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 | 0 | { |
58 | 0 | struct sta_info *sta; |
59 | |
|
60 | 0 | for (sta = hapd->sta_list; sta; sta = sta->next) { |
61 | 0 | if (cb(hapd, sta, ctx)) |
62 | 0 | return 1; |
63 | 0 | } |
64 | | |
65 | 0 | return 0; |
66 | 0 | } |
67 | | |
68 | | |
69 | | struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) |
70 | 2.16k | { |
71 | 2.16k | struct sta_info *s; |
72 | | |
73 | 2.16k | s = hapd->sta_hash[STA_HASH(sta)]; |
74 | 2.16k | while (s != NULL && os_memcmp(s->addr, sta, 6) != 0) |
75 | 0 | s = s->hnext; |
76 | 2.16k | return s; |
77 | 2.16k | } |
78 | | |
79 | | |
80 | | #ifdef CONFIG_IEEE80211BE |
81 | | struct sta_info * ap_get_link_sta(struct hostapd_data *hapd, |
82 | | const u8 *link_addr) |
83 | | { |
84 | | struct sta_info *link_sta; |
85 | | |
86 | | for (link_sta = hapd->sta_list; link_sta; link_sta = link_sta->next) { |
87 | | if (link_sta->mld_info.mld_sta && |
88 | | ether_addr_equal(link_sta->mld_info.links[hapd->mld_link_id].peer_addr, |
89 | | link_addr)) |
90 | | return link_sta; |
91 | | } |
92 | | |
93 | | return NULL; |
94 | | } |
95 | | #endif /* CONFIG_IEEE80211BE */ |
96 | | |
97 | | |
98 | | #ifdef CONFIG_P2P |
99 | | struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr) |
100 | | { |
101 | | struct sta_info *sta; |
102 | | |
103 | | for (sta = hapd->sta_list; sta; sta = sta->next) { |
104 | | const u8 *p2p_dev_addr; |
105 | | |
106 | | if (sta->p2p_ie == NULL) |
107 | | continue; |
108 | | |
109 | | p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie); |
110 | | if (p2p_dev_addr == NULL) |
111 | | continue; |
112 | | |
113 | | if (ether_addr_equal(p2p_dev_addr, addr)) |
114 | | return sta; |
115 | | } |
116 | | |
117 | | return NULL; |
118 | | } |
119 | | #endif /* CONFIG_P2P */ |
120 | | |
121 | | |
122 | | static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta) |
123 | 2.16k | { |
124 | 2.16k | struct sta_info *tmp; |
125 | | |
126 | 2.16k | if (hapd->sta_list == sta) { |
127 | 2.16k | hapd->sta_list = sta->next; |
128 | 2.16k | return; |
129 | 2.16k | } |
130 | | |
131 | 0 | tmp = hapd->sta_list; |
132 | 0 | while (tmp != NULL && tmp->next != sta) |
133 | 0 | tmp = tmp->next; |
134 | 0 | if (tmp == NULL) { |
135 | 0 | wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from " |
136 | 0 | "list.", MAC2STR(sta->addr)); |
137 | 0 | } else |
138 | 0 | tmp->next = sta->next; |
139 | 0 | } |
140 | | |
141 | | |
142 | | void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta) |
143 | 2.16k | { |
144 | 2.16k | sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)]; |
145 | 2.16k | hapd->sta_hash[STA_HASH(sta->addr)] = sta; |
146 | 2.16k | } |
147 | | |
148 | | |
149 | | static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) |
150 | 2.16k | { |
151 | 2.16k | struct sta_info *s; |
152 | | |
153 | 2.16k | s = hapd->sta_hash[STA_HASH(sta->addr)]; |
154 | 2.16k | if (s == NULL) return; |
155 | 2.16k | if (os_memcmp(s->addr, sta->addr, 6) == 0) { |
156 | 2.16k | hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext; |
157 | 2.16k | return; |
158 | 2.16k | } |
159 | | |
160 | 0 | while (s->hnext != NULL && |
161 | 0 | !ether_addr_equal(s->hnext->addr, sta->addr)) |
162 | 0 | s = s->hnext; |
163 | 0 | if (s->hnext != NULL) |
164 | 0 | s->hnext = s->hnext->hnext; |
165 | 0 | else |
166 | 0 | wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR |
167 | 0 | " from hash table", MAC2STR(sta->addr)); |
168 | 0 | } |
169 | | |
170 | | |
171 | | void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta) |
172 | 2.16k | { |
173 | 2.16k | sta_ip6addr_del(hapd, sta); |
174 | 2.16k | } |
175 | | |
176 | | |
177 | | #ifdef CONFIG_PASN |
178 | | |
179 | | void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta) |
180 | | { |
181 | | if (sta->pasn) { |
182 | | wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR, |
183 | | MAC2STR(sta->addr)); |
184 | | |
185 | | if (sta->pasn->ecdh) |
186 | | crypto_ecdh_deinit(sta->pasn->ecdh); |
187 | | |
188 | | wpabuf_free(sta->pasn->secret); |
189 | | sta->pasn->secret = NULL; |
190 | | |
191 | | #ifdef CONFIG_SAE |
192 | | sae_clear_data(&sta->pasn->sae); |
193 | | #endif /* CONFIG_SAE */ |
194 | | |
195 | | #ifdef CONFIG_FILS |
196 | | /* In practice this pointer should be NULL */ |
197 | | wpabuf_free(sta->pasn->fils.erp_resp); |
198 | | sta->pasn->fils.erp_resp = NULL; |
199 | | #endif /* CONFIG_FILS */ |
200 | | |
201 | | pasn_data_deinit(sta->pasn); |
202 | | sta->pasn = NULL; |
203 | | } |
204 | | } |
205 | | |
206 | | #endif /* CONFIG_PASN */ |
207 | | |
208 | | |
209 | | static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) |
210 | 2.16k | { |
211 | | #ifdef CONFIG_IEEE80211BE |
212 | | if (hostapd_sta_is_link_sta(hapd, sta)) { |
213 | | hostapd_drv_link_sta_remove(hapd, sta->addr); |
214 | | return; |
215 | | } |
216 | | #endif /* CONFIG_IEEE80211BE */ |
217 | | |
218 | 2.16k | hostapd_drv_sta_remove(hapd, sta->addr); |
219 | 2.16k | } |
220 | | |
221 | | |
222 | | #ifdef CONFIG_IEEE80211BE |
223 | | |
224 | | void set_wpa_sm_for_each_partner_link(struct hostapd_data *hapd, |
225 | | struct sta_info *psta, void *wpa_sm) |
226 | | { |
227 | | struct sta_info *lsta; |
228 | | struct hostapd_data *lhapd; |
229 | | |
230 | | if (!ap_sta_is_mld(hapd, psta)) |
231 | | return; |
232 | | |
233 | | for_each_mld_link(lhapd, hapd) { |
234 | | if (lhapd == hapd) |
235 | | continue; |
236 | | |
237 | | lsta = ap_get_sta(lhapd, psta->addr); |
238 | | if (lsta) |
239 | | lsta->wpa_sm = wpa_sm; |
240 | | } |
241 | | } |
242 | | |
243 | | |
244 | | void clear_wpa_sm_for_each_partner_link(struct hostapd_data *hapd, |
245 | | struct sta_info *psta) |
246 | | { |
247 | | set_wpa_sm_for_each_partner_link(hapd, psta, NULL); |
248 | | } |
249 | | |
250 | | #endif /* CONFIG_IEEE80211BE */ |
251 | | |
252 | | |
253 | | void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) |
254 | 2.16k | { |
255 | 2.16k | #ifndef CONFIG_NO_VLAN |
256 | 2.16k | struct hostapd_data *vlan_bss = hapd; |
257 | 2.16k | #endif /* CONFIG_NO_VLAN */ |
258 | 2.16k | int set_beacon = 0; |
259 | | |
260 | 2.16k | accounting_sta_stop(hapd, sta); |
261 | | |
262 | | /* just in case */ |
263 | 2.16k | ap_sta_set_authorized(hapd, sta, 0); |
264 | 2.16k | hostapd_set_sta_flags(hapd, sta); |
265 | | |
266 | 2.16k | if ((sta->flags & WLAN_STA_WDS) || |
267 | 2.16k | (sta->flags & WLAN_STA_MULTI_AP && |
268 | 0 | (hapd->conf->multi_ap & BACKHAUL_BSS) && |
269 | 0 | hapd->conf->wds_sta && |
270 | 0 | !(sta->flags & WLAN_STA_WPS))) |
271 | 0 | hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); |
272 | | |
273 | 2.16k | if (sta->ipaddr) |
274 | 0 | hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); |
275 | 2.16k | ap_sta_ip6addr_del(hapd, sta); |
276 | | |
277 | 2.16k | if (!hapd->iface->driver_ap_teardown && |
278 | 2.16k | !(sta->flags & WLAN_STA_PREAUTH)) { |
279 | 2.16k | __ap_free_sta(hapd, sta); |
280 | 2.16k | sta->added_unassoc = 0; |
281 | 2.16k | } |
282 | | |
283 | 2.16k | ap_sta_hash_del(hapd, sta); |
284 | 2.16k | ap_sta_list_del(hapd, sta); |
285 | | |
286 | 2.16k | if (sta->aid > 0) |
287 | 0 | hapd->sta_aid[(sta->aid - 1) / 32] &= |
288 | 0 | ~BIT((sta->aid - 1) % 32); |
289 | | |
290 | 2.16k | hapd->num_sta--; |
291 | 2.16k | if (sta->nonerp_set) { |
292 | 0 | sta->nonerp_set = 0; |
293 | 0 | hapd->iface->num_sta_non_erp--; |
294 | 0 | if (hapd->iface->num_sta_non_erp == 0) |
295 | 0 | set_beacon++; |
296 | 0 | } |
297 | | |
298 | 2.16k | if (sta->no_short_slot_time_set) { |
299 | 0 | sta->no_short_slot_time_set = 0; |
300 | 0 | hapd->iface->num_sta_no_short_slot_time--; |
301 | 0 | if (hapd->iface->current_mode && |
302 | 0 | hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G |
303 | 0 | && hapd->iface->num_sta_no_short_slot_time == 0) |
304 | 0 | set_beacon++; |
305 | 0 | } |
306 | | |
307 | 2.16k | if (sta->no_short_preamble_set) { |
308 | 0 | sta->no_short_preamble_set = 0; |
309 | 0 | hapd->iface->num_sta_no_short_preamble--; |
310 | 0 | if (hapd->iface->current_mode && |
311 | 0 | hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G |
312 | 0 | && hapd->iface->num_sta_no_short_preamble == 0) |
313 | 0 | set_beacon++; |
314 | 0 | } |
315 | | |
316 | 2.16k | if (sta->no_ht_gf_set) { |
317 | 0 | sta->no_ht_gf_set = 0; |
318 | 0 | hapd->iface->num_sta_ht_no_gf--; |
319 | 0 | } |
320 | | |
321 | 2.16k | if (sta->no_ht_set) { |
322 | 0 | sta->no_ht_set = 0; |
323 | 0 | hapd->iface->num_sta_no_ht--; |
324 | 0 | } |
325 | | |
326 | 2.16k | if (sta->ht_20mhz_set) { |
327 | 0 | sta->ht_20mhz_set = 0; |
328 | 0 | hapd->iface->num_sta_ht_20mhz--; |
329 | 0 | } |
330 | | |
331 | | #ifdef CONFIG_TAXONOMY |
332 | | wpabuf_free(sta->probe_ie_taxonomy); |
333 | | sta->probe_ie_taxonomy = NULL; |
334 | | wpabuf_free(sta->assoc_ie_taxonomy); |
335 | | sta->assoc_ie_taxonomy = NULL; |
336 | | #endif /* CONFIG_TAXONOMY */ |
337 | | |
338 | 2.16k | ht40_intolerant_remove(hapd->iface, sta); |
339 | | |
340 | | #ifdef CONFIG_P2P |
341 | | if (sta->no_p2p_set) { |
342 | | sta->no_p2p_set = 0; |
343 | | hapd->num_sta_no_p2p--; |
344 | | if (hapd->num_sta_no_p2p == 0) |
345 | | hostapd_p2p_non_p2p_sta_disconnected(hapd); |
346 | | } |
347 | | #endif /* CONFIG_P2P */ |
348 | | |
349 | 2.16k | #ifdef NEED_AP_MLME |
350 | 2.16k | if (hostapd_ht_operation_update(hapd->iface) > 0) |
351 | 0 | set_beacon++; |
352 | 2.16k | #endif /* NEED_AP_MLME */ |
353 | | |
354 | | #ifdef CONFIG_MESH |
355 | | if (hapd->mesh_sta_free_cb) |
356 | | hapd->mesh_sta_free_cb(hapd, sta); |
357 | | #endif /* CONFIG_MESH */ |
358 | | |
359 | 2.16k | if (set_beacon) |
360 | 0 | ieee802_11_update_beacons(hapd->iface); |
361 | | |
362 | 2.16k | wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR, |
363 | 2.16k | __func__, MAC2STR(sta->addr)); |
364 | 2.16k | eloop_cancel_timeout(ap_handle_timer, hapd, sta); |
365 | 2.16k | eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); |
366 | 2.16k | eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); |
367 | 2.16k | ap_sta_clear_disconnect_timeouts(hapd, sta); |
368 | 2.16k | ap_sta_clear_assoc_timeout(hapd, sta); |
369 | 2.16k | sae_clear_retransmit_timer(hapd, sta); |
370 | | |
371 | 2.16k | ieee802_1x_free_station(hapd, sta); |
372 | | |
373 | | #ifdef CONFIG_IEEE80211BE |
374 | | if (!ap_sta_is_mld(hapd, sta) || |
375 | | hapd->mld_link_id == sta->mld_assoc_link_id) { |
376 | | wpa_auth_sta_deinit(sta->wpa_sm); |
377 | | /* Remove references from partner links. */ |
378 | | clear_wpa_sm_for_each_partner_link(hapd, sta); |
379 | | } |
380 | | |
381 | | /* Release group references in case non-association link STA is removed |
382 | | * before association link STA */ |
383 | | if (hostapd_sta_is_link_sta(hapd, sta)) |
384 | | wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id, |
385 | | false); |
386 | | #else /* CONFIG_IEEE80211BE */ |
387 | 2.16k | wpa_auth_sta_deinit(sta->wpa_sm); |
388 | 2.16k | #endif /* CONFIG_IEEE80211BE */ |
389 | | |
390 | 2.16k | rsn_preauth_free_station(hapd, sta); |
391 | 2.16k | #ifndef CONFIG_NO_RADIUS |
392 | 2.16k | if (hapd->radius) |
393 | 0 | radius_client_flush_auth(hapd->radius, sta->addr); |
394 | 2.16k | #endif /* CONFIG_NO_RADIUS */ |
395 | | |
396 | 2.16k | #ifndef CONFIG_NO_VLAN |
397 | | #ifdef CONFIG_IEEE80211BE |
398 | | if (hapd->conf->mld_ap) { |
399 | | vlan_bss = hostapd_mld_get_first_bss(hapd); |
400 | | if (!vlan_bss) |
401 | | vlan_bss = hapd; |
402 | | } |
403 | | #endif /* CONFIG_IEEE80211BE */ |
404 | | /* |
405 | | * sta->wpa_sm->group needs to be released before so that |
406 | | * vlan_remove_dynamic() can check that no stations are left on the |
407 | | * AP_VLAN netdev. |
408 | | */ |
409 | 2.16k | if (sta->vlan_id) |
410 | 0 | vlan_remove_dynamic(vlan_bss, sta->vlan_id); |
411 | 2.16k | if (sta->vlan_id_bound) { |
412 | | /* |
413 | | * Need to remove the STA entry before potentially removing the |
414 | | * VLAN. |
415 | | */ |
416 | 0 | if (hapd->iface->driver_ap_teardown && |
417 | 0 | !(sta->flags & WLAN_STA_PREAUTH)) { |
418 | 0 | hostapd_drv_sta_remove(hapd, sta->addr); |
419 | 0 | sta->added_unassoc = 0; |
420 | 0 | } |
421 | 0 | vlan_remove_dynamic(vlan_bss, sta->vlan_id_bound); |
422 | 0 | } |
423 | 2.16k | #endif /* CONFIG_NO_VLAN */ |
424 | | |
425 | 2.16k | os_free(sta->challenge); |
426 | | |
427 | 2.16k | os_free(sta->sa_query_trans_id); |
428 | 2.16k | eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); |
429 | | |
430 | | #ifdef CONFIG_P2P |
431 | | p2p_group_notif_disassoc(hapd->p2p_group, sta->addr); |
432 | | #endif /* CONFIG_P2P */ |
433 | | |
434 | 2.16k | #if defined(CONFIG_INTERWORKING) || defined(CONFIG_DPP) |
435 | 2.16k | if (sta->gas_dialog) { |
436 | 0 | int i; |
437 | |
|
438 | 0 | for (i = 0; i < GAS_DIALOG_MAX; i++) |
439 | 0 | gas_serv_dialog_clear(&sta->gas_dialog[i]); |
440 | 0 | os_free(sta->gas_dialog); |
441 | 0 | } |
442 | 2.16k | #endif /* CONFIG_INTERWORKING || CONFIG_DPP */ |
443 | | |
444 | 2.16k | wpabuf_free(sta->wps_ie); |
445 | 2.16k | wpabuf_free(sta->p2p_ie); |
446 | 2.16k | wpabuf_free(sta->hs20_ie); |
447 | 2.16k | wpabuf_free(sta->roaming_consortium); |
448 | | #ifdef CONFIG_FST |
449 | | wpabuf_free(sta->mb_ies); |
450 | | #endif /* CONFIG_FST */ |
451 | | |
452 | 2.16k | os_free(sta->ht_capabilities); |
453 | 2.16k | os_free(sta->vht_capabilities); |
454 | 2.16k | os_free(sta->vht_operation); |
455 | 2.16k | os_free(sta->he_capab); |
456 | 2.16k | os_free(sta->he_6ghz_capab); |
457 | 2.16k | os_free(sta->eht_capab); |
458 | 2.16k | hostapd_free_psk_list(sta->psk); |
459 | 2.16k | os_free(sta->identity); |
460 | 2.16k | os_free(sta->radius_cui); |
461 | 2.16k | os_free(sta->t_c_url); |
462 | 2.16k | wpabuf_free(sta->hs20_deauth_req); |
463 | 2.16k | os_free(sta->hs20_session_info_url); |
464 | | |
465 | | #ifdef CONFIG_SAE |
466 | | sae_clear_data(sta->sae); |
467 | | os_free(sta->sae); |
468 | | #endif /* CONFIG_SAE */ |
469 | | |
470 | 2.16k | mbo_ap_sta_free(sta); |
471 | 2.16k | os_free(sta->supp_op_classes); |
472 | | |
473 | | #ifdef CONFIG_FILS |
474 | | os_free(sta->fils_pending_assoc_req); |
475 | | wpabuf_free(sta->fils_hlp_resp); |
476 | | wpabuf_free(sta->hlp_dhcp_discover); |
477 | | eloop_cancel_timeout(fils_hlp_timeout, hapd, sta); |
478 | | #ifdef CONFIG_FILS_SK_PFS |
479 | | crypto_ecdh_deinit(sta->fils_ecdh); |
480 | | wpabuf_clear_free(sta->fils_dh_ss); |
481 | | wpabuf_free(sta->fils_g_sta); |
482 | | #endif /* CONFIG_FILS_SK_PFS */ |
483 | | #endif /* CONFIG_FILS */ |
484 | | |
485 | | #ifdef CONFIG_OWE |
486 | | bin_clear_free(sta->owe_pmk, sta->owe_pmk_len); |
487 | | crypto_ecdh_deinit(sta->owe_ecdh); |
488 | | #endif /* CONFIG_OWE */ |
489 | | |
490 | | #ifdef CONFIG_DPP2 |
491 | | dpp_pfs_free(sta->dpp_pfs); |
492 | | sta->dpp_pfs = NULL; |
493 | | #endif /* CONFIG_DPP2 */ |
494 | | |
495 | 2.16k | os_free(sta->ext_capability); |
496 | | |
497 | | #ifdef CONFIG_WNM_AP |
498 | | eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta); |
499 | | #endif /* CONFIG_WNM_AP */ |
500 | | |
501 | | #ifdef CONFIG_PASN |
502 | | ap_free_sta_pasn(hapd, sta); |
503 | | #endif /* CONFIG_PASN */ |
504 | | |
505 | 2.16k | os_free(sta->ifname_wds); |
506 | | |
507 | | #ifdef CONFIG_IEEE80211BE |
508 | | ap_sta_free_sta_profile(&sta->mld_info); |
509 | | ml_deinit_link_reconf_req(&sta->reconf_req); |
510 | | #endif /* CONFIG_IEEE80211BE */ |
511 | | |
512 | | #ifdef CONFIG_TESTING_OPTIONS |
513 | | os_free(sta->sae_postponed_commit); |
514 | | forced_memzero(sta->last_tk, WPA_TK_MAX_LEN); |
515 | | #endif /* CONFIG_TESTING_OPTIONS */ |
516 | | |
517 | 2.16k | wpabuf_free(sta->sae_pw_id); |
518 | | |
519 | 2.16k | os_free(sta); |
520 | 2.16k | } |
521 | | |
522 | | |
523 | | void hostapd_free_stas(struct hostapd_data *hapd) |
524 | 2.16k | { |
525 | 2.16k | struct sta_info *sta, *prev; |
526 | | |
527 | 2.16k | sta = hapd->sta_list; |
528 | | |
529 | 4.32k | while (sta) { |
530 | 2.16k | prev = sta; |
531 | 2.16k | if (sta->flags & WLAN_STA_AUTH) { |
532 | 0 | mlme_deauthenticate_indication( |
533 | 0 | hapd, sta, WLAN_REASON_UNSPECIFIED); |
534 | 0 | } |
535 | 2.16k | sta = sta->next; |
536 | 2.16k | wpa_printf(MSG_DEBUG, "Removing station " MACSTR, |
537 | 2.16k | MAC2STR(prev->addr)); |
538 | 2.16k | ap_free_sta(hapd, prev); |
539 | 2.16k | } |
540 | 2.16k | } |
541 | | |
542 | | |
543 | | #ifdef CONFIG_IEEE80211BE |
544 | | void hostapd_free_link_stas(struct hostapd_data *hapd) |
545 | | { |
546 | | struct sta_info *sta, *prev; |
547 | | |
548 | | sta = hapd->sta_list; |
549 | | while (sta) { |
550 | | prev = sta; |
551 | | sta = sta->next; |
552 | | |
553 | | if (!hostapd_sta_is_link_sta(hapd, prev)) |
554 | | continue; |
555 | | |
556 | | wpa_printf(MSG_DEBUG, "Removing link station from MLD " MACSTR, |
557 | | MAC2STR(prev->addr)); |
558 | | ap_free_sta(hapd, prev); |
559 | | } |
560 | | } |
561 | | #endif /* CONFIG_IEEE80211BE */ |
562 | | |
563 | | |
564 | | /** |
565 | | * ap_handle_timer - Per STA timer handler |
566 | | * @eloop_ctx: struct hostapd_data * |
567 | | * @timeout_ctx: struct sta_info * |
568 | | * |
569 | | * This function is called to check station activity and to remove inactive |
570 | | * stations. |
571 | | */ |
572 | | void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) |
573 | 0 | { |
574 | 0 | struct hostapd_data *hapd = eloop_ctx; |
575 | 0 | struct sta_info *sta = timeout_ctx; |
576 | 0 | unsigned long next_time = 0; |
577 | 0 | int reason; |
578 | 0 | int max_inactivity = hapd->conf->ap_max_inactivity; |
579 | |
|
580 | 0 | wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d", |
581 | 0 | hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags, |
582 | 0 | sta->timeout_next); |
583 | 0 | if (sta->timeout_next == STA_REMOVE) { |
584 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |
585 | 0 | HOSTAPD_LEVEL_INFO, "deauthenticated due to " |
586 | 0 | "local deauth request"); |
587 | 0 | ap_free_sta(hapd, sta); |
588 | 0 | return; |
589 | 0 | } |
590 | | |
591 | 0 | if (sta->max_idle_period) |
592 | 0 | max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; |
593 | |
|
594 | 0 | if ((sta->flags & WLAN_STA_ASSOC) && |
595 | 0 | (sta->timeout_next == STA_NULLFUNC || |
596 | 0 | sta->timeout_next == STA_DISASSOC)) { |
597 | 0 | int inactive_sec; |
598 | | /* |
599 | | * Add random value to timeout so that we don't end up bouncing |
600 | | * all stations at the same time if we have lots of associated |
601 | | * stations that are idle (but keep re-associating). |
602 | | */ |
603 | 0 | int fuzz = os_random() % 20; |
604 | 0 | inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr); |
605 | 0 | if (inactive_sec == -1) { |
606 | 0 | wpa_msg(hapd->msg_ctx, MSG_DEBUG, |
607 | 0 | "Check inactivity: Could not " |
608 | 0 | "get station info from kernel driver for " |
609 | 0 | MACSTR, MAC2STR(sta->addr)); |
610 | | /* |
611 | | * The driver may not support this functionality. |
612 | | * Anyway, try again after the next inactivity timeout, |
613 | | * but do not disconnect the station now. |
614 | | */ |
615 | 0 | next_time = max_inactivity + fuzz; |
616 | 0 | } else if (inactive_sec == -ENOENT) { |
617 | 0 | wpa_msg(hapd->msg_ctx, MSG_DEBUG, |
618 | 0 | "Station " MACSTR " has lost its driver entry", |
619 | 0 | MAC2STR(sta->addr)); |
620 | | |
621 | | /* Avoid sending client probe on removed client */ |
622 | 0 | sta->timeout_next = STA_DISASSOC; |
623 | 0 | goto skip_poll; |
624 | 0 | } else if (inactive_sec < max_inactivity) { |
625 | | #ifdef CONFIG_TESTING_OPTIONS |
626 | | if (hapd->conf->skip_inactivity_poll == -1) { |
627 | | wpa_msg(hapd->msg_ctx, MSG_DEBUG, |
628 | | "Force inactivity timeout for station " |
629 | | MACSTR |
630 | | " even though it has been active %is ago", |
631 | | MAC2STR(sta->addr), inactive_sec); |
632 | | sta->timeout_next = STA_DISASSOC; |
633 | | goto skip_poll; |
634 | | } |
635 | | #endif /* CONFIG_TESTING_OPTIONS */ |
636 | | /* station activity detected; reset timeout state */ |
637 | 0 | wpa_msg(hapd->msg_ctx, MSG_DEBUG, |
638 | 0 | "Station " MACSTR " has been active %is ago", |
639 | 0 | MAC2STR(sta->addr), inactive_sec); |
640 | 0 | sta->timeout_next = STA_NULLFUNC; |
641 | 0 | next_time = max_inactivity + fuzz - inactive_sec; |
642 | 0 | } else { |
643 | 0 | wpa_msg(hapd->msg_ctx, MSG_DEBUG, |
644 | 0 | "Station " MACSTR " has been " |
645 | 0 | "inactive too long: %d sec, max allowed: %d", |
646 | 0 | MAC2STR(sta->addr), inactive_sec, |
647 | 0 | max_inactivity); |
648 | |
|
649 | 0 | if (hapd->conf->skip_inactivity_poll) |
650 | 0 | sta->timeout_next = STA_DISASSOC; |
651 | 0 | } |
652 | 0 | } |
653 | | |
654 | 0 | if ((sta->flags & WLAN_STA_ASSOC) && |
655 | 0 | sta->timeout_next == STA_DISASSOC && |
656 | 0 | !(sta->flags & WLAN_STA_PENDING_POLL) && |
657 | 0 | !hapd->conf->skip_inactivity_poll) { |
658 | 0 | wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR |
659 | 0 | " has ACKed data poll", MAC2STR(sta->addr)); |
660 | | /* data nullfunc frame poll did not produce TX errors; assume |
661 | | * station ACKed it */ |
662 | 0 | sta->timeout_next = STA_NULLFUNC; |
663 | 0 | next_time = max_inactivity; |
664 | 0 | } |
665 | |
|
666 | 0 | skip_poll: |
667 | 0 | if (next_time) { |
668 | 0 | wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " |
669 | 0 | "for " MACSTR " (%lu seconds)", |
670 | 0 | __func__, MAC2STR(sta->addr), next_time); |
671 | 0 | eloop_register_timeout(next_time, 0, ap_handle_timer, hapd, |
672 | 0 | sta); |
673 | 0 | return; |
674 | 0 | } |
675 | | |
676 | 0 | if (sta->timeout_next == STA_NULLFUNC && |
677 | 0 | (sta->flags & WLAN_STA_ASSOC)) { |
678 | 0 | wpa_printf(MSG_DEBUG, " Polling STA"); |
679 | 0 | sta->flags |= WLAN_STA_PENDING_POLL; |
680 | 0 | hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr, |
681 | 0 | sta->flags & WLAN_STA_WMM); |
682 | 0 | } else if (sta->timeout_next != STA_REMOVE) { |
683 | 0 | int deauth = sta->timeout_next == STA_DEAUTH; |
684 | |
|
685 | 0 | if (!deauth && !(sta->flags & WLAN_STA_ASSOC)) { |
686 | | /* Cannot disassociate not-associated STA, so move |
687 | | * directly to deauthentication. */ |
688 | 0 | sta->timeout_next = STA_DEAUTH; |
689 | 0 | deauth = 1; |
690 | 0 | } |
691 | |
|
692 | 0 | wpa_dbg(hapd->msg_ctx, MSG_DEBUG, |
693 | 0 | "Timeout, sending %s info to STA " MACSTR, |
694 | 0 | deauth ? "deauthentication" : "disassociation", |
695 | 0 | MAC2STR(sta->addr)); |
696 | |
|
697 | 0 | if (deauth) { |
698 | 0 | hostapd_drv_sta_deauth( |
699 | 0 | hapd, sta->addr, |
700 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
701 | 0 | } else { |
702 | 0 | reason = (sta->timeout_next == STA_DISASSOC) ? |
703 | 0 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : |
704 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID; |
705 | |
|
706 | 0 | hostapd_drv_sta_disassoc(hapd, sta->addr, reason); |
707 | 0 | } |
708 | 0 | } |
709 | |
|
710 | 0 | switch (sta->timeout_next) { |
711 | 0 | case STA_NULLFUNC: |
712 | 0 | sta->timeout_next = STA_DISASSOC; |
713 | 0 | wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " |
714 | 0 | "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)", |
715 | 0 | __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY); |
716 | 0 | eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer, |
717 | 0 | hapd, sta); |
718 | 0 | break; |
719 | 0 | case STA_DISASSOC: |
720 | 0 | case STA_DISASSOC_FROM_CLI: |
721 | 0 | ap_sta_set_authorized(hapd, sta, 0); |
722 | 0 | sta->flags &= ~WLAN_STA_ASSOC; |
723 | 0 | hostapd_set_sta_flags(hapd, sta); |
724 | 0 | ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); |
725 | 0 | if (!sta->acct_terminate_cause) |
726 | 0 | sta->acct_terminate_cause = |
727 | 0 | RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; |
728 | 0 | accounting_sta_stop(hapd, sta); |
729 | 0 | ieee802_1x_free_station(hapd, sta); |
730 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |
731 | 0 | HOSTAPD_LEVEL_INFO, "disassociated due to " |
732 | 0 | "inactivity"); |
733 | 0 | reason = (sta->timeout_next == STA_DISASSOC) ? |
734 | 0 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : |
735 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID; |
736 | 0 | sta->timeout_next = STA_DEAUTH; |
737 | 0 | wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " |
738 | 0 | "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)", |
739 | 0 | __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY); |
740 | 0 | eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, |
741 | 0 | hapd, sta); |
742 | 0 | mlme_disassociate_indication(hapd, sta, reason); |
743 | 0 | break; |
744 | 0 | case STA_DEAUTH: |
745 | 0 | case STA_REMOVE: |
746 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |
747 | 0 | HOSTAPD_LEVEL_INFO, "deauthenticated due to " |
748 | 0 | "inactivity (timer DEAUTH/REMOVE)"); |
749 | 0 | if (!sta->acct_terminate_cause) |
750 | 0 | sta->acct_terminate_cause = |
751 | 0 | RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; |
752 | 0 | mlme_deauthenticate_indication( |
753 | 0 | hapd, sta, |
754 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
755 | 0 | ap_free_sta(hapd, sta); |
756 | 0 | break; |
757 | 0 | } |
758 | 0 | } |
759 | | |
760 | | |
761 | | static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) |
762 | 0 | { |
763 | 0 | struct hostapd_data *hapd = eloop_ctx; |
764 | 0 | struct sta_info *sta = timeout_ctx; |
765 | |
|
766 | 0 | wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR, |
767 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
768 | 0 | if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC | |
769 | 0 | WLAN_STA_AUTHORIZED))) { |
770 | 0 | if (sta->flags & WLAN_STA_GAS) { |
771 | 0 | wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA " |
772 | 0 | "entry " MACSTR, MAC2STR(sta->addr)); |
773 | 0 | ap_free_sta(hapd, sta); |
774 | 0 | } |
775 | 0 | return; |
776 | 0 | } |
777 | | |
778 | 0 | hostapd_drv_sta_deauth(hapd, sta->addr, |
779 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
780 | 0 | mlme_deauthenticate_indication(hapd, sta, |
781 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
782 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |
783 | 0 | HOSTAPD_LEVEL_INFO, "deauthenticated due to " |
784 | 0 | "session timeout"); |
785 | 0 | sta->acct_terminate_cause = |
786 | 0 | RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT; |
787 | 0 | ap_free_sta(hapd, sta); |
788 | 0 | } |
789 | | |
790 | | |
791 | | void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta, |
792 | | u32 session_timeout) |
793 | 0 | { |
794 | 0 | if (eloop_replenish_timeout(session_timeout, 0, |
795 | 0 | ap_handle_session_timer, hapd, sta) == 1) { |
796 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |
797 | 0 | HOSTAPD_LEVEL_DEBUG, "setting session timeout " |
798 | 0 | "to %d seconds", session_timeout); |
799 | 0 | } |
800 | 0 | } |
801 | | |
802 | | |
803 | | void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, |
804 | | u32 session_timeout) |
805 | 0 | { |
806 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |
807 | 0 | HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d " |
808 | 0 | "seconds", session_timeout); |
809 | 0 | eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); |
810 | 0 | eloop_register_timeout(session_timeout, 0, ap_handle_session_timer, |
811 | 0 | hapd, sta); |
812 | 0 | } |
813 | | |
814 | | |
815 | | void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta) |
816 | 0 | { |
817 | 0 | eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); |
818 | 0 | } |
819 | | |
820 | | |
821 | | static void ap_handle_session_warning_timer(void *eloop_ctx, void *timeout_ctx) |
822 | 0 | { |
823 | | #ifdef CONFIG_WNM_AP |
824 | | struct hostapd_data *hapd = eloop_ctx; |
825 | | struct sta_info *sta = timeout_ctx; |
826 | | |
827 | | wpa_printf(MSG_DEBUG, "%s: WNM: Session warning time reached for " |
828 | | MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); |
829 | | if (sta->hs20_session_info_url == NULL) |
830 | | return; |
831 | | |
832 | | wnm_send_ess_disassoc_imminent(hapd, sta, sta->hs20_session_info_url, |
833 | | sta->hs20_disassoc_timer); |
834 | | #endif /* CONFIG_WNM_AP */ |
835 | 0 | } |
836 | | |
837 | | |
838 | | void ap_sta_session_warning_timeout(struct hostapd_data *hapd, |
839 | | struct sta_info *sta, int warning_time) |
840 | 0 | { |
841 | 0 | eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta); |
842 | 0 | eloop_register_timeout(warning_time, 0, ap_handle_session_warning_timer, |
843 | 0 | hapd, sta); |
844 | 0 | } |
845 | | |
846 | | |
847 | | static void ap_sta_assoc_timeout(void *eloop_ctx, void *timeout_ctx) |
848 | 0 | { |
849 | 0 | struct hostapd_data *hapd = eloop_ctx; |
850 | 0 | struct sta_info *sta = timeout_ctx; |
851 | |
|
852 | 0 | if (sta->flags & WLAN_STA_ASSOC) |
853 | 0 | return; |
854 | | |
855 | 0 | wpa_printf(MSG_DEBUG, "STA " MACSTR |
856 | 0 | " did not complete association in time - remove it", |
857 | 0 | MAC2STR(sta->addr)); |
858 | 0 | if (sta->flags & WLAN_STA_AUTH) |
859 | 0 | ap_sta_deauthenticate(hapd, sta, |
860 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
861 | 0 | else |
862 | 0 | ap_free_sta(hapd, sta); |
863 | 0 | } |
864 | | |
865 | | |
866 | | struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) |
867 | 2.16k | { |
868 | 2.16k | struct sta_info *sta; |
869 | 2.16k | int i; |
870 | 2.16k | int max_inactivity = hapd->conf->ap_max_inactivity; |
871 | | |
872 | 2.16k | sta = ap_get_sta(hapd, addr); |
873 | 2.16k | if (sta) |
874 | 0 | return sta; |
875 | | |
876 | 2.16k | wpa_printf(MSG_DEBUG, " New STA"); |
877 | 2.16k | if (hapd->num_sta >= hapd->conf->max_num_sta) { |
878 | | /* FIX: might try to remove some old STAs first? */ |
879 | 0 | wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)", |
880 | 0 | hapd->num_sta, hapd->conf->max_num_sta); |
881 | 0 | return NULL; |
882 | 0 | } |
883 | | |
884 | 2.16k | sta = os_zalloc(sizeof(struct sta_info)); |
885 | 2.16k | if (sta == NULL) { |
886 | 0 | wpa_printf(MSG_ERROR, "malloc failed"); |
887 | 0 | return NULL; |
888 | 0 | } |
889 | 2.16k | sta->acct_interim_interval = hapd->conf->acct_interim_interval; |
890 | 2.16k | if (accounting_sta_get_id(hapd, sta) < 0) { |
891 | 0 | os_free(sta); |
892 | 0 | return NULL; |
893 | 0 | } |
894 | | |
895 | 2.16k | for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) { |
896 | 2.16k | if (!hapd->iface->basic_rates) |
897 | 2.16k | break; |
898 | 0 | if (hapd->iface->basic_rates[i] <= 0) |
899 | 0 | break; |
900 | 0 | sta->supported_rates[i] = hapd->iface->basic_rates[i] / 5; |
901 | 0 | } |
902 | 2.16k | sta->supported_rates_len = i; |
903 | | |
904 | 2.16k | if (sta->max_idle_period) |
905 | 0 | max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; |
906 | | |
907 | 2.16k | if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { |
908 | 2.16k | wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout " |
909 | 2.16k | "for " MACSTR " (%d seconds - ap_max_inactivity)", |
910 | 2.16k | __func__, MAC2STR(addr), |
911 | 2.16k | max_inactivity); |
912 | 2.16k | eloop_register_timeout(max_inactivity, 0, |
913 | 2.16k | ap_handle_timer, hapd, sta); |
914 | 2.16k | } |
915 | | |
916 | | /* initialize STA info data */ |
917 | 2.16k | os_memcpy(sta->addr, addr, ETH_ALEN); |
918 | 2.16k | sta->next = hapd->sta_list; |
919 | 2.16k | hapd->sta_list = sta; |
920 | 2.16k | hapd->num_sta++; |
921 | 2.16k | ap_sta_hash_add(hapd, sta); |
922 | 2.16k | ap_sta_remove_in_other_bss(hapd, sta); |
923 | 2.16k | sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; |
924 | 2.16k | dl_list_init(&sta->ip6addr); |
925 | | |
926 | | #ifdef CONFIG_TAXONOMY |
927 | | sta_track_claim_taxonomy_info(hapd->iface, addr, |
928 | | &sta->probe_ie_taxonomy); |
929 | | #endif /* CONFIG_TAXONOMY */ |
930 | | |
931 | 2.16k | if (!(hapd->conf->mesh & MESH_ENABLED)) |
932 | 2.16k | eloop_register_timeout(60, 0, ap_sta_assoc_timeout, hapd, sta); |
933 | | |
934 | 2.16k | return sta; |
935 | 2.16k | } |
936 | | |
937 | | |
938 | | static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) |
939 | 0 | { |
940 | 0 | ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); |
941 | |
|
942 | 0 | if (sta->ipaddr) |
943 | 0 | hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr); |
944 | 0 | ap_sta_ip6addr_del(hapd, sta); |
945 | |
|
946 | 0 | wpa_printf(MSG_DEBUG, "%s: Removing STA " MACSTR " from kernel driver", |
947 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
948 | 0 | if (hostapd_drv_sta_remove(hapd, sta->addr) && |
949 | 0 | sta->flags & WLAN_STA_ASSOC) { |
950 | 0 | wpa_printf(MSG_DEBUG, "%s: Could not remove station " MACSTR |
951 | 0 | " from kernel driver", |
952 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
953 | 0 | return -1; |
954 | 0 | } |
955 | 0 | sta->added_unassoc = 0; |
956 | 0 | return 0; |
957 | 0 | } |
958 | | |
959 | | |
960 | | static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd, |
961 | | struct sta_info *sta) |
962 | 2.16k | { |
963 | 2.16k | struct hostapd_iface *iface = hapd->iface; |
964 | 2.16k | size_t i; |
965 | | |
966 | 2.16k | for (i = 0; i < iface->num_bss; i++) { |
967 | 0 | struct hostapd_data *bss = iface->bss[i]; |
968 | 0 | struct sta_info *sta2; |
969 | | /* bss should always be set during operation, but it may be |
970 | | * NULL during reconfiguration. Assume the STA is not |
971 | | * associated to another BSS in that case to avoid NULL pointer |
972 | | * dereferences. */ |
973 | 0 | if (bss == hapd || bss == NULL) |
974 | 0 | continue; |
975 | 0 | sta2 = ap_get_sta(bss, sta->addr); |
976 | 0 | if (!sta2) |
977 | 0 | continue; |
978 | | |
979 | 0 | wpa_printf(MSG_DEBUG, "%s: disconnect old STA " MACSTR |
980 | 0 | " association from another BSS %s", |
981 | 0 | hapd->conf->iface, MAC2STR(sta2->addr), |
982 | 0 | bss->conf->iface); |
983 | 0 | ap_sta_disconnect(bss, sta2, sta2->addr, |
984 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
985 | 0 | } |
986 | 2.16k | } |
987 | | |
988 | | |
989 | | static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx) |
990 | 0 | { |
991 | 0 | struct hostapd_data *hapd = eloop_ctx; |
992 | 0 | struct sta_info *sta = timeout_ctx; |
993 | |
|
994 | 0 | wpa_printf(MSG_DEBUG, "%s: Disassociation callback for STA " MACSTR, |
995 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
996 | 0 | ap_sta_remove(hapd, sta); |
997 | 0 | mlme_disassociate_indication(hapd, sta, sta->disassoc_reason); |
998 | 0 | } |
999 | | |
1000 | | |
1001 | | static void ap_sta_disconnect_common(struct hostapd_data *hapd, |
1002 | | struct sta_info *sta, unsigned int timeout, |
1003 | | bool free_1x) |
1004 | 0 | { |
1005 | 0 | sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; |
1006 | |
|
1007 | 0 | ap_sta_set_authorized(hapd, sta, 0); |
1008 | 0 | hostapd_set_sta_flags(hapd, sta); |
1009 | |
|
1010 | 0 | wpa_printf(MSG_DEBUG, |
1011 | 0 | "reschedule ap_handle_timer timeout (%u sec) for " MACSTR, |
1012 | 0 | MAC2STR(sta->addr), timeout); |
1013 | |
|
1014 | 0 | eloop_cancel_timeout(ap_handle_timer, hapd, sta); |
1015 | 0 | eloop_register_timeout(timeout, 0, ap_handle_timer, hapd, sta); |
1016 | 0 | accounting_sta_stop(hapd, sta); |
1017 | 0 | if (free_1x) |
1018 | 0 | ieee802_1x_free_station(hapd, sta); |
1019 | | #ifdef CONFIG_IEEE80211BE |
1020 | | if (!ap_sta_is_mld(hapd, sta) || |
1021 | | hapd->mld_link_id == sta->mld_assoc_link_id) { |
1022 | | wpa_auth_sta_deinit(sta->wpa_sm); |
1023 | | clear_wpa_sm_for_each_partner_link(hapd, sta); |
1024 | | } |
1025 | | #else /* CONFIG_IEEE80211BE */ |
1026 | 0 | wpa_auth_sta_deinit(sta->wpa_sm); |
1027 | 0 | #endif /* CONFIG_IEEE80211BE */ |
1028 | |
|
1029 | 0 | sta->wpa_sm = NULL; |
1030 | 0 | } |
1031 | | |
1032 | | |
1033 | | static void ap_sta_disassociate_common(struct hostapd_data *hapd, |
1034 | | struct sta_info *sta, u16 reason) |
1035 | 0 | { |
1036 | 0 | sta->disassoc_reason = reason; |
1037 | 0 | sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; |
1038 | 0 | eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); |
1039 | 0 | eloop_register_timeout(hapd->iface->drv_flags & |
1040 | 0 | WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, |
1041 | 0 | ap_sta_disassoc_cb_timeout, hapd, sta); |
1042 | 0 | } |
1043 | | |
1044 | | |
1045 | | static void ap_sta_handle_disassociate(struct hostapd_data *hapd, |
1046 | | struct sta_info *sta, u16 reason) |
1047 | 0 | { |
1048 | 0 | wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR, |
1049 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
1050 | |
|
1051 | 0 | if (hapd->iface->current_mode && |
1052 | 0 | hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { |
1053 | | /* Skip deauthentication in DMG/IEEE 802.11ad */ |
1054 | 0 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | |
1055 | 0 | WLAN_STA_ASSOC_REQ_OK); |
1056 | 0 | sta->timeout_next = STA_REMOVE; |
1057 | 0 | } else { |
1058 | 0 | sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); |
1059 | 0 | sta->timeout_next = STA_DEAUTH; |
1060 | 0 | } |
1061 | |
|
1062 | 0 | ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC, |
1063 | 0 | true); |
1064 | 0 | ap_sta_disassociate_common(hapd, sta, reason); |
1065 | 0 | } |
1066 | | |
1067 | | |
1068 | | static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx) |
1069 | 0 | { |
1070 | 0 | struct hostapd_data *hapd = eloop_ctx; |
1071 | 0 | struct sta_info *sta = timeout_ctx; |
1072 | |
|
1073 | 0 | wpa_printf(MSG_DEBUG, "%s: Deauthentication callback for STA " MACSTR, |
1074 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
1075 | 0 | ap_sta_remove(hapd, sta); |
1076 | 0 | mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason); |
1077 | 0 | } |
1078 | | |
1079 | | |
1080 | | static void ap_sta_deauthenticate_common(struct hostapd_data *hapd, |
1081 | | struct sta_info *sta, u16 reason) |
1082 | 0 | { |
1083 | 0 | sta->deauth_reason = reason; |
1084 | 0 | sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; |
1085 | 0 | eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); |
1086 | 0 | eloop_register_timeout(hapd->iface->drv_flags & |
1087 | 0 | WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0, |
1088 | 0 | ap_sta_deauth_cb_timeout, hapd, sta); |
1089 | 0 | } |
1090 | | |
1091 | | |
1092 | | static void ap_sta_handle_deauthenticate(struct hostapd_data *hapd, |
1093 | | struct sta_info *sta, u16 reason) |
1094 | 0 | { |
1095 | 0 | wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR, |
1096 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
1097 | |
|
1098 | 0 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); |
1099 | |
|
1100 | 0 | sta->timeout_next = STA_REMOVE; |
1101 | 0 | ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH, |
1102 | 0 | true); |
1103 | 0 | ap_sta_deauthenticate_common(hapd, sta, reason); |
1104 | 0 | } |
1105 | | |
1106 | | |
1107 | | static void ap_sta_handle_disconnect(struct hostapd_data *hapd, |
1108 | | struct sta_info *sta, u16 reason) |
1109 | 0 | { |
1110 | 0 | wpa_printf(MSG_DEBUG, "%s: disconnect STA " MACSTR, |
1111 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
1112 | |
|
1113 | 0 | sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); |
1114 | 0 | wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); |
1115 | 0 | ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); |
1116 | 0 | sta->timeout_next = STA_REMOVE; |
1117 | |
|
1118 | 0 | ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH, |
1119 | 0 | false); |
1120 | 0 | ap_sta_deauthenticate_common(hapd, sta, reason); |
1121 | 0 | } |
1122 | | |
1123 | | |
1124 | | enum ap_sta_disconnect_op { |
1125 | | AP_STA_DEAUTHENTICATE, |
1126 | | AP_STA_DISASSOCIATE, |
1127 | | AP_STA_DISCONNECT |
1128 | | }; |
1129 | | |
1130 | | static bool ap_sta_ml_disconnect(struct hostapd_data *hapd, |
1131 | | struct sta_info *sta, u16 reason, |
1132 | | enum ap_sta_disconnect_op op) |
1133 | 0 | { |
1134 | | #ifdef CONFIG_IEEE80211BE |
1135 | | struct hostapd_data *assoc_hapd, *tmp_hapd; |
1136 | | struct sta_info *assoc_sta; |
1137 | | unsigned int i, link_id; |
1138 | | struct hapd_interfaces *interfaces; |
1139 | | |
1140 | | if (!hostapd_is_multiple_link_mld(hapd)) |
1141 | | return false; |
1142 | | |
1143 | | /* |
1144 | | * Get the station on which the association was performed, as it holds |
1145 | | * the information about all the other links. |
1146 | | */ |
1147 | | assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd); |
1148 | | if (!assoc_sta) |
1149 | | return false; |
1150 | | interfaces = assoc_hapd->iface->interfaces; |
1151 | | |
1152 | | for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { |
1153 | | if (!assoc_sta->mld_info.links[link_id].valid) |
1154 | | continue; |
1155 | | |
1156 | | for (i = 0; i < interfaces->count; i++) { |
1157 | | struct sta_info *tmp_sta; |
1158 | | |
1159 | | tmp_hapd = interfaces->iface[i]->bss[0]; |
1160 | | |
1161 | | if (!hostapd_is_ml_partner(tmp_hapd, assoc_hapd)) |
1162 | | continue; |
1163 | | |
1164 | | for (tmp_sta = tmp_hapd->sta_list; tmp_sta; |
1165 | | tmp_sta = tmp_sta->next) { |
1166 | | /* |
1167 | | * Handle the station on which the association |
1168 | | * was done only after all other link station |
1169 | | * are removed. Since there is a only a single |
1170 | | * station per hapd with the same association |
1171 | | * link simply break; |
1172 | | */ |
1173 | | if (tmp_sta == assoc_sta) |
1174 | | break; |
1175 | | |
1176 | | if (tmp_sta->mld_assoc_link_id != |
1177 | | assoc_sta->mld_assoc_link_id || |
1178 | | tmp_sta->aid != assoc_sta->aid) |
1179 | | continue; |
1180 | | |
1181 | | if (op == AP_STA_DISASSOCIATE) |
1182 | | ap_sta_handle_disassociate(tmp_hapd, |
1183 | | tmp_sta, |
1184 | | reason); |
1185 | | else if (op == AP_STA_DEAUTHENTICATE) |
1186 | | ap_sta_handle_deauthenticate(tmp_hapd, |
1187 | | tmp_sta, |
1188 | | reason); |
1189 | | else |
1190 | | ap_sta_handle_disconnect(tmp_hapd, |
1191 | | tmp_sta, |
1192 | | reason); |
1193 | | break; |
1194 | | } |
1195 | | } |
1196 | | } |
1197 | | |
1198 | | /* Disconnect the station on which the association was performed. */ |
1199 | | if (op == AP_STA_DISASSOCIATE) |
1200 | | ap_sta_handle_disassociate(assoc_hapd, assoc_sta, reason); |
1201 | | else if (op == AP_STA_DEAUTHENTICATE) |
1202 | | ap_sta_handle_deauthenticate(assoc_hapd, assoc_sta, reason); |
1203 | | else |
1204 | | ap_sta_handle_disconnect(assoc_hapd, assoc_sta, reason); |
1205 | | |
1206 | | return true; |
1207 | | #else /* CONFIG_IEEE80211BE */ |
1208 | 0 | return false; |
1209 | 0 | #endif /* CONFIG_IEEE80211BE */ |
1210 | 0 | } |
1211 | | |
1212 | | |
1213 | | void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, |
1214 | | u16 reason) |
1215 | 0 | { |
1216 | 0 | if (ap_sta_ml_disconnect(hapd, sta, reason, AP_STA_DISASSOCIATE)) |
1217 | 0 | return; |
1218 | | |
1219 | 0 | ap_sta_handle_disassociate(hapd, sta, reason); |
1220 | 0 | } |
1221 | | |
1222 | | |
1223 | | void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, |
1224 | | u16 reason) |
1225 | 0 | { |
1226 | 0 | if (hapd->iface->current_mode && |
1227 | 0 | hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { |
1228 | | /* Deauthentication is not used in DMG/IEEE 802.11ad; |
1229 | | * disassociate the STA instead. */ |
1230 | 0 | ap_sta_disassociate(hapd, sta, reason); |
1231 | 0 | return; |
1232 | 0 | } |
1233 | | |
1234 | 0 | if (ap_sta_ml_disconnect(hapd, sta, reason, AP_STA_DEAUTHENTICATE)) |
1235 | 0 | return; |
1236 | | |
1237 | 0 | ap_sta_handle_deauthenticate(hapd, sta, reason); |
1238 | 0 | } |
1239 | | |
1240 | | |
1241 | | #ifdef CONFIG_WPS |
1242 | | int ap_sta_wps_cancel(struct hostapd_data *hapd, |
1243 | | struct sta_info *sta, void *ctx) |
1244 | 0 | { |
1245 | 0 | if (sta && (sta->flags & WLAN_STA_WPS)) { |
1246 | 0 | ap_sta_deauthenticate(hapd, sta, |
1247 | 0 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1248 | 0 | wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR, |
1249 | 0 | __func__, MAC2STR(sta->addr)); |
1250 | 0 | return 1; |
1251 | 0 | } |
1252 | | |
1253 | 0 | return 0; |
1254 | 0 | } |
1255 | | #endif /* CONFIG_WPS */ |
1256 | | |
1257 | | |
1258 | | static int ap_sta_get_free_vlan_id(struct hostapd_data *hapd) |
1259 | 0 | { |
1260 | 0 | struct hostapd_vlan *vlan; |
1261 | 0 | struct hostapd_data *vlan_bss = hapd; |
1262 | 0 | int vlan_id = MAX_VLAN_ID + 2; |
1263 | |
|
1264 | | #ifdef CONFIG_IEEE80211BE |
1265 | | if (hapd->conf->mld_ap) { |
1266 | | vlan_bss = hostapd_mld_get_first_bss(hapd); |
1267 | | if (!vlan_bss) |
1268 | | vlan_bss = hapd; |
1269 | | } |
1270 | | #endif /* CONFIG_IEEE80211BE */ |
1271 | |
|
1272 | 0 | retry: |
1273 | 0 | for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) { |
1274 | 0 | if (vlan->vlan_id == vlan_id) { |
1275 | 0 | vlan_id++; |
1276 | 0 | goto retry; |
1277 | 0 | } |
1278 | 0 | } |
1279 | 0 | return vlan_id; |
1280 | 0 | } |
1281 | | |
1282 | | |
1283 | | int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta, |
1284 | | struct vlan_description *vlan_desc) |
1285 | 0 | { |
1286 | 0 | struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL; |
1287 | 0 | struct hostapd_data *vlan_bss = hapd; |
1288 | 0 | int old_vlan_id, vlan_id = 0, ret = 0; |
1289 | |
|
1290 | | #ifdef CONFIG_IEEE80211BE |
1291 | | if (hapd->conf->mld_ap) { |
1292 | | vlan_bss = hostapd_mld_get_first_bss(hapd); |
1293 | | if (!vlan_bss) |
1294 | | vlan_bss = hapd; |
1295 | | } |
1296 | | #endif /* CONFIG_IEEE80211BE */ |
1297 | | |
1298 | | /* Check if there is something to do */ |
1299 | 0 | if (hapd->conf->ssid.per_sta_vif && !sta->vlan_id) { |
1300 | | /* This sta is lacking its own vif */ |
1301 | 0 | } else if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED && |
1302 | 0 | !hapd->conf->ssid.per_sta_vif && sta->vlan_id) { |
1303 | | /* sta->vlan_id needs to be reset */ |
1304 | 0 | } else if (!vlan_compare(vlan_desc, sta->vlan_desc)) { |
1305 | 0 | return 0; /* nothing to change */ |
1306 | 0 | } |
1307 | | |
1308 | | /* Now the real VLAN changed or the STA just needs its own vif */ |
1309 | 0 | if (hapd->conf->ssid.per_sta_vif) { |
1310 | | /* Assign a new vif, always */ |
1311 | | /* find a free vlan_id sufficiently big */ |
1312 | 0 | vlan_id = ap_sta_get_free_vlan_id(hapd); |
1313 | | /* Get wildcard VLAN */ |
1314 | 0 | for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) { |
1315 | 0 | if (vlan->vlan_id == VLAN_ID_WILDCARD) |
1316 | 0 | break; |
1317 | 0 | } |
1318 | 0 | if (!vlan) { |
1319 | 0 | hostapd_logger(hapd, sta->addr, |
1320 | 0 | HOSTAPD_MODULE_IEEE80211, |
1321 | 0 | HOSTAPD_LEVEL_DEBUG, |
1322 | 0 | "per_sta_vif missing wildcard"); |
1323 | 0 | vlan_id = 0; |
1324 | 0 | ret = -1; |
1325 | 0 | goto done; |
1326 | 0 | } |
1327 | 0 | } else if (vlan_desc && vlan_desc->notempty) { |
1328 | 0 | for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) { |
1329 | 0 | if (!vlan_compare(&vlan->vlan_desc, vlan_desc)) |
1330 | 0 | break; |
1331 | 0 | if (vlan->vlan_id == VLAN_ID_WILDCARD) |
1332 | 0 | wildcard_vlan = vlan; |
1333 | 0 | } |
1334 | 0 | if (vlan) { |
1335 | 0 | vlan_id = vlan->vlan_id; |
1336 | 0 | } else if (wildcard_vlan) { |
1337 | 0 | vlan = wildcard_vlan; |
1338 | 0 | vlan_id = vlan_desc->untagged; |
1339 | 0 | if (vlan_desc->tagged[0]) { |
1340 | | /* Tagged VLAN configuration */ |
1341 | 0 | vlan_id = ap_sta_get_free_vlan_id(vlan_bss); |
1342 | 0 | } |
1343 | 0 | } else { |
1344 | 0 | hostapd_logger(vlan_bss, sta->addr, |
1345 | 0 | HOSTAPD_MODULE_IEEE80211, |
1346 | 0 | HOSTAPD_LEVEL_DEBUG, |
1347 | 0 | "missing vlan and wildcard for vlan=%d%s", |
1348 | 0 | vlan_desc->untagged, |
1349 | 0 | vlan_desc->tagged[0] ? "+" : ""); |
1350 | 0 | vlan_id = 0; |
1351 | 0 | ret = -1; |
1352 | 0 | goto done; |
1353 | 0 | } |
1354 | 0 | } |
1355 | | |
1356 | 0 | if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) { |
1357 | 0 | vlan = vlan_add_dynamic(vlan_bss, vlan, vlan_id, vlan_desc); |
1358 | 0 | if (vlan == NULL) { |
1359 | 0 | hostapd_logger(vlan_bss, sta->addr, |
1360 | 0 | HOSTAPD_MODULE_IEEE80211, |
1361 | 0 | HOSTAPD_LEVEL_DEBUG, |
1362 | 0 | "could not add dynamic VLAN interface for vlan=%d%s", |
1363 | 0 | vlan_desc ? vlan_desc->untagged : -1, |
1364 | 0 | (vlan_desc && vlan_desc->tagged[0]) ? |
1365 | 0 | "+" : ""); |
1366 | 0 | vlan_id = 0; |
1367 | 0 | ret = -1; |
1368 | 0 | goto done; |
1369 | 0 | } |
1370 | | |
1371 | 0 | hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211, |
1372 | 0 | HOSTAPD_LEVEL_DEBUG, |
1373 | 0 | "added new dynamic VLAN interface '%s'", |
1374 | 0 | vlan->ifname); |
1375 | 0 | } else if (vlan && vlan->dynamic_vlan > 0) { |
1376 | 0 | vlan->dynamic_vlan++; |
1377 | 0 | hostapd_logger(vlan_bss, sta->addr, |
1378 | 0 | HOSTAPD_MODULE_IEEE80211, |
1379 | 0 | HOSTAPD_LEVEL_DEBUG, |
1380 | 0 | "updated existing dynamic VLAN interface '%s'", |
1381 | 0 | vlan->ifname); |
1382 | 0 | } |
1383 | 0 | done: |
1384 | 0 | old_vlan_id = sta->vlan_id; |
1385 | 0 | sta->vlan_id = vlan_id; |
1386 | 0 | sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL; |
1387 | |
|
1388 | 0 | if (vlan_id != old_vlan_id && old_vlan_id) |
1389 | 0 | vlan_remove_dynamic(vlan_bss, old_vlan_id); |
1390 | |
|
1391 | 0 | return ret; |
1392 | 0 | } |
1393 | | |
1394 | | |
1395 | | int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) |
1396 | 0 | { |
1397 | 0 | #ifndef CONFIG_NO_VLAN |
1398 | 0 | const char *iface; |
1399 | 0 | struct hostapd_vlan *vlan = NULL; |
1400 | 0 | struct hostapd_data *vlan_bss = hapd; |
1401 | 0 | int ret; |
1402 | 0 | int old_vlanid = sta->vlan_id_bound; |
1403 | 0 | int mld_link_id = -1; |
1404 | |
|
1405 | | #ifdef CONFIG_IEEE80211BE |
1406 | | if (hapd->conf->mld_ap) { |
1407 | | mld_link_id = hapd->mld_link_id; |
1408 | | vlan_bss = hostapd_mld_get_first_bss(hapd); |
1409 | | if (!vlan_bss) |
1410 | | vlan_bss = hapd; |
1411 | | } |
1412 | | #endif /* CONFIG_IEEE80211BE */ |
1413 | |
|
1414 | 0 | if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) { |
1415 | 0 | wpa_printf(MSG_DEBUG, |
1416 | 0 | "Do not override WDS VLAN assignment for STA " |
1417 | 0 | MACSTR, MAC2STR(sta->addr)); |
1418 | 0 | return 0; |
1419 | 0 | } |
1420 | | |
1421 | 0 | iface = hapd->conf->iface; |
1422 | 0 | if (hapd->conf->ssid.vlan[0]) |
1423 | 0 | iface = hapd->conf->ssid.vlan; |
1424 | |
|
1425 | 0 | if (sta->vlan_id > 0) { |
1426 | 0 | for (vlan = vlan_bss->conf->vlan; vlan; vlan = vlan->next) { |
1427 | 0 | if (vlan->vlan_id == sta->vlan_id) |
1428 | 0 | break; |
1429 | 0 | } |
1430 | 0 | if (vlan) |
1431 | 0 | iface = vlan->ifname; |
1432 | 0 | } |
1433 | | |
1434 | | /* |
1435 | | * Do not increment ref counters if the VLAN ID remains same, but do |
1436 | | * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might |
1437 | | * have been called before. |
1438 | | */ |
1439 | 0 | if (sta->vlan_id == old_vlanid) |
1440 | 0 | goto skip_counting; |
1441 | | |
1442 | 0 | if (sta->vlan_id > 0 && !vlan && |
1443 | 0 | !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { |
1444 | 0 | hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211, |
1445 | 0 | HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " |
1446 | 0 | "binding station to (vlan_id=%d)", |
1447 | 0 | sta->vlan_id); |
1448 | 0 | ret = -1; |
1449 | 0 | goto done; |
1450 | 0 | } else if (vlan && vlan->dynamic_vlan > 0) { |
1451 | 0 | vlan->dynamic_vlan++; |
1452 | 0 | hostapd_logger(vlan_bss, sta->addr, |
1453 | 0 | HOSTAPD_MODULE_IEEE80211, |
1454 | 0 | HOSTAPD_LEVEL_DEBUG, |
1455 | 0 | "updated existing dynamic VLAN interface '%s'", |
1456 | 0 | iface); |
1457 | 0 | } |
1458 | | |
1459 | | /* ref counters have been increased, so mark the station */ |
1460 | 0 | sta->vlan_id_bound = sta->vlan_id; |
1461 | |
|
1462 | 0 | skip_counting: |
1463 | 0 | hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211, |
1464 | 0 | HOSTAPD_LEVEL_DEBUG, "binding station to interface " |
1465 | 0 | "'%s'", iface); |
1466 | |
|
1467 | 0 | if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) |
1468 | 0 | wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); |
1469 | |
|
1470 | 0 | ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id, |
1471 | 0 | mld_link_id); |
1472 | 0 | if (ret < 0) { |
1473 | 0 | hostapd_logger(vlan_bss, sta->addr, HOSTAPD_MODULE_IEEE80211, |
1474 | 0 | HOSTAPD_LEVEL_DEBUG, "could not bind the STA " |
1475 | 0 | "entry to vlan_id=%d", sta->vlan_id); |
1476 | 0 | } |
1477 | | |
1478 | | /* During 1x reauth, if the vlan id changes, then remove the old id. */ |
1479 | 0 | if (old_vlanid > 0 && old_vlanid != sta->vlan_id) |
1480 | 0 | vlan_remove_dynamic(vlan_bss, old_vlanid); |
1481 | 0 | done: |
1482 | |
|
1483 | 0 | return ret; |
1484 | | #else /* CONFIG_NO_VLAN */ |
1485 | | return 0; |
1486 | | #endif /* CONFIG_NO_VLAN */ |
1487 | 0 | } |
1488 | | |
1489 | | |
1490 | | void ap_sta_set_sa_query_timeout(struct hostapd_data *hapd, |
1491 | | struct sta_info *sta, int value) |
1492 | 0 | { |
1493 | 0 | sta->sa_query_timed_out = value; |
1494 | | #ifdef CONFIG_IEEE80211BE |
1495 | | if (ap_sta_is_mld(hapd, sta)) { |
1496 | | struct hostapd_data *lhapd; |
1497 | | |
1498 | | for_each_mld_link(lhapd, hapd) { |
1499 | | struct sta_info *lsta; |
1500 | | |
1501 | | if (lhapd == hapd) |
1502 | | continue; |
1503 | | |
1504 | | lsta = ap_get_sta(lhapd, sta->addr); |
1505 | | if (lsta) |
1506 | | lsta->sa_query_timed_out = value; |
1507 | | } |
1508 | | } |
1509 | | #endif /* CONFIG_IEEE80211BE */ |
1510 | 0 | } |
1511 | | |
1512 | | |
1513 | | int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta) |
1514 | 0 | { |
1515 | 0 | u32 tu; |
1516 | 0 | struct os_reltime now, passed; |
1517 | 0 | os_get_reltime(&now); |
1518 | 0 | os_reltime_sub(&now, &sta->sa_query_start, &passed); |
1519 | 0 | tu = (passed.sec * 1000000 + passed.usec) / 1024; |
1520 | 0 | if (hapd->conf->assoc_sa_query_max_timeout < tu) { |
1521 | 0 | hostapd_logger(hapd, sta->addr, |
1522 | 0 | HOSTAPD_MODULE_IEEE80211, |
1523 | 0 | HOSTAPD_LEVEL_DEBUG, |
1524 | 0 | "association SA Query timed out"); |
1525 | 0 | ap_sta_set_sa_query_timeout(hapd, sta, 1); |
1526 | 0 | os_free(sta->sa_query_trans_id); |
1527 | 0 | sta->sa_query_trans_id = NULL; |
1528 | 0 | sta->sa_query_count = 0; |
1529 | 0 | eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); |
1530 | 0 | return 1; |
1531 | 0 | } |
1532 | | |
1533 | 0 | return 0; |
1534 | 0 | } |
1535 | | |
1536 | | |
1537 | | static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) |
1538 | 0 | { |
1539 | 0 | struct hostapd_data *hapd = eloop_ctx; |
1540 | 0 | struct sta_info *sta = timeout_ctx; |
1541 | 0 | unsigned int timeout, sec, usec; |
1542 | 0 | u8 *trans_id, *nbuf; |
1543 | |
|
1544 | 0 | wpa_printf(MSG_DEBUG, "%s: SA Query timer for STA " MACSTR |
1545 | 0 | " (count=%d)", |
1546 | 0 | hapd->conf->iface, MAC2STR(sta->addr), sta->sa_query_count); |
1547 | |
|
1548 | 0 | if (sta->sa_query_count > 0 && |
1549 | 0 | ap_check_sa_query_timeout(hapd, sta)) |
1550 | 0 | return; |
1551 | 0 | if (sta->sa_query_count >= 1000) |
1552 | 0 | return; |
1553 | | |
1554 | 0 | nbuf = os_realloc_array(sta->sa_query_trans_id, |
1555 | 0 | sta->sa_query_count + 1, |
1556 | 0 | WLAN_SA_QUERY_TR_ID_LEN); |
1557 | 0 | if (nbuf == NULL) |
1558 | 0 | return; |
1559 | 0 | if (sta->sa_query_count == 0) { |
1560 | | /* Starting a new SA Query procedure */ |
1561 | 0 | os_get_reltime(&sta->sa_query_start); |
1562 | 0 | } |
1563 | 0 | trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN; |
1564 | 0 | sta->sa_query_trans_id = nbuf; |
1565 | 0 | sta->sa_query_count++; |
1566 | |
|
1567 | 0 | if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) { |
1568 | | /* |
1569 | | * We don't really care which ID is used here, so simply |
1570 | | * hardcode this if the mostly theoretical os_get_random() |
1571 | | * failure happens. |
1572 | | */ |
1573 | 0 | trans_id[0] = 0x12; |
1574 | 0 | trans_id[1] = 0x34; |
1575 | 0 | } |
1576 | |
|
1577 | 0 | timeout = hapd->conf->assoc_sa_query_retry_timeout; |
1578 | 0 | sec = ((timeout / 1000) * 1024) / 1000; |
1579 | 0 | usec = (timeout % 1000) * 1024; |
1580 | 0 | eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta); |
1581 | |
|
1582 | 0 | hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |
1583 | 0 | HOSTAPD_LEVEL_DEBUG, |
1584 | 0 | "association SA Query attempt %d", sta->sa_query_count); |
1585 | |
|
1586 | 0 | ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id); |
1587 | 0 | } |
1588 | | |
1589 | | |
1590 | | void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta) |
1591 | 0 | { |
1592 | 0 | ap_sa_query_timer(hapd, sta); |
1593 | 0 | } |
1594 | | |
1595 | | |
1596 | | void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) |
1597 | 0 | { |
1598 | 0 | eloop_cancel_timeout(ap_sa_query_timer, hapd, sta); |
1599 | 0 | os_free(sta->sa_query_trans_id); |
1600 | 0 | sta->sa_query_trans_id = NULL; |
1601 | 0 | sta->sa_query_count = 0; |
1602 | 0 | } |
1603 | | |
1604 | | |
1605 | | const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, |
1606 | | struct sta_info *sta) |
1607 | 0 | { |
1608 | 0 | struct hostapd_wpa_psk *psk; |
1609 | 0 | struct hostapd_ssid *ssid; |
1610 | 0 | const u8 *pmk; |
1611 | 0 | int pmk_len; |
1612 | |
|
1613 | 0 | ssid = &hapd->conf->ssid; |
1614 | |
|
1615 | 0 | pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); |
1616 | 0 | if (!pmk || pmk_len != PMK_LEN) |
1617 | 0 | return NULL; |
1618 | | |
1619 | 0 | for (psk = ssid->wpa_psk; psk; psk = psk->next) |
1620 | 0 | if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0) |
1621 | 0 | break; |
1622 | 0 | if (!psk || !psk->keyid[0]) |
1623 | 0 | return NULL; |
1624 | | |
1625 | 0 | return psk->keyid; |
1626 | 0 | } |
1627 | | |
1628 | | |
1629 | | const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd, |
1630 | | struct sta_info *sta) |
1631 | 0 | { |
1632 | 0 | return wpa_auth_get_dpp_pkhash(sta->wpa_sm); |
1633 | 0 | } |
1634 | | |
1635 | | |
1636 | | bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta, |
1637 | | int authorized) |
1638 | 2.16k | { |
1639 | 2.16k | if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) |
1640 | 2.16k | return false; |
1641 | | |
1642 | 0 | if (authorized) { |
1643 | 0 | int mld_assoc_link_id = -1; |
1644 | |
|
1645 | | #ifdef CONFIG_IEEE80211BE |
1646 | | if (ap_sta_is_mld(hapd, sta)) { |
1647 | | if (sta->mld_assoc_link_id == hapd->mld_link_id) |
1648 | | mld_assoc_link_id = sta->mld_assoc_link_id; |
1649 | | else |
1650 | | mld_assoc_link_id = -2; |
1651 | | } |
1652 | | #endif /* CONFIG_IEEE80211BE */ |
1653 | 0 | if (mld_assoc_link_id != -2) |
1654 | 0 | hostapd_prune_associations(hapd, sta->addr, |
1655 | 0 | mld_assoc_link_id); |
1656 | 0 | sta->flags |= WLAN_STA_AUTHORIZED; |
1657 | 0 | } else { |
1658 | 0 | sta->flags &= ~WLAN_STA_AUTHORIZED; |
1659 | 0 | } |
1660 | |
|
1661 | 0 | return true; |
1662 | 2.16k | } |
1663 | | |
1664 | | |
1665 | | void ap_sta_set_authorized_event(struct hostapd_data *hapd, |
1666 | | struct sta_info *sta, int authorized) |
1667 | 0 | { |
1668 | 0 | const u8 *dev_addr = NULL; |
1669 | 0 | char buf[100]; |
1670 | | #ifdef CONFIG_P2P |
1671 | | u8 addr[ETH_ALEN]; |
1672 | | u8 ip_addr_buf[4]; |
1673 | | #endif /* CONFIG_P2P */ |
1674 | 0 | const u8 *ip_ptr = NULL; |
1675 | |
|
1676 | | #ifdef CONFIG_P2P |
1677 | | if (hapd->p2p_group == NULL) { |
1678 | | if (sta->p2p_ie != NULL && |
1679 | | p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0) |
1680 | | dev_addr = addr; |
1681 | | } else |
1682 | | dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); |
1683 | | |
1684 | | if (dev_addr) |
1685 | | os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR, |
1686 | | MAC2STR(sta->addr), MAC2STR(dev_addr)); |
1687 | | else |
1688 | | #endif /* CONFIG_P2P */ |
1689 | 0 | os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr)); |
1690 | |
|
1691 | 0 | if (authorized) { |
1692 | 0 | const u8 *dpp_pkhash; |
1693 | 0 | const char *keyid; |
1694 | 0 | char dpp_pkhash_buf[100]; |
1695 | 0 | char keyid_buf[100]; |
1696 | 0 | char ip_addr[100]; |
1697 | 0 | char vlanid_buf[20]; |
1698 | |
|
1699 | 0 | dpp_pkhash_buf[0] = '\0'; |
1700 | 0 | keyid_buf[0] = '\0'; |
1701 | 0 | ip_addr[0] = '\0'; |
1702 | 0 | vlanid_buf[0] = '\0'; |
1703 | |
|
1704 | | #ifdef CONFIG_P2P |
1705 | | if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) { |
1706 | | os_snprintf(ip_addr, sizeof(ip_addr), |
1707 | | " ip_addr=%u.%u.%u.%u", |
1708 | | ip_addr_buf[0], ip_addr_buf[1], |
1709 | | ip_addr_buf[2], ip_addr_buf[3]); |
1710 | | ip_ptr = ip_addr_buf; |
1711 | | } |
1712 | | #endif /* CONFIG_P2P */ |
1713 | |
|
1714 | 0 | keyid = ap_sta_wpa_get_keyid(hapd, sta); |
1715 | 0 | if (keyid) { |
1716 | 0 | os_snprintf(keyid_buf, sizeof(keyid_buf), |
1717 | 0 | " keyid=%s", keyid); |
1718 | 0 | } |
1719 | |
|
1720 | 0 | dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta); |
1721 | 0 | if (dpp_pkhash) { |
1722 | 0 | const char *prefix = " dpp_pkhash="; |
1723 | 0 | size_t plen = os_strlen(prefix); |
1724 | |
|
1725 | 0 | os_strlcpy(dpp_pkhash_buf, prefix, |
1726 | 0 | sizeof(dpp_pkhash_buf)); |
1727 | 0 | wpa_snprintf_hex(&dpp_pkhash_buf[plen], |
1728 | 0 | sizeof(dpp_pkhash_buf) - plen, |
1729 | 0 | dpp_pkhash, SHA256_MAC_LEN); |
1730 | 0 | } |
1731 | |
|
1732 | 0 | #ifndef CONFIG_NO_VLAN |
1733 | 0 | if (sta->vlan_id) |
1734 | 0 | os_snprintf(vlanid_buf, sizeof(vlanid_buf), |
1735 | 0 | " vlanid=%u", sta->vlan_id); |
1736 | 0 | #endif /* CONFIG_NO_VLAN */ |
1737 | |
|
1738 | 0 | wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s%s", |
1739 | 0 | buf, ip_addr, keyid_buf, dpp_pkhash_buf, vlanid_buf); |
1740 | |
|
1741 | 0 | if (hapd->msg_ctx_parent && |
1742 | 0 | hapd->msg_ctx_parent != hapd->msg_ctx) |
1743 | 0 | wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, |
1744 | 0 | AP_STA_CONNECTED "%s%s%s%s%s", |
1745 | 0 | buf, ip_addr, keyid_buf, |
1746 | 0 | dpp_pkhash_buf, vlanid_buf); |
1747 | 0 | } else { |
1748 | 0 | wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); |
1749 | |
|
1750 | 0 | if (hapd->msg_ctx_parent && |
1751 | 0 | hapd->msg_ctx_parent != hapd->msg_ctx) |
1752 | 0 | wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, |
1753 | 0 | AP_STA_DISCONNECTED "%s", buf); |
1754 | 0 | } |
1755 | |
|
1756 | 0 | if (hapd->sta_authorized_cb) |
1757 | 0 | hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, |
1758 | 0 | sta->addr, authorized, dev_addr, |
1759 | 0 | ip_ptr); |
1760 | |
|
1761 | | #ifdef CONFIG_FST |
1762 | | if (hapd->iface->fst) { |
1763 | | if (authorized) |
1764 | | fst_notify_peer_connected(hapd->iface->fst, sta->addr); |
1765 | | else |
1766 | | fst_notify_peer_disconnected(hapd->iface->fst, |
1767 | | sta->addr); |
1768 | | } |
1769 | | #endif /* CONFIG_FST */ |
1770 | 0 | } |
1771 | | |
1772 | | |
1773 | | bool ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, |
1774 | | int authorized) |
1775 | 2.16k | { |
1776 | 2.16k | if (!ap_sta_set_authorized_flag(hapd, sta, authorized)) |
1777 | 2.16k | return false; |
1778 | 0 | ap_sta_set_authorized_event(hapd, sta, authorized); |
1779 | 0 | return true; |
1780 | 2.16k | } |
1781 | | |
1782 | | |
1783 | | void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, |
1784 | | const u8 *addr, u16 reason) |
1785 | 0 | { |
1786 | 0 | if (sta) |
1787 | 0 | wpa_printf(MSG_DEBUG, "%s: %s STA " MACSTR " reason=%u", |
1788 | 0 | hapd->conf->iface, __func__, MAC2STR(sta->addr), |
1789 | 0 | reason); |
1790 | 0 | else if (addr) |
1791 | 0 | wpa_printf(MSG_DEBUG, "%s: %s addr " MACSTR " reason=%u", |
1792 | 0 | hapd->conf->iface, __func__, MAC2STR(addr), |
1793 | 0 | reason); |
1794 | |
|
1795 | 0 | if (sta == NULL && addr) |
1796 | 0 | sta = ap_get_sta(hapd, addr); |
1797 | |
|
1798 | 0 | if (addr) |
1799 | 0 | hostapd_drv_sta_deauth(hapd, addr, reason); |
1800 | |
|
1801 | 0 | if (sta == NULL) |
1802 | 0 | return; |
1803 | | |
1804 | 0 | if (hapd->iface->current_mode && |
1805 | 0 | hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { |
1806 | | /* Deauthentication is not used in DMG/IEEE 802.11ad; |
1807 | | * disassociate the STA instead. */ |
1808 | 0 | ap_sta_disassociate_common(hapd, sta, reason); |
1809 | 0 | return; |
1810 | 0 | } |
1811 | | |
1812 | 0 | if (ap_sta_ml_disconnect(hapd, sta, reason, AP_STA_DISCONNECT)) |
1813 | 0 | return; |
1814 | | |
1815 | 0 | ap_sta_handle_disconnect(hapd, sta, reason); |
1816 | 0 | } |
1817 | | |
1818 | | |
1819 | | void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta) |
1820 | 0 | { |
1821 | 0 | if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) { |
1822 | 0 | wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame"); |
1823 | 0 | return; |
1824 | 0 | } |
1825 | 0 | sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB; |
1826 | 0 | eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta); |
1827 | 0 | ap_sta_deauth_cb_timeout(hapd, sta); |
1828 | 0 | } |
1829 | | |
1830 | | |
1831 | | void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta) |
1832 | 0 | { |
1833 | 0 | if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) { |
1834 | 0 | wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame"); |
1835 | 0 | return; |
1836 | 0 | } |
1837 | 0 | sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB; |
1838 | 0 | eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta); |
1839 | 0 | ap_sta_disassoc_cb_timeout(hapd, sta); |
1840 | 0 | } |
1841 | | |
1842 | | |
1843 | | void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd, |
1844 | | struct sta_info *sta) |
1845 | 2.16k | { |
1846 | 2.16k | if (eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta) > 0) |
1847 | 0 | wpa_printf(MSG_DEBUG, |
1848 | 0 | "%s: Removed ap_sta_deauth_cb_timeout timeout for " |
1849 | 0 | MACSTR, |
1850 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
1851 | 2.16k | if (eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta) > 0) |
1852 | 0 | wpa_printf(MSG_DEBUG, |
1853 | 0 | "%s: Removed ap_sta_disassoc_cb_timeout timeout for " |
1854 | 0 | MACSTR, |
1855 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
1856 | 2.16k | if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0) |
1857 | 0 | { |
1858 | 0 | wpa_printf(MSG_DEBUG, |
1859 | 0 | "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for " |
1860 | 0 | MACSTR, |
1861 | 0 | hapd->conf->iface, MAC2STR(sta->addr)); |
1862 | 0 | if (sta->flags & WLAN_STA_WPS) |
1863 | 0 | hostapd_wps_eap_completed(hapd); |
1864 | 0 | } |
1865 | 2.16k | } |
1866 | | |
1867 | | |
1868 | | void ap_sta_clear_assoc_timeout(struct hostapd_data *hapd, |
1869 | | struct sta_info *sta) |
1870 | 2.16k | { |
1871 | 2.16k | eloop_cancel_timeout(ap_sta_assoc_timeout, hapd, sta); |
1872 | 2.16k | } |
1873 | | |
1874 | | |
1875 | | int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) |
1876 | 0 | { |
1877 | 0 | int res; |
1878 | |
|
1879 | 0 | buf[0] = '\0'; |
1880 | 0 | res = os_snprintf(buf, buflen, |
1881 | 0 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
1882 | 0 | (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), |
1883 | 0 | (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), |
1884 | 0 | (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), |
1885 | 0 | (flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" : |
1886 | 0 | ""), |
1887 | 0 | (flags & WLAN_STA_SHORT_PREAMBLE ? |
1888 | 0 | "[SHORT_PREAMBLE]" : ""), |
1889 | 0 | (flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""), |
1890 | 0 | (flags & WLAN_STA_WMM ? "[WMM]" : ""), |
1891 | 0 | (flags & WLAN_STA_MFP ? "[MFP]" : ""), |
1892 | 0 | (flags & WLAN_STA_WPS ? "[WPS]" : ""), |
1893 | 0 | (flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), |
1894 | 0 | (flags & WLAN_STA_WDS ? "[WDS]" : ""), |
1895 | 0 | (flags & WLAN_STA_NONERP ? "[NonERP]" : ""), |
1896 | 0 | (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), |
1897 | 0 | (flags & WLAN_STA_GAS ? "[GAS]" : ""), |
1898 | 0 | (flags & WLAN_STA_HT ? "[HT]" : ""), |
1899 | 0 | (flags & WLAN_STA_VHT ? "[VHT]" : ""), |
1900 | 0 | (flags & WLAN_STA_HE ? "[HE]" : ""), |
1901 | 0 | (flags & WLAN_STA_EHT ? "[EHT]" : ""), |
1902 | 0 | (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""), |
1903 | 0 | (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""), |
1904 | 0 | (flags & WLAN_STA_SPP_AMSDU ? "[SPP-A-MSDU]" : ""), |
1905 | 0 | (flags & WLAN_STA_WNM_SLEEP_MODE ? |
1906 | 0 | "[WNM_SLEEP_MODE]" : "")); |
1907 | 0 | if (os_snprintf_error(buflen, res)) |
1908 | 0 | res = -1; |
1909 | |
|
1910 | 0 | return res; |
1911 | 0 | } |
1912 | | |
1913 | | |
1914 | | static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx) |
1915 | 0 | { |
1916 | 0 | struct hostapd_data *hapd = eloop_ctx; |
1917 | 0 | struct sta_info *sta = timeout_ctx; |
1918 | 0 | u16 reason; |
1919 | |
|
1920 | 0 | wpa_dbg(hapd->msg_ctx, MSG_DEBUG, |
1921 | 0 | "IEEE 802.1X: Scheduled disconnection of " MACSTR |
1922 | 0 | " after EAP-Failure", MAC2STR(sta->addr)); |
1923 | |
|
1924 | 0 | reason = sta->disconnect_reason_code; |
1925 | 0 | if (!reason) |
1926 | 0 | reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED; |
1927 | 0 | ap_sta_disconnect(hapd, sta, sta->addr, reason); |
1928 | 0 | if (sta->flags & WLAN_STA_WPS) |
1929 | 0 | hostapd_wps_eap_completed(hapd); |
1930 | 0 | } |
1931 | | |
1932 | | |
1933 | | void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, |
1934 | | struct sta_info *sta, |
1935 | | unsigned timeout) |
1936 | 0 | { |
1937 | 0 | wpa_dbg(hapd->msg_ctx, MSG_DEBUG, |
1938 | 0 | "IEEE 802.1X: Force disconnection of " MACSTR |
1939 | 0 | " after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout); |
1940 | | |
1941 | | /* |
1942 | | * Add a small sleep to increase likelihood of previously requested |
1943 | | * EAP-Failure TX getting out before this should the driver reorder |
1944 | | * operations. |
1945 | | */ |
1946 | 0 | eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta); |
1947 | 0 | eloop_register_timeout(0, timeout * 1000, |
1948 | 0 | ap_sta_delayed_1x_auth_fail_cb, hapd, sta); |
1949 | 0 | } |
1950 | | |
1951 | | |
1952 | | int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, |
1953 | | struct sta_info *sta) |
1954 | 0 | { |
1955 | 0 | return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb, |
1956 | 0 | hapd, sta); |
1957 | 0 | } |
1958 | | |
1959 | | |
1960 | | #ifdef CONFIG_IEEE80211BE |
1961 | | static void ap_sta_remove_link_sta(struct hostapd_data *hapd, |
1962 | | struct sta_info *sta) |
1963 | | { |
1964 | | struct hostapd_data *tmp_hapd; |
1965 | | |
1966 | | for_each_mld_link(tmp_hapd, hapd) { |
1967 | | struct sta_info *tmp_sta; |
1968 | | |
1969 | | if (hapd == tmp_hapd) |
1970 | | continue; |
1971 | | |
1972 | | for (tmp_sta = tmp_hapd->sta_list; tmp_sta; |
1973 | | tmp_sta = tmp_sta->next) { |
1974 | | if (tmp_sta == sta || |
1975 | | !ether_addr_equal(tmp_sta->addr, sta->addr)) |
1976 | | continue; |
1977 | | |
1978 | | ap_free_sta(tmp_hapd, tmp_sta); |
1979 | | break; |
1980 | | } |
1981 | | } |
1982 | | } |
1983 | | #endif /* CONFIG_IEEE80211BE */ |
1984 | | |
1985 | | |
1986 | | int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) |
1987 | 0 | { |
1988 | 0 | const u8 *mld_link_addr = NULL; |
1989 | 0 | bool mld_link_sta = false; |
1990 | 0 | u16 eml_cap = 0; |
1991 | | |
1992 | | /* |
1993 | | * If a station that is already associated to the AP, is trying to |
1994 | | * authenticate again, remove the STA entry, in order to make sure the |
1995 | | * STA PS state gets cleared and configuration gets updated. To handle |
1996 | | * this, station's added_unassoc flag is cleared once the station has |
1997 | | * completed association. |
1998 | | */ |
1999 | |
|
2000 | | #ifdef CONFIG_IEEE80211BE |
2001 | | if (ap_sta_is_mld(hapd, sta)) { |
2002 | | u8 mld_link_id = hapd->mld_link_id; |
2003 | | |
2004 | | mld_link_sta = sta->mld_assoc_link_id != mld_link_id; |
2005 | | mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr; |
2006 | | eml_cap = sta->mld_info.common_info.eml_capa; |
2007 | | |
2008 | | /* |
2009 | | * In case the AP is affiliated with an AP MLD, we need to |
2010 | | * remove the station from all relevant links/APs. |
2011 | | */ |
2012 | | ap_sta_remove_link_sta(hapd, sta); |
2013 | | } |
2014 | | #endif /* CONFIG_IEEE80211BE */ |
2015 | |
|
2016 | 0 | ap_sta_set_authorized(hapd, sta, 0); |
2017 | 0 | hostapd_drv_sta_remove(hapd, sta->addr); |
2018 | 0 | sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED); |
2019 | |
|
2020 | 0 | if (hostapd_sta_add(hapd, sta->addr, 0, 0, |
2021 | 0 | sta->supported_rates, |
2022 | 0 | sta->supported_rates_len, |
2023 | 0 | 0, NULL, NULL, NULL, 0, NULL, 0, NULL, |
2024 | 0 | sta->flags, 0, 0, 0, 0, |
2025 | 0 | mld_link_addr, mld_link_sta, eml_cap)) { |
2026 | 0 | hostapd_logger(hapd, sta->addr, |
2027 | 0 | HOSTAPD_MODULE_IEEE80211, |
2028 | 0 | HOSTAPD_LEVEL_NOTICE, |
2029 | 0 | "Could not add STA to kernel driver"); |
2030 | 0 | return -1; |
2031 | 0 | } |
2032 | | |
2033 | 0 | sta->added_unassoc = 1; |
2034 | 0 | return 0; |
2035 | 0 | } |
2036 | | |
2037 | | |
2038 | | #ifdef CONFIG_IEEE80211BE |
2039 | | void ap_sta_free_sta_profile(struct mld_info *info) |
2040 | | { |
2041 | | int i; |
2042 | | |
2043 | | if (!info) |
2044 | | return; |
2045 | | |
2046 | | for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { |
2047 | | os_free(info->links[i].resp_sta_profile); |
2048 | | info->links[i].resp_sta_profile = NULL; |
2049 | | } |
2050 | | } |
2051 | | #endif /* CONFIG_IEEE80211BE */ |