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