1 /*
2 * Control interface for shared AP commands
3 * Copyright (c) 2004-2014, 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_get_sta_tx_rx(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)29 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
30 struct sta_info *sta,
31 char *buf, size_t buflen)
32 {
33 struct hostap_sta_driver_data data;
34 int ret;
35 int len = 0;
36
37 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
38 return 0;
39
40 ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
41 "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n"
42 "signal=%d\n",
43 data.rx_packets, data.tx_packets,
44 data.rx_bytes, data.tx_bytes, data.inactive_msec,
45 data.signal);
46 if (os_snprintf_error(buflen, ret))
47 return 0;
48 len += ret;
49
50 ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu",
51 data.current_rx_rate);
52 if (os_snprintf_error(buflen - len, ret))
53 return len;
54 len += ret;
55 if (data.flags & STA_DRV_DATA_RX_MCS) {
56 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
57 data.rx_mcs);
58 if (!os_snprintf_error(buflen - len, ret))
59 len += ret;
60 }
61 if (data.flags & STA_DRV_DATA_RX_VHT_MCS) {
62 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
63 data.rx_vhtmcs);
64 if (!os_snprintf_error(buflen - len, ret))
65 len += ret;
66 }
67 if (data.flags & STA_DRV_DATA_RX_VHT_NSS) {
68 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
69 data.rx_vht_nss);
70 if (!os_snprintf_error(buflen - len, ret))
71 len += ret;
72 }
73 if (data.flags & STA_DRV_DATA_RX_SHORT_GI) {
74 ret = os_snprintf(buf + len, buflen - len, " shortGI");
75 if (!os_snprintf_error(buflen - len, ret))
76 len += ret;
77 }
78 ret = os_snprintf(buf + len, buflen - len, "\n");
79 if (!os_snprintf_error(buflen - len, ret))
80 len += ret;
81
82 ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu",
83 data.current_tx_rate);
84 if (os_snprintf_error(buflen - len, ret))
85 return len;
86 len += ret;
87 if (data.flags & STA_DRV_DATA_TX_MCS) {
88 ret = os_snprintf(buf + len, buflen - len, " mcs %u",
89 data.tx_mcs);
90 if (!os_snprintf_error(buflen - len, ret))
91 len += ret;
92 }
93 if (data.flags & STA_DRV_DATA_TX_VHT_MCS) {
94 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u",
95 data.tx_vhtmcs);
96 if (!os_snprintf_error(buflen - len, ret))
97 len += ret;
98 }
99 if (data.flags & STA_DRV_DATA_TX_VHT_NSS) {
100 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u",
101 data.tx_vht_nss);
102 if (!os_snprintf_error(buflen - len, ret))
103 len += ret;
104 }
105 if (data.flags & STA_DRV_DATA_TX_SHORT_GI) {
106 ret = os_snprintf(buf + len, buflen - len, " shortGI");
107 if (!os_snprintf_error(buflen - len, ret))
108 len += ret;
109 }
110 ret = os_snprintf(buf + len, buflen - len, "\n");
111 if (!os_snprintf_error(buflen - len, ret))
112 len += ret;
113
114 return len;
115 }
116
117
hostapd_get_sta_conn_time(struct sta_info * sta,char * buf,size_t buflen)118 static int hostapd_get_sta_conn_time(struct sta_info *sta,
119 char *buf, size_t buflen)
120 {
121 struct os_reltime age;
122 int ret;
123
124 if (!sta->connected_time.sec)
125 return 0;
126
127 os_reltime_age(&sta->connected_time, &age);
128
129 ret = os_snprintf(buf, buflen, "connected_time=%u\n",
130 (unsigned int) age.sec);
131 if (os_snprintf_error(buflen, ret))
132 return 0;
133 return ret;
134 }
135
136
timeout_next_str(int val)137 static const char * timeout_next_str(int val)
138 {
139 switch (val) {
140 case STA_NULLFUNC:
141 return "NULLFUNC POLL";
142 case STA_DISASSOC:
143 return "DISASSOC";
144 case STA_DEAUTH:
145 return "DEAUTH";
146 case STA_REMOVE:
147 return "REMOVE";
148 case STA_DISASSOC_FROM_CLI:
149 return "DISASSOC_FROM_CLI";
150 }
151
152 return "?";
153 }
154
155
hostapd_ctrl_iface_sta_mib(struct hostapd_data * hapd,struct sta_info * sta,char * buf,size_t buflen)156 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
157 struct sta_info *sta,
158 char *buf, size_t buflen)
159 {
160 int len, res, ret, i;
161
162 if (!sta)
163 return 0;
164
165 len = 0;
166 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
167 MAC2STR(sta->addr));
168 if (os_snprintf_error(buflen - len, ret))
169 return len;
170 len += ret;
171
172 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
173 if (ret < 0)
174 return len;
175 len += ret;
176
177 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
178 "listen_interval=%d\nsupported_rates=",
179 sta->aid, sta->capability, sta->listen_interval);
180 if (os_snprintf_error(buflen - len, ret))
181 return len;
182 len += ret;
183
184 for (i = 0; i < sta->supported_rates_len; i++) {
185 ret = os_snprintf(buf + len, buflen - len, "%02x%s",
186 sta->supported_rates[i],
187 i + 1 < sta->supported_rates_len ? " " : "");
188 if (os_snprintf_error(buflen - len, ret))
189 return len;
190 len += ret;
191 }
192
193 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
194 timeout_next_str(sta->timeout_next));
195 if (os_snprintf_error(buflen - len, ret))
196 return len;
197 len += ret;
198
199 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
200 if (res >= 0)
201 len += res;
202 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
203 if (res >= 0)
204 len += res;
205 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
206 if (res >= 0)
207 len += res;
208 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
209 buflen - len);
210 if (res >= 0)
211 len += res;
212 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
213 if (res >= 0)
214 len += res;
215
216 len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
217 len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
218
219 #ifdef CONFIG_SAE
220 if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
221 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
222 sta->sae->group);
223 if (!os_snprintf_error(buflen - len, res))
224 len += res;
225 }
226 #endif /* CONFIG_SAE */
227
228 if (sta->vlan_id > 0) {
229 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
230 sta->vlan_id);
231 if (!os_snprintf_error(buflen - len, res))
232 len += res;
233 }
234
235 res = mbo_ap_get_info(sta, buf + len, buflen - len);
236 if (res >= 0)
237 len += res;
238
239 if (sta->supp_op_classes &&
240 buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) {
241 len += os_snprintf(buf + len, buflen - len, "supp_op_classes=");
242 len += wpa_snprintf_hex(buf + len, buflen - len,
243 sta->supp_op_classes + 1,
244 sta->supp_op_classes[0]);
245 len += os_snprintf(buf + len, buflen - len, "\n");
246 }
247
248 return len;
249 }
250
251
hostapd_ctrl_iface_sta_first(struct hostapd_data * hapd,char * buf,size_t buflen)252 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
253 char *buf, size_t buflen)
254 {
255 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
256 }
257
258
hostapd_ctrl_iface_sta(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)259 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
260 char *buf, size_t buflen)
261 {
262 u8 addr[ETH_ALEN];
263 int ret;
264 const char *pos;
265 struct sta_info *sta;
266
267 if (hwaddr_aton(txtaddr, addr)) {
268 ret = os_snprintf(buf, buflen, "FAIL\n");
269 if (os_snprintf_error(buflen, ret))
270 return 0;
271 return ret;
272 }
273
274 sta = ap_get_sta(hapd, addr);
275 if (sta == NULL)
276 return -1;
277
278 pos = os_strchr(txtaddr, ' ');
279 if (pos) {
280 pos++;
281
282 #ifdef HOSTAPD_DUMP_STATE
283 if (os_strcmp(pos, "eapol") == 0) {
284 if (sta->eapol_sm == NULL)
285 return -1;
286 return eapol_auth_dump_state(sta->eapol_sm, buf,
287 buflen);
288 }
289 #endif /* HOSTAPD_DUMP_STATE */
290
291 return -1;
292 }
293
294 ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
295 ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
296
297 return ret;
298 }
299
300
hostapd_ctrl_iface_sta_next(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)301 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
302 char *buf, size_t buflen)
303 {
304 u8 addr[ETH_ALEN];
305 struct sta_info *sta;
306 int ret;
307
308 if (hwaddr_aton(txtaddr, addr) ||
309 (sta = ap_get_sta(hapd, addr)) == NULL) {
310 ret = os_snprintf(buf, buflen, "FAIL\n");
311 if (os_snprintf_error(buflen, ret))
312 return 0;
313 return ret;
314 }
315
316 if (!sta->next)
317 return 0;
318
319 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
320 }
321
322
323 #ifdef CONFIG_P2P_MANAGER
p2p_manager_disconnect(struct hostapd_data * hapd,u16 stype,u8 minor_reason_code,const u8 * addr)324 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
325 u8 minor_reason_code, const u8 *addr)
326 {
327 struct ieee80211_mgmt *mgmt;
328 int ret;
329 u8 *pos;
330
331 if (!hapd->drv_priv || !hapd->driver->send_frame)
332 return -1;
333
334 mgmt = os_zalloc(sizeof(*mgmt) + 100);
335 if (mgmt == NULL)
336 return -1;
337
338 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
339 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
340 " with minor reason code %u (stype=%u (%s))",
341 MAC2STR(addr), minor_reason_code, stype,
342 fc2str(le_to_host16(mgmt->frame_control)));
343
344 os_memcpy(mgmt->da, addr, ETH_ALEN);
345 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
346 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
347 if (stype == WLAN_FC_STYPE_DEAUTH) {
348 mgmt->u.deauth.reason_code =
349 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
350 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
351 } else {
352 mgmt->u.disassoc.reason_code =
353 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
354 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
355 }
356
357 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
358 *pos++ = 4 + 3 + 1;
359 WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
360 pos += 4;
361
362 *pos++ = P2P_ATTR_MINOR_REASON_CODE;
363 WPA_PUT_LE16(pos, 1);
364 pos += 2;
365 *pos++ = minor_reason_code;
366
367 ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
368 pos - (u8 *) mgmt, 1);
369 os_free(mgmt);
370
371 return ret < 0 ? -1 : 0;
372 }
373 #endif /* CONFIG_P2P_MANAGER */
374
375
hostapd_ctrl_iface_deauthenticate(struct hostapd_data * hapd,const char * txtaddr)376 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
377 const char *txtaddr)
378 {
379 u8 addr[ETH_ALEN];
380 struct sta_info *sta;
381 const char *pos;
382 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
383
384 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
385 txtaddr);
386
387 if (hwaddr_aton(txtaddr, addr))
388 return -1;
389
390 pos = os_strstr(txtaddr, " reason=");
391 if (pos)
392 reason = atoi(pos + 8);
393
394 pos = os_strstr(txtaddr, " test=");
395 if (pos) {
396 struct ieee80211_mgmt mgmt;
397 int encrypt;
398 if (!hapd->drv_priv || !hapd->driver->send_frame)
399 return -1;
400 pos += 6;
401 encrypt = atoi(pos);
402 os_memset(&mgmt, 0, sizeof(mgmt));
403 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
404 WLAN_FC_STYPE_DEAUTH);
405 os_memcpy(mgmt.da, addr, ETH_ALEN);
406 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
407 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
408 mgmt.u.deauth.reason_code = host_to_le16(reason);
409 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
410 IEEE80211_HDRLEN +
411 sizeof(mgmt.u.deauth),
412 encrypt) < 0)
413 return -1;
414 return 0;
415 }
416
417 #ifdef CONFIG_P2P_MANAGER
418 pos = os_strstr(txtaddr, " p2p=");
419 if (pos) {
420 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
421 atoi(pos + 5), addr);
422 }
423 #endif /* CONFIG_P2P_MANAGER */
424
425 if (os_strstr(txtaddr, " tx=0"))
426 hostapd_drv_sta_remove(hapd, addr);
427 else
428 hostapd_drv_sta_deauth(hapd, addr, reason);
429 sta = ap_get_sta(hapd, addr);
430 if (sta)
431 ap_sta_deauthenticate(hapd, sta, reason);
432 else if (addr[0] == 0xff)
433 hostapd_free_stas(hapd);
434
435 return 0;
436 }
437
438
hostapd_ctrl_iface_disassociate(struct hostapd_data * hapd,const char * txtaddr)439 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
440 const char *txtaddr)
441 {
442 u8 addr[ETH_ALEN];
443 struct sta_info *sta;
444 const char *pos;
445 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
446
447 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
448 txtaddr);
449
450 if (hwaddr_aton(txtaddr, addr))
451 return -1;
452
453 pos = os_strstr(txtaddr, " reason=");
454 if (pos)
455 reason = atoi(pos + 8);
456
457 pos = os_strstr(txtaddr, " test=");
458 if (pos) {
459 struct ieee80211_mgmt mgmt;
460 int encrypt;
461 if (!hapd->drv_priv || !hapd->driver->send_frame)
462 return -1;
463 pos += 6;
464 encrypt = atoi(pos);
465 os_memset(&mgmt, 0, sizeof(mgmt));
466 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
467 WLAN_FC_STYPE_DISASSOC);
468 os_memcpy(mgmt.da, addr, ETH_ALEN);
469 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
470 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
471 mgmt.u.disassoc.reason_code = host_to_le16(reason);
472 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
473 IEEE80211_HDRLEN +
474 sizeof(mgmt.u.deauth),
475 encrypt) < 0)
476 return -1;
477 return 0;
478 }
479
480 #ifdef CONFIG_P2P_MANAGER
481 pos = os_strstr(txtaddr, " p2p=");
482 if (pos) {
483 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
484 atoi(pos + 5), addr);
485 }
486 #endif /* CONFIG_P2P_MANAGER */
487
488 if (os_strstr(txtaddr, " tx=0"))
489 hostapd_drv_sta_remove(hapd, addr);
490 else
491 hostapd_drv_sta_disassoc(hapd, addr, reason);
492 sta = ap_get_sta(hapd, addr);
493 if (sta)
494 ap_sta_disassociate(hapd, sta, reason);
495 else if (addr[0] == 0xff)
496 hostapd_free_stas(hapd);
497
498 return 0;
499 }
500
501
502 #ifdef CONFIG_TAXONOMY
hostapd_ctrl_iface_signature(struct hostapd_data * hapd,const char * txtaddr,char * buf,size_t buflen)503 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd,
504 const char *txtaddr,
505 char *buf, size_t buflen)
506 {
507 u8 addr[ETH_ALEN];
508 struct sta_info *sta;
509
510 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr);
511
512 if (hwaddr_aton(txtaddr, addr))
513 return -1;
514
515 sta = ap_get_sta(hapd, addr);
516 if (!sta)
517 return -1;
518
519 return retrieve_sta_taxonomy(hapd, sta, buf, buflen);
520 }
521 #endif /* CONFIG_TAXONOMY */
522
523
hostapd_ctrl_iface_poll_sta(struct hostapd_data * hapd,const char * txtaddr)524 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd,
525 const char *txtaddr)
526 {
527 u8 addr[ETH_ALEN];
528 struct sta_info *sta;
529
530 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr);
531
532 if (hwaddr_aton(txtaddr, addr))
533 return -1;
534
535 sta = ap_get_sta(hapd, addr);
536 if (!sta)
537 return -1;
538
539 hostapd_drv_poll_client(hapd, hapd->own_addr, addr,
540 sta->flags & WLAN_STA_WMM);
541 return 0;
542 }
543
544
hostapd_ctrl_iface_status(struct hostapd_data * hapd,char * buf,size_t buflen)545 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
546 size_t buflen)
547 {
548 struct hostapd_iface *iface = hapd->iface;
549 int len = 0, ret;
550 size_t i;
551
552 ret = os_snprintf(buf + len, buflen - len,
553 "state=%s\n"
554 "phy=%s\n"
555 "freq=%d\n"
556 "num_sta_non_erp=%d\n"
557 "num_sta_no_short_slot_time=%d\n"
558 "num_sta_no_short_preamble=%d\n"
559 "olbc=%d\n"
560 "num_sta_ht_no_gf=%d\n"
561 "num_sta_no_ht=%d\n"
562 "num_sta_ht_20_mhz=%d\n"
563 "num_sta_ht40_intolerant=%d\n"
564 "olbc_ht=%d\n"
565 "ht_op_mode=0x%x\n",
566 hostapd_state_text(iface->state),
567 iface->phy,
568 iface->freq,
569 iface->num_sta_non_erp,
570 iface->num_sta_no_short_slot_time,
571 iface->num_sta_no_short_preamble,
572 iface->olbc,
573 iface->num_sta_ht_no_gf,
574 iface->num_sta_no_ht,
575 iface->num_sta_ht_20mhz,
576 iface->num_sta_ht40_intolerant,
577 iface->olbc_ht,
578 iface->ht_op_mode);
579 if (os_snprintf_error(buflen - len, ret))
580 return len;
581 len += ret;
582
583 if (!iface->cac_started || !iface->dfs_cac_ms) {
584 ret = os_snprintf(buf + len, buflen - len,
585 "cac_time_seconds=%d\n"
586 "cac_time_left_seconds=N/A\n",
587 iface->dfs_cac_ms / 1000);
588 } else {
589 /* CAC started and CAC time set - calculate remaining time */
590 struct os_reltime now;
591 unsigned int left_time;
592
593 os_reltime_age(&iface->dfs_cac_start, &now);
594 left_time = iface->dfs_cac_ms / 1000 - now.sec;
595 ret = os_snprintf(buf + len, buflen - len,
596 "cac_time_seconds=%u\n"
597 "cac_time_left_seconds=%u\n",
598 iface->dfs_cac_ms / 1000,
599 left_time);
600 }
601 if (os_snprintf_error(buflen - len, ret))
602 return len;
603 len += ret;
604
605 ret = os_snprintf(buf + len, buflen - len,
606 "channel=%u\n"
607 "secondary_channel=%d\n"
608 "ieee80211n=%d\n"
609 "ieee80211ac=%d\n",
610 iface->conf->channel,
611 iface->conf->ieee80211n && !hapd->conf->disable_11n ?
612 iface->conf->secondary_channel : 0,
613 iface->conf->ieee80211n && !hapd->conf->disable_11n,
614 iface->conf->ieee80211ac &&
615 !hapd->conf->disable_11ac);
616 if (os_snprintf_error(buflen - len, ret))
617 return len;
618 len += ret;
619 if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
620 ret = os_snprintf(buf + len, buflen - len,
621 "vht_oper_chwidth=%d\n"
622 "vht_oper_centr_freq_seg0_idx=%d\n"
623 "vht_oper_centr_freq_seg1_idx=%d\n",
624 iface->conf->vht_oper_chwidth,
625 iface->conf->vht_oper_centr_freq_seg0_idx,
626 iface->conf->vht_oper_centr_freq_seg1_idx);
627 if (os_snprintf_error(buflen - len, ret))
628 return len;
629 len += ret;
630 }
631
632 for (i = 0; i < iface->num_bss; i++) {
633 struct hostapd_data *bss = iface->bss[i];
634 ret = os_snprintf(buf + len, buflen - len,
635 "bss[%d]=%s\n"
636 "bssid[%d]=" MACSTR "\n"
637 "ssid[%d]=%s\n"
638 "num_sta[%d]=%d\n",
639 (int) i, bss->conf->iface,
640 (int) i, MAC2STR(bss->own_addr),
641 (int) i,
642 wpa_ssid_txt(bss->conf->ssid.ssid,
643 bss->conf->ssid.ssid_len),
644 (int) i, bss->num_sta);
645 if (os_snprintf_error(buflen - len, ret))
646 return len;
647 len += ret;
648 }
649
650 return len;
651 }
652
653
hostapd_parse_csa_settings(const char * pos,struct csa_settings * settings)654 int hostapd_parse_csa_settings(const char *pos,
655 struct csa_settings *settings)
656 {
657 char *end;
658
659 os_memset(settings, 0, sizeof(*settings));
660 settings->cs_count = strtol(pos, &end, 10);
661 if (pos == end) {
662 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
663 return -1;
664 }
665
666 settings->freq_params.freq = atoi(end);
667 if (settings->freq_params.freq == 0) {
668 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
669 return -1;
670 }
671
672 #define SET_CSA_SETTING(str) \
673 do { \
674 const char *pos2 = os_strstr(pos, " " #str "="); \
675 if (pos2) { \
676 pos2 += sizeof(" " #str "=") - 1; \
677 settings->freq_params.str = atoi(pos2); \
678 } \
679 } while (0)
680
681 SET_CSA_SETTING(center_freq1);
682 SET_CSA_SETTING(center_freq2);
683 SET_CSA_SETTING(bandwidth);
684 SET_CSA_SETTING(sec_channel_offset);
685 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
686 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
687 settings->block_tx = !!os_strstr(pos, " blocktx");
688 #undef SET_CSA_SETTING
689
690 return 0;
691 }
692
693
hostapd_ctrl_iface_stop_ap(struct hostapd_data * hapd)694 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
695 {
696 return hostapd_drv_stop_ap(hapd);
697 }
698
699
hostapd_ctrl_iface_pmksa_list(struct hostapd_data * hapd,char * buf,size_t len)700 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
701 size_t len)
702 {
703 return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
704 }
705
706
hostapd_ctrl_iface_pmksa_flush(struct hostapd_data * hapd)707 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
708 {
709 wpa_auth_pmksa_flush(hapd->wpa_auth);
710 }
711
712
hostapd_ctrl_iface_pmksa_add(struct hostapd_data * hapd,char * cmd)713 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd)
714 {
715 u8 spa[ETH_ALEN];
716 u8 pmkid[PMKID_LEN];
717 u8 pmk[PMK_LEN_MAX];
718 size_t pmk_len;
719 char *pos, *pos2;
720 int akmp = 0, expiration = 0;
721
722 /*
723 * Entry format:
724 * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp>
725 */
726
727 if (hwaddr_aton(cmd, spa))
728 return -1;
729
730 pos = os_strchr(cmd, ' ');
731 if (!pos)
732 return -1;
733 pos++;
734
735 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
736 return -1;
737
738 pos = os_strchr(pos, ' ');
739 if (!pos)
740 return -1;
741 pos++;
742
743 pos2 = os_strchr(pos, ' ');
744 if (!pos2)
745 return -1;
746 pmk_len = (pos2 - pos) / 2;
747 if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX ||
748 hexstr2bin(pos, pmk, pmk_len) < 0)
749 return -1;
750
751 pos = pos2 + 1;
752
753 if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
754 return -1;
755
756 return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
757 pmkid, expiration, akmp);
758 }
759
760
761 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
762 #ifdef CONFIG_MESH
763
hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data * hapd,const u8 * addr,char * buf,size_t len)764 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
765 const u8 *addr, char *buf, size_t len)
766 {
767 return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
768 }
769
770
hostapd_ctrl_iface_pmksa_create_entry(const u8 * aa,char * cmd)771 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
772 {
773 u8 spa[ETH_ALEN];
774 u8 pmkid[PMKID_LEN];
775 u8 pmk[PMK_LEN_MAX];
776 char *pos;
777 int expiration;
778
779 /*
780 * Entry format:
781 * <BSSID> <PMKID> <PMK> <expiration in seconds>
782 */
783
784 if (hwaddr_aton(cmd, spa))
785 return NULL;
786
787 pos = os_strchr(cmd, ' ');
788 if (!pos)
789 return NULL;
790 pos++;
791
792 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
793 return NULL;
794
795 pos = os_strchr(pos, ' ');
796 if (!pos)
797 return NULL;
798 pos++;
799
800 if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
801 return NULL;
802
803 pos = os_strchr(pos, ' ');
804 if (!pos)
805 return NULL;
806 pos++;
807
808 if (sscanf(pos, "%d", &expiration) != 1)
809 return NULL;
810
811 return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
812 }
813
814 #endif /* CONFIG_MESH */
815 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
816