1 /* 2 * Control interface for shared AP commands 3 * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 11 #include "utils/common.h" 12 #include "common/ieee802_11_defs.h" 13 #include "common/sae.h" 14 #include "eapol_auth/eapol_auth_sm.h" 15 #include "fst/fst_ctrl_iface.h" 16 #include "hostapd.h" 17 #include "ieee802_1x.h" 18 #include "wpa_auth.h" 19 #include "ieee802_11.h" 20 #include "sta_info.h" 21 #include "wps_hostapd.h" 22 #include "p2p_hostapd.h" 23 #include "ctrl_iface_ap.h" 24 #include "ap_drv_ops.h" 25 26 27 static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd, 28 struct sta_info *sta, 29 char *buf, size_t buflen) 30 { 31 struct hostap_sta_driver_data data; 32 int ret; 33 34 if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0) 35 return 0; 36 37 ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n" 38 "rx_bytes=%lu\ntx_bytes=%lu\n", 39 data.rx_packets, data.tx_packets, 40 data.rx_bytes, data.tx_bytes); 41 if (os_snprintf_error(buflen, ret)) 42 return 0; 43 return ret; 44 } 45 46 47 static int hostapd_get_sta_conn_time(struct sta_info *sta, 48 char *buf, size_t buflen) 49 { 50 struct os_reltime age; 51 int ret; 52 53 if (!sta->connected_time.sec) 54 return 0; 55 56 os_reltime_age(&sta->connected_time, &age); 57 58 ret = os_snprintf(buf, buflen, "connected_time=%u\n", 59 (unsigned int) age.sec); 60 if (os_snprintf_error(buflen, ret)) 61 return 0; 62 return ret; 63 } 64 65 66 static const char * timeout_next_str(int val) 67 { 68 switch (val) { 69 case STA_NULLFUNC: 70 return "NULLFUNC POLL"; 71 case STA_DISASSOC: 72 return "DISASSOC"; 73 case STA_DEAUTH: 74 return "DEAUTH"; 75 case STA_REMOVE: 76 return "REMOVE"; 77 case STA_DISASSOC_FROM_CLI: 78 return "DISASSOC_FROM_CLI"; 79 } 80 81 return "?"; 82 } 83 84 85 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, 86 struct sta_info *sta, 87 char *buf, size_t buflen) 88 { 89 int len, res, ret, i; 90 91 if (!sta) 92 return 0; 93 94 len = 0; 95 ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=", 96 MAC2STR(sta->addr)); 97 if (os_snprintf_error(buflen - len, ret)) 98 return len; 99 len += ret; 100 101 ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len); 102 if (ret < 0) 103 return len; 104 len += ret; 105 106 ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n" 107 "listen_interval=%d\nsupported_rates=", 108 sta->aid, sta->capability, sta->listen_interval); 109 if (os_snprintf_error(buflen - len, ret)) 110 return len; 111 len += ret; 112 113 for (i = 0; i < sta->supported_rates_len; i++) { 114 ret = os_snprintf(buf + len, buflen - len, "%02x%s", 115 sta->supported_rates[i], 116 i + 1 < sta->supported_rates_len ? " " : ""); 117 if (os_snprintf_error(buflen - len, ret)) 118 return len; 119 len += ret; 120 } 121 122 ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n", 123 timeout_next_str(sta->timeout_next)); 124 if (os_snprintf_error(buflen - len, ret)) 125 return len; 126 len += ret; 127 128 res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); 129 if (res >= 0) 130 len += res; 131 res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len); 132 if (res >= 0) 133 len += res; 134 res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len); 135 if (res >= 0) 136 len += res; 137 res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len, 138 buflen - len); 139 if (res >= 0) 140 len += res; 141 res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len); 142 if (res >= 0) 143 len += res; 144 145 len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len); 146 len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len); 147 148 #ifdef CONFIG_SAE 149 if (sta->sae && sta->sae->state == SAE_ACCEPTED) { 150 res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n", 151 sta->sae->group); 152 if (!os_snprintf_error(buflen - len, res)) 153 len += res; 154 } 155 #endif /* CONFIG_SAE */ 156 157 if (sta->vlan_id > 0) { 158 res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n", 159 sta->vlan_id); 160 if (!os_snprintf_error(buflen - len, res)) 161 len += res; 162 } 163 164 return len; 165 } 166 167 168 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd, 169 char *buf, size_t buflen) 170 { 171 return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen); 172 } 173 174 175 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr, 176 char *buf, size_t buflen) 177 { 178 u8 addr[ETH_ALEN]; 179 int ret; 180 const char *pos; 181 struct sta_info *sta; 182 183 if (hwaddr_aton(txtaddr, addr)) { 184 ret = os_snprintf(buf, buflen, "FAIL\n"); 185 if (os_snprintf_error(buflen, ret)) 186 return 0; 187 return ret; 188 } 189 190 sta = ap_get_sta(hapd, addr); 191 if (sta == NULL) 192 return -1; 193 194 pos = os_strchr(txtaddr, ' '); 195 if (pos) { 196 pos++; 197 198 #ifdef HOSTAPD_DUMP_STATE 199 if (os_strcmp(pos, "eapol") == 0) { 200 if (sta->eapol_sm == NULL) 201 return -1; 202 return eapol_auth_dump_state(sta->eapol_sm, buf, 203 buflen); 204 } 205 #endif /* HOSTAPD_DUMP_STATE */ 206 207 return -1; 208 } 209 210 ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen); 211 ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret); 212 213 return ret; 214 } 215 216 217 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr, 218 char *buf, size_t buflen) 219 { 220 u8 addr[ETH_ALEN]; 221 struct sta_info *sta; 222 int ret; 223 224 if (hwaddr_aton(txtaddr, addr) || 225 (sta = ap_get_sta(hapd, addr)) == NULL) { 226 ret = os_snprintf(buf, buflen, "FAIL\n"); 227 if (os_snprintf_error(buflen, ret)) 228 return 0; 229 return ret; 230 } 231 232 if (!sta->next) 233 return 0; 234 235 return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen); 236 } 237 238 239 #ifdef CONFIG_P2P_MANAGER 240 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, 241 u8 minor_reason_code, const u8 *addr) 242 { 243 struct ieee80211_mgmt *mgmt; 244 int ret; 245 u8 *pos; 246 247 if (hapd->driver->send_frame == NULL) 248 return -1; 249 250 mgmt = os_zalloc(sizeof(*mgmt) + 100); 251 if (mgmt == NULL) 252 return -1; 253 254 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); 255 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR 256 " with minor reason code %u (stype=%u (%s))", 257 MAC2STR(addr), minor_reason_code, stype, 258 fc2str(mgmt->frame_control)); 259 260 os_memcpy(mgmt->da, addr, ETH_ALEN); 261 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 262 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 263 if (stype == WLAN_FC_STYPE_DEAUTH) { 264 mgmt->u.deauth.reason_code = 265 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 266 pos = (u8 *) (&mgmt->u.deauth.reason_code + 1); 267 } else { 268 mgmt->u.disassoc.reason_code = 269 host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 270 pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1); 271 } 272 273 *pos++ = WLAN_EID_VENDOR_SPECIFIC; 274 *pos++ = 4 + 3 + 1; 275 WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE); 276 pos += 4; 277 278 *pos++ = P2P_ATTR_MINOR_REASON_CODE; 279 WPA_PUT_LE16(pos, 1); 280 pos += 2; 281 *pos++ = minor_reason_code; 282 283 ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt, 284 pos - (u8 *) mgmt, 1); 285 os_free(mgmt); 286 287 return ret < 0 ? -1 : 0; 288 } 289 #endif /* CONFIG_P2P_MANAGER */ 290 291 292 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, 293 const char *txtaddr) 294 { 295 u8 addr[ETH_ALEN]; 296 struct sta_info *sta; 297 const char *pos; 298 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; 299 300 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", 301 txtaddr); 302 303 if (hwaddr_aton(txtaddr, addr)) 304 return -1; 305 306 pos = os_strstr(txtaddr, " reason="); 307 if (pos) 308 reason = atoi(pos + 8); 309 310 pos = os_strstr(txtaddr, " test="); 311 if (pos) { 312 struct ieee80211_mgmt mgmt; 313 int encrypt; 314 if (hapd->driver->send_frame == NULL) 315 return -1; 316 pos += 6; 317 encrypt = atoi(pos); 318 os_memset(&mgmt, 0, sizeof(mgmt)); 319 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 320 WLAN_FC_STYPE_DEAUTH); 321 os_memcpy(mgmt.da, addr, ETH_ALEN); 322 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 323 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 324 mgmt.u.deauth.reason_code = host_to_le16(reason); 325 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, 326 IEEE80211_HDRLEN + 327 sizeof(mgmt.u.deauth), 328 encrypt) < 0) 329 return -1; 330 return 0; 331 } 332 333 #ifdef CONFIG_P2P_MANAGER 334 pos = os_strstr(txtaddr, " p2p="); 335 if (pos) { 336 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH, 337 atoi(pos + 5), addr); 338 } 339 #endif /* CONFIG_P2P_MANAGER */ 340 341 hostapd_drv_sta_deauth(hapd, addr, reason); 342 sta = ap_get_sta(hapd, addr); 343 if (sta) 344 ap_sta_deauthenticate(hapd, sta, reason); 345 else if (addr[0] == 0xff) 346 hostapd_free_stas(hapd); 347 348 return 0; 349 } 350 351 352 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, 353 const char *txtaddr) 354 { 355 u8 addr[ETH_ALEN]; 356 struct sta_info *sta; 357 const char *pos; 358 u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; 359 360 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", 361 txtaddr); 362 363 if (hwaddr_aton(txtaddr, addr)) 364 return -1; 365 366 pos = os_strstr(txtaddr, " reason="); 367 if (pos) 368 reason = atoi(pos + 8); 369 370 pos = os_strstr(txtaddr, " test="); 371 if (pos) { 372 struct ieee80211_mgmt mgmt; 373 int encrypt; 374 if (hapd->driver->send_frame == NULL) 375 return -1; 376 pos += 6; 377 encrypt = atoi(pos); 378 os_memset(&mgmt, 0, sizeof(mgmt)); 379 mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 380 WLAN_FC_STYPE_DISASSOC); 381 os_memcpy(mgmt.da, addr, ETH_ALEN); 382 os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 383 os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 384 mgmt.u.disassoc.reason_code = host_to_le16(reason); 385 if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, 386 IEEE80211_HDRLEN + 387 sizeof(mgmt.u.deauth), 388 encrypt) < 0) 389 return -1; 390 return 0; 391 } 392 393 #ifdef CONFIG_P2P_MANAGER 394 pos = os_strstr(txtaddr, " p2p="); 395 if (pos) { 396 return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC, 397 atoi(pos + 5), addr); 398 } 399 #endif /* CONFIG_P2P_MANAGER */ 400 401 hostapd_drv_sta_disassoc(hapd, addr, reason); 402 sta = ap_get_sta(hapd, addr); 403 if (sta) 404 ap_sta_disassociate(hapd, sta, reason); 405 else if (addr[0] == 0xff) 406 hostapd_free_stas(hapd); 407 408 return 0; 409 } 410 411 412 int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, 413 size_t buflen) 414 { 415 struct hostapd_iface *iface = hapd->iface; 416 int len = 0, ret; 417 size_t i; 418 419 ret = os_snprintf(buf + len, buflen - len, 420 "state=%s\n" 421 "phy=%s\n" 422 "freq=%d\n" 423 "num_sta_non_erp=%d\n" 424 "num_sta_no_short_slot_time=%d\n" 425 "num_sta_no_short_preamble=%d\n" 426 "olbc=%d\n" 427 "num_sta_ht_no_gf=%d\n" 428 "num_sta_no_ht=%d\n" 429 "num_sta_ht_20_mhz=%d\n" 430 "num_sta_ht40_intolerant=%d\n" 431 "olbc_ht=%d\n" 432 "ht_op_mode=0x%x\n", 433 hostapd_state_text(iface->state), 434 iface->phy, 435 iface->freq, 436 iface->num_sta_non_erp, 437 iface->num_sta_no_short_slot_time, 438 iface->num_sta_no_short_preamble, 439 iface->olbc, 440 iface->num_sta_ht_no_gf, 441 iface->num_sta_no_ht, 442 iface->num_sta_ht_20mhz, 443 iface->num_sta_ht40_intolerant, 444 iface->olbc_ht, 445 iface->ht_op_mode); 446 if (os_snprintf_error(buflen - len, ret)) 447 return len; 448 len += ret; 449 450 if (!iface->cac_started || !iface->dfs_cac_ms) { 451 ret = os_snprintf(buf + len, buflen - len, 452 "cac_time_seconds=%d\n" 453 "cac_time_left_seconds=N/A\n", 454 iface->dfs_cac_ms / 1000); 455 } else { 456 /* CAC started and CAC time set - calculate remaining time */ 457 struct os_reltime now; 458 unsigned int left_time; 459 460 os_reltime_age(&iface->dfs_cac_start, &now); 461 left_time = iface->dfs_cac_ms / 1000 - now.sec; 462 ret = os_snprintf(buf + len, buflen - len, 463 "cac_time_seconds=%u\n" 464 "cac_time_left_seconds=%u\n", 465 iface->dfs_cac_ms / 1000, 466 left_time); 467 } 468 if (os_snprintf_error(buflen - len, ret)) 469 return len; 470 len += ret; 471 472 ret = os_snprintf(buf + len, buflen - len, 473 "channel=%u\n" 474 "secondary_channel=%d\n" 475 "ieee80211n=%d\n" 476 "ieee80211ac=%d\n" 477 "vht_oper_chwidth=%d\n" 478 "vht_oper_centr_freq_seg0_idx=%d\n" 479 "vht_oper_centr_freq_seg1_idx=%d\n", 480 iface->conf->channel, 481 iface->conf->secondary_channel, 482 iface->conf->ieee80211n, 483 iface->conf->ieee80211ac, 484 iface->conf->vht_oper_chwidth, 485 iface->conf->vht_oper_centr_freq_seg0_idx, 486 iface->conf->vht_oper_centr_freq_seg1_idx); 487 if (os_snprintf_error(buflen - len, ret)) 488 return len; 489 len += ret; 490 491 for (i = 0; i < iface->num_bss; i++) { 492 struct hostapd_data *bss = iface->bss[i]; 493 ret = os_snprintf(buf + len, buflen - len, 494 "bss[%d]=%s\n" 495 "bssid[%d]=" MACSTR "\n" 496 "ssid[%d]=%s\n" 497 "num_sta[%d]=%d\n", 498 (int) i, bss->conf->iface, 499 (int) i, MAC2STR(bss->own_addr), 500 (int) i, 501 wpa_ssid_txt(bss->conf->ssid.ssid, 502 bss->conf->ssid.ssid_len), 503 (int) i, bss->num_sta); 504 if (os_snprintf_error(buflen - len, ret)) 505 return len; 506 len += ret; 507 } 508 509 return len; 510 } 511 512 513 int hostapd_parse_csa_settings(const char *pos, 514 struct csa_settings *settings) 515 { 516 char *end; 517 518 os_memset(settings, 0, sizeof(*settings)); 519 settings->cs_count = strtol(pos, &end, 10); 520 if (pos == end) { 521 wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided"); 522 return -1; 523 } 524 525 settings->freq_params.freq = atoi(end); 526 if (settings->freq_params.freq == 0) { 527 wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided"); 528 return -1; 529 } 530 531 #define SET_CSA_SETTING(str) \ 532 do { \ 533 const char *pos2 = os_strstr(pos, " " #str "="); \ 534 if (pos2) { \ 535 pos2 += sizeof(" " #str "=") - 1; \ 536 settings->freq_params.str = atoi(pos2); \ 537 } \ 538 } while (0) 539 540 SET_CSA_SETTING(center_freq1); 541 SET_CSA_SETTING(center_freq2); 542 SET_CSA_SETTING(bandwidth); 543 SET_CSA_SETTING(sec_channel_offset); 544 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht"); 545 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht"); 546 settings->block_tx = !!os_strstr(pos, " blocktx"); 547 #undef SET_CSA_SETTING 548 549 return 0; 550 } 551 552 553 int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd) 554 { 555 return hostapd_drv_stop_ap(hapd); 556 } 557