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