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