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 "eapol_auth/eapol_auth_sm.h"
15 #include "fst/fst_ctrl_iface.h"
16 #include "hostapd.h"
17 #include "ieee802_1x.h"
18 #include "wpa_auth.h"
19 #include "ieee802_11.h"
20 #include "sta_info.h"
21 #include "wps_hostapd.h"
22 #include "p2p_hostapd.h"
23 #include "ctrl_iface_ap.h"
24 #include "ap_drv_ops.h"
25 #include "mbo_ap.h"
26 #include "taxonomy.h"
27
28
hostapd_write_ht_mcs_bitmask(char * buf,size_t buflen,size_t curr_len,const u8 * mcs_set)29 static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
30 size_t curr_len, const u8 *mcs_set)
31 {
32 int ret;
33 size_t len = curr_len;
34
35 ret = os_snprintf(buf + len, buflen - len,
36 "ht_mcs_bitmask=");
37 if (os_snprintf_error(buflen - len, ret))
38 return len;
39 len += ret;
40
41 /* 77 first bits (+ 3 reserved bits) */
42 len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10);
43
44 ret = os_snprintf(buf + len, buflen - len, "\n");
45 if (os_snprintf_error(buflen - len, ret))
46 return curr_len;
47 len += ret;
48
49 return len;
50 }
51
52
hostapd_get_sta_conn_time(struct sta_info * sta,struct hostap_sta_driver_data * data,char * buf,size_t buflen)53 static int hostapd_get_sta_conn_time(struct sta_info *sta,
54 struct hostap_sta_driver_data *data,
55 char *buf, size_t buflen)
56 {
57 struct os_reltime age;
58 unsigned long secs;
59 int ret;
60
61 if (sta->connected_time.sec) {
62 /* Locally maintained time in AP mode */
63 os_reltime_age(&sta->connected_time, &age);
64 secs = (unsigned long) age.sec;
65 } else if (data->flags & STA_DRV_DATA_CONN_TIME) {
66 /* Time from the driver in mesh mode */
67 secs = data->connected_sec;
68 } else {
69 return 0;
70 }
71
72 ret = os_snprintf(buf, buflen, "connected_time=%lu\n", secs);
73 if (os_snprintf_error(buflen, ret))
74 return 0;
75 return ret;
76 }
77
78
hostapd_get_sta_info(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)79 static int hostapd_get_sta_info(struct hostapd_data *hapd,
80 struct sta_info *sta,
81 char *buf, size_t buflen)
82 {
83 struct hostap_sta_driver_data data;
84 int ret;
85 int len = 0;
86
87 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
88 return 0;
89
90 ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
91 "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
92 "signal=%d\n",
93 data.rx_packets, data.tx_packets,
94 data.rx_bytes, data.tx_bytes, data.inactive_msec,
95 data.signal);
96 if (os_snprintf_error(buflen, ret))
97 return 0;
98 len += ret;
99
100 ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
101 data.current_rx_rate);
102 if (os_snprintf_error(buflen - len, ret))
103 return len;
104 len += ret;
105 if (data.flags & STA_DRV_DATA_RX_MCS) {
106 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
107 data.rx_mcs);
108 if (!os_snprintf_error(buflen - len, ret))
109 len += ret;
110 }
111 if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
112 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
113 data.rx_vhtmcs);
114 if (!os_snprintf_error(buflen - len, ret))
115 len += ret;
116 }
117 if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
118 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
119 data.rx_vht_nss);
120 if (!os_snprintf_error(buflen - len, ret))
121 len += ret;
122 }
123 if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
124 ret = os_snprintf(buf + len, buflen - len, " shortGI");
125 if (!os_snprintf_error(buflen - len, ret))
126 len += ret;
127 }
128 ret = os_snprintf(buf + len, buflen - len, "\n");
129 if (!os_snprintf_error(buflen - len, ret))
130 len += ret;
131
132 ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
133 data.current_tx_rate);
134 if (os_snprintf_error(buflen - len, ret))
135 return len;
136 len += ret;
137 if (data.flags & STA_DRV_DATA_TX_MCS) {
138 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
139 data.tx_mcs);
140 if (!os_snprintf_error(buflen - len, ret))
141 len += ret;
142 }
143 if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
144 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
145 data.tx_vhtmcs);
146 if (!os_snprintf_error(buflen - len, ret))
147 len += ret;
148 }
149 if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
150 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
151 data.tx_vht_nss);
152 if (!os_snprintf_error(buflen - len, ret))
153 len += ret;
154 }
155 if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
156 ret = os_snprintf(buf + len, buflen - len, " shortGI");
157 if (!os_snprintf_error(buflen - len, ret))
158 len += ret;
159 }
160 ret = os_snprintf(buf + len, buflen - len, "\n");
161 if (!os_snprintf_error(buflen - len, ret))
162 len += ret;
163
164 if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
165 ret = os_snprintf(buf + len, buflen - len,
166 "rx_vht_mcs_map=%04x\n"
167 "tx_vht_mcs_map=%04x\n",
168 le_to_host16(sta->vht_capabilities->
169 vht_supported_mcs_set.rx_map),
170 le_to_host16(sta->vht_capabilities->
171 vht_supported_mcs_set.tx_map));
172 if (!os_snprintf_error(buflen - len, ret))
173 len += ret;
174 }
175
176 if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
177 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
178 sta->ht_capabilities->
179 supported_mcs_set);
180 }
181
182 if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) {
183 ret = os_snprintf(buf + len, buflen - len,
184 "last_ack_signal=%d\n", data.last_ack_rssi);
185 if (!os_snprintf_error(buflen - len, ret))
186 len += ret;
187 }
188
189 len += hostapd_get_sta_conn_time(sta, &data, buf + len, buflen - len);
190
191 return len;
192 }
193
194
timeout_next_str(int val)195 static const char * timeout_next_str(int val)
196 {
197 switch (val) {
198 case STA_NULLFUNC:
199 return "NULLFUNC POLL";
200 case STA_DISASSOC:
201 return "DISASSOC";
202 case STA_DEAUTH:
203 return "DEAUTH";
204 case STA_REMOVE:
205 return "REMOVE";
206 case STA_DISASSOC_FROM_CLI:
207 return "DISASSOC_FROM_CLI";
208 }
209
210 return "?";
211 }
212
213
hostapd_ctrl_iface_sta_mib(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)214 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
215 struct sta_info *sta,
216 char *buf, size_t buflen)
217 {
218 int len, res, ret, i;
219 const char *keyid;
220
221 if (!sta)
222 return 0;
223
224 len = 0;
225 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
226 MAC2STR(sta->addr));
227 if (os_snprintf_error(buflen - len, ret))
228 return len;
229 len += ret;
230
231 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
232 if (ret < 0)
233 return len;
234 len += ret;
235
236 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
237 "listen_interval=%d\nsupported_rates=",
238 sta->aid, sta->capability, sta->listen_interval);
239 if (os_snprintf_error(buflen - len, ret))
240 return len;
241 len += ret;
242
243 for (i = 0; i < sta->supported_rates_len; i++) {
244 ret = os_snprintf(buf + len, buflen - len, "%02x%s",
245 sta->supported_rates[i],
246 i + 1 < sta->supported_rates_len ? " " : "");
247 if (os_snprintf_error(buflen - len, ret))
248 return len;
249 len += ret;
250 }
251
252 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
253 timeout_next_str(sta->timeout_next));
254 if (os_snprintf_error(buflen - len, ret))
255 return len;
256 len += ret;
257
258 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
259 if (res >= 0)
260 len += res;
261 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
262 if (res >= 0)
263 len += res;
264 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
265 if (res >= 0)
266 len += res;
267 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
268 buflen - len);
269 if (res >= 0)
270 len += res;
271 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
272 if (res >= 0)
273 len += res;
274
275 len += hostapd_get_sta_info(hapd, sta, buf + len, buflen - len);
276
277 #ifdef CONFIG_SAE
278 if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
279 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
280 sta->sae->group);
281 if (!os_snprintf_error(buflen - len, res))
282 len += res;
283 }
284
285 if (sta->sae && sta->sae->tmp) {
286 const u8 *pos;
287 unsigned int j, count;
288 struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups;
289
290 res = os_snprintf(buf + len, buflen - len,
291 "sae_rejected_groups=");
292 if (!os_snprintf_error(buflen - len, res))
293 len += res;
294
295 if (groups) {
296 pos = wpabuf_head(groups);
297 count = wpabuf_len(groups) / 2;
298 } else {
299 pos = NULL;
300 count = 0;
301 }
302 for (j = 0; pos && j < count; j++) {
303 res = os_snprintf(buf + len, buflen - len, "%s%d",
304 j == 0 ? "" : " ", WPA_GET_LE16(pos));
305 if (!os_snprintf_error(buflen - len, res))
306 len += res;
307 pos += 2;
308 }
309
310 res = os_snprintf(buf + len, buflen - len, "\n");
311 if (!os_snprintf_error(buflen - len, res))
312 len += res;
313 }
314 #endif /* CONFIG_SAE */
315
316 if (sta->vlan_id > 0) {
317 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
318 sta->vlan_id);
319 if (!os_snprintf_error(buflen - len, res))
320 len += res;
321 }
322
323 res = mbo_ap_get_info(sta, buf + len, buflen - len);
324 if (res >= 0)
325 len += res;
326
327 if (sta->supp_op_classes &&
328 buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
329 len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
330 len += wpa_snprintf_hex(buf + len, buflen - len,
331 sta->supp_op_classes + 1,
332 sta->supp_op_classes[0]);
333 len += os_snprintf(buf + len, buflen - len, "\n");
334 }
335
336 if (sta->power_capab) {
337 ret = os_snprintf(buf + len, buflen - len,
338 "min_txpower=%d\n"
339 "max_txpower=%d\n",
340 sta->min_tx_power, sta->max_tx_power);
341 if (!os_snprintf_error(buflen - len, ret))
342 len += ret;
343 }
344
345 #ifdef CONFIG_IEEE80211AC
346 if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) {
347 res = os_snprintf(buf + len, buflen - len,
348 "vht_caps_info=0x%08x\n",
349 le_to_host32(sta->vht_capabilities->
350 vht_capabilities_info));
351 if (!os_snprintf_error(buflen - len, res))
352 len += res;
353 }
354 #endif /* CONFIG_IEEE80211AC */
355
356 if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) {
357 res = os_snprintf(buf + len, buflen - len,
358 "ht_caps_info=0x%04x\n",
359 le_to_host16(sta->ht_capabilities->
360 ht_capabilities_info));
361 if (!os_snprintf_error(buflen - len, res))
362 len += res;
363 }
364
365 if (sta->ext_capability &&
366 buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) {
367 len += os_snprintf(buf + len, buflen - len, "ext_capab=");
368 len += wpa_snprintf_hex(buf + len, buflen - len,
369 sta->ext_capability + 1,
370 sta->ext_capability[0]);
371 len += os_snprintf(buf + len, buflen - len, "\n");
372 }
373
374 if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) {
375 ret = os_snprintf(buf + len, buflen - len,
376 "wds_sta_ifname=%s\n", sta->ifname_wds);
377 if (!os_snprintf_error(buflen - len, ret))
378 len += ret;
379 }
380
381 keyid = ap_sta_wpa_get_keyid(hapd, sta);
382 if (keyid) {
383 ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid);
384 if (!os_snprintf_error(buflen - len, ret))
385 len += ret;
386 }
387
388 return len;
389 }
390
391
hostapd_ctrl_iface_sta_first(struct hostapd_data * hapd,char * buf,size_t buflen)392 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
393 char *buf, size_t buflen)
394 {
395 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
396 }
397
398
hostapd_ctrl_iface_sta(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)399 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
400 char *buf, size_t buflen)
401 {
402 u8 addr[ETH_ALEN];
403 int ret;
404 const char *pos;
405 struct sta_info *sta;
406
407 if (hwaddr_aton(txtaddr, addr)) {
408 ret = os_snprintf(buf, buflen, "FAIL\n");
409 if (os_snprintf_error(buflen, ret))
410 return 0;
411 return ret;
412 }
413
414 sta = ap_get_sta(hapd, addr);
415 if (sta == NULL)
416 return -1;
417
418 pos = os_strchr(txtaddr, ' ');
419 if (pos) {
420 pos++;
421
422 #ifdef HOSTAPD_DUMP_STATE
423 if (os_strcmp(pos, "eapol") == 0) {
424 if (sta->eapol_sm == NULL)
425 return -1;
426 return eapol_auth_dump_state(sta->eapol_sm, buf,
427 buflen);
428 }
429 #endif /* HOSTAPD_DUMP_STATE */
430
431 return -1;
432 }
433
434 ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
435 ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
436
437 return ret;
438 }
439
440
hostapd_ctrl_iface_sta_next(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)441 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
442 char *buf, size_t buflen)
443 {
444 u8 addr[ETH_ALEN];
445 struct sta_info *sta;
446 int ret;
447
448 if (hwaddr_aton(txtaddr, addr) ||
449 (sta = ap_get_sta(hapd, addr)) == NULL) {
450 ret = os_snprintf(buf, buflen, "FAIL\n");
451 if (os_snprintf_error(buflen, ret))
452 return 0;
453 return ret;
454 }
455
456 if (!sta->next)
457 return 0;
458
459 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
460 }
461
462
463 #ifdef CONFIG_P2P_MANAGER
p2p_manager_disconnect(struct hostapd_data * hapd,u16 stype,u8 minor_reason_code,const u8 * addr)464 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
465 u8 minor_reason_code, const u8 *addr)
466 {
467 struct ieee80211_mgmt *mgmt;
468 int ret;
469 u8 *pos;
470
471 mgmt = os_zalloc(sizeof(*mgmt) + 100);
472 if (mgmt == NULL)
473 return -1;
474
475 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
476 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
477 " with minor reason code %u (stype=%u (%s))",
478 MAC2STR(addr), minor_reason_code, stype,
479 fc2str(le_to_host16(mgmt->frame_control)));
480
481 os_memcpy(mgmt->da, addr, ETH_ALEN);
482 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
483 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
484 if (stype == WLAN_FC_STYPE_DEAUTH) {
485 mgmt->u.deauth.reason_code =
486 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
487 pos = mgmt->u.deauth.variable;
488 } else {
489 mgmt->u.disassoc.reason_code =
490 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
491 pos = mgmt->u.disassoc.variable;
492 }
493
494 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
495 *pos++ = 4 + 3 + 1;
496 WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
497 pos += 4;
498
499 *pos++ = P2P_ATTR_MINOR_REASON_CODE;
500 WPA_PUT_LE16(pos, 1);
501 pos += 2;
502 *pos++ = minor_reason_code;
503
504 ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0,
505 0);
506 os_free(mgmt);
507
508 return ret < 0 ? -1 : 0;
509 }
510 #endif /* CONFIG_P2P_MANAGER */
511
512
hostapd_ctrl_iface_deauthenticate(struct hostapd_data * hapd,const char * txtaddr)513 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
514 const char *txtaddr)
515 {
516 u8 addr[ETH_ALEN];
517 struct sta_info *sta;
518 const char *pos;
519 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
520
521 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
522 txtaddr);
523
524 if (hwaddr_aton(txtaddr, addr))
525 return -1;
526
527 pos = os_strstr(txtaddr, " reason=");
528 if (pos)
529 reason = atoi(pos + 8);
530
531 pos = os_strstr(txtaddr, " test=");
532 if (pos) {
533 struct ieee80211_mgmt mgmt;
534 int encrypt;
535
536 pos += 6;
537 encrypt = atoi(pos);
538 os_memset(&mgmt, 0, sizeof(mgmt));
539 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
540 WLAN_FC_STYPE_DEAUTH);
541 os_memcpy(mgmt.da, addr, ETH_ALEN);
542 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
543 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
544 mgmt.u.deauth.reason_code = host_to_le16(reason);
545 if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
546 IEEE80211_HDRLEN +
547 sizeof(mgmt.u.deauth),
548 0, NULL, 0, !encrypt) < 0)
549 return -1;
550 return 0;
551 }
552
553 #ifdef CONFIG_P2P_MANAGER
554 pos = os_strstr(txtaddr, " p2p=");
555 if (pos) {
556 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
557 atoi(pos + 5), addr);
558 }
559 #endif /* CONFIG_P2P_MANAGER */
560
561 if (os_strstr(txtaddr, " tx=0"))
562 hostapd_drv_sta_remove(hapd, addr);
563 else
564 hostapd_drv_sta_deauth(hapd, addr, reason);
565 sta = ap_get_sta(hapd, addr);
566 if (sta)
567 ap_sta_deauthenticate(hapd, sta, reason);
568 else if (addr[0] == 0xff)
569 hostapd_free_stas(hapd);
570
571 return 0;
572 }
573
574
hostapd_ctrl_iface_disassociate(struct hostapd_data * hapd,const char * txtaddr)575 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
576 const char *txtaddr)
577 {
578 u8 addr[ETH_ALEN];
579 struct sta_info *sta;
580 const char *pos;
581 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
582
583 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
584 txtaddr);
585
586 if (hwaddr_aton(txtaddr, addr))
587 return -1;
588
589 pos = os_strstr(txtaddr, " reason=");
590 if (pos)
591 reason = atoi(pos + 8);
592
593 pos = os_strstr(txtaddr, " test=");
594 if (pos) {
595 struct ieee80211_mgmt mgmt;
596 int encrypt;
597
598 pos += 6;
599 encrypt = atoi(pos);
600 os_memset(&mgmt, 0, sizeof(mgmt));
601 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
602 WLAN_FC_STYPE_DISASSOC);
603 os_memcpy(mgmt.da, addr, ETH_ALEN);
604 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
605 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
606 mgmt.u.disassoc.reason_code = host_to_le16(reason);
607 if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt,
608 IEEE80211_HDRLEN +
609 sizeof(mgmt.u.deauth),
610 0, NULL, 0, !encrypt) < 0)
611 return -1;
612 return 0;
613 }
614
615 #ifdef CONFIG_P2P_MANAGER
616 pos = os_strstr(txtaddr, " p2p=");
617 if (pos) {
618 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
619 atoi(pos + 5), addr);
620 }
621 #endif /* CONFIG_P2P_MANAGER */
622
623 if (os_strstr(txtaddr, " tx=0"))
624 hostapd_drv_sta_remove(hapd, addr);
625 else
626 hostapd_drv_sta_disassoc(hapd, addr, reason);
627 sta = ap_get_sta(hapd, addr);
628 if (sta)
629 ap_sta_disassociate(hapd, sta, reason);
630 else if (addr[0] == 0xff)
631 hostapd_free_stas(hapd);
632
633 return 0;
634 }
635
636
637 #ifdef CONFIG_TAXONOMY
hostapd_ctrl_iface_signature(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)638 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
639 const char *txtaddr,
640 char *buf, size_t buflen)
641 {
642 u8 addr[ETH_ALEN];
643 struct sta_info *sta;
644
645 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
646
647 if (hwaddr_aton(txtaddr, addr))
648 return -1;
649
650 sta = ap_get_sta(hapd, addr);
651 if (!sta)
652 return -1;
653
654 return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
655 }
656 #endif /* CONFIG_TAXONOMY */
657
658
hostapd_ctrl_iface_poll_sta(struct hostapd_data * hapd,const char * txtaddr)659 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
660 const char *txtaddr)
661 {
662 u8 addr[ETH_ALEN];
663 struct sta_info *sta;
664
665 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
666
667 if (hwaddr_aton(txtaddr, addr))
668 return -1;
669
670 sta = ap_get_sta(hapd, addr);
671 if (!sta)
672 return -1;
673
674 hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
675 sta->flags & WLAN_STA_WMM);
676 return 0;
677 }
678
679
hostapd_ctrl_iface_status(struct hostapd_data * hapd,char * buf,size_t buflen)680 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
681 size_t buflen)
682 {
683 struct hostapd_iface *iface = hapd->iface;
684 struct hostapd_hw_modes *mode = iface->current_mode;
685 int len = 0, ret, j;
686 size_t i;
687
688 ret = os_snprintf(buf + len, buflen - len,
689 "state=%s\n"
690 "phy=%s\n"
691 "freq=%d\n"
692 "num_sta_non_erp=%d\n"
693 "num_sta_no_short_slot_time=%d\n"
694 "num_sta_no_short_preamble=%d\n"
695 "olbc=%d\n"
696 "num_sta_ht_no_gf=%d\n"
697 "num_sta_no_ht=%d\n"
698 "num_sta_ht_20_mhz=%d\n"
699 "num_sta_ht40_intolerant=%d\n"
700 "olbc_ht=%d\n"
701 "ht_op_mode=0x%x\n",
702 hostapd_state_text(iface->state),
703 iface->phy,
704 iface->freq,
705 iface->num_sta_non_erp,
706 iface->num_sta_no_short_slot_time,
707 iface->num_sta_no_short_preamble,
708 iface->olbc,
709 iface->num_sta_ht_no_gf,
710 iface->num_sta_no_ht,
711 iface->num_sta_ht_20mhz,
712 iface->num_sta_ht40_intolerant,
713 iface->olbc_ht,
714 iface->ht_op_mode);
715 if (os_snprintf_error(buflen - len, ret))
716 return len;
717 len += ret;
718
719 if (!iface->cac_started || !iface->dfs_cac_ms) {
720 ret = os_snprintf(buf + len, buflen - len,
721 "cac_time_seconds=%d\n"
722 "cac_time_left_seconds=N/A\n",
723 iface->dfs_cac_ms / 1000);
724 } else {
725 /* CAC started and CAC time set - calculate remaining time */
726 struct os_reltime now;
727 unsigned int left_time;
728
729 os_reltime_age(&iface->dfs_cac_start, &now);
730 left_time = iface->dfs_cac_ms / 1000 - now.sec;
731 ret = os_snprintf(buf + len, buflen - len,
732 "cac_time_seconds=%u\n"
733 "cac_time_left_seconds=%u\n",
734 iface->dfs_cac_ms / 1000,
735 left_time);
736 }
737 if (os_snprintf_error(buflen - len, ret))
738 return len;
739 len += ret;
740
741 ret = os_snprintf(buf + len, buflen - len,
742 "channel=%u\n"
743 "edmg_enable=%d\n"
744 "edmg_channel=%d\n"
745 "secondary_channel=%d\n"
746 "ieee80211n=%d\n"
747 "ieee80211ac=%d\n"
748 "ieee80211ax=%d\n"
749 "beacon_int=%u\n"
750 "dtim_period=%d\n",
751 iface->conf->channel,
752 iface->conf->enable_edmg,
753 iface->conf->edmg_channel,
754 iface->conf->ieee80211n && !hapd->conf->disable_11n ?
755 iface->conf->secondary_channel : 0,
756 iface->conf->ieee80211n && !hapd->conf->disable_11n,
757 iface->conf->ieee80211ac &&
758 !hapd->conf->disable_11ac,
759 iface->conf->ieee80211ax &&
760 !hapd->conf->disable_11ax,
761 iface->conf->beacon_int,
762 hapd->conf->dtim_period);
763 if (os_snprintf_error(buflen - len, ret))
764 return len;
765 len += ret;
766
767 #ifdef CONFIG_IEEE80211AX
768 if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
769 ret = os_snprintf(buf + len, buflen - len,
770 "he_oper_chwidth=%d\n"
771 "he_oper_centr_freq_seg0_idx=%d\n"
772 "he_oper_centr_freq_seg1_idx=%d\n",
773 iface->conf->he_oper_chwidth,
774 iface->conf->he_oper_centr_freq_seg0_idx,
775 iface->conf->he_oper_centr_freq_seg1_idx);
776 if (os_snprintf_error(buflen - len, ret))
777 return len;
778 len += ret;
779 }
780 #endif /* CONFIG_IEEE80211AX */
781
782 if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
783 ret = os_snprintf(buf + len, buflen - len,
784 "vht_oper_chwidth=%d\n"
785 "vht_oper_centr_freq_seg0_idx=%d\n"
786 "vht_oper_centr_freq_seg1_idx=%d\n"
787 "vht_caps_info=%08x\n",
788 iface->conf->vht_oper_chwidth,
789 iface->conf->vht_oper_centr_freq_seg0_idx,
790 iface->conf->vht_oper_centr_freq_seg1_idx,
791 iface->conf->vht_capab);
792 if (os_snprintf_error(buflen - len, ret))
793 return len;
794 len += ret;
795 }
796
797 if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) {
798 u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]);
799 u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]);
800
801 ret = os_snprintf(buf + len, buflen - len,
802 "rx_vht_mcs_map=%04x\n"
803 "tx_vht_mcs_map=%04x\n",
804 rxmap, txmap);
805 if (os_snprintf_error(buflen - len, ret))
806 return len;
807 len += ret;
808 }
809
810 if (iface->conf->ieee80211n && !hapd->conf->disable_11n) {
811 ret = os_snprintf(buf + len, buflen - len,
812 "ht_caps_info=%04x\n",
813 hapd->iconf->ht_capab);
814 if (os_snprintf_error(buflen - len, ret))
815 return len;
816 len += ret;
817 }
818
819 if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) {
820 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len,
821 mode->mcs_set);
822 }
823
824 if (iface->current_rates && iface->num_rates) {
825 ret = os_snprintf(buf + len, buflen - len, "supported_rates=");
826 if (os_snprintf_error(buflen - len, ret))
827 return len;
828 len += ret;
829
830 for (j = 0; j < iface->num_rates; j++) {
831 ret = os_snprintf(buf + len, buflen - len, "%s%02x",
832 j > 0 ? " " : "",
833 iface->current_rates[j].rate / 5);
834 if (os_snprintf_error(buflen - len, ret))
835 return len;
836 len += ret;
837 }
838 ret = os_snprintf(buf + len, buflen - len, "\n");
839 if (os_snprintf_error(buflen - len, ret))
840 return len;
841 len += ret;
842 }
843
844 for (j = 0; mode && j < mode->num_channels; j++) {
845 if (mode->channels[j].freq == iface->freq) {
846 ret = os_snprintf(buf + len, buflen - len,
847 "max_txpower=%u\n",
848 mode->channels[j].max_tx_power);
849 if (os_snprintf_error(buflen - len, ret))
850 return len;
851 len += ret;
852 break;
853 }
854 }
855
856 for (i = 0; i < iface->num_bss; i++) {
857 struct hostapd_data *bss = iface->bss[i];
858 ret = os_snprintf(buf + len, buflen - len,
859 "bss[%d]=%s\n"
860 "bssid[%d]=" MACSTR "\n"
861 "ssid[%d]=%s\n"
862 "num_sta[%d]=%d\n",
863 (int) i, bss->conf->iface,
864 (int) i, MAC2STR(bss->own_addr),
865 (int) i,
866 wpa_ssid_txt(bss->conf->ssid.ssid,
867 bss->conf->ssid.ssid_len),
868 (int) i, bss->num_sta);
869 if (os_snprintf_error(buflen - len, ret))
870 return len;
871 len += ret;
872 }
873
874 if (hapd->conf->chan_util_avg_period) {
875 ret = os_snprintf(buf + len, buflen - len,
876 "chan_util_avg=%u\n",
877 iface->chan_util_average);
878 if (os_snprintf_error(buflen - len, ret))
879 return len;
880 len += ret;
881 }
882
883 return len;
884 }
885
886
hostapd_parse_csa_settings(const char * pos,struct csa_settings * settings)887 int hostapd_parse_csa_settings(const char *pos,
888 struct csa_settings *settings)
889 {
890 char *end;
891
892 os_memset(settings, 0, sizeof(*settings));
893 settings->cs_count = strtol(pos, &end, 10);
894 if (pos == end) {
895 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
896 return -1;
897 }
898
899 settings->freq_params.freq = atoi(end);
900 if (settings->freq_params.freq == 0) {
901 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
902 return -1;
903 }
904
905 #define SET_CSA_SETTING(str) \
906 do { \
907 const char *pos2 = os_strstr(pos, " " #str "="); \
908 if (pos2) { \
909 pos2 += sizeof(" " #str "=") - 1; \
910 settings->freq_params.str = atoi(pos2); \
911 } \
912 } while (0)
913
914 SET_CSA_SETTING(center_freq1);
915 SET_CSA_SETTING(center_freq2);
916 SET_CSA_SETTING(bandwidth);
917 SET_CSA_SETTING(sec_channel_offset);
918 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
919 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
920 settings->freq_params.he_enabled = !!os_strstr(pos, " he");
921 settings->block_tx = !!os_strstr(pos, " blocktx");
922 #undef SET_CSA_SETTING
923
924 return 0;
925 }
926
927
hostapd_ctrl_iface_stop_ap(struct hostapd_data * hapd)928 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
929 {
930 return hostapd_drv_stop_ap(hapd);
931 }
932
933
hostapd_ctrl_iface_pmksa_list(struct hostapd_data * hapd,char * buf,size_t len)934 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
935 size_t len)
936 {
937 return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
938 }
939
940
hostapd_ctrl_iface_pmksa_flush(struct hostapd_data * hapd)941 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
942 {
943 wpa_auth_pmksa_flush(hapd->wpa_auth);
944 }
945
946
hostapd_ctrl_iface_pmksa_add(struct hostapd_data * hapd,char * cmd)947 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
948 {
949 u8 spa[ETH_ALEN];
950 u8 pmkid[PMKID_LEN];
951 u8 pmk[PMK_LEN_MAX];
952 size_t pmk_len;
953 char *pos, *pos2;
954 int akmp = 0, expiration = 0;
955
956 /*
957 * Entry format:
958 * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
959 */
960
961 if (hwaddr_aton(cmd, spa))
962 return -1;
963
964 pos = os_strchr(cmd, ' ');
965 if (!pos)
966 return -1;
967 pos++;
968
969 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
970 return -1;
971
972 pos = os_strchr(pos, ' ');
973 if (!pos)
974 return -1;
975 pos++;
976
977 pos2 = os_strchr(pos, ' ');
978 if (!pos2)
979 return -1;
980 pmk_len = (pos2 - pos) / 2;
981 if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
982 hexstr2bin(pos, pmk, pmk_len) < 0)
983 return -1;
984
985 pos = pos2 + 1;
986
987 if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
988 return -1;
989
990 return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
991 pmkid, expiration, akmp);
992 }
993
994
995 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
996 #ifdef CONFIG_MESH
997
hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data * hapd,const u8 * addr,char * buf,size_t len)998 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
999 const u8 *addr, char *buf, size_t len)
1000 {
1001 return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
1002 }
1003
1004
hostapd_ctrl_iface_pmksa_create_entry(const u8 * aa,char * cmd)1005 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
1006 {
1007 u8 spa[ETH_ALEN];
1008 u8 pmkid[PMKID_LEN];
1009 u8 pmk[PMK_LEN_MAX];
1010 char *pos;
1011 int expiration;
1012
1013 /*
1014 * Entry format:
1015 * <BSSID> <PMKID> <PMK> <expiration in seconds>
1016 */
1017
1018 if (hwaddr_aton(cmd, spa))
1019 return NULL;
1020
1021 pos = os_strchr(cmd, ' ');
1022 if (!pos)
1023 return NULL;
1024 pos++;
1025
1026 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
1027 return NULL;
1028
1029 pos = os_strchr(pos, ' ');
1030 if (!pos)
1031 return NULL;
1032 pos++;
1033
1034 if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
1035 return NULL;
1036
1037 pos = os_strchr(pos, ' ');
1038 if (!pos)
1039 return NULL;
1040 pos++;
1041
1042 if (sscanf(pos, "%d", &expiration) != 1)
1043 return NULL;
1044
1045 return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
1046 }
1047
1048 #endif /* CONFIG_MESH */
1049 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
1050