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