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