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 #include "wnm_ap.h" 28 29 30 static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen, 31 size_t curr_len, const u8 *mcs_set) 32 { 33 int ret; 34 size_t len = curr_len; 35 36 ret = os_snprintf(buf + len, buflen - len, 37 "ht_mcs_bitmask="); 38 if (os_snprintf_error(buflen - len, ret)) 39 return len; 40 len += ret; 41 42 /* 77 first bits (+ 3 reserved bits) */ 43 len += wpa_snprintf_hex(buf + len, buflen - len, mcs_set, 10); 44 45 ret = os_snprintf(buf + len, buflen - len, "\n"); 46 if (os_snprintf_error(buflen - len, ret)) 47 return curr_len; 48 len += ret; 49 50 return len; 51 } 52 53 54 static int hostapd_get_sta_conn_time(struct sta_info *sta, 55 struct hostap_sta_driver_data *data, 56 char *buf, size_t buflen) 57 { 58 struct os_reltime age; 59 unsigned long secs; 60 int ret; 61 62 if (sta->connected_time.sec) { 63 /* Locally maintained time in AP mode */ 64 os_reltime_age(&sta->connected_time, &age); 65 secs = (unsigned long) age.sec; 66 } else if (data->flags & STA_DRV_DATA_CONN_TIME) { 67 /* Time from the driver in mesh mode */ 68 secs = data->connected_sec; 69 } else { 70 return 0; 71 } 72 73 ret = os_snprintf(buf, buflen, "connected_time=%lu\n", secs); 74 if (os_snprintf_error(buflen, ret)) 75 return 0; 76 return ret; 77 } 78 79 80 static int hostapd_get_sta_info(struct hostapd_data *hapd, 81 struct sta_info *sta, 82 char *buf, size_t buflen) 83 { 84 struct hostap_sta_driver_data data; 85 int ret; 86 int len = 0; 87 88 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) 89 return 0; 90 91 ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n" 92 "rx_bytes=%llu\ntx_bytes=%llu\ninactive_msec=%lu\n" 93 "signal=%d\n", 94 data.rx_packets, data.tx_packets, 95 data.rx_bytes, data.tx_bytes, data.inactive_msec, 96 data.signal); 97 if (os_snprintf_error(buflen, ret)) 98 return 0; 99 len += ret; 100 101 ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu", 102 data.current_rx_rate / 100); 103 if (os_snprintf_error(buflen - len, ret)) 104 return len; 105 len += ret; 106 if (data.flags & STA_DRV_DATA_RX_MCS) { 107 ret = os_snprintf(buf + len, buflen - len, " mcs %u", 108 data.rx_mcs); 109 if (!os_snprintf_error(buflen - len, ret)) 110 len += ret; 111 } 112 if (data.flags & STA_DRV_DATA_RX_VHT_MCS) { 113 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u", 114 data.rx_vhtmcs); 115 if (!os_snprintf_error(buflen - len, ret)) 116 len += ret; 117 } 118 if (data.flags & STA_DRV_DATA_RX_VHT_NSS) { 119 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u", 120 data.rx_vht_nss); 121 if (!os_snprintf_error(buflen - len, ret)) 122 len += ret; 123 } 124 if (data.flags & STA_DRV_DATA_RX_SHORT_GI) { 125 ret = os_snprintf(buf + len, buflen - len, " shortGI"); 126 if (!os_snprintf_error(buflen - len, ret)) 127 len += ret; 128 } 129 ret = os_snprintf(buf + len, buflen - len, "\n"); 130 if (!os_snprintf_error(buflen - len, ret)) 131 len += ret; 132 133 ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu", 134 data.current_tx_rate / 100); 135 if (os_snprintf_error(buflen - len, ret)) 136 return len; 137 len += ret; 138 if (data.flags & STA_DRV_DATA_TX_MCS) { 139 ret = os_snprintf(buf + len, buflen - len, " mcs %u", 140 data.tx_mcs); 141 if (!os_snprintf_error(buflen - len, ret)) 142 len += ret; 143 } 144 if (data.flags & STA_DRV_DATA_TX_VHT_MCS) { 145 ret = os_snprintf(buf + len, buflen - len, " vhtmcs %u", 146 data.tx_vhtmcs); 147 if (!os_snprintf_error(buflen - len, ret)) 148 len += ret; 149 } 150 if (data.flags & STA_DRV_DATA_TX_VHT_NSS) { 151 ret = os_snprintf(buf + len, buflen - len, " vhtnss %u", 152 data.tx_vht_nss); 153 if (!os_snprintf_error(buflen - len, ret)) 154 len += ret; 155 } 156 if (data.flags & STA_DRV_DATA_TX_SHORT_GI) { 157 ret = os_snprintf(buf + len, buflen - len, " shortGI"); 158 if (!os_snprintf_error(buflen - len, ret)) 159 len += ret; 160 } 161 ret = os_snprintf(buf + len, buflen - len, "\n"); 162 if (!os_snprintf_error(buflen - len, ret)) 163 len += ret; 164 165 if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) { 166 ret = os_snprintf(buf + len, buflen - len, 167 "rx_vht_mcs_map=%04x\n" 168 "tx_vht_mcs_map=%04x\n", 169 le_to_host16(sta->vht_capabilities-> 170 vht_supported_mcs_set.rx_map), 171 le_to_host16(sta->vht_capabilities-> 172 vht_supported_mcs_set.tx_map)); 173 if (!os_snprintf_error(buflen - len, ret)) 174 len += ret; 175 } 176 177 if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) { 178 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len, 179 sta->ht_capabilities-> 180 supported_mcs_set); 181 } 182 183 if (data.flags & STA_DRV_DATA_LAST_ACK_RSSI) { 184 ret = os_snprintf(buf + len, buflen - len, 185 "last_ack_signal=%d\n", data.last_ack_rssi); 186 if (!os_snprintf_error(buflen - len, ret)) 187 len += ret; 188 } 189 190 len += hostapd_get_sta_conn_time(sta, &data, buf + len, buflen - len); 191 192 return len; 193 } 194 195 196 static const char * timeout_next_str(int val) 197 { 198 switch (val) { 199 case STA_NULLFUNC: 200 return "NULLFUNC POLL"; 201 case STA_DISASSOC: 202 return "DISASSOC"; 203 case STA_DEAUTH: 204 return "DEAUTH"; 205 case STA_REMOVE: 206 return "REMOVE"; 207 case STA_DISASSOC_FROM_CLI: 208 return "DISASSOC_FROM_CLI"; 209 default: 210 return "?"; 211 } 212 } 213 214 215 static const char * hw_mode_str(enum hostapd_hw_mode mode) 216 { 217 switch (mode) { 218 case HOSTAPD_MODE_IEEE80211B: 219 return "b"; 220 case HOSTAPD_MODE_IEEE80211G: 221 return "g"; 222 case HOSTAPD_MODE_IEEE80211A: 223 return "a"; 224 case HOSTAPD_MODE_IEEE80211AD: 225 return "ad"; 226 case HOSTAPD_MODE_IEEE80211ANY: 227 return "any"; 228 case NUM_HOSTAPD_MODES: 229 return "invalid"; 230 } 231 return "unknown"; 232 } 233 234 235 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, 236 struct sta_info *sta, 237 char *buf, size_t buflen) 238 { 239 int len, res, ret, i; 240 const char *keyid; 241 const u8 *dpp_pkhash; 242 243 if (!sta) 244 return 0; 245 246 len = 0; 247 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=", 248 MAC2STR(sta->addr)); 249 if (os_snprintf_error(buflen - len, ret)) 250 return len; 251 len += ret; 252 253 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len); 254 if (ret < 0) 255 return len; 256 len += ret; 257 258 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n" 259 "listen_interval=%d\nsupported_rates=", 260 sta->aid, sta->capability, sta->listen_interval); 261 if (os_snprintf_error(buflen - len, ret)) 262 return len; 263 len += ret; 264 265 for (i = 0; i < sta->supported_rates_len; i++) { 266 ret = os_snprintf(buf + len, buflen - len, "%02x%s", 267 sta->supported_rates[i], 268 i + 1 < sta->supported_rates_len ? " " : ""); 269 if (os_snprintf_error(buflen - len, ret)) 270 return len; 271 len += ret; 272 } 273 274 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n", 275 timeout_next_str(sta->timeout_next)); 276 if (os_snprintf_error(buflen - len, ret)) 277 return len; 278 len += ret; 279 280 if (sta->max_idle_period) { 281 ret = os_snprintf(buf + len, buflen - len, 282 "max_idle_period=%d\n", sta->max_idle_period); 283 if (os_snprintf_error(buflen - len, ret)) 284 return len; 285 len += ret; 286 } 287 288 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); 289 if (res >= 0) 290 len += res; 291 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len); 292 if (res >= 0) 293 len += res; 294 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); 295 if (res >= 0) 296 len += res; 297 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len, 298 buflen - len); 299 if (res >= 0) 300 len += res; 301 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len); 302 if (res >= 0) 303 len += res; 304 305 len += hostapd_get_sta_info(hapd, sta, buf + len, buflen - len); 306 307 #ifdef CONFIG_SAE 308 if (sta->sae && sta->sae->state == SAE_ACCEPTED) { 309 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n", 310 sta->sae->group); 311 if (!os_snprintf_error(buflen - len, res)) 312 len += res; 313 } 314 315 if (sta->sae && sta->sae->tmp) { 316 const u8 *pos; 317 unsigned int j, count; 318 struct wpabuf *groups = sta->sae->tmp->peer_rejected_groups; 319 320 res = os_snprintf(buf + len, buflen - len, 321 "sae_rejected_groups="); 322 if (!os_snprintf_error(buflen - len, res)) 323 len += res; 324 325 if (groups) { 326 pos = wpabuf_head(groups); 327 count = wpabuf_len(groups) / 2; 328 } else { 329 pos = NULL; 330 count = 0; 331 } 332 for (j = 0; pos && j < count; j++) { 333 res = os_snprintf(buf + len, buflen - len, "%s%d", 334 j == 0 ? "" : " ", WPA_GET_LE16(pos)); 335 if (!os_snprintf_error(buflen - len, res)) 336 len += res; 337 pos += 2; 338 } 339 340 res = os_snprintf(buf + len, buflen - len, "\n"); 341 if (!os_snprintf_error(buflen - len, res)) 342 len += res; 343 } 344 #endif /* CONFIG_SAE */ 345 346 if (sta->vlan_id > 0) { 347 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n", 348 sta->vlan_id); 349 if (!os_snprintf_error(buflen - len, res)) 350 len += res; 351 } 352 353 res = mbo_ap_get_info(sta, buf + len, buflen - len); 354 if (res >= 0) 355 len += res; 356 357 if (sta->supp_op_classes && 358 buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) { 359 res = os_snprintf(buf + len, buflen - len, "supp_op_classes="); 360 if (!os_snprintf_error(buflen - len, res)) 361 len += res; 362 len += wpa_snprintf_hex(buf + len, buflen - len, 363 sta->supp_op_classes + 1, 364 sta->supp_op_classes[0]); 365 res = os_snprintf(buf + len, buflen - len, "\n"); 366 if (!os_snprintf_error(buflen - len, res)) 367 len += res; 368 } 369 370 if (sta->power_capab) { 371 ret = os_snprintf(buf + len, buflen - len, 372 "min_txpower=%d\n" 373 "max_txpower=%d\n", 374 sta->min_tx_power, sta->max_tx_power); 375 if (!os_snprintf_error(buflen - len, ret)) 376 len += ret; 377 } 378 379 #ifdef CONFIG_IEEE80211AX 380 if ((sta->flags & WLAN_STA_HE) && sta->he_capab) { 381 res = os_snprintf(buf + len, buflen - len, "he_capab="); 382 if (!os_snprintf_error(buflen - len, res)) 383 len += res; 384 len += wpa_snprintf_hex(buf + len, buflen - len, 385 (const u8 *) sta->he_capab, 386 sta->he_capab_len); 387 res = os_snprintf(buf + len, buflen - len, "\n"); 388 if (!os_snprintf_error(buflen - len, res)) 389 len += res; 390 } 391 #endif /* CONFIG_IEEE80211AX */ 392 393 #ifdef CONFIG_IEEE80211BE 394 if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) { 395 res = os_snprintf(buf + len, buflen - len, "eht_capab="); 396 if (!os_snprintf_error(buflen - len, res)) 397 len += res; 398 len += wpa_snprintf_hex(buf + len, buflen - len, 399 (const u8 *) sta->eht_capab, 400 sta->eht_capab_len); 401 res = os_snprintf(buf + len, buflen - len, "\n"); 402 if (!os_snprintf_error(buflen - len, res)) 403 len += res; 404 } 405 #endif /* CONFIG_IEEE80211BE */ 406 407 #ifdef CONFIG_IEEE80211AC 408 if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) { 409 res = os_snprintf(buf + len, buflen - len, 410 "vht_caps_info=0x%08x\n", 411 le_to_host32(sta->vht_capabilities-> 412 vht_capabilities_info)); 413 if (!os_snprintf_error(buflen - len, res)) 414 len += res; 415 416 res = os_snprintf(buf + len, buflen - len, "vht_capab="); 417 if (!os_snprintf_error(buflen - len, res)) 418 len += res; 419 len += wpa_snprintf_hex(buf + len, buflen - len, 420 (const u8 *) sta->vht_capabilities, 421 sizeof(*sta->vht_capabilities)); 422 res = os_snprintf(buf + len, buflen - len, "\n"); 423 if (!os_snprintf_error(buflen - len, res)) 424 len += res; 425 } 426 #endif /* CONFIG_IEEE80211AC */ 427 428 if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) { 429 res = os_snprintf(buf + len, buflen - len, 430 "ht_caps_info=0x%04x\n", 431 le_to_host16(sta->ht_capabilities-> 432 ht_capabilities_info)); 433 if (!os_snprintf_error(buflen - len, res)) 434 len += res; 435 } 436 437 if (sta->ext_capability && 438 buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) { 439 res = os_snprintf(buf + len, buflen - len, "ext_capab="); 440 if (!os_snprintf_error(buflen - len, res)) 441 len += res; 442 len += wpa_snprintf_hex(buf + len, buflen - len, 443 sta->ext_capability + 1, 444 sta->ext_capability[0]); 445 res = os_snprintf(buf + len, buflen - len, "\n"); 446 if (!os_snprintf_error(buflen - len, res)) 447 len += res; 448 } 449 450 if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) { 451 ret = os_snprintf(buf + len, buflen - len, 452 "wds_sta_ifname=%s\n", sta->ifname_wds); 453 if (!os_snprintf_error(buflen - len, ret)) 454 len += ret; 455 } 456 457 keyid = ap_sta_wpa_get_keyid(hapd, sta); 458 if (keyid) { 459 ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid); 460 if (!os_snprintf_error(buflen - len, ret)) 461 len += ret; 462 } 463 464 dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta); 465 if (dpp_pkhash) { 466 ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash="); 467 if (!os_snprintf_error(buflen - len, ret)) 468 len += ret; 469 len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash, 470 SHA256_MAC_LEN); 471 ret = os_snprintf(buf + len, buflen - len, "\n"); 472 if (!os_snprintf_error(buflen - len, ret)) 473 len += ret; 474 } 475 476 #ifdef CONFIG_IEEE80211BE 477 if (sta->mld_info.mld_sta) { 478 for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) { 479 if (!sta->mld_info.links[i].valid) 480 continue; 481 ret = os_snprintf( 482 buf + len, buflen - len, 483 "peer_addr[%d]=" MACSTR "\n", 484 i, MAC2STR(sta->mld_info.links[i].peer_addr)); 485 if (!os_snprintf_error(buflen - len, ret)) 486 len += ret; 487 } 488 } 489 #endif /* CONFIG_IEEE80211BE */ 490 491 return len; 492 } 493 494 495 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, 496 char *buf, size_t buflen) 497 { 498 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen); 499 } 500 501 502 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, 503 char *buf, size_t buflen) 504 { 505 u8 addr[ETH_ALEN]; 506 int ret; 507 const char *pos; 508 struct sta_info *sta; 509 510 if (hwaddr_aton(txtaddr, addr)) { 511 ret = os_snprintf(buf, buflen, "FAIL\n"); 512 if (os_snprintf_error(buflen, ret)) 513 return 0; 514 return ret; 515 } 516 517 sta = ap_get_sta(hapd, addr); 518 if (sta == NULL) 519 return -1; 520 521 pos = os_strchr(txtaddr, ' '); 522 if (pos) { 523 pos++; 524 525 #ifdef HOSTAPD_DUMP_STATE 526 if (os_strcmp(pos, "eapol") == 0) { 527 if (sta->eapol_sm == NULL) 528 return -1; 529 return eapol_auth_dump_state(sta->eapol_sm, buf, 530 buflen); 531 } 532 #endif /* HOSTAPD_DUMP_STATE */ 533 534 return -1; 535 } 536 537 ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen); 538 ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret); 539 540 return ret; 541 } 542 543 544 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, 545 char *buf, size_t buflen) 546 { 547 u8 addr[ETH_ALEN]; 548 struct sta_info *sta; 549 int ret; 550 551 if (hwaddr_aton(txtaddr, addr) || 552 (sta = ap_get_sta(hapd, addr)) == NULL) { 553 ret = os_snprintf(buf, buflen, "FAIL\n"); 554 if (os_snprintf_error(buflen, ret)) 555 return 0; 556 return ret; 557 } 558 559 if (!sta->next) 560 return 0; 561 562 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); 563 } 564 565 566 #ifdef CONFIG_P2P_MANAGER 567 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, 568 u8 minor_reason_code, const u8 *addr) 569 { 570 struct ieee80211_mgmt *mgmt; 571 int ret; 572 u8 *pos; 573 574 mgmt = os_zalloc(sizeof(*mgmt) + 100); 575 if (mgmt == NULL) 576 return -1; 577 578 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); 579 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR 580 " with minor reason code %u (stype=%u (%s))", 581 MAC2STR(addr), minor_reason_code, stype, 582 fc2str(le_to_host16(mgmt->frame_control))); 583 584 os_memcpy(mgmt->da, addr, ETH_ALEN); 585 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 586 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 587 if (stype == WLAN_FC_STYPE_DEAUTH) { 588 mgmt->u.deauth.reason_code = 589 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 590 pos = mgmt->u.deauth.variable; 591 } else { 592 mgmt->u.disassoc.reason_code = 593 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 594 pos = mgmt->u.disassoc.variable; 595 } 596 597 *pos++ = WLAN_EID_VENDOR_SPECIFIC; 598 *pos++ = 4 + 3 + 1; 599 WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE); 600 pos += 4; 601 602 *pos++ = P2P_ATTR_MINOR_REASON_CODE; 603 WPA_PUT_LE16(pos, 1); 604 pos += 2; 605 *pos++ = minor_reason_code; 606 607 ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0, 608 0); 609 os_free(mgmt); 610 611 return ret < 0 ? -1 : 0; 612 } 613 #endif /* CONFIG_P2P_MANAGER */ 614 615 616 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, 617 const char *txtaddr) 618 { 619 u8 addr[ETH_ALEN]; 620 struct sta_info *sta; 621 const char *pos; 622 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; 623 624 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", 625 txtaddr); 626 627 if (hwaddr_aton(txtaddr, addr)) 628 return -1; 629 630 pos = os_strstr(txtaddr, " reason="); 631 if (pos) 632 reason = atoi(pos + 8); 633 634 pos = os_strstr(txtaddr, " test="); 635 if (pos) { 636 struct ieee80211_mgmt mgmt; 637 int encrypt; 638 639 pos += 6; 640 encrypt = atoi(pos); 641 os_memset(&mgmt, 0, sizeof(mgmt)); 642 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 643 WLAN_FC_STYPE_DEAUTH); 644 os_memcpy(mgmt.da, addr, ETH_ALEN); 645 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 646 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 647 mgmt.u.deauth.reason_code = host_to_le16(reason); 648 if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt, 649 IEEE80211_HDRLEN + 650 sizeof(mgmt.u.deauth), 651 0, NULL, 0, !encrypt) < 0) 652 return -1; 653 return 0; 654 } 655 656 #ifdef CONFIG_P2P_MANAGER 657 pos = os_strstr(txtaddr, " p2p="); 658 if (pos) { 659 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH, 660 atoi(pos + 5), addr); 661 } 662 #endif /* CONFIG_P2P_MANAGER */ 663 664 if (os_strstr(txtaddr, " tx=0")) 665 hostapd_drv_sta_remove(hapd, addr); 666 else 667 hostapd_drv_sta_deauth(hapd, addr, reason); 668 sta = ap_get_sta(hapd, addr); 669 if (sta) 670 ap_sta_deauthenticate(hapd, sta, reason); 671 else if (addr[0] == 0xff) 672 hostapd_free_stas(hapd); 673 674 return 0; 675 } 676 677 678 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, 679 const char *txtaddr) 680 { 681 u8 addr[ETH_ALEN]; 682 struct sta_info *sta; 683 const char *pos; 684 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; 685 686 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", 687 txtaddr); 688 689 if (hwaddr_aton(txtaddr, addr)) 690 return -1; 691 692 pos = os_strstr(txtaddr, " reason="); 693 if (pos) 694 reason = atoi(pos + 8); 695 696 pos = os_strstr(txtaddr, " test="); 697 if (pos) { 698 struct ieee80211_mgmt mgmt; 699 int encrypt; 700 701 pos += 6; 702 encrypt = atoi(pos); 703 os_memset(&mgmt, 0, sizeof(mgmt)); 704 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 705 WLAN_FC_STYPE_DISASSOC); 706 os_memcpy(mgmt.da, addr, ETH_ALEN); 707 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 708 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 709 mgmt.u.disassoc.reason_code = host_to_le16(reason); 710 if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt, 711 IEEE80211_HDRLEN + 712 sizeof(mgmt.u.deauth), 713 0, NULL, 0, !encrypt) < 0) 714 return -1; 715 return 0; 716 } 717 718 #ifdef CONFIG_P2P_MANAGER 719 pos = os_strstr(txtaddr, " p2p="); 720 if (pos) { 721 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC, 722 atoi(pos + 5), addr); 723 } 724 #endif /* CONFIG_P2P_MANAGER */ 725 726 if (os_strstr(txtaddr, " tx=0")) 727 hostapd_drv_sta_remove(hapd, addr); 728 else 729 hostapd_drv_sta_disassoc(hapd, addr, reason); 730 sta = ap_get_sta(hapd, addr); 731 if (sta) 732 ap_sta_disassociate(hapd, sta, reason); 733 else if (addr[0] == 0xff) 734 hostapd_free_stas(hapd); 735 736 return 0; 737 } 738 739 740 #ifdef CONFIG_TAXONOMY 741 int hostapd_ctrl_iface_signature(struct hostapd_data *hapd, 742 const char *txtaddr, 743 char *buf, size_t buflen) 744 { 745 u8 addr[ETH_ALEN]; 746 struct sta_info *sta; 747 748 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE SIGNATURE %s", txtaddr); 749 750 if (hwaddr_aton(txtaddr, addr)) 751 return -1; 752 753 sta = ap_get_sta(hapd, addr); 754 if (!sta) 755 return -1; 756 757 return retrieve_sta_taxonomy(hapd, sta, buf, buflen); 758 } 759 #endif /* CONFIG_TAXONOMY */ 760 761 762 int hostapd_ctrl_iface_poll_sta(struct hostapd_data *hapd, 763 const char *txtaddr) 764 { 765 u8 addr[ETH_ALEN]; 766 struct sta_info *sta; 767 768 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE POLL_STA %s", txtaddr); 769 770 if (hwaddr_aton(txtaddr, addr)) 771 return -1; 772 773 sta = ap_get_sta(hapd, addr); 774 if (!sta) 775 return -1; 776 777 hostapd_drv_poll_client(hapd, hapd->own_addr, addr, 778 sta->flags & WLAN_STA_WMM); 779 return 0; 780 } 781 782 783 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, 784 size_t buflen) 785 { 786 struct hostapd_iface *iface = hapd->iface; 787 struct hostapd_hw_modes *mode = iface->current_mode; 788 struct hostapd_config *iconf = hapd->iconf; 789 int len = 0, ret, j; 790 size_t i; 791 792 ret = os_snprintf(buf + len, buflen - len, 793 "state=%s\n" 794 "phy=%s\n" 795 "freq=%d\n" 796 "num_sta_non_erp=%d\n" 797 "num_sta_no_short_slot_time=%d\n" 798 "num_sta_no_short_preamble=%d\n" 799 "olbc=%d\n" 800 "num_sta_ht_no_gf=%d\n" 801 "num_sta_no_ht=%d\n" 802 "num_sta_ht_20_mhz=%d\n" 803 "num_sta_ht40_intolerant=%d\n" 804 "olbc_ht=%d\n" 805 "ht_op_mode=0x%x\n", 806 hostapd_state_text(iface->state), 807 iface->phy, 808 iface->freq, 809 iface->num_sta_non_erp, 810 iface->num_sta_no_short_slot_time, 811 iface->num_sta_no_short_preamble, 812 iface->olbc, 813 iface->num_sta_ht_no_gf, 814 iface->num_sta_no_ht, 815 iface->num_sta_ht_20mhz, 816 iface->num_sta_ht40_intolerant, 817 iface->olbc_ht, 818 iface->ht_op_mode); 819 if (os_snprintf_error(buflen - len, ret)) 820 return len; 821 len += ret; 822 823 if (mode) { 824 ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n", 825 hw_mode_str(mode->mode)); 826 if (os_snprintf_error(buflen - len, ret)) 827 return len; 828 len += ret; 829 } 830 831 if (iconf->country[0] && iconf->country[1]) { 832 ret = os_snprintf(buf + len, buflen - len, 833 "country_code=%c%c\ncountry3=0x%X\n", 834 iconf->country[0], iconf->country[1], 835 iconf->country[2]); 836 if (os_snprintf_error(buflen - len, ret)) 837 return len; 838 len += ret; 839 } 840 841 if (!iface->cac_started || !iface->dfs_cac_ms) { 842 ret = os_snprintf(buf + len, buflen - len, 843 "cac_time_seconds=%d\n" 844 "cac_time_left_seconds=N/A\n", 845 iface->dfs_cac_ms / 1000); 846 } else { 847 /* CAC started and CAC time set - calculate remaining time */ 848 struct os_reltime now; 849 long left_time; 850 851 os_reltime_age(&iface->dfs_cac_start, &now); 852 left_time = (long) iface->dfs_cac_ms / 1000 - now.sec; 853 ret = os_snprintf(buf + len, buflen - len, 854 "cac_time_seconds=%u\n" 855 "cac_time_left_seconds=%lu\n", 856 iface->dfs_cac_ms / 1000, 857 left_time > 0 ? left_time : 0); 858 } 859 if (os_snprintf_error(buflen - len, ret)) 860 return len; 861 len += ret; 862 863 ret = os_snprintf(buf + len, buflen - len, 864 "channel=%u\n" 865 "edmg_enable=%d\n" 866 "edmg_channel=%d\n" 867 "secondary_channel=%d\n" 868 "ieee80211n=%d\n" 869 "ieee80211ac=%d\n" 870 "ieee80211ax=%d\n" 871 "ieee80211be=%d\n" 872 "beacon_int=%u\n" 873 "dtim_period=%d\n", 874 iface->conf->channel, 875 iface->conf->enable_edmg, 876 iface->conf->edmg_channel, 877 iface->conf->ieee80211n && !hapd->conf->disable_11n ? 878 iface->conf->secondary_channel : 0, 879 iface->conf->ieee80211n && !hapd->conf->disable_11n, 880 iface->conf->ieee80211ac && 881 !hapd->conf->disable_11ac, 882 iface->conf->ieee80211ax && 883 !hapd->conf->disable_11ax, 884 iface->conf->ieee80211be && 885 !hapd->conf->disable_11be, 886 iface->conf->beacon_int, 887 hapd->conf->dtim_period); 888 if (os_snprintf_error(buflen - len, ret)) 889 return len; 890 len += ret; 891 892 #ifdef CONFIG_IEEE80211BE 893 if (iface->conf->ieee80211be && !hapd->conf->disable_11be) { 894 ret = os_snprintf(buf + len, buflen - len, 895 "eht_oper_chwidth=%d\n" 896 "eht_oper_centr_freq_seg0_idx=%d\n", 897 iface->conf->eht_oper_chwidth, 898 iface->conf->eht_oper_centr_freq_seg0_idx); 899 if (os_snprintf_error(buflen - len, ret)) 900 return len; 901 len += ret; 902 903 if (is_6ghz_op_class(iface->conf->op_class) && 904 hostapd_get_oper_chwidth(iface->conf) == 905 CONF_OPER_CHWIDTH_320MHZ) { 906 ret = os_snprintf(buf + len, buflen - len, 907 "eht_bw320_offset=%d\n", 908 iface->conf->eht_bw320_offset); 909 if (os_snprintf_error(buflen - len, ret)) 910 return len; 911 len += ret; 912 } 913 914 if (hapd->conf->mld_ap) { 915 struct hostapd_data *link_bss; 916 917 ret = os_snprintf(buf + len, buflen - len, 918 "num_links=%d\n", 919 hapd->mld->num_links); 920 if (os_snprintf_error(buflen - len, ret)) 921 return len; 922 len += ret; 923 924 /* Self BSS */ 925 ret = os_snprintf(buf + len, buflen - len, 926 "link_id=%d\n" 927 "link_addr=" MACSTR "\n", 928 hapd->mld_link_id, 929 MAC2STR(hapd->own_addr)); 930 if (os_snprintf_error(buflen - len, ret)) 931 return len; 932 len += ret; 933 934 /* Partner BSSs */ 935 for_each_mld_link(link_bss, hapd) { 936 if (link_bss == hapd) 937 continue; 938 939 ret = os_snprintf(buf + len, buflen - len, 940 "partner_link[%d]=" MACSTR 941 "\n", 942 link_bss->mld_link_id, 943 MAC2STR(link_bss->own_addr)); 944 if (os_snprintf_error(buflen - len, ret)) 945 return len; 946 len += ret; 947 } 948 } 949 } 950 #endif /* CONFIG_IEEE80211BE */ 951 952 #ifdef CONFIG_IEEE80211AX 953 if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) { 954 ret = os_snprintf(buf + len, buflen - len, 955 "he_oper_chwidth=%d\n" 956 "he_oper_centr_freq_seg0_idx=%d\n" 957 "he_oper_centr_freq_seg1_idx=%d\n", 958 iface->conf->he_oper_chwidth, 959 iface->conf->he_oper_centr_freq_seg0_idx, 960 iface->conf->he_oper_centr_freq_seg1_idx); 961 if (os_snprintf_error(buflen - len, ret)) 962 return len; 963 len += ret; 964 965 if (!iconf->he_op.he_bss_color_disabled && 966 iconf->he_op.he_bss_color) { 967 ret = os_snprintf(buf + len, buflen - len, 968 "he_bss_color=%d\n", 969 iconf->he_op.he_bss_color); 970 if (os_snprintf_error(buflen - len, ret)) 971 return len; 972 len += ret; 973 } 974 } 975 #endif /* CONFIG_IEEE80211AX */ 976 977 if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) { 978 ret = os_snprintf(buf + len, buflen - len, 979 "vht_oper_chwidth=%d\n" 980 "vht_oper_centr_freq_seg0_idx=%d\n" 981 "vht_oper_centr_freq_seg1_idx=%d\n" 982 "vht_caps_info=%08x\n", 983 iface->conf->vht_oper_chwidth, 984 iface->conf->vht_oper_centr_freq_seg0_idx, 985 iface->conf->vht_oper_centr_freq_seg1_idx, 986 iface->conf->vht_capab); 987 if (os_snprintf_error(buflen - len, ret)) 988 return len; 989 len += ret; 990 } 991 992 if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) { 993 u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]); 994 u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]); 995 996 ret = os_snprintf(buf + len, buflen - len, 997 "rx_vht_mcs_map=%04x\n" 998 "tx_vht_mcs_map=%04x\n", 999 rxmap, txmap); 1000 if (os_snprintf_error(buflen - len, ret)) 1001 return len; 1002 len += ret; 1003 } 1004 1005 if (iface->conf->ieee80211n && !hapd->conf->disable_11n) { 1006 ret = os_snprintf(buf + len, buflen - len, 1007 "ht_caps_info=%04x\n", 1008 hapd->iconf->ht_capab); 1009 if (os_snprintf_error(buflen - len, ret)) 1010 return len; 1011 len += ret; 1012 } 1013 1014 if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) { 1015 len = hostapd_write_ht_mcs_bitmask(buf, buflen, len, 1016 mode->mcs_set); 1017 } 1018 1019 if (iface->current_rates && iface->num_rates) { 1020 ret = os_snprintf(buf + len, buflen - len, "supported_rates="); 1021 if (os_snprintf_error(buflen - len, ret)) 1022 return len; 1023 len += ret; 1024 1025 for (j = 0; j < iface->num_rates; j++) { 1026 ret = os_snprintf(buf + len, buflen - len, "%s%02x", 1027 j > 0 ? " " : "", 1028 iface->current_rates[j].rate / 5); 1029 if (os_snprintf_error(buflen - len, ret)) 1030 return len; 1031 len += ret; 1032 } 1033 ret = os_snprintf(buf + len, buflen - len, "\n"); 1034 if (os_snprintf_error(buflen - len, ret)) 1035 return len; 1036 len += ret; 1037 } 1038 1039 for (j = 0; mode && j < mode->num_channels; j++) { 1040 if (mode->channels[j].freq == iface->freq) { 1041 ret = os_snprintf(buf + len, buflen - len, 1042 "max_txpower=%u\n", 1043 mode->channels[j].max_tx_power); 1044 if (os_snprintf_error(buflen - len, ret)) 1045 return len; 1046 len += ret; 1047 break; 1048 } 1049 } 1050 1051 for (i = 0; i < iface->num_bss; i++) { 1052 struct hostapd_data *bss = iface->bss[i]; 1053 ret = os_snprintf(buf + len, buflen - len, 1054 "bss[%d]=%s\n" 1055 "bssid[%d]=" MACSTR "\n" 1056 "ssid[%d]=%s\n" 1057 "num_sta[%d]=%d\n", 1058 (int) i, bss->conf->iface, 1059 (int) i, MAC2STR(bss->own_addr), 1060 (int) i, 1061 wpa_ssid_txt(bss->conf->ssid.ssid, 1062 bss->conf->ssid.ssid_len), 1063 (int) i, bss->num_sta); 1064 if (os_snprintf_error(buflen - len, ret)) 1065 return len; 1066 len += ret; 1067 1068 #ifdef CONFIG_IEEE80211BE 1069 if (bss->conf->mld_ap) { 1070 ret = os_snprintf(buf + len, buflen - len, 1071 "mld_addr[%d]=" MACSTR "\n" 1072 "mld_id[%d]=%d\n" 1073 "mld_link_id[%d]=%d\n", 1074 (int) i, MAC2STR(bss->mld->mld_addr), 1075 (int) i, hostapd_get_mld_id(bss), 1076 (int) i, bss->mld_link_id); 1077 if (os_snprintf_error(buflen - len, ret)) 1078 return len; 1079 len += ret; 1080 } 1081 #endif /* CONFIG_IEEE80211BE */ 1082 } 1083 1084 if (hapd->conf->chan_util_avg_period) { 1085 ret = os_snprintf(buf + len, buflen - len, 1086 "chan_util_avg=%u\n", 1087 iface->chan_util_average); 1088 if (os_snprintf_error(buflen - len, ret)) 1089 return len; 1090 len += ret; 1091 } 1092 1093 return len; 1094 } 1095 1096 1097 int hostapd_parse_csa_settings(const char *pos, 1098 struct csa_settings *settings) 1099 { 1100 char *end; 1101 1102 os_memset(settings, 0, sizeof(*settings)); 1103 settings->cs_count = strtol(pos, &end, 10); 1104 if (pos == end) { 1105 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided"); 1106 return -1; 1107 } 1108 1109 settings->freq_params.freq = atoi(end); 1110 if (settings->freq_params.freq == 0) { 1111 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided"); 1112 return -1; 1113 } 1114 1115 #define SET_CSA_SETTING(str) \ 1116 do { \ 1117 const char *pos2 = os_strstr(pos, " " #str "="); \ 1118 if (pos2) { \ 1119 pos2 += sizeof(" " #str "=") - 1; \ 1120 settings->freq_params.str = atoi(pos2); \ 1121 } \ 1122 } while (0) 1123 1124 #define SET_CSA_SETTING_EXT(str) \ 1125 do { \ 1126 const char *pos2 = os_strstr(pos, " " #str "="); \ 1127 if (pos2) { \ 1128 pos2 += sizeof(" " #str "=") - 1; \ 1129 settings->str = atoi(pos2); \ 1130 } \ 1131 } while (0) 1132 1133 SET_CSA_SETTING(center_freq1); 1134 SET_CSA_SETTING(center_freq2); 1135 SET_CSA_SETTING(bandwidth); 1136 SET_CSA_SETTING(sec_channel_offset); 1137 SET_CSA_SETTING_EXT(punct_bitmap); 1138 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht"); 1139 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht"); 1140 settings->freq_params.he_enabled = !!os_strstr(pos, " he"); 1141 settings->freq_params.eht_enabled = !!os_strstr(pos, " eht"); 1142 settings->block_tx = !!os_strstr(pos, " blocktx"); 1143 #undef SET_CSA_SETTING 1144 #undef SET_CSA_SETTING_EXT 1145 1146 return 0; 1147 } 1148 1149 1150 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd) 1151 { 1152 return hostapd_drv_stop_ap(hapd); 1153 } 1154 1155 1156 int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf, 1157 size_t len) 1158 { 1159 return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len); 1160 } 1161 1162 1163 void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd) 1164 { 1165 wpa_auth_pmksa_flush(hapd->wpa_auth); 1166 } 1167 1168 1169 int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd) 1170 { 1171 u8 spa[ETH_ALEN]; 1172 u8 pmkid[PMKID_LEN]; 1173 u8 pmk[PMK_LEN_MAX]; 1174 size_t pmk_len; 1175 char *pos, *pos2; 1176 int akmp = 0, expiration = 0; 1177 1178 /* 1179 * Entry format: 1180 * <STA addr> <PMKID> <PMK> <expiration in seconds> <akmp> 1181 */ 1182 1183 if (hwaddr_aton(cmd, spa)) 1184 return -1; 1185 1186 pos = os_strchr(cmd, ' '); 1187 if (!pos) 1188 return -1; 1189 pos++; 1190 1191 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0) 1192 return -1; 1193 1194 pos = os_strchr(pos, ' '); 1195 if (!pos) 1196 return -1; 1197 pos++; 1198 1199 pos2 = os_strchr(pos, ' '); 1200 if (!pos2) 1201 return -1; 1202 pmk_len = (pos2 - pos) / 2; 1203 if (pmk_len < PMK_LEN || pmk_len > PMK_LEN_MAX || 1204 hexstr2bin(pos, pmk, pmk_len) < 0) 1205 return -1; 1206 1207 pos = pos2 + 1; 1208 1209 if (sscanf(pos, "%d %d", &expiration, &akmp) != 2) 1210 return -1; 1211 1212 return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len, 1213 pmkid, expiration, akmp, NULL); 1214 } 1215 1216 1217 #ifdef CONFIG_PMKSA_CACHE_EXTERNAL 1218 #ifdef CONFIG_MESH 1219 1220 int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd, 1221 const u8 *addr, char *buf, size_t len) 1222 { 1223 return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len); 1224 } 1225 1226 1227 void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd) 1228 { 1229 u8 spa[ETH_ALEN]; 1230 u8 pmkid[PMKID_LEN]; 1231 u8 pmk[PMK_LEN_MAX]; 1232 char *pos; 1233 int expiration; 1234 1235 /* 1236 * Entry format: 1237 * <BSSID> <PMKID> <PMK> <expiration in seconds> 1238 */ 1239 1240 if (hwaddr_aton(cmd, spa)) 1241 return NULL; 1242 1243 pos = os_strchr(cmd, ' '); 1244 if (!pos) 1245 return NULL; 1246 pos++; 1247 1248 if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0) 1249 return NULL; 1250 1251 pos = os_strchr(pos, ' '); 1252 if (!pos) 1253 return NULL; 1254 pos++; 1255 1256 if (hexstr2bin(pos, pmk, PMK_LEN) < 0) 1257 return NULL; 1258 1259 pos = os_strchr(pos, ' '); 1260 if (!pos) 1261 return NULL; 1262 pos++; 1263 1264 if (sscanf(pos, "%d", &expiration) != 1) 1265 return NULL; 1266 1267 return wpa_auth_pmksa_create_entry(aa, spa, pmk, PMK_LEN, 1268 WPA_KEY_MGMT_SAE, pmkid, expiration); 1269 } 1270 1271 #endif /* CONFIG_MESH */ 1272 #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ 1273 1274 1275 #ifdef CONFIG_WNM_AP 1276 1277 int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, 1278 const char *cmd) 1279 { 1280 u8 addr[ETH_ALEN]; 1281 int disassoc_timer; 1282 struct sta_info *sta; 1283 1284 if (hwaddr_aton(cmd, addr)) 1285 return -1; 1286 if (cmd[17] != ' ') 1287 return -1; 1288 disassoc_timer = atoi(cmd + 17); 1289 1290 sta = ap_get_sta(hapd, addr); 1291 if (sta == NULL) { 1292 wpa_printf(MSG_DEBUG, "Station " MACSTR 1293 " not found for disassociation imminent message", 1294 MAC2STR(addr)); 1295 return -1; 1296 } 1297 1298 return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); 1299 } 1300 1301 1302 int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, 1303 const char *cmd) 1304 { 1305 u8 addr[ETH_ALEN]; 1306 const char *url, *timerstr; 1307 int disassoc_timer; 1308 struct sta_info *sta; 1309 1310 if (hwaddr_aton(cmd, addr)) 1311 return -1; 1312 1313 sta = ap_get_sta(hapd, addr); 1314 if (sta == NULL) { 1315 wpa_printf(MSG_DEBUG, "Station " MACSTR 1316 " not found for ESS disassociation imminent message", 1317 MAC2STR(addr)); 1318 return -1; 1319 } 1320 1321 timerstr = cmd + 17; 1322 if (*timerstr != ' ') 1323 return -1; 1324 timerstr++; 1325 disassoc_timer = atoi(timerstr); 1326 if (disassoc_timer < 0 || disassoc_timer > 65535) 1327 return -1; 1328 1329 url = os_strchr(timerstr, ' '); 1330 if (url == NULL) 1331 return -1; 1332 url++; 1333 1334 return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); 1335 } 1336 1337 1338 int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, 1339 const char *cmd) 1340 { 1341 u8 addr[ETH_ALEN]; 1342 const char *pos, *end; 1343 int disassoc_timer = 0; 1344 struct sta_info *sta; 1345 u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01; 1346 u8 bss_term_dur[12]; 1347 char *url = NULL; 1348 int ret; 1349 u8 nei_rep[1000]; 1350 int nei_len; 1351 u8 mbo[10]; 1352 size_t mbo_len = 0; 1353 1354 if (hwaddr_aton(cmd, addr)) { 1355 wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); 1356 return -1; 1357 } 1358 1359 sta = ap_get_sta(hapd, addr); 1360 if (sta == NULL) { 1361 wpa_printf(MSG_DEBUG, "Station " MACSTR 1362 " not found for BSS TM Request message", 1363 MAC2STR(addr)); 1364 return -1; 1365 } 1366 1367 pos = os_strstr(cmd, " disassoc_timer="); 1368 if (pos) { 1369 pos += 16; 1370 disassoc_timer = atoi(pos); 1371 if (disassoc_timer < 0 || disassoc_timer > 65535) { 1372 wpa_printf(MSG_DEBUG, "Invalid disassoc_timer"); 1373 return -1; 1374 } 1375 } 1376 1377 pos = os_strstr(cmd, " valid_int="); 1378 if (pos) { 1379 pos += 11; 1380 valid_int = atoi(pos); 1381 } 1382 1383 pos = os_strstr(cmd, " dialog_token="); 1384 if (pos) { 1385 pos += 14; 1386 dialog_token = atoi(pos); 1387 } 1388 1389 pos = os_strstr(cmd, " bss_term="); 1390 if (pos) { 1391 pos += 10; 1392 req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED; 1393 /* TODO: TSF configurable/learnable */ 1394 bss_term_dur[0] = 4; /* Subelement ID */ 1395 bss_term_dur[1] = 10; /* Length */ 1396 os_memset(&bss_term_dur[2], 0, 8); 1397 end = os_strchr(pos, ','); 1398 if (end == NULL) { 1399 wpa_printf(MSG_DEBUG, "Invalid bss_term data"); 1400 return -1; 1401 } 1402 end++; 1403 WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); 1404 } 1405 1406 nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep, 1407 sizeof(nei_rep)); 1408 if (nei_len < 0) 1409 return -1; 1410 1411 pos = os_strstr(cmd, " url="); 1412 if (pos) { 1413 size_t len; 1414 pos += 5; 1415 end = os_strchr(pos, ' '); 1416 if (end) 1417 len = end - pos; 1418 else 1419 len = os_strlen(pos); 1420 url = os_malloc(len + 1); 1421 if (url == NULL) 1422 return -1; 1423 os_memcpy(url, pos, len); 1424 url[len] = '\0'; 1425 req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; 1426 } 1427 1428 if (os_strstr(cmd, " pref=1")) 1429 req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; 1430 if (os_strstr(cmd, " abridged=1")) 1431 req_mode |= WNM_BSS_TM_REQ_ABRIDGED; 1432 if (os_strstr(cmd, " disassoc_imminent=1")) 1433 req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; 1434 if (os_strstr(cmd, " link_removal_imminent=1")) 1435 req_mode |= WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT; 1436 1437 #ifdef CONFIG_MBO 1438 pos = os_strstr(cmd, "mbo="); 1439 if (pos) { 1440 unsigned int mbo_reason, cell_pref, reassoc_delay; 1441 u8 *mbo_pos = mbo; 1442 1443 ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason, 1444 &reassoc_delay, &cell_pref); 1445 if (ret != 3) { 1446 wpa_printf(MSG_DEBUG, 1447 "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>"); 1448 ret = -1; 1449 goto fail; 1450 } 1451 1452 if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) { 1453 wpa_printf(MSG_DEBUG, 1454 "Invalid MBO transition reason code %u", 1455 mbo_reason); 1456 ret = -1; 1457 goto fail; 1458 } 1459 1460 /* Valid values for Cellular preference are: 0, 1, 255 */ 1461 if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) { 1462 wpa_printf(MSG_DEBUG, 1463 "Invalid MBO cellular capability %u", 1464 cell_pref); 1465 ret = -1; 1466 goto fail; 1467 } 1468 1469 if (reassoc_delay > 65535 || 1470 (reassoc_delay && 1471 !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) { 1472 wpa_printf(MSG_DEBUG, 1473 "MBO: Assoc retry delay is only valid in disassoc imminent mode"); 1474 ret = -1; 1475 goto fail; 1476 } 1477 1478 *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON; 1479 *mbo_pos++ = 1; 1480 *mbo_pos++ = mbo_reason; 1481 *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF; 1482 *mbo_pos++ = 1; 1483 *mbo_pos++ = cell_pref; 1484 1485 if (reassoc_delay) { 1486 *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY; 1487 *mbo_pos++ = 2; 1488 WPA_PUT_LE16(mbo_pos, reassoc_delay); 1489 mbo_pos += 2; 1490 } 1491 1492 mbo_len = mbo_pos - mbo; 1493 } 1494 #endif /* CONFIG_MBO */ 1495 1496 ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, 1497 valid_int, bss_term_dur, dialog_token, url, 1498 nei_len ? nei_rep : NULL, nei_len, 1499 mbo_len ? mbo : NULL, mbo_len); 1500 #ifdef CONFIG_MBO 1501 fail: 1502 #endif /* CONFIG_MBO */ 1503 os_free(url); 1504 return ret; 1505 } 1506 1507 #endif /* CONFIG_WNM_AP */ 1508 1509 1510 int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, 1511 const char *txtaddr) 1512 { 1513 u8 addr[ETH_ALEN]; 1514 struct vlan_description vlan_id; 1515 1516 if (!(*num)) 1517 return 0; 1518 1519 if (hwaddr_aton(txtaddr, addr)) 1520 return -1; 1521 1522 if (hostapd_maclist_found(*acl, *num, addr, &vlan_id)) 1523 hostapd_remove_acl_mac(acl, num, addr); 1524 1525 return 0; 1526 } 1527 1528 1529 void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, 1530 int *num) 1531 { 1532 while (*num) 1533 hostapd_remove_acl_mac(acl, num, (*acl)[0].addr); 1534 } 1535 1536 1537 int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, 1538 char *buf, size_t buflen) 1539 { 1540 int i = 0, len = 0, ret = 0; 1541 1542 if (!acl) 1543 return 0; 1544 1545 while (i < num) { 1546 ret = os_snprintf(buf + len, buflen - len, 1547 MACSTR " VLAN_ID=%d\n", 1548 MAC2STR(acl[i].addr), 1549 acl[i].vlan_id.untagged); 1550 if (ret < 0 || (size_t) ret >= buflen - len) 1551 return len; 1552 i++; 1553 len += ret; 1554 } 1555 return len; 1556 } 1557 1558 1559 int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, 1560 const char *cmd) 1561 { 1562 u8 addr[ETH_ALEN]; 1563 struct vlan_description vlan_id; 1564 int ret = 0, vlanid = 0; 1565 const char *pos; 1566 1567 if (hwaddr_aton(cmd, addr)) 1568 return -1; 1569 1570 pos = os_strstr(cmd, "VLAN_ID="); 1571 if (pos) 1572 vlanid = atoi(pos + 8); 1573 1574 if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) { 1575 ret = hostapd_add_acl_maclist(acl, num, vlanid, addr); 1576 if (ret != -1 && *acl) 1577 qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); 1578 } 1579 1580 return ret < 0 ? -1 : 0; 1581 } 1582 1583 1584 int hostapd_disassoc_accept_mac(struct hostapd_data *hapd) 1585 { 1586 struct sta_info *sta; 1587 struct vlan_description vlan_id; 1588 1589 if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED) 1590 return 0; 1591 1592 for (sta = hapd->sta_list; sta; sta = sta->next) { 1593 if (!hostapd_maclist_found(hapd->conf->accept_mac, 1594 hapd->conf->num_accept_mac, 1595 sta->addr, &vlan_id) || 1596 (vlan_id.notempty && 1597 vlan_compare(&vlan_id, sta->vlan_desc))) 1598 ap_sta_disconnect(hapd, sta, sta->addr, 1599 WLAN_REASON_UNSPECIFIED); 1600 } 1601 1602 return 0; 1603 } 1604 1605 1606 int hostapd_disassoc_deny_mac(struct hostapd_data *hapd) 1607 { 1608 struct sta_info *sta; 1609 struct vlan_description vlan_id; 1610 1611 for (sta = hapd->sta_list; sta; sta = sta->next) { 1612 if (hostapd_maclist_found(hapd->conf->deny_mac, 1613 hapd->conf->num_deny_mac, sta->addr, 1614 &vlan_id) && 1615 (!vlan_id.notempty || 1616 !vlan_compare(&vlan_id, sta->vlan_desc))) 1617 ap_sta_disconnect(hapd, sta, sta->addr, 1618 WLAN_REASON_UNSPECIFIED); 1619 } 1620 1621 return 0; 1622 } 1623