1 /*
2 * Control interface for shared AP commands
3 * Copyright (c) 2004-2019, 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 "common/ieee802_11_defs.h"
13 #include "common/sae.h"
14 #include "common/hw_features_common.h"
15 #include "eapol_auth/eapol_auth_sm.h"
16 #include "fst/fst_ctrl_iface.h"
17 #include "hostapd.h"
18 #include "ieee802_1x.h"
19 #include "wpa_auth.h"
20 #include "ieee802_11.h"
21 #include "sta_info.h"
22 #include "wps_hostapd.h"
23 #include "p2p_hostapd.h"
24 #include "ctrl_iface_ap.h"
25 #include "ap_drv_ops.h"
26 #include "mbo_ap.h"
27 #include "taxonomy.h"
28 #include "wnm_ap.h"
29
30
hostapd_write_ht_mcs_bitmask(char * buf,size_t buflen,size_t curr_len,const u8 * mcs_set)31 static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
32 size_t curr_len, const u8 *mcs_set)
33 {
34 int ret;
35 size_t len = curr_len;
36
37 ret = os_snprintf(buf + len, buflen - len,
38 "ht_mcs_bitmask=");
39 if (os_snprintf_error(buflen - len, ret))
40 return len;
41 len += ret;
42
43 /* 77 first bits (+ 3 reserved bits) */
44 len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
45
46 ret = os_snprintf(buf + len, buflen - len, "\n");
47 if (os_snprintf_error(buflen - len, ret))
48 return curr_len;
49 len += ret;
50
51 return len;
52 }
53
54
hostapd_get_sta_conn_time(struct sta_info * sta,struct hostap_sta_driver_data * data,char * buf,size_t buflen)55 static int hostapd_get_sta_conn_time(struct sta_info *sta,
56 struct hostap_sta_driver_data *data,
57 char *buf, size_t buflen)
58 {
59 struct os_reltime age;
60 unsigned long secs;
61 int ret;
62
63 if (sta->connected_time.sec) {
64 /* Locally maintained time in AP mode */
65 os_reltime_age(&sta->connected_time, &age);
66 secs = (unsigned long) age.sec;
67 } else if (data->flags & STA_DRV_DATA_CONN_TIME) {
68 /* Time from the driver in mesh mode */
69 secs = data->connected_sec;
70 } else {
71 return 0;
72 }
73
74 ret = os_snprintf(buf, buflen, "connected_time=%lu\n", secs);
75 if (os_snprintf_error(buflen, ret))
76 return 0;
77 return ret;
78 }
79
80
hostapd_get_sta_info(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)81 static int hostapd_get_sta_info(struct hostapd_data *hapd,
82 struct sta_info *sta,
83 char *buf, size_t buflen)
84 {
85 struct hostap_sta_driver_data data;
86 int ret;
87 int len = 0;
88
89 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
90 return 0;
91
92 ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
93 "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
94 "signal=%d\n",
95 data.rx_packets, data.tx_packets,
96 data.rx_bytes, data.tx_bytes, data.inactive_msec,
97 data.signal);
98 if (os_snprintf_error(buflen, ret))
99 return 0;
100 len += ret;
101
102 ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
103 data.current_rx_rate / 100);
104 if (os_snprintf_error(buflen - len, ret))
105 return len;
106 len += ret;
107 if (data.flags & STA_DRV_DATA_RX_MCS) {
108 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
109 data.rx_mcs);
110 if (!os_snprintf_error(buflen - len, ret))
111 len += ret;
112 }
113 if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
114 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
115 data.rx_vhtmcs);
116 if (!os_snprintf_error(buflen - len, ret))
117 len += ret;
118 }
119 if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
120 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
121 data.rx_vht_nss);
122 if (!os_snprintf_error(buflen - len, ret))
123 len += ret;
124 }
125 if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
126 ret = os_snprintf(buf + len, buflen - len, " shortGI");
127 if (!os_snprintf_error(buflen - len, ret))
128 len += ret;
129 }
130 ret = os_snprintf(buf + len, buflen - len, "\n");
131 if (!os_snprintf_error(buflen - len, ret))
132 len += ret;
133
134 ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
135 data.current_tx_rate / 100);
136 if (os_snprintf_error(buflen - len, ret))
137 return len;
138 len += ret;
139 if (data.flags & STA_DRV_DATA_TX_MCS) {
140 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
141 data.tx_mcs);
142 if (!os_snprintf_error(buflen - len, ret))
143 len += ret;
144 }
145 if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
146 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
147 data.tx_vhtmcs);
148 if (!os_snprintf_error(buflen - len, ret))
149 len += ret;
150 }
151 if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
152 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
153 data.tx_vht_nss);
154 if (!os_snprintf_error(buflen - len, ret))
155 len += ret;
156 }
157 if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
158 ret = os_snprintf(buf + len, buflen - len, " shortGI");
159 if (!os_snprintf_error(buflen - len, ret))
160 len += ret;
161 }
162 ret = os_snprintf(buf + len, buflen - len, "\n");
163 if (!os_snprintf_error(buflen - len, ret))
164 len += ret;
165
166 if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
167 ret = os_snprintf(buf + len, buflen - len,
168 "rx_vht_mcs_map=%04x\n"
169 "tx_vht_mcs_map=%04x\n",
170 le_to_host16(sta->vht_capabilities->
171 vht_supported_mcs_set.rx_map),
172 le_to_host16(sta->vht_capabilities->
173 vht_supported_mcs_set.tx_map));
174 if (!os_snprintf_error(buflen - len, ret))
175 len += ret;
176 }
177
178 if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
179 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
180 sta->ht_capabilities->
181 supported_mcs_set);
182 }
183
184 if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
185 ret = os_snprintf(buf + len, buflen - len,
186 "last_ack_signal=%d\n", data.last_ack_rssi);
187 if (!os_snprintf_error(buflen - len, ret))
188 len += ret;
189 }
190
191 len += hostapd_get_sta_conn_time(sta, &data, buf + len, buflen - len);
192
193 return len;
194 }
195
196
timeout_next_str(int val)197 static const char * timeout_next_str(int val)
198 {
199 switch (val) {
200 case STA_NULLFUNC:
201 return "NULLFUNC POLL";
202 case STA_DISASSOC:
203 return "DISASSOC";
204 case STA_DEAUTH:
205 return "DEAUTH";
206 case STA_REMOVE:
207 return "REMOVE";
208 case STA_DISASSOC_FROM_CLI:
209 return "DISASSOC_FROM_CLI";
210 default:
211 return "?";
212 }
213 }
214
215
hw_mode_str(enum hostapd_hw_mode mode)216 static const char * hw_mode_str(enum hostapd_hw_mode mode)
217 {
218 switch (mode) {
219 case HOSTAPD_MODE_IEEE80211B:
220 return "b";
221 case HOSTAPD_MODE_IEEE80211G:
222 return "g";
223 case HOSTAPD_MODE_IEEE80211A:
224 return "a";
225 case HOSTAPD_MODE_IEEE80211AD:
226 return "ad";
227 case HOSTAPD_MODE_IEEE80211ANY:
228 return "any";
229 case NUM_HOSTAPD_MODES:
230 return "invalid";
231 }
232 return "unknown";
233 }
234
235
hostapd_ctrl_iface_sta_mib(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)236 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
237 struct sta_info *sta,
238 char *buf, size_t buflen)
239 {
240 int len, res, ret, i;
241 const char *keyid;
242 const u8 *dpp_pkhash;
243
244 if (!sta)
245 return 0;
246
247 len = 0;
248 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
249 MAC2STR(sta->addr));
250 if (os_snprintf_error(buflen - len, ret))
251 return len;
252 len += ret;
253
254 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
255 if (ret < 0)
256 return len;
257 len += ret;
258
259 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
260 "listen_interval=%d\nsupported_rates=",
261 sta->aid, sta->capability, sta->listen_interval);
262 if (os_snprintf_error(buflen - len, ret))
263 return len;
264 len += ret;
265
266 for (i = 0; i < sta->supported_rates_len; i++) {
267 ret = os_snprintf(buf + len, buflen - len, "%02x%s",
268 sta->supported_rates[i],
269 i + 1 < sta->supported_rates_len ? " " : "");
270 if (os_snprintf_error(buflen - len, ret))
271 return len;
272 len += ret;
273 }
274
275 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
276 timeout_next_str(sta->timeout_next));
277 if (os_snprintf_error(buflen - len, ret))
278 return len;
279 len += ret;
280
281 if (sta->max_idle_period) {
282 ret = os_snprintf(buf + len, buflen - len,
283 "max_idle_period=%d\n", sta->max_idle_period);
284 if (os_snprintf_error(buflen - len, ret))
285 return len;
286 len += ret;
287 }
288
289 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
290 if (res >= 0)
291 len += res;
292 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
293 if (res >= 0)
294 len += res;
295 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
296 if (res >= 0)
297 len += res;
298 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
299 buflen - len);
300 if (res >= 0)
301 len += res;
302 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
303 if (res >= 0)
304 len += res;
305
306 len += hostapd_get_sta_info(hapd, sta, buf + len, buflen - len);
307
308 #ifdef CONFIG_SAE
309 if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
310 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
311 sta->sae->group);
312 if (!os_snprintf_error(buflen - len, res))
313 len += res;
314 }
315
316 if (sta->sae && sta->sae->tmp) {
317 const u8 *pos;
318 unsigned int j, count;
319 struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
320
321 res = os_snprintf(buf + len, buflen - len,
322 "sae_rejected_groups=");
323 if (!os_snprintf_error(buflen - len, res))
324 len += res;
325
326 if (groups) {
327 pos = wpabuf_head(groups);
328 count = wpabuf_len(groups) / 2;
329 } else {
330 pos = NULL;
331 count = 0;
332 }
333 for (j = 0; pos && j < count; j++) {
334 res = os_snprintf(buf + len, buflen - len, "%s%d",
335 j == 0 ? "" : " ", WPA_GET_LE16(pos));
336 if (!os_snprintf_error(buflen - len, res))
337 len += res;
338 pos += 2;
339 }
340
341 res = os_snprintf(buf + len, buflen - len, "\n");
342 if (!os_snprintf_error(buflen - len, res))
343 len += res;
344 }
345 #endif /* CONFIG_SAE */
346
347 if (sta->vlan_id > 0) {
348 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
349 sta->vlan_id);
350 if (!os_snprintf_error(buflen - len, res))
351 len += res;
352 }
353
354 res = mbo_ap_get_info(sta, buf + len, buflen - len);
355 if (res >= 0)
356 len += res;
357
358 if (sta->supp_op_classes &&
359 buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
360 res = os_snprintf(buf + len, buflen - len, "supp_op_classes=");
361 if (!os_snprintf_error(buflen - len, res))
362 len += res;
363 len += wpa_snprintf_hex(buf + len, buflen - len,
364 sta->supp_op_classes + 1,
365 sta->supp_op_classes[0]);
366 res = os_snprintf(buf + len, buflen - len, "\n");
367 if (!os_snprintf_error(buflen - len, res))
368 len += res;
369 }
370
371 if (sta->power_capab) {
372 ret = os_snprintf(buf + len, buflen - len,
373 "min_txpower=%d\n"
374 "max_txpower=%d\n",
375 sta->min_tx_power, sta->max_tx_power);
376 if (!os_snprintf_error(buflen - len, ret))
377 len += ret;
378 }
379
380 #ifdef CONFIG_IEEE80211AX
381 if ((sta->flags & WLAN_STA_HE) && sta->he_capab) {
382 res = os_snprintf(buf + len, buflen - len, "he_capab=");
383 if (!os_snprintf_error(buflen - len, res))
384 len += res;
385 len += wpa_snprintf_hex(buf + len, buflen - len,
386 (const u8 *) sta->he_capab,
387 sta->he_capab_len);
388 res = os_snprintf(buf + len, buflen - len, "\n");
389 if (!os_snprintf_error(buflen - len, res))
390 len += res;
391 }
392 #endif /* CONFIG_IEEE80211AX */
393
394 #ifdef CONFIG_IEEE80211BE
395 if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) {
396 res = os_snprintf(buf + len, buflen - len, "eht_capab=");
397 if (!os_snprintf_error(buflen - len, res))
398 len += res;
399 len += wpa_snprintf_hex(buf + len, buflen - len,
400 (const u8 *) sta->eht_capab,
401 sta->eht_capab_len);
402 res = os_snprintf(buf + len, buflen - len, "\n");
403 if (!os_snprintf_error(buflen - len, res))
404 len += res;
405 }
406 #endif /* CONFIG_IEEE80211BE */
407
408 #ifdef CONFIG_IEEE80211AC
409 if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
410 res = os_snprintf(buf + len, buflen - len,
411 "vht_caps_info=0x%08x\n",
412 le_to_host32(sta->vht_capabilities->
413 vht_capabilities_info));
414 if (!os_snprintf_error(buflen - len, res))
415 len += res;
416
417 res = os_snprintf(buf + len, buflen - len, "vht_capab=");
418 if (!os_snprintf_error(buflen - len, res))
419 len += res;
420 len += wpa_snprintf_hex(buf + len, buflen - len,
421 (const u8 *) sta->vht_capabilities,
422 sizeof(*sta->vht_capabilities));
423 res = os_snprintf(buf + len, buflen - len, "\n");
424 if (!os_snprintf_error(buflen - len, res))
425 len += res;
426 }
427 #endif /* CONFIG_IEEE80211AC */
428
429 if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
430 res = os_snprintf(buf + len, buflen - len,
431 "ht_caps_info=0x%04x\n",
432 le_to_host16(sta->ht_capabilities->
433 ht_capabilities_info));
434 if (!os_snprintf_error(buflen - len, res))
435 len += res;
436 }
437
438 if (sta->ext_capability &&
439 buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
440 res = os_snprintf(buf + len, buflen - len, "ext_capab=");
441 if (!os_snprintf_error(buflen - len, res))
442 len += res;
443 len += wpa_snprintf_hex(buf + len, buflen - len,
444 sta->ext_capability + 1,
445 sta->ext_capability[0]);
446 res = os_snprintf(buf + len, buflen - len, "\n");
447 if (!os_snprintf_error(buflen - len, res))
448 len += res;
449 }
450
451 if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
452 ret = os_snprintf(buf + len, buflen - len,
453 "wds_sta_ifname=%s\n", sta->ifname_wds);
454 if (!os_snprintf_error(buflen - len, ret))
455 len += ret;
456 }
457
458 keyid = ap_sta_wpa_get_keyid(hapd, sta);
459 if (keyid) {
460 ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
461 if (!os_snprintf_error(buflen - len, ret))
462 len += ret;
463 }
464
465 dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
466 if (dpp_pkhash) {
467 ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=");
468 if (!os_snprintf_error(buflen - len, ret))
469 len += ret;
470 len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash,
471 SHA256_MAC_LEN);
472 ret = os_snprintf(buf + len, buflen - len, "\n");
473 if (!os_snprintf_error(buflen - len, ret))
474 len += ret;
475 }
476
477 #ifdef CONFIG_IEEE80211BE
478 if (sta->mld_info.mld_sta) {
479 u16 mld_sta_capa = sta->mld_info.common_info.mld_capa;
480 u8 max_simul_links = mld_sta_capa &
481 EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
482
483 for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) {
484 if (!sta->mld_info.links[i].valid)
485 continue;
486 ret = os_snprintf(
487 buf + len, buflen - len,
488 "peer_addr[%d]=" MACSTR "\n",
489 i, MAC2STR(sta->mld_info.links[i].peer_addr));
490 if (!os_snprintf_error(buflen - len, ret))
491 len += ret;
492 }
493
494 ret = os_snprintf(buf + len, buflen - len,
495 "max_simul_links=%d\n", max_simul_links);
496 if (!os_snprintf_error(buflen - len, ret))
497 len += ret;
498 }
499 #endif /* CONFIG_IEEE80211BE */
500
501 return len;
502 }
503
504
hostapd_ctrl_iface_sta_first(struct hostapd_data * hapd,char * buf,size_t buflen)505 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
506 char *buf, size_t buflen)
507 {
508 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
509 }
510
511
hostapd_ctrl_iface_sta(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)512 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
513 char *buf, size_t buflen)
514 {
515 u8 addr[ETH_ALEN];
516 int ret;
517 const char *pos;
518 struct sta_info *sta;
519
520 if (hwaddr_aton(txtaddr, addr)) {
521 ret = os_snprintf(buf, buflen, "FAIL\n");
522 if (os_snprintf_error(buflen, ret))
523 return 0;
524 return ret;
525 }
526
527 sta = ap_get_sta(hapd, addr);
528 if (sta == NULL)
529 return -1;
530
531 pos = os_strchr(txtaddr, ' ');
532 if (pos) {
533 pos++;
534
535 #ifdef HOSTAPD_DUMP_STATE
536 if (os_strcmp(pos, "eapol") == 0) {
537 if (sta->eapol_sm == NULL)
538 return -1;
539 return eapol_auth_dump_state(sta->eapol_sm, buf,
540 buflen);
541 }
542 #endif /* HOSTAPD_DUMP_STATE */
543
544 return -1;
545 }
546
547 ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
548 ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
549
550 return ret;
551 }
552
553
hostapd_ctrl_iface_sta_next(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)554 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
555 char *buf, size_t buflen)
556 {
557 u8 addr[ETH_ALEN];
558 struct sta_info *sta;
559 int ret;
560
561 if (hwaddr_aton(txtaddr, addr) ||
562 (sta = ap_get_sta(hapd, addr)) == NULL) {
563 ret = os_snprintf(buf, buflen, "FAIL\n");
564 if (os_snprintf_error(buflen, ret))
565 return 0;
566 return ret;
567 }
568
569 if (!sta->next)
570 return 0;
571
572 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
573 }
574
575
576 #ifdef CONFIG_P2P_MANAGER
p2p_manager_disconnect(struct hostapd_data * hapd,u16 stype,u8 minor_reason_code,const u8 * addr)577 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
578 u8 minor_reason_code, const u8 *addr)
579 {
580 struct ieee80211_mgmt *mgmt;
581 int ret;
582 u8 *pos;
583
584 mgmt = os_zalloc(sizeof(*mgmt) + 100);
585 if (mgmt == NULL)
586 return -1;
587
588 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
589 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
590 " with minor reason code %u (stype=%u (%s))",
591 MAC2STR(addr), minor_reason_code, stype,
592 fc2str(le_to_host16(mgmt->frame_control)));
593
594 os_memcpy(mgmt->da, addr, ETH_ALEN);
595 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
596 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
597 if (stype == WLAN_FC_STYPE_DEAUTH) {
598 mgmt->u.deauth.reason_code =
599 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
600 pos = mgmt->u.deauth.variable;
601 } else {
602 mgmt->u.disassoc.reason_code =
603 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
604 pos = mgmt->u.disassoc.variable;
605 }
606
607 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
608 *pos++ = 4 + 3 + 1;
609 WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
610 pos += 4;
611
612 *pos++ = P2P_ATTR_MINOR_REASON_CODE;
613 WPA_PUT_LE16(pos, 1);
614 pos += 2;
615 *pos++ = minor_reason_code;
616
617 ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
618 0);
619 os_free(mgmt);
620
621 return ret < 0 ? -1 : 0;
622 }
623 #endif /* CONFIG_P2P_MANAGER */
624
625
hostapd_ctrl_iface_deauthenticate(struct hostapd_data * hapd,const char * txtaddr)626 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
627 const char *txtaddr)
628 {
629 u8 addr[ETH_ALEN];
630 struct sta_info *sta;
631 const char *pos;
632 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
633
634 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
635 txtaddr);
636
637 if (hwaddr_aton(txtaddr, addr))
638 return -1;
639
640 pos = os_strstr(txtaddr, " reason=");
641 if (pos)
642 reason = atoi(pos + 8);
643
644 pos = os_strstr(txtaddr, " test=");
645 if (pos) {
646 struct ieee80211_mgmt mgmt;
647 int encrypt;
648
649 pos += 6;
650 encrypt = atoi(pos);
651 os_memset(&mgmt, 0, sizeof(mgmt));
652 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
653 WLAN_FC_STYPE_DEAUTH);
654 os_memcpy(mgmt.da, addr, ETH_ALEN);
655 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
656 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
657 mgmt.u.deauth.reason_code = host_to_le16(reason);
658 if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
659 IEEE80211_HDRLEN +
660 sizeof(mgmt.u.deauth),
661 0, NULL, 0, !encrypt) < 0)
662 return -1;
663 return 0;
664 }
665
666 #ifdef CONFIG_P2P_MANAGER
667 pos = os_strstr(txtaddr, " p2p=");
668 if (pos) {
669 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
670 atoi(pos + 5), addr);
671 }
672 #endif /* CONFIG_P2P_MANAGER */
673
674 sta = ap_get_sta(hapd, addr);
675 if (os_strstr(txtaddr, " tx=0")) {
676 hostapd_drv_sta_remove(hapd, addr);
677 if (sta)
678 ap_free_sta(hapd, sta);
679 } else {
680 hostapd_drv_sta_deauth(hapd, addr, reason);
681 if (sta)
682 ap_sta_deauthenticate(hapd, sta, reason);
683 else if (addr[0] == 0xff)
684 hostapd_free_stas(hapd);
685 }
686
687 return 0;
688 }
689
690
hostapd_ctrl_iface_disassociate(struct hostapd_data * hapd,const char * txtaddr)691 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
692 const char *txtaddr)
693 {
694 u8 addr[ETH_ALEN];
695 struct sta_info *sta;
696 const char *pos;
697 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
698
699 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
700 txtaddr);
701
702 if (hwaddr_aton(txtaddr, addr))
703 return -1;
704
705 pos = os_strstr(txtaddr, " reason=");
706 if (pos)
707 reason = atoi(pos + 8);
708
709 pos = os_strstr(txtaddr, " test=");
710 if (pos) {
711 struct ieee80211_mgmt mgmt;
712 int encrypt;
713
714 pos += 6;
715 encrypt = atoi(pos);
716 os_memset(&mgmt, 0, sizeof(mgmt));
717 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
718 WLAN_FC_STYPE_DISASSOC);
719 os_memcpy(mgmt.da, addr, ETH_ALEN);
720 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
721 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
722 mgmt.u.disassoc.reason_code = host_to_le16(reason);
723 if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
724 IEEE80211_HDRLEN +
725 sizeof(mgmt.u.deauth),
726 0, NULL, 0, !encrypt) < 0)
727 return -1;
728 return 0;
729 }
730
731 #ifdef CONFIG_P2P_MANAGER
732 pos = os_strstr(txtaddr, " p2p=");
733 if (pos) {
734 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
735 atoi(pos + 5), addr);
736 }
737 #endif /* CONFIG_P2P_MANAGER */
738
739 sta = ap_get_sta(hapd, addr);
740 if (os_strstr(txtaddr, " tx=0")) {
741 hostapd_drv_sta_remove(hapd, addr);
742 if (sta)
743 ap_free_sta(hapd, sta);
744 } else {
745 hostapd_drv_sta_disassoc(hapd, addr, reason);
746 if (sta)
747 ap_sta_disassociate(hapd, sta, reason);
748 else if (addr[0] == 0xff)
749 hostapd_free_stas(hapd);
750 }
751
752 return 0;
753 }
754
755
756 #ifdef CONFIG_TAXONOMY
hostapd_ctrl_iface_signature(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)757 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
758 const char *txtaddr,
759 char *buf, size_t buflen)
760 {
761 u8 addr[ETH_ALEN];
762 struct sta_info *sta;
763
764 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
765
766 if (hwaddr_aton(txtaddr, addr))
767 return -1;
768
769 sta = ap_get_sta(hapd, addr);
770 if (!sta)
771 return -1;
772
773 return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
774 }
775 #endif /* CONFIG_TAXONOMY */
776
777
hostapd_ctrl_iface_poll_sta(struct hostapd_data * hapd,const char * txtaddr)778 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
779 const char *txtaddr)
780 {
781 u8 addr[ETH_ALEN];
782 struct sta_info *sta;
783
784 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
785
786 if (hwaddr_aton(txtaddr, addr))
787 return -1;
788
789 sta = ap_get_sta(hapd, addr);
790 if (!sta)
791 return -1;
792
793 hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
794 sta->flags & WLAN_STA_WMM);
795 return 0;
796 }
797
798
hostapd_ctrl_iface_status(struct hostapd_data * hapd,char * buf,size_t buflen)799 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
800 size_t buflen)
801 {
802 struct hostapd_iface *iface = hapd->iface;
803 struct hostapd_hw_modes *mode = iface->current_mode;
804 struct hostapd_config *iconf = hapd->iconf;
805 int len = 0, ret, j;
806 size_t i;
807
808 ret = os_snprintf(buf + len, buflen - len,
809 "state=%s\n"
810 "phy=%s\n"
811 "freq=%d\n"
812 "num_sta_non_erp=%d\n"
813 "num_sta_no_short_slot_time=%d\n"
814 "num_sta_no_short_preamble=%d\n"
815 "olbc=%d\n"
816 "num_sta_ht_no_gf=%d\n"
817 "num_sta_no_ht=%d\n"
818 "num_sta_ht_20_mhz=%d\n"
819 "num_sta_ht40_intolerant=%d\n"
820 "olbc_ht=%d\n"
821 "ht_op_mode=0x%x\n",
822 hostapd_state_text(iface->state),
823 iface->phy,
824 iface->freq,
825 iface->num_sta_non_erp,
826 iface->num_sta_no_short_slot_time,
827 iface->num_sta_no_short_preamble,
828 iface->olbc,
829 iface->num_sta_ht_no_gf,
830 iface->num_sta_no_ht,
831 iface->num_sta_ht_20mhz,
832 iface->num_sta_ht40_intolerant,
833 iface->olbc_ht,
834 iface->ht_op_mode);
835 if (os_snprintf_error(buflen - len, ret))
836 return len;
837 len += ret;
838
839 if (mode) {
840 ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n",
841 hw_mode_str(mode->mode));
842 if (os_snprintf_error(buflen - len, ret))
843 return len;
844 len += ret;
845 }
846
847 if (iconf->country[0] && iconf->country[1]) {
848 ret = os_snprintf(buf + len, buflen - len,
849 "country_code=%c%c\ncountry3=0x%X\n",
850 iconf->country[0], iconf->country[1],
851 iconf->country[2]);
852 if (os_snprintf_error(buflen - len, ret))
853 return len;
854 len += ret;
855 }
856
857 if (!iface->cac_started || !iface->dfs_cac_ms) {
858 ret = os_snprintf(buf + len, buflen - len,
859 "cac_time_seconds=%d\n"
860 "cac_time_left_seconds=N/A\n",
861 iface->dfs_cac_ms / 1000);
862 } else {
863 /* CAC started and CAC time set - calculate remaining time */
864 struct os_reltime now;
865 long left_time;
866
867 os_reltime_age(&iface->dfs_cac_start, &now);
868 left_time = (long) iface->dfs_cac_ms / 1000 - now.sec;
869 ret = os_snprintf(buf + len, buflen - len,
870 "cac_time_seconds=%u\n"
871 "cac_time_left_seconds=%lu\n",
872 iface->dfs_cac_ms / 1000,
873 left_time > 0 ? left_time : 0);
874 }
875 if (os_snprintf_error(buflen - len, ret))
876 return len;
877 len += ret;
878
879 ret = os_snprintf(buf + len, buflen - len,
880 "channel=%u\n"
881 "edmg_enable=%d\n"
882 "edmg_channel=%d\n"
883 "secondary_channel=%d\n"
884 "ieee80211n=%d\n"
885 "ieee80211ac=%d\n"
886 "ieee80211ax=%d\n"
887 "ieee80211be=%d\n"
888 "beacon_int=%u\n"
889 "dtim_period=%d\n",
890 iface->conf->channel,
891 iface->conf->enable_edmg,
892 iface->conf->edmg_channel,
893 hostapd_is_ht_enabled(hapd) ?
894 iface->conf->secondary_channel : 0,
895 hostapd_is_ht_enabled(hapd),
896 hostapd_is_vht_enabled(hapd),
897 hostapd_is_he_enabled(hapd),
898 hostapd_is_eht_enabled(hapd),
899 iface->conf->beacon_int,
900 hapd->conf->dtim_period);
901 if (os_snprintf_error(buflen - len, ret))
902 return len;
903 len += ret;
904
905 #ifdef CONFIG_IEEE80211BE
906 if (hostapd_is_eht_enabled(hapd)) {
907 ret = os_snprintf(buf + len, buflen - len,
908 "eht_oper_chwidth=%d\n"
909 "eht_oper_centr_freq_seg0_idx=%d\n",
910 iface->conf->eht_oper_chwidth,
911 iface->conf->eht_oper_centr_freq_seg0_idx);
912 if (os_snprintf_error(buflen - len, ret))
913 return len;
914 len += ret;
915
916 if (is_6ghz_op_class(iface->conf->op_class) &&
917 hostapd_get_oper_chwidth(iface->conf) ==
918 CONF_OPER_CHWIDTH_320MHZ) {
919 ret = os_snprintf(buf + len, buflen - len,
920 "eht_bw320_offset=%d\n",
921 iface->conf->eht_bw320_offset);
922 if (os_snprintf_error(buflen - len, ret))
923 return len;
924 len += ret;
925 }
926
927 if (hapd->iconf->punct_bitmap) {
928 ret = os_snprintf(buf + len, buflen - len,
929 "punct_bitmap=0x%x\n",
930 hapd->iconf->punct_bitmap);
931 if (os_snprintf_error(buflen - len, ret))
932 return len;
933 len += ret;
934 }
935
936 if (hapd->conf->mld_ap) {
937 struct hostapd_data *link_bss;
938
939 ret = os_snprintf(buf + len, buflen - len,
940 "num_links=%d\n",
941 hapd->mld->num_links);
942 if (os_snprintf_error(buflen - len, ret))
943 return len;
944 len += ret;
945
946 /* Self BSS */
947 ret = os_snprintf(buf + len, buflen - len,
948 "link_id=%d\n"
949 "link_addr=" MACSTR "\n",
950 hapd->mld_link_id,
951 MAC2STR(hapd->own_addr));
952 if (os_snprintf_error(buflen - len, ret))
953 return len;
954 len += ret;
955
956 /* Partner BSSs */
957 for_each_mld_link(link_bss, hapd) {
958 if (link_bss == hapd)
959 continue;
960
961 ret = os_snprintf(buf + len, buflen - len,
962 "partner_link[%d]=" MACSTR
963 "\n",
964 link_bss->mld_link_id,
965 MAC2STR(link_bss->own_addr));
966 if (os_snprintf_error(buflen - len, ret))
967 return len;
968 len += ret;
969 }
970
971 ret = os_snprintf(buf + len, buflen - len,
972 "ap_mld_type=%s\n",
973 (hapd->iface->mld_mld_capa &
974 EHT_ML_MLD_CAPA_AP_MLD_TYPE_IND_MASK)
975 ? "NSTR" : "STR");
976 if (os_snprintf_error(buflen - len, ret))
977 return len;
978 len += ret;
979 }
980 }
981 #endif /* CONFIG_IEEE80211BE */
982
983 #ifdef CONFIG_IEEE80211AX
984 if (hostapd_is_he_enabled(hapd)) {
985 ret = os_snprintf(buf + len, buflen - len,
986 "he_oper_chwidth=%d\n"
987 "he_oper_centr_freq_seg0_idx=%d\n"
988 "he_oper_centr_freq_seg1_idx=%d\n",
989 iface->conf->he_oper_chwidth,
990 iface->conf->he_oper_centr_freq_seg0_idx,
991 iface->conf->he_oper_centr_freq_seg1_idx);
992 if (os_snprintf_error(buflen - len, ret))
993 return len;
994 len += ret;
995
996 if (!iconf->he_op.he_bss_color_disabled &&
997 iconf->he_op.he_bss_color) {
998 ret = os_snprintf(buf + len, buflen - len,
999 "he_bss_color=%d\n",
1000 iconf->he_op.he_bss_color);
1001 if (os_snprintf_error(buflen - len, ret))
1002 return len;
1003 len += ret;
1004 }
1005 }
1006 #endif /* CONFIG_IEEE80211AX */
1007
1008 if (hostapd_is_vht_enabled(hapd)) {
1009 ret = os_snprintf(buf + len, buflen - len,
1010 "vht_oper_chwidth=%d\n"
1011 "vht_oper_centr_freq_seg0_idx=%d\n"
1012 "vht_oper_centr_freq_seg1_idx=%d\n"
1013 "vht_caps_info=%08x\n",
1014 iface->conf->vht_oper_chwidth,
1015 iface->conf->vht_oper_centr_freq_seg0_idx,
1016 iface->conf->vht_oper_centr_freq_seg1_idx,
1017 iface->conf->vht_capab);
1018 if (os_snprintf_error(buflen - len, ret))
1019 return len;
1020 len += ret;
1021 }
1022
1023 if (hostapd_is_vht_enabled(hapd) && mode) {
1024 u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
1025 u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
1026
1027 ret = os_snprintf(buf + len, buflen - len,
1028 "rx_vht_mcs_map=%04x\n"
1029 "tx_vht_mcs_map=%04x\n",
1030 rxmap, txmap);
1031 if (os_snprintf_error(buflen - len, ret))
1032 return len;
1033 len += ret;
1034 }
1035
1036 if (hostapd_is_ht_enabled(hapd)) {
1037 ret = os_snprintf(buf + len, buflen - len,
1038 "ht_caps_info=%04x\n",
1039 hapd->iconf->ht_capab);
1040 if (os_snprintf_error(buflen - len, ret))
1041 return len;
1042 len += ret;
1043 }
1044
1045 if (hostapd_is_ht_enabled(hapd) && mode) {
1046 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
1047 mode->mcs_set);
1048 }
1049
1050 if (hapd->current_rates && hapd->num_rates) {
1051 ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
1052 if (os_snprintf_error(buflen - len, ret))
1053 return len;
1054 len += ret;
1055
1056 for (j = 0; j < hapd->num_rates; j++) {
1057 ret = os_snprintf(buf + len, buflen - len, "%s%02x",
1058 j > 0 ? " " : "",
1059 hapd->current_rates[j].rate / 5);
1060 if (os_snprintf_error(buflen - len, ret))
1061 return len;
1062 len += ret;
1063 }
1064 ret = os_snprintf(buf + len, buflen - len, "\n");
1065 if (os_snprintf_error(buflen - len, ret))
1066 return len;
1067 len += ret;
1068 }
1069
1070 for (j = 0; mode && j < mode->num_channels; j++) {
1071 if (mode->channels[j].freq == iface->freq) {
1072 ret = os_snprintf(buf + len, buflen - len,
1073 "max_txpower=%u\n",
1074 mode->channels[j].max_tx_power);
1075 if (os_snprintf_error(buflen - len, ret))
1076 return len;
1077 len += ret;
1078 break;
1079 }
1080 }
1081
1082 for (i = 0; i < iface->num_bss; i++) {
1083 struct hostapd_data *bss = iface->bss[i];
1084 ret = os_snprintf(buf + len, buflen - len,
1085 "bss[%d]=%s\n"
1086 "bssid[%d]=" MACSTR "\n"
1087 "ssid[%d]=%s\n"
1088 "num_sta[%d]=%d\n",
1089 (int) i, bss->conf->iface,
1090 (int) i, MAC2STR(bss->own_addr),
1091 (int) i,
1092 wpa_ssid_txt(bss->conf->ssid.ssid,
1093 bss->conf->ssid.ssid_len),
1094 (int) i, bss->num_sta);
1095 if (os_snprintf_error(buflen - len, ret))
1096 return len;
1097 len += ret;
1098
1099 #ifdef CONFIG_IEEE80211BE
1100 if (bss->conf->mld_ap) {
1101 ret = os_snprintf(buf + len, buflen - len,
1102 "mld_addr[%d]=" MACSTR "\n"
1103 "mld_id[%d]=%d\n"
1104 "mld_link_id[%d]=%d\n",
1105 (int) i, MAC2STR(bss->mld->mld_addr),
1106 (int) i, hostapd_get_mld_id(bss),
1107 (int) i, bss->mld_link_id);
1108 if (os_snprintf_error(buflen - len, ret))
1109 return len;
1110 len += ret;
1111 }
1112 #endif /* CONFIG_IEEE80211BE */
1113 }
1114
1115 if (hapd->conf->chan_util_avg_period) {
1116 ret = os_snprintf(buf + len, buflen - len,
1117 "chan_util_avg=%u\n",
1118 iface->chan_util_average);
1119 if (os_snprintf_error(buflen - len, ret))
1120 return len;
1121 len += ret;
1122 }
1123
1124 return len;
1125 }
1126
1127
hostapd_parse_freq_params(const char * pos,struct hostapd_freq_params * params,unsigned int freq)1128 int hostapd_parse_freq_params(const char *pos,
1129 struct hostapd_freq_params *params,
1130 unsigned int freq)
1131 {
1132 os_memset(params, 0, sizeof(*params));
1133
1134 if (freq)
1135 params->freq = freq;
1136 else
1137 params->freq = atoi(pos);
1138
1139 if (params->freq == 0) {
1140 wpa_printf(MSG_ERROR, "freq_params: invalid freq provided");
1141 return -1;
1142 }
1143
1144 #define SET_FREQ_PARAM(str) \
1145 do { \
1146 const char *pos2 = os_strstr(pos, " " #str "="); \
1147 if (pos2) { \
1148 pos2 += sizeof(" " #str "=") - 1; \
1149 params->str = atoi(pos2); \
1150 } \
1151 } while (0)
1152
1153 SET_FREQ_PARAM(center_freq1);
1154 SET_FREQ_PARAM(center_freq2);
1155 SET_FREQ_PARAM(bandwidth);
1156 SET_FREQ_PARAM(sec_channel_offset);
1157 SET_FREQ_PARAM(punct_bitmap);
1158 params->ht_enabled = !!os_strstr(pos, " ht");
1159 params->vht_enabled = !!os_strstr(pos, " vht");
1160 params->eht_enabled = !!os_strstr(pos, " eht");
1161 params->he_enabled = !!os_strstr(pos, " he") ||
1162 params->eht_enabled;
1163 #undef SET_FREQ_PARAM
1164
1165 return 0;
1166 }
1167
1168
get_target_hw_mode(struct hostapd_iface * iface,int freq)1169 static struct hostapd_hw_modes * get_target_hw_mode(struct hostapd_iface *iface,
1170 int freq)
1171 {
1172 int i;
1173 enum hostapd_hw_mode target_mode;
1174 bool is_6ghz = is_6ghz_freq(freq);
1175
1176 if (freq < 4000)
1177 target_mode = HOSTAPD_MODE_IEEE80211G;
1178 else if (freq > 50000)
1179 target_mode = HOSTAPD_MODE_IEEE80211AD;
1180 else
1181 target_mode = HOSTAPD_MODE_IEEE80211A;
1182
1183 for (i = 0; i < iface->num_hw_features; i++) {
1184 struct hostapd_hw_modes *mode;
1185
1186 mode = &iface->hw_features[i];
1187 if (mode->mode == target_mode && mode->is_6ghz == is_6ghz)
1188 return mode;
1189 }
1190
1191 return NULL;
1192 }
1193
1194
1195 static bool
hostapd_ctrl_is_freq_in_mode(struct hostapd_hw_modes * mode,struct hostapd_multi_hw_info * current_hw_info,int freq)1196 hostapd_ctrl_is_freq_in_mode(struct hostapd_hw_modes *mode,
1197 struct hostapd_multi_hw_info *current_hw_info,
1198 int freq)
1199 {
1200 struct hostapd_channel_data *chan;
1201 int i;
1202
1203 for (i = 0; i < mode->num_channels; i++) {
1204 chan = &mode->channels[i];
1205
1206 if (chan->flag & HOSTAPD_CHAN_DISABLED)
1207 continue;
1208
1209 if (!chan_in_current_hw_info(current_hw_info, chan))
1210 continue;
1211
1212 if (chan->freq == freq)
1213 return true;
1214 }
1215 return false;
1216 }
1217
1218
hostapd_ctrl_check_freq_params(struct hostapd_freq_params * params,u16 punct_bitmap)1219 static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
1220 u16 punct_bitmap)
1221 {
1222 u32 start_freq;
1223 bool is_6g = is_6ghz_freq(params->freq);
1224
1225 if (is_6g) {
1226 const int bw_idx[] = { 20, 40, 80, 160, 320 };
1227 int idx, bw;
1228
1229 /* The 6 GHz band requires HE to be enabled. */
1230 params->he_enabled = 1;
1231
1232 if (params->center_freq1) {
1233 if (params->freq == 5935)
1234 idx = (params->center_freq1 - 5925) / 5;
1235 else
1236 idx = (params->center_freq1 - 5950) / 5;
1237
1238 bw = center_idx_to_bw_6ghz(idx);
1239 if (bw < 0 || bw >= (int) ARRAY_SIZE(bw_idx) ||
1240 bw_idx[bw] != params->bandwidth)
1241 return -1;
1242 }
1243 } else { /* Non-6 GHz channel */
1244 /* An EHT STA is also an HE STA as defined in
1245 * IEEE Std 802.11be-2024, 4.3.16a (Extremely high throughput
1246 * (EHT) STA). */
1247 if (params->he_enabled || params->eht_enabled) {
1248 params->he_enabled = 1;
1249 /* An HE STA is also a VHT STA if operating in the 5 GHz
1250 * band and an HE STA is also an HT STA in the 2.4 GHz
1251 * band as defined in IEEE Std 802.11ax-2021, 4.3.15a.
1252 * A VHT STA is an HT STA as defined in IEEE
1253 * Std 802.11, 4.3.15. */
1254 if (IS_5GHZ(params->freq))
1255 params->vht_enabled = 1;
1256
1257 params->ht_enabled = 1;
1258 }
1259 }
1260
1261 switch (params->bandwidth) {
1262 case 0:
1263 /* bandwidth not specified: use 20 MHz by default */
1264 /* fall-through */
1265 case 20:
1266 if (params->center_freq1 &&
1267 params->center_freq1 != params->freq)
1268 return -1;
1269
1270 if (params->center_freq2 || params->sec_channel_offset)
1271 return -1;
1272
1273 if (punct_bitmap)
1274 return -1;
1275 break;
1276 case 40:
1277 if (params->center_freq2 ||
1278 (!is_6g && !params->sec_channel_offset))
1279 return -1;
1280
1281 if (punct_bitmap)
1282 return -1;
1283
1284 if (!params->center_freq1)
1285 break;
1286 switch (params->sec_channel_offset) {
1287 case 1:
1288 if (params->freq + 10 != params->center_freq1)
1289 return -1;
1290 break;
1291 case -1:
1292 if (params->freq - 10 != params->center_freq1)
1293 return -1;
1294 break;
1295 case 0:
1296 if (!is_6g)
1297 return -1;
1298 break;
1299 default:
1300 return -1;
1301 }
1302 break;
1303 case 80:
1304 if (!params->center_freq1 ||
1305 (!is_6g && !params->sec_channel_offset))
1306 return 1;
1307
1308 switch (params->sec_channel_offset) {
1309 case 1:
1310 if (params->freq - 10 != params->center_freq1 &&
1311 params->freq + 30 != params->center_freq1)
1312 return 1;
1313 break;
1314 case -1:
1315 if (params->freq + 10 != params->center_freq1 &&
1316 params->freq - 30 != params->center_freq1)
1317 return -1;
1318 break;
1319 case 0:
1320 if (!is_6g)
1321 return -1;
1322 break;
1323 default:
1324 return -1;
1325 }
1326
1327 if (params->center_freq2 && punct_bitmap)
1328 return -1;
1329
1330 /* Adjacent and overlapped are not allowed for 80+80 */
1331 if (params->center_freq2 &&
1332 params->center_freq1 - params->center_freq2 <= 80 &&
1333 params->center_freq2 - params->center_freq1 <= 80)
1334 return 1;
1335 break;
1336 case 160:
1337 if (!params->center_freq1 || params->center_freq2 ||
1338 (!is_6g && !params->sec_channel_offset))
1339 return -1;
1340
1341 switch (params->sec_channel_offset) {
1342 case 1:
1343 if (params->freq + 70 != params->center_freq1 &&
1344 params->freq + 30 != params->center_freq1 &&
1345 params->freq - 10 != params->center_freq1 &&
1346 params->freq - 50 != params->center_freq1)
1347 return -1;
1348 break;
1349 case -1:
1350 if (params->freq + 50 != params->center_freq1 &&
1351 params->freq + 10 != params->center_freq1 &&
1352 params->freq - 30 != params->center_freq1 &&
1353 params->freq - 70 != params->center_freq1)
1354 return -1;
1355 break;
1356 case 0:
1357 if (!is_6g)
1358 return -1;
1359 break;
1360 default:
1361 return -1;
1362 }
1363 break;
1364 case 320:
1365 if (!params->center_freq1 || params->center_freq2)
1366 return -1;
1367
1368 switch (params->sec_channel_offset) {
1369 case 1:
1370 if (params->freq + 150 != params->center_freq1 &&
1371 params->freq + 110 != params->center_freq1 &&
1372 params->freq + 70 != params->center_freq1 &&
1373 params->freq + 30 != params->center_freq1 &&
1374 params->freq - 10 != params->center_freq1 &&
1375 params->freq - 50 != params->center_freq1 &&
1376 params->freq - 90 != params->center_freq1 &&
1377 params->freq - 130 != params->center_freq1)
1378 return -1;
1379 break;
1380 case -1:
1381 if (params->freq + 130 != params->center_freq1 &&
1382 params->freq + 90 != params->center_freq1 &&
1383 params->freq + 50 != params->center_freq1 &&
1384 params->freq + 10 != params->center_freq1 &&
1385 params->freq - 30 != params->center_freq1 &&
1386 params->freq - 70 != params->center_freq1 &&
1387 params->freq - 110 != params->center_freq1 &&
1388 params->freq - 150 != params->center_freq1)
1389 return -1;
1390 break;
1391 case 0:
1392 break;
1393 default:
1394 return -1;
1395 }
1396 break;
1397 default:
1398 return -1;
1399 }
1400
1401 if (!punct_bitmap)
1402 return 0;
1403
1404 if (!params->eht_enabled) {
1405 wpa_printf(MSG_ERROR,
1406 "Preamble puncturing supported only in EHT");
1407 return -1;
1408 }
1409
1410 if (params->freq >= 2412 && params->freq <= 2484) {
1411 wpa_printf(MSG_ERROR,
1412 "Preamble puncturing is not supported in 2.4 GHz");
1413 return -1;
1414 }
1415
1416 start_freq = params->center_freq1 - (params->bandwidth / 2);
1417 if (!is_punct_bitmap_valid(params->bandwidth,
1418 (params->freq - start_freq) / 20,
1419 punct_bitmap)) {
1420 wpa_printf(MSG_ERROR, "Invalid preamble puncturing bitmap");
1421 return -1;
1422 }
1423
1424 return 0;
1425 }
1426
1427
hostapd_parse_csa_settings(struct hostapd_iface * iface,const char * pos,struct csa_settings * settings)1428 int hostapd_parse_csa_settings(struct hostapd_iface *iface,
1429 const char *pos,
1430 struct csa_settings *settings)
1431 {
1432 struct hostapd_hw_modes *target_mode;
1433 char *end;
1434 int ret;
1435
1436 os_memset(settings, 0, sizeof(*settings));
1437 settings->cs_count = strtol(pos, &end, 10);
1438 if (pos == end) {
1439 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
1440 return -1;
1441 }
1442
1443 settings->block_tx = !!os_strstr(pos, " blocktx");
1444
1445 ret = hostapd_parse_freq_params(end, &settings->freq_params, 0);
1446 if (ret < 0) {
1447 wpa_printf(MSG_INFO,
1448 "chanswitch: failed to parse frequency parameters");
1449 return ret;
1450 }
1451
1452 target_mode = get_target_hw_mode(iface, settings->freq_params.freq);
1453 if (!target_mode) {
1454 wpa_printf(MSG_DEBUG,
1455 "chanswitch: Invalid frequency settings provided for hw mode");
1456 return -1;
1457 }
1458
1459 if (iface->num_hw_features > 1 &&
1460 !hostapd_ctrl_is_freq_in_mode(target_mode, iface->current_hw_info,
1461 settings->freq_params.freq)) {
1462 wpa_printf(MSG_INFO,
1463 "chanswitch: Invalid frequency settings provided for multi band phy");
1464 return -1;
1465 }
1466
1467 ret = hostapd_ctrl_check_freq_params(&settings->freq_params,
1468 settings->freq_params.punct_bitmap);
1469 if (ret) {
1470 wpa_printf(MSG_INFO,
1471 "chanswitch: invalid frequency settings provided");
1472 return ret;
1473 }
1474
1475 return 0;
1476 }
1477
1478
hostapd_ctrl_iface_stop_ap(struct hostapd_data * hapd)1479 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
1480 {
1481 return hostapd_drv_stop_ap(hapd);
1482 }
1483
1484
hostapd_ctrl_iface_pmksa_list(struct hostapd_data * hapd,char * buf,size_t len)1485 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
1486 size_t len)
1487 {
1488 return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
1489 }
1490
1491
hostapd_ctrl_iface_pmksa_flush(struct hostapd_data * hapd)1492 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
1493 {
1494 wpa_auth_pmksa_flush(hapd->wpa_auth);
1495 }
1496
1497
hostapd_ctrl_iface_pmksa_add(struct hostapd_data * hapd,char * cmd)1498 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
1499 {
1500 u8 spa[ETH_ALEN];
1501 u8 pmkid[PMKID_LEN];
1502 u8 pmk[PMK_LEN_MAX];
1503 size_t pmk_len;
1504 char *pos, *pos2;
1505 int akmp = 0, expiration = 0;
1506 int ret;
1507
1508 /*
1509 * Entry format:
1510 * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
1511 */
1512
1513 if (hwaddr_aton(cmd, spa))
1514 return -1;
1515
1516 pos = os_strchr(cmd, ' ');
1517 if (!pos)
1518 return -1;
1519 pos++;
1520
1521 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
1522 return -1;
1523
1524 pos = os_strchr(pos, ' ');
1525 if (!pos)
1526 return -1;
1527 pos++;
1528
1529 pos2 = os_strchr(pos, ' ');
1530 if (!pos2)
1531 return -1;
1532 pmk_len = (pos2 - pos) / 2;
1533 if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
1534 hexstr2bin(pos, pmk, pmk_len) < 0)
1535 return -1;
1536
1537 pos = pos2 + 1;
1538
1539 if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
1540 return -1;
1541
1542 ret = wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
1543 pmkid, expiration, akmp, NULL, false);
1544 if (ret)
1545 return ret;
1546
1547 #ifdef CONFIG_IEEE80211BE
1548 if (hapd->conf->mld_ap)
1549 ret = wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
1550 pmkid, expiration, akmp, NULL, true);
1551 #endif /* CONFIG_IEEE80211BE */
1552
1553 return ret;
1554 }
1555
1556
1557 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
1558 #ifdef CONFIG_MESH
1559
hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data * hapd,const u8 * addr,char * buf,size_t len)1560 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
1561 const u8 *addr, char *buf, size_t len)
1562 {
1563 return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
1564 }
1565
1566
hostapd_ctrl_iface_pmksa_create_entry(const u8 * aa,char * cmd)1567 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
1568 {
1569 u8 spa[ETH_ALEN];
1570 u8 pmkid[PMKID_LEN];
1571 u8 pmk[PMK_LEN_MAX];
1572 char *pos;
1573 int expiration;
1574
1575 /*
1576 * Entry format:
1577 * <BSSID> <PMKID> <PMK> <expiration in seconds>
1578 */
1579
1580 if (hwaddr_aton(cmd, spa))
1581 return NULL;
1582
1583 pos = os_strchr(cmd, ' ');
1584 if (!pos)
1585 return NULL;
1586 pos++;
1587
1588 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
1589 return NULL;
1590
1591 pos = os_strchr(pos, ' ');
1592 if (!pos)
1593 return NULL;
1594 pos++;
1595
1596 if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
1597 return NULL;
1598
1599 pos = os_strchr(pos, ' ');
1600 if (!pos)
1601 return NULL;
1602 pos++;
1603
1604 if (sscanf(pos, "%d", &expiration) != 1)
1605 return NULL;
1606
1607 return wpa_auth_pmksa_create_entry(aa, spa, pmk, PMK_LEN,
1608 WPA_KEY_MGMT_SAE, pmkid, expiration);
1609 }
1610
1611 #endif /* CONFIG_MESH */
1612 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
1613
1614
1615 #ifdef CONFIG_WNM_AP
1616
hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data * hapd,const char * cmd)1617 int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
1618 const char *cmd)
1619 {
1620 u8 addr[ETH_ALEN];
1621 int disassoc_timer;
1622 struct sta_info *sta;
1623
1624 if (hwaddr_aton(cmd, addr))
1625 return -1;
1626 if (cmd[17] != ' ')
1627 return -1;
1628 disassoc_timer = atoi(cmd + 17);
1629
1630 sta = ap_get_sta(hapd, addr);
1631 if (sta == NULL) {
1632 wpa_printf(MSG_DEBUG, "Station " MACSTR
1633 " not found for disassociation imminent message",
1634 MAC2STR(addr));
1635 return -1;
1636 }
1637
1638 return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
1639 }
1640
1641
hostapd_ctrl_iface_ess_disassoc(struct hostapd_data * hapd,const char * cmd)1642 int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
1643 const char *cmd)
1644 {
1645 u8 addr[ETH_ALEN];
1646 const char *url, *timerstr;
1647 int disassoc_timer;
1648 struct sta_info *sta;
1649
1650 if (hwaddr_aton(cmd, addr))
1651 return -1;
1652
1653 sta = ap_get_sta(hapd, addr);
1654 if (sta == NULL) {
1655 wpa_printf(MSG_DEBUG, "Station " MACSTR
1656 " not found for ESS disassociation imminent message",
1657 MAC2STR(addr));
1658 return -1;
1659 }
1660
1661 timerstr = cmd + 17;
1662 if (*timerstr != ' ')
1663 return -1;
1664 timerstr++;
1665 disassoc_timer = atoi(timerstr);
1666 if (disassoc_timer < 0 || disassoc_timer > 65535)
1667 return -1;
1668
1669 url = os_strchr(timerstr, ' ');
1670 if (url == NULL)
1671 return -1;
1672 url++;
1673
1674 return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
1675 }
1676
1677
hostapd_ctrl_iface_bss_tm_req(struct hostapd_data * hapd,const char * cmd)1678 int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
1679 const char *cmd)
1680 {
1681 u8 addr[ETH_ALEN];
1682 const char *pos, *end;
1683 int disassoc_timer = 0;
1684 struct sta_info *sta;
1685 u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
1686 u8 bss_term_dur[12];
1687 char *url = NULL;
1688 int ret;
1689 u8 nei_rep[1000];
1690 int nei_len;
1691 u8 mbo[10];
1692 size_t mbo_len = 0;
1693
1694 if (hwaddr_aton(cmd, addr)) {
1695 wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
1696 return -1;
1697 }
1698
1699 sta = ap_get_sta(hapd, addr);
1700 if (sta == NULL) {
1701 wpa_printf(MSG_DEBUG, "Station " MACSTR
1702 " not found for BSS TM Request message",
1703 MAC2STR(addr));
1704 return -1;
1705 }
1706
1707 pos = os_strstr(cmd, " disassoc_timer=");
1708 if (pos) {
1709 pos += 16;
1710 disassoc_timer = atoi(pos);
1711 if (disassoc_timer < 0 || disassoc_timer > 65535) {
1712 wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
1713 return -1;
1714 }
1715 }
1716
1717 pos = os_strstr(cmd, " valid_int=");
1718 if (pos) {
1719 pos += 11;
1720 valid_int = atoi(pos);
1721 }
1722
1723 pos = os_strstr(cmd, " dialog_token=");
1724 if (pos) {
1725 pos += 14;
1726 dialog_token = atoi(pos);
1727 }
1728
1729 pos = os_strstr(cmd, " bss_term=");
1730 if (pos) {
1731 pos += 10;
1732 req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
1733 /* TODO: TSF configurable/learnable */
1734 bss_term_dur[0] = 4; /* Subelement ID */
1735 bss_term_dur[1] = 10; /* Length */
1736 os_memset(&bss_term_dur[2], 0, 8);
1737 end = os_strchr(pos, ',');
1738 if (end == NULL) {
1739 wpa_printf(MSG_DEBUG, "Invalid bss_term data");
1740 return -1;
1741 }
1742 end++;
1743 WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
1744 }
1745
1746 nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
1747 sizeof(nei_rep));
1748 if (nei_len < 0)
1749 return -1;
1750
1751 pos = os_strstr(cmd, " url=");
1752 if (pos) {
1753 size_t len;
1754 pos += 5;
1755 end = os_strchr(pos, ' ');
1756 if (end)
1757 len = end - pos;
1758 else
1759 len = os_strlen(pos);
1760 url = os_malloc(len + 1);
1761 if (url == NULL)
1762 return -1;
1763 os_memcpy(url, pos, len);
1764 url[len] = '\0';
1765 req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
1766 }
1767
1768 if (os_strstr(cmd, " pref=1"))
1769 req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
1770 if (os_strstr(cmd, " abridged=1"))
1771 req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1772 if (os_strstr(cmd, " disassoc_imminent=1"))
1773 req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
1774 if (os_strstr(cmd, " link_removal_imminent=1"))
1775 req_mode |= WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT;
1776
1777 #ifdef CONFIG_MBO
1778 pos = os_strstr(cmd, "mbo=");
1779 if (pos) {
1780 unsigned int mbo_reason, cell_pref, reassoc_delay;
1781 u8 *mbo_pos = mbo;
1782
1783 ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
1784 &reassoc_delay, &cell_pref);
1785 if (ret != 3) {
1786 wpa_printf(MSG_DEBUG,
1787 "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
1788 ret = -1;
1789 goto fail;
1790 }
1791
1792 if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
1793 wpa_printf(MSG_DEBUG,
1794 "Invalid MBO transition reason code %u",
1795 mbo_reason);
1796 ret = -1;
1797 goto fail;
1798 }
1799
1800 /* Valid values for Cellular preference are: 0, 1, 255 */
1801 if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
1802 wpa_printf(MSG_DEBUG,
1803 "Invalid MBO cellular capability %u",
1804 cell_pref);
1805 ret = -1;
1806 goto fail;
1807 }
1808
1809 if (reassoc_delay > 65535 ||
1810 (reassoc_delay &&
1811 !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
1812 wpa_printf(MSG_DEBUG,
1813 "MBO: Assoc retry delay is only valid in disassoc imminent mode");
1814 ret = -1;
1815 goto fail;
1816 }
1817
1818 *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
1819 *mbo_pos++ = 1;
1820 *mbo_pos++ = mbo_reason;
1821 *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
1822 *mbo_pos++ = 1;
1823 *mbo_pos++ = cell_pref;
1824
1825 if (reassoc_delay) {
1826 *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
1827 *mbo_pos++ = 2;
1828 WPA_PUT_LE16(mbo_pos, reassoc_delay);
1829 mbo_pos += 2;
1830 }
1831
1832 mbo_len = mbo_pos - mbo;
1833 }
1834 #endif /* CONFIG_MBO */
1835
1836 ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
1837 valid_int, bss_term_dur, dialog_token, url,
1838 nei_len ? nei_rep : NULL, nei_len,
1839 mbo_len ? mbo : NULL, mbo_len);
1840 #ifdef CONFIG_MBO
1841 fail:
1842 #endif /* CONFIG_MBO */
1843 os_free(url);
1844 return ret;
1845 }
1846
1847 #endif /* CONFIG_WNM_AP */
1848
1849
hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry ** acl,int * num,const char * txtaddr)1850 int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
1851 const char *txtaddr)
1852 {
1853 u8 addr[ETH_ALEN];
1854 struct vlan_description vlan_id;
1855
1856 if (!(*num))
1857 return 0;
1858
1859 if (hwaddr_aton(txtaddr, addr))
1860 return -1;
1861
1862 if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
1863 hostapd_remove_acl_mac(acl, num, addr);
1864
1865 return 0;
1866 }
1867
1868
hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry ** acl,int * num)1869 void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
1870 int *num)
1871 {
1872 while (*num)
1873 hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
1874 }
1875
1876
hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry * acl,int num,char * buf,size_t buflen)1877 int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
1878 char *buf, size_t buflen)
1879 {
1880 int i = 0, len = 0, ret = 0;
1881
1882 if (!acl)
1883 return 0;
1884
1885 while (i < num) {
1886 ret = os_snprintf(buf + len, buflen - len,
1887 MACSTR " VLAN_ID=%d\n",
1888 MAC2STR(acl[i].addr),
1889 acl[i].vlan_id.untagged);
1890 if (ret < 0 || (size_t) ret >= buflen - len)
1891 return len;
1892 i++;
1893 len += ret;
1894 }
1895 return len;
1896 }
1897
1898
hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry ** acl,int * num,const char * cmd)1899 int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
1900 const char *cmd)
1901 {
1902 u8 addr[ETH_ALEN];
1903 struct vlan_description vlan_id;
1904 int ret = 0, vlanid = 0;
1905 const char *pos;
1906
1907 if (hwaddr_aton(cmd, addr))
1908 return -1;
1909
1910 pos = os_strstr(cmd, "VLAN_ID=");
1911 if (pos)
1912 vlanid = atoi(pos + 8);
1913
1914 if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
1915 ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
1916 if (ret != -1 && *acl)
1917 qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
1918 }
1919
1920 return ret < 0 ? -1 : 0;
1921 }
1922
1923
hostapd_disassoc_accept_mac(struct hostapd_data * hapd)1924 int hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
1925 {
1926 struct sta_info *sta;
1927 struct vlan_description vlan_id;
1928
1929 if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
1930 return 0;
1931
1932 for (sta = hapd->sta_list; sta; sta = sta->next) {
1933 if (!hostapd_maclist_found(hapd->conf->accept_mac,
1934 hapd->conf->num_accept_mac,
1935 sta->addr, &vlan_id) ||
1936 (vlan_id.notempty &&
1937 vlan_compare(&vlan_id, sta->vlan_desc)))
1938 ap_sta_disconnect(hapd, sta, sta->addr,
1939 WLAN_REASON_UNSPECIFIED);
1940 }
1941
1942 return 0;
1943 }
1944
1945
hostapd_disassoc_deny_mac(struct hostapd_data * hapd)1946 int hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
1947 {
1948 struct sta_info *sta;
1949 struct vlan_description vlan_id;
1950
1951 for (sta = hapd->sta_list; sta; sta = sta->next) {
1952 #ifdef CONFIG_IEEE80211BE
1953 int link_id;
1954 struct mld_link_info *info;
1955 #endif /* CONFIG_IEEE80211BE */
1956
1957 if (hostapd_maclist_found(hapd->conf->deny_mac,
1958 hapd->conf->num_deny_mac, sta->addr,
1959 &vlan_id) &&
1960 (!vlan_id.notempty ||
1961 !vlan_compare(&vlan_id, sta->vlan_desc)))
1962 ap_sta_disconnect(hapd, sta, sta->addr,
1963 WLAN_REASON_UNSPECIFIED);
1964 #ifdef CONFIG_IEEE80211BE
1965 for (link_id = 0; hapd->conf->mld_ap &&
1966 link_id < MAX_NUM_MLD_LINKS &&
1967 sta->mld_info.mld_sta; link_id++) {
1968 info = &sta->mld_info.links[link_id];
1969 if (!info->valid || link_id != hapd->mld_link_id)
1970 continue;
1971
1972 if (hostapd_maclist_found(hapd->conf->deny_mac,
1973 hapd->conf->num_deny_mac,
1974 info->peer_addr,
1975 &vlan_id) &&
1976 (!vlan_id.notempty ||
1977 !vlan_compare(&vlan_id, sta->vlan_desc)))
1978 ap_sta_disconnect(hapd, sta, sta->addr,
1979 WLAN_REASON_UNSPECIFIED);
1980 }
1981 #endif /* CONFIG_IEEE80211BE */
1982 }
1983
1984 return 0;
1985 }
1986