ctrl_iface.c revision e0e48dc666fb14a7bb60264ca87463ba7bc1fe0b
1/* 2 * hostapd / UNIX domain socket -based control interface 3 * Copyright (c) 2004-2013, 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#ifndef CONFIG_NATIVE_WINDOWS 12 13#include <sys/un.h> 14#include <sys/stat.h> 15#include <stddef.h> 16 17#include "utils/common.h" 18#include "utils/eloop.h" 19#include "common/version.h" 20#include "common/ieee802_11_defs.h" 21#include "drivers/driver.h" 22#include "radius/radius_client.h" 23#include "ap/hostapd.h" 24#include "ap/ap_config.h" 25#include "ap/ieee802_1x.h" 26#include "ap/wpa_auth.h" 27#include "ap/ieee802_11.h" 28#include "ap/sta_info.h" 29#include "ap/wps_hostapd.h" 30#include "ap/ctrl_iface_ap.h" 31#include "ap/ap_drv_ops.h" 32#include "ap/wpa_auth.h" 33#include "wps/wps_defs.h" 34#include "wps/wps.h" 35#include "config_file.h" 36#include "ctrl_iface.h" 37 38 39struct wpa_ctrl_dst { 40 struct wpa_ctrl_dst *next; 41 struct sockaddr_un addr; 42 socklen_t addrlen; 43 int debug_level; 44 int errors; 45}; 46 47 48static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 49 const char *buf, size_t len); 50 51 52static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, 53 struct sockaddr_un *from, 54 socklen_t fromlen) 55{ 56 struct wpa_ctrl_dst *dst; 57 58 dst = os_zalloc(sizeof(*dst)); 59 if (dst == NULL) 60 return -1; 61 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 62 dst->addrlen = fromlen; 63 dst->debug_level = MSG_INFO; 64 dst->next = hapd->ctrl_dst; 65 hapd->ctrl_dst = dst; 66 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", 67 (u8 *) from->sun_path, 68 fromlen - offsetof(struct sockaddr_un, sun_path)); 69 return 0; 70} 71 72 73static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, 74 struct sockaddr_un *from, 75 socklen_t fromlen) 76{ 77 struct wpa_ctrl_dst *dst, *prev = NULL; 78 79 dst = hapd->ctrl_dst; 80 while (dst) { 81 if (fromlen == dst->addrlen && 82 os_memcmp(from->sun_path, dst->addr.sun_path, 83 fromlen - offsetof(struct sockaddr_un, sun_path)) 84 == 0) { 85 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", 86 (u8 *) from->sun_path, 87 fromlen - 88 offsetof(struct sockaddr_un, sun_path)); 89 if (prev == NULL) 90 hapd->ctrl_dst = dst->next; 91 else 92 prev->next = dst->next; 93 os_free(dst); 94 return 0; 95 } 96 prev = dst; 97 dst = dst->next; 98 } 99 return -1; 100} 101 102 103static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, 104 struct sockaddr_un *from, 105 socklen_t fromlen, 106 char *level) 107{ 108 struct wpa_ctrl_dst *dst; 109 110 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 111 112 dst = hapd->ctrl_dst; 113 while (dst) { 114 if (fromlen == dst->addrlen && 115 os_memcmp(from->sun_path, dst->addr.sun_path, 116 fromlen - offsetof(struct sockaddr_un, sun_path)) 117 == 0) { 118 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " 119 "level", (u8 *) from->sun_path, fromlen - 120 offsetof(struct sockaddr_un, sun_path)); 121 dst->debug_level = atoi(level); 122 return 0; 123 } 124 dst = dst->next; 125 } 126 127 return -1; 128} 129 130 131static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, 132 const char *txtaddr) 133{ 134 u8 addr[ETH_ALEN]; 135 struct sta_info *sta; 136 137 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); 138 139 if (hwaddr_aton(txtaddr, addr)) 140 return -1; 141 142 sta = ap_get_sta(hapd, addr); 143 if (sta) 144 return 0; 145 146 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " 147 "notification", MAC2STR(addr)); 148 sta = ap_sta_add(hapd, addr); 149 if (sta == NULL) 150 return -1; 151 152 hostapd_new_assoc_sta(hapd, sta, 0); 153 return 0; 154} 155 156 157#ifdef CONFIG_IEEE80211W 158#ifdef NEED_AP_MLME 159static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, 160 const char *txtaddr) 161{ 162 u8 addr[ETH_ALEN]; 163 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; 164 165 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); 166 167 if (hwaddr_aton(txtaddr, addr) || 168 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) 169 return -1; 170 171 ieee802_11_send_sa_query_req(hapd, addr, trans_id); 172 173 return 0; 174} 175#endif /* NEED_AP_MLME */ 176#endif /* CONFIG_IEEE80211W */ 177 178 179#ifdef CONFIG_WPS 180static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) 181{ 182 char *pin = os_strchr(txt, ' '); 183 char *timeout_txt; 184 int timeout; 185 u8 addr_buf[ETH_ALEN], *addr = NULL; 186 char *pos; 187 188 if (pin == NULL) 189 return -1; 190 *pin++ = '\0'; 191 192 timeout_txt = os_strchr(pin, ' '); 193 if (timeout_txt) { 194 *timeout_txt++ = '\0'; 195 timeout = atoi(timeout_txt); 196 pos = os_strchr(timeout_txt, ' '); 197 if (pos) { 198 *pos++ = '\0'; 199 if (hwaddr_aton(pos, addr_buf) == 0) 200 addr = addr_buf; 201 } 202 } else 203 timeout = 0; 204 205 return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout); 206} 207 208 209static int hostapd_ctrl_iface_wps_check_pin( 210 struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen) 211{ 212 char pin[9]; 213 size_t len; 214 char *pos; 215 int ret; 216 217 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", 218 (u8 *) cmd, os_strlen(cmd)); 219 for (pos = cmd, len = 0; *pos != '\0'; pos++) { 220 if (*pos < '0' || *pos > '9') 221 continue; 222 pin[len++] = *pos; 223 if (len == 9) { 224 wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); 225 return -1; 226 } 227 } 228 if (len != 4 && len != 8) { 229 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); 230 return -1; 231 } 232 pin[len] = '\0'; 233 234 if (len == 8) { 235 unsigned int pin_val; 236 pin_val = atoi(pin); 237 if (!wps_pin_valid(pin_val)) { 238 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); 239 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); 240 if (ret < 0 || (size_t) ret >= buflen) 241 return -1; 242 return ret; 243 } 244 } 245 246 ret = os_snprintf(buf, buflen, "%s", pin); 247 if (ret < 0 || (size_t) ret >= buflen) 248 return -1; 249 250 return ret; 251} 252 253 254#ifdef CONFIG_WPS_NFC 255static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd, 256 char *pos) 257{ 258 size_t len; 259 struct wpabuf *buf; 260 int ret; 261 262 len = os_strlen(pos); 263 if (len & 0x01) 264 return -1; 265 len /= 2; 266 267 buf = wpabuf_alloc(len); 268 if (buf == NULL) 269 return -1; 270 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { 271 wpabuf_free(buf); 272 return -1; 273 } 274 275 ret = hostapd_wps_nfc_tag_read(hapd, buf); 276 wpabuf_free(buf); 277 278 return ret; 279} 280 281 282static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd, 283 char *cmd, char *reply, 284 size_t max_len) 285{ 286 int ndef; 287 struct wpabuf *buf; 288 int res; 289 290 if (os_strcmp(cmd, "WPS") == 0) 291 ndef = 0; 292 else if (os_strcmp(cmd, "NDEF") == 0) 293 ndef = 1; 294 else 295 return -1; 296 297 buf = hostapd_wps_nfc_config_token(hapd, ndef); 298 if (buf == NULL) 299 return -1; 300 301 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 302 wpabuf_len(buf)); 303 reply[res++] = '\n'; 304 reply[res] = '\0'; 305 306 wpabuf_free(buf); 307 308 return res; 309} 310 311 312static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd, 313 char *reply, size_t max_len, 314 int ndef) 315{ 316 struct wpabuf *buf; 317 int res; 318 319 buf = hostapd_wps_nfc_token_gen(hapd, ndef); 320 if (buf == NULL) 321 return -1; 322 323 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 324 wpabuf_len(buf)); 325 reply[res++] = '\n'; 326 reply[res] = '\0'; 327 328 wpabuf_free(buf); 329 330 return res; 331} 332 333 334static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd, 335 char *cmd, char *reply, 336 size_t max_len) 337{ 338 if (os_strcmp(cmd, "WPS") == 0) 339 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, 340 max_len, 0); 341 342 if (os_strcmp(cmd, "NDEF") == 0) 343 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, 344 max_len, 1); 345 346 if (os_strcmp(cmd, "enable") == 0) 347 return hostapd_wps_nfc_token_enable(hapd); 348 349 if (os_strcmp(cmd, "disable") == 0) { 350 hostapd_wps_nfc_token_disable(hapd); 351 return 0; 352 } 353 354 return -1; 355} 356 357 358static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd, 359 char *cmd, char *reply, 360 size_t max_len) 361{ 362 struct wpabuf *buf; 363 int res; 364 char *pos; 365 int ndef; 366 367 pos = os_strchr(cmd, ' '); 368 if (pos == NULL) 369 return -1; 370 *pos++ = '\0'; 371 372 if (os_strcmp(cmd, "WPS") == 0) 373 ndef = 0; 374 else if (os_strcmp(cmd, "NDEF") == 0) 375 ndef = 1; 376 else 377 return -1; 378 379 if (os_strcmp(pos, "WPS-CR") == 0) 380 buf = hostapd_wps_nfc_hs_cr(hapd, ndef); 381 else 382 buf = NULL; 383 if (buf == NULL) 384 return -1; 385 386 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 387 wpabuf_len(buf)); 388 reply[res++] = '\n'; 389 reply[res] = '\0'; 390 391 wpabuf_free(buf); 392 393 return res; 394} 395 396 397static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd, 398 char *cmd) 399{ 400 /* 401 * Since NFC connection handover provided full WPS Credential, there is 402 * no need for additional operations within hostapd. Just report this in 403 * debug log. 404 */ 405 wpa_printf(MSG_DEBUG, "NFC: Connection handover reported: %s", cmd); 406 return 0; 407} 408 409#endif /* CONFIG_WPS_NFC */ 410 411 412static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt, 413 char *buf, size_t buflen) 414{ 415 int timeout = 300; 416 char *pos; 417 const char *pin_txt; 418 419 pos = os_strchr(txt, ' '); 420 if (pos) 421 *pos++ = '\0'; 422 423 if (os_strcmp(txt, "disable") == 0) { 424 hostapd_wps_ap_pin_disable(hapd); 425 return os_snprintf(buf, buflen, "OK\n"); 426 } 427 428 if (os_strcmp(txt, "random") == 0) { 429 if (pos) 430 timeout = atoi(pos); 431 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout); 432 if (pin_txt == NULL) 433 return -1; 434 return os_snprintf(buf, buflen, "%s", pin_txt); 435 } 436 437 if (os_strcmp(txt, "get") == 0) { 438 pin_txt = hostapd_wps_ap_pin_get(hapd); 439 if (pin_txt == NULL) 440 return -1; 441 return os_snprintf(buf, buflen, "%s", pin_txt); 442 } 443 444 if (os_strcmp(txt, "set") == 0) { 445 char *pin; 446 if (pos == NULL) 447 return -1; 448 pin = pos; 449 pos = os_strchr(pos, ' '); 450 if (pos) { 451 *pos++ = '\0'; 452 timeout = atoi(pos); 453 } 454 if (os_strlen(pin) > buflen) 455 return -1; 456 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0) 457 return -1; 458 return os_snprintf(buf, buflen, "%s", pin); 459 } 460 461 return -1; 462} 463 464 465static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) 466{ 467 char *pos; 468 char *ssid, *auth, *encr = NULL, *key = NULL; 469 470 ssid = txt; 471 pos = os_strchr(txt, ' '); 472 if (!pos) 473 return -1; 474 *pos++ = '\0'; 475 476 auth = pos; 477 pos = os_strchr(pos, ' '); 478 if (pos) { 479 *pos++ = '\0'; 480 encr = pos; 481 pos = os_strchr(pos, ' '); 482 if (pos) { 483 *pos++ = '\0'; 484 key = pos; 485 } 486 } 487 488 return hostapd_wps_config_ap(hapd, ssid, auth, encr, key); 489} 490 491 492static const char * pbc_status_str(enum pbc_status status) 493{ 494 switch (status) { 495 case WPS_PBC_STATUS_DISABLE: 496 return "Disabled"; 497 case WPS_PBC_STATUS_ACTIVE: 498 return "Active"; 499 case WPS_PBC_STATUS_TIMEOUT: 500 return "Timed-out"; 501 case WPS_PBC_STATUS_OVERLAP: 502 return "Overlap"; 503 default: 504 return "Unknown"; 505 } 506} 507 508 509static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd, 510 char *buf, size_t buflen) 511{ 512 int ret; 513 char *pos, *end; 514 515 pos = buf; 516 end = buf + buflen; 517 518 ret = os_snprintf(pos, end - pos, "PBC Status: %s\n", 519 pbc_status_str(hapd->wps_stats.pbc_status)); 520 521 if (ret < 0 || ret >= end - pos) 522 return pos - buf; 523 pos += ret; 524 525 ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n", 526 (hapd->wps_stats.status == WPS_STATUS_SUCCESS ? 527 "Success": 528 (hapd->wps_stats.status == WPS_STATUS_FAILURE ? 529 "Failed" : "None"))); 530 531 if (ret < 0 || ret >= end - pos) 532 return pos - buf; 533 pos += ret; 534 535 /* If status == Failure - Add possible Reasons */ 536 if(hapd->wps_stats.status == WPS_STATUS_FAILURE && 537 hapd->wps_stats.failure_reason > 0) { 538 ret = os_snprintf(pos, end - pos, 539 "Failure Reason: %s\n", 540 wps_ei_str(hapd->wps_stats.failure_reason)); 541 542 if (ret < 0 || ret >= end - pos) 543 return pos - buf; 544 pos += ret; 545 } 546 547 if (hapd->wps_stats.status) { 548 ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n", 549 MAC2STR(hapd->wps_stats.peer_addr)); 550 551 if (ret < 0 || ret >= end - pos) 552 return pos - buf; 553 pos += ret; 554 } 555 556 return pos - buf; 557} 558 559#endif /* CONFIG_WPS */ 560 561 562#ifdef CONFIG_INTERWORKING 563 564static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd, 565 const char *cmd) 566{ 567 u8 qos_map_set[16 + 2 * 21], count = 0; 568 const char *pos = cmd; 569 int val, ret; 570 571 for (;;) { 572 if (count == sizeof(qos_map_set)) { 573 wpa_printf(MSG_ERROR, "Too many qos_map_set parameters"); 574 return -1; 575 } 576 577 val = atoi(pos); 578 if (val < 0 || val > 255) { 579 wpa_printf(MSG_INFO, "Invalid QoS Map Set"); 580 return -1; 581 } 582 583 qos_map_set[count++] = val; 584 pos = os_strchr(pos, ','); 585 if (!pos) 586 break; 587 pos++; 588 } 589 590 if (count < 16 || count & 1) { 591 wpa_printf(MSG_INFO, "Invalid QoS Map Set"); 592 return -1; 593 } 594 595 ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count); 596 if (ret) { 597 wpa_printf(MSG_INFO, "Failed to set QoS Map Set"); 598 return -1; 599 } 600 601 os_memcpy(hapd->conf->qos_map_set, qos_map_set, count); 602 hapd->conf->qos_map_set_len = count; 603 604 return 0; 605} 606 607 608static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd, 609 const char *cmd) 610{ 611 u8 addr[ETH_ALEN]; 612 struct sta_info *sta; 613 struct wpabuf *buf; 614 u8 *qos_map_set = hapd->conf->qos_map_set; 615 u8 qos_map_set_len = hapd->conf->qos_map_set_len; 616 int ret; 617 618 if (!qos_map_set_len) { 619 wpa_printf(MSG_INFO, "QoS Map Set is not set"); 620 return -1; 621 } 622 623 if (hwaddr_aton(cmd, addr)) 624 return -1; 625 626 sta = ap_get_sta(hapd, addr); 627 if (sta == NULL) { 628 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " 629 "for QoS Map Configuration message", 630 MAC2STR(addr)); 631 return -1; 632 } 633 634 if (!sta->qos_map_enabled) { 635 wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate " 636 "support for QoS Map", MAC2STR(addr)); 637 return -1; 638 } 639 640 buf = wpabuf_alloc(2 + 2 + qos_map_set_len); 641 if (buf == NULL) 642 return -1; 643 644 wpabuf_put_u8(buf, WLAN_ACTION_QOS); 645 wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG); 646 647 /* QoS Map Set Element */ 648 wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET); 649 wpabuf_put_u8(buf, qos_map_set_len); 650 wpabuf_put_data(buf, qos_map_set, qos_map_set_len); 651 652 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, 653 wpabuf_head(buf), wpabuf_len(buf)); 654 wpabuf_free(buf); 655 656 return ret; 657} 658 659#endif /* CONFIG_INTERWORKING */ 660 661 662#ifdef CONFIG_WNM 663 664static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, 665 const char *cmd) 666{ 667 u8 addr[ETH_ALEN]; 668 u8 buf[1000], *pos; 669 struct ieee80211_mgmt *mgmt; 670 int disassoc_timer; 671 672 if (hwaddr_aton(cmd, addr)) 673 return -1; 674 if (cmd[17] != ' ') 675 return -1; 676 disassoc_timer = atoi(cmd + 17); 677 678 os_memset(buf, 0, sizeof(buf)); 679 mgmt = (struct ieee80211_mgmt *) buf; 680 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 681 WLAN_FC_STYPE_ACTION); 682 os_memcpy(mgmt->da, addr, ETH_ALEN); 683 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 684 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 685 mgmt->u.action.category = WLAN_ACTION_WNM; 686 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 687 mgmt->u.action.u.bss_tm_req.dialog_token = 1; 688 mgmt->u.action.u.bss_tm_req.req_mode = 689 WNM_BSS_TM_REQ_DISASSOC_IMMINENT; 690 mgmt->u.action.u.bss_tm_req.disassoc_timer = 691 host_to_le16(disassoc_timer); 692 mgmt->u.action.u.bss_tm_req.validity_interval = 0; 693 694 pos = mgmt->u.action.u.bss_tm_req.variable; 695 696 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 697 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 698 "Management Request frame"); 699 return -1; 700 } 701 702 return 0; 703} 704 705 706static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, 707 const char *cmd) 708{ 709 u8 addr[ETH_ALEN]; 710 const char *url, *timerstr; 711 u8 buf[1000], *pos; 712 struct ieee80211_mgmt *mgmt; 713 size_t url_len; 714 int disassoc_timer; 715 716 if (hwaddr_aton(cmd, addr)) 717 return -1; 718 719 timerstr = cmd + 17; 720 if (*timerstr != ' ') 721 return -1; 722 timerstr++; 723 disassoc_timer = atoi(timerstr); 724 if (disassoc_timer < 0 || disassoc_timer > 65535) 725 return -1; 726 727 url = os_strchr(timerstr, ' '); 728 if (url == NULL) 729 return -1; 730 url++; 731 url_len = os_strlen(url); 732 if (url_len > 255) 733 return -1; 734 735 os_memset(buf, 0, sizeof(buf)); 736 mgmt = (struct ieee80211_mgmt *) buf; 737 mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 738 WLAN_FC_STYPE_ACTION); 739 os_memcpy(mgmt->da, addr, ETH_ALEN); 740 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); 741 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); 742 mgmt->u.action.category = WLAN_ACTION_WNM; 743 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; 744 mgmt->u.action.u.bss_tm_req.dialog_token = 1; 745 mgmt->u.action.u.bss_tm_req.req_mode = 746 WNM_BSS_TM_REQ_DISASSOC_IMMINENT | 747 WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; 748 mgmt->u.action.u.bss_tm_req.disassoc_timer = 749 host_to_le16(disassoc_timer); 750 mgmt->u.action.u.bss_tm_req.validity_interval = 0x01; 751 752 pos = mgmt->u.action.u.bss_tm_req.variable; 753 754 /* Session Information URL */ 755 *pos++ = url_len; 756 os_memcpy(pos, url, url_len); 757 pos += url_len; 758 759 if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { 760 wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " 761 "Management Request frame"); 762 return -1; 763 } 764 765 /* send disassociation frame after time-out */ 766 if (disassoc_timer) { 767 struct sta_info *sta; 768 int timeout, beacon_int; 769 770 /* 771 * Prevent STA from reconnecting using cached PMKSA to force 772 * full authentication with the authentication server (which may 773 * decide to reject the connection), 774 */ 775 wpa_auth_pmksa_remove(hapd->wpa_auth, addr); 776 777 sta = ap_get_sta(hapd, addr); 778 if (sta == NULL) { 779 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " 780 "for ESS disassociation imminent message", 781 MAC2STR(addr)); 782 return -1; 783 } 784 785 beacon_int = hapd->iconf->beacon_int; 786 if (beacon_int < 1) 787 beacon_int = 100; /* best guess */ 788 /* Calculate timeout in ms based on beacon_int in TU */ 789 timeout = disassoc_timer * beacon_int * 128 / 125; 790 wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR 791 " set to %d ms", MAC2STR(addr), timeout); 792 793 sta->timeout_next = STA_DISASSOC_FROM_CLI; 794 eloop_cancel_timeout(ap_handle_timer, hapd, sta); 795 eloop_register_timeout(timeout / 1000, 796 timeout % 1000 * 1000, 797 ap_handle_timer, hapd, sta); 798 } 799 800 return 0; 801} 802 803#endif /* CONFIG_WNM */ 804 805 806static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, 807 char *buf, size_t buflen) 808{ 809 int ret; 810 char *pos, *end; 811 812 pos = buf; 813 end = buf + buflen; 814 815 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n" 816 "ssid=%s\n", 817 MAC2STR(hapd->own_addr), 818 wpa_ssid_txt(hapd->conf->ssid.ssid, 819 hapd->conf->ssid.ssid_len)); 820 if (ret < 0 || ret >= end - pos) 821 return pos - buf; 822 pos += ret; 823 824#ifdef CONFIG_WPS 825 ret = os_snprintf(pos, end - pos, "wps_state=%s\n", 826 hapd->conf->wps_state == 0 ? "disabled" : 827 (hapd->conf->wps_state == 1 ? "not configured" : 828 "configured")); 829 if (ret < 0 || ret >= end - pos) 830 return pos - buf; 831 pos += ret; 832 833 if (hapd->conf->wps_state && hapd->conf->wpa && 834 hapd->conf->ssid.wpa_passphrase) { 835 ret = os_snprintf(pos, end - pos, "passphrase=%s\n", 836 hapd->conf->ssid.wpa_passphrase); 837 if (ret < 0 || ret >= end - pos) 838 return pos - buf; 839 pos += ret; 840 } 841 842 if (hapd->conf->wps_state && hapd->conf->wpa && 843 hapd->conf->ssid.wpa_psk && 844 hapd->conf->ssid.wpa_psk->group) { 845 char hex[PMK_LEN * 2 + 1]; 846 wpa_snprintf_hex(hex, sizeof(hex), 847 hapd->conf->ssid.wpa_psk->psk, PMK_LEN); 848 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex); 849 if (ret < 0 || ret >= end - pos) 850 return pos - buf; 851 pos += ret; 852 } 853#endif /* CONFIG_WPS */ 854 855 if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) { 856 ret = os_snprintf(pos, end - pos, "key_mgmt="); 857 if (ret < 0 || ret >= end - pos) 858 return pos - buf; 859 pos += ret; 860 861 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { 862 ret = os_snprintf(pos, end - pos, "WPA-PSK "); 863 if (ret < 0 || ret >= end - pos) 864 return pos - buf; 865 pos += ret; 866 } 867 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 868 ret = os_snprintf(pos, end - pos, "WPA-EAP "); 869 if (ret < 0 || ret >= end - pos) 870 return pos - buf; 871 pos += ret; 872 } 873#ifdef CONFIG_IEEE80211R 874 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { 875 ret = os_snprintf(pos, end - pos, "FT-PSK "); 876 if (ret < 0 || ret >= end - pos) 877 return pos - buf; 878 pos += ret; 879 } 880 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 881 ret = os_snprintf(pos, end - pos, "FT-EAP "); 882 if (ret < 0 || ret >= end - pos) 883 return pos - buf; 884 pos += ret; 885 } 886#endif /* CONFIG_IEEE80211R */ 887#ifdef CONFIG_IEEE80211W 888 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 889 ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 "); 890 if (ret < 0 || ret >= end - pos) 891 return pos - buf; 892 pos += ret; 893 } 894 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 895 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 "); 896 if (ret < 0 || ret >= end - pos) 897 return pos - buf; 898 pos += ret; 899 } 900#endif /* CONFIG_IEEE80211W */ 901 902 ret = os_snprintf(pos, end - pos, "\n"); 903 if (ret < 0 || ret >= end - pos) 904 return pos - buf; 905 pos += ret; 906 } 907 908 if (hapd->conf->wpa) { 909 ret = os_snprintf(pos, end - pos, "group_cipher=%s\n", 910 wpa_cipher_txt(hapd->conf->wpa_group)); 911 if (ret < 0 || ret >= end - pos) 912 return pos - buf; 913 pos += ret; 914 } 915 916 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) { 917 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher="); 918 if (ret < 0 || ret >= end - pos) 919 return pos - buf; 920 pos += ret; 921 922 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise, 923 " "); 924 if (ret < 0) 925 return pos - buf; 926 pos += ret; 927 928 ret = os_snprintf(pos, end - pos, "\n"); 929 if (ret < 0 || ret >= end - pos) 930 return pos - buf; 931 pos += ret; 932 } 933 934 if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) { 935 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher="); 936 if (ret < 0 || ret >= end - pos) 937 return pos - buf; 938 pos += ret; 939 940 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise, 941 " "); 942 if (ret < 0) 943 return pos - buf; 944 pos += ret; 945 946 ret = os_snprintf(pos, end - pos, "\n"); 947 if (ret < 0 || ret >= end - pos) 948 return pos - buf; 949 pos += ret; 950 } 951 952 return pos - buf; 953} 954 955 956static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) 957{ 958 char *value; 959 int ret = 0; 960 961 value = os_strchr(cmd, ' '); 962 if (value == NULL) 963 return -1; 964 *value++ = '\0'; 965 966 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); 967 if (0) { 968#ifdef CONFIG_WPS_TESTING 969 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { 970 long int val; 971 val = strtol(value, NULL, 0); 972 if (val < 0 || val > 0xff) { 973 ret = -1; 974 wpa_printf(MSG_DEBUG, "WPS: Invalid " 975 "wps_version_number %ld", val); 976 } else { 977 wps_version_number = val; 978 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " 979 "version %u.%u", 980 (wps_version_number & 0xf0) >> 4, 981 wps_version_number & 0x0f); 982 hostapd_wps_update_ie(hapd); 983 } 984 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { 985 wps_testing_dummy_cred = atoi(value); 986 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", 987 wps_testing_dummy_cred); 988#endif /* CONFIG_WPS_TESTING */ 989#ifdef CONFIG_INTERWORKING 990 } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) { 991 int val = atoi(value); 992 if (val <= 0) 993 ret = -1; 994 else 995 hapd->gas_frag_limit = val; 996#endif /* CONFIG_INTERWORKING */ 997 } else { 998 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); 999 } 1000 1001 return ret; 1002} 1003 1004 1005static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd, 1006 char *buf, size_t buflen) 1007{ 1008 int res; 1009 1010 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); 1011 1012 if (os_strcmp(cmd, "version") == 0) { 1013 res = os_snprintf(buf, buflen, "%s", VERSION_STR); 1014 if (res < 0 || (unsigned int) res >= buflen) 1015 return -1; 1016 return res; 1017 } 1018 1019 return -1; 1020} 1021 1022 1023static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface) 1024{ 1025 if (hostapd_enable_iface(iface) < 0) { 1026 wpa_printf(MSG_ERROR, "Enabling of interface failed"); 1027 return -1; 1028 } 1029 return 0; 1030} 1031 1032 1033static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface) 1034{ 1035 if (hostapd_reload_iface(iface) < 0) { 1036 wpa_printf(MSG_ERROR, "Reloading of interface failed"); 1037 return -1; 1038 } 1039 return 0; 1040} 1041 1042 1043static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) 1044{ 1045 if (hostapd_disable_iface(iface) < 0) { 1046 wpa_printf(MSG_ERROR, "Disabling of interface failed"); 1047 return -1; 1048 } 1049 return 0; 1050} 1051 1052 1053#ifdef CONFIG_TESTING_OPTIONS 1054static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) 1055{ 1056 union wpa_event_data data; 1057 char *pos, *param; 1058 enum wpa_event_type event; 1059 1060 wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd); 1061 1062 os_memset(&data, 0, sizeof(data)); 1063 1064 param = os_strchr(cmd, ' '); 1065 if (param == NULL) 1066 return -1; 1067 *param++ = '\0'; 1068 1069 if (os_strcmp(cmd, "DETECTED") == 0) 1070 event = EVENT_DFS_RADAR_DETECTED; 1071 else if (os_strcmp(cmd, "CAC-FINISHED") == 0) 1072 event = EVENT_DFS_CAC_FINISHED; 1073 else if (os_strcmp(cmd, "CAC-ABORTED") == 0) 1074 event = EVENT_DFS_CAC_ABORTED; 1075 else if (os_strcmp(cmd, "NOP-FINISHED") == 0) 1076 event = EVENT_DFS_NOP_FINISHED; 1077 else { 1078 wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s", 1079 cmd); 1080 return -1; 1081 } 1082 1083 pos = os_strstr(param, "freq="); 1084 if (pos) 1085 data.dfs_event.freq = atoi(pos + 5); 1086 1087 pos = os_strstr(param, "ht_enabled=1"); 1088 if (pos) 1089 data.dfs_event.ht_enabled = 1; 1090 1091 pos = os_strstr(param, "chan_offset="); 1092 if (pos) 1093 data.dfs_event.chan_offset = atoi(pos + 12); 1094 1095 pos = os_strstr(param, "chan_width="); 1096 if (pos) 1097 data.dfs_event.chan_width = atoi(pos + 11); 1098 1099 pos = os_strstr(param, "cf1="); 1100 if (pos) 1101 data.dfs_event.cf1 = atoi(pos + 4); 1102 1103 pos = os_strstr(param, "cf2="); 1104 if (pos) 1105 data.dfs_event.cf2 = atoi(pos + 4); 1106 1107 wpa_supplicant_event(hapd, event, &data); 1108 1109 return 0; 1110} 1111#endif /* CONFIG_TESTING_OPTIONS */ 1112 1113 1114static int hostapd_ctrl_iface_chan_switch(struct hostapd_data *hapd, char *pos) 1115{ 1116#ifdef NEED_AP_MLME 1117 struct csa_settings settings; 1118 int ret = hostapd_parse_csa_settings(pos, &settings); 1119 1120 if (ret) 1121 return ret; 1122 1123 return hostapd_switch_channel(hapd, &settings); 1124#else /* NEED_AP_MLME */ 1125 return -1; 1126#endif /* NEED_AP_MLME */ 1127} 1128 1129 1130static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, 1131 void *sock_ctx) 1132{ 1133 struct hostapd_data *hapd = eloop_ctx; 1134 char buf[256]; 1135 int res; 1136 struct sockaddr_un from; 1137 socklen_t fromlen = sizeof(from); 1138 char *reply; 1139 const int reply_size = 4096; 1140 int reply_len; 1141 int level = MSG_DEBUG; 1142 1143 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 1144 (struct sockaddr *) &from, &fromlen); 1145 if (res < 0) { 1146 perror("recvfrom(ctrl_iface)"); 1147 return; 1148 } 1149 buf[res] = '\0'; 1150 if (os_strcmp(buf, "PING") == 0) 1151 level = MSG_EXCESSIVE; 1152 wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res); 1153 1154 reply = os_malloc(reply_size); 1155 if (reply == NULL) { 1156 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 1157 fromlen); 1158 return; 1159 } 1160 1161 os_memcpy(reply, "OK\n", 3); 1162 reply_len = 3; 1163 1164 if (os_strcmp(buf, "PING") == 0) { 1165 os_memcpy(reply, "PONG\n", 5); 1166 reply_len = 5; 1167 } else if (os_strncmp(buf, "RELOG", 5) == 0) { 1168 if (wpa_debug_reopen_file() < 0) 1169 reply_len = -1; 1170 } else if (os_strcmp(buf, "STATUS") == 0) { 1171 reply_len = hostapd_ctrl_iface_status(hapd, reply, 1172 reply_size); 1173 } else if (os_strcmp(buf, "MIB") == 0) { 1174 reply_len = ieee802_11_get_mib(hapd, reply, reply_size); 1175 if (reply_len >= 0) { 1176 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, 1177 reply_size - reply_len); 1178 if (res < 0) 1179 reply_len = -1; 1180 else 1181 reply_len += res; 1182 } 1183 if (reply_len >= 0) { 1184 res = ieee802_1x_get_mib(hapd, reply + reply_len, 1185 reply_size - reply_len); 1186 if (res < 0) 1187 reply_len = -1; 1188 else 1189 reply_len += res; 1190 } 1191#ifndef CONFIG_NO_RADIUS 1192 if (reply_len >= 0) { 1193 res = radius_client_get_mib(hapd->radius, 1194 reply + reply_len, 1195 reply_size - reply_len); 1196 if (res < 0) 1197 reply_len = -1; 1198 else 1199 reply_len += res; 1200 } 1201#endif /* CONFIG_NO_RADIUS */ 1202 } else if (os_strcmp(buf, "STA-FIRST") == 0) { 1203 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, 1204 reply_size); 1205 } else if (os_strncmp(buf, "STA ", 4) == 0) { 1206 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, 1207 reply_size); 1208 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { 1209 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, 1210 reply_size); 1211 } else if (os_strcmp(buf, "ATTACH") == 0) { 1212 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) 1213 reply_len = -1; 1214 } else if (os_strcmp(buf, "DETACH") == 0) { 1215 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) 1216 reply_len = -1; 1217 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 1218 if (hostapd_ctrl_iface_level(hapd, &from, fromlen, 1219 buf + 6)) 1220 reply_len = -1; 1221 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { 1222 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) 1223 reply_len = -1; 1224 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { 1225 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15)) 1226 reply_len = -1; 1227 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { 1228 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) 1229 reply_len = -1; 1230#ifdef CONFIG_IEEE80211W 1231#ifdef NEED_AP_MLME 1232 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { 1233 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) 1234 reply_len = -1; 1235#endif /* NEED_AP_MLME */ 1236#endif /* CONFIG_IEEE80211W */ 1237#ifdef CONFIG_WPS 1238 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { 1239 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) 1240 reply_len = -1; 1241 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { 1242 reply_len = hostapd_ctrl_iface_wps_check_pin( 1243 hapd, buf + 14, reply, reply_size); 1244 } else if (os_strcmp(buf, "WPS_PBC") == 0) { 1245 if (hostapd_wps_button_pushed(hapd, NULL)) 1246 reply_len = -1; 1247 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { 1248 if (hostapd_wps_cancel(hapd)) 1249 reply_len = -1; 1250 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { 1251 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11, 1252 reply, reply_size); 1253 } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) { 1254 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0) 1255 reply_len = -1; 1256 } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) { 1257 reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply, 1258 reply_size); 1259#ifdef CONFIG_WPS_NFC 1260 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { 1261 if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17)) 1262 reply_len = -1; 1263 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) { 1264 reply_len = hostapd_ctrl_iface_wps_nfc_config_token( 1265 hapd, buf + 21, reply, reply_size); 1266 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { 1267 reply_len = hostapd_ctrl_iface_wps_nfc_token( 1268 hapd, buf + 14, reply, reply_size); 1269 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) { 1270 reply_len = hostapd_ctrl_iface_nfc_get_handover_sel( 1271 hapd, buf + 21, reply, reply_size); 1272 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) { 1273 if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20)) 1274 reply_len = -1; 1275#endif /* CONFIG_WPS_NFC */ 1276#endif /* CONFIG_WPS */ 1277#ifdef CONFIG_INTERWORKING 1278 } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) { 1279 if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16)) 1280 reply_len = -1; 1281 } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) { 1282 if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18)) 1283 reply_len = -1; 1284#endif /* CONFIG_INTERWORKING */ 1285#ifdef CONFIG_WNM 1286 } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { 1287 if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18)) 1288 reply_len = -1; 1289 } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) { 1290 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13)) 1291 reply_len = -1; 1292#endif /* CONFIG_WNM */ 1293 } else if (os_strcmp(buf, "GET_CONFIG") == 0) { 1294 reply_len = hostapd_ctrl_iface_get_config(hapd, reply, 1295 reply_size); 1296 } else if (os_strncmp(buf, "SET ", 4) == 0) { 1297 if (hostapd_ctrl_iface_set(hapd, buf + 4)) 1298 reply_len = -1; 1299 } else if (os_strncmp(buf, "GET ", 4) == 0) { 1300 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply, 1301 reply_size); 1302 } else if (os_strncmp(buf, "ENABLE", 6) == 0) { 1303 if (hostapd_ctrl_iface_enable(hapd->iface)) 1304 reply_len = -1; 1305 } else if (os_strncmp(buf, "RELOAD", 6) == 0) { 1306 if (hostapd_ctrl_iface_reload(hapd->iface)) 1307 reply_len = -1; 1308 } else if (os_strncmp(buf, "DISABLE", 7) == 0) { 1309 if (hostapd_ctrl_iface_disable(hapd->iface)) 1310 reply_len = -1; 1311#ifdef CONFIG_TESTING_OPTIONS 1312 } else if (os_strncmp(buf, "RADAR ", 6) == 0) { 1313 if (hostapd_ctrl_iface_radar(hapd, buf + 6)) 1314 reply_len = -1; 1315#endif /* CONFIG_TESTING_OPTIONS */ 1316 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { 1317 if (hostapd_ctrl_iface_chan_switch(hapd, buf + 12)) 1318 reply_len = -1; 1319 } else { 1320 os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 1321 reply_len = 16; 1322 } 1323 1324 if (reply_len < 0) { 1325 os_memcpy(reply, "FAIL\n", 5); 1326 reply_len = 5; 1327 } 1328 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); 1329 os_free(reply); 1330} 1331 1332 1333static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) 1334{ 1335 char *buf; 1336 size_t len; 1337 1338 if (hapd->conf->ctrl_interface == NULL) 1339 return NULL; 1340 1341 len = os_strlen(hapd->conf->ctrl_interface) + 1342 os_strlen(hapd->conf->iface) + 2; 1343 buf = os_malloc(len); 1344 if (buf == NULL) 1345 return NULL; 1346 1347 os_snprintf(buf, len, "%s/%s", 1348 hapd->conf->ctrl_interface, hapd->conf->iface); 1349 buf[len - 1] = '\0'; 1350 return buf; 1351} 1352 1353 1354static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global, 1355 const char *txt, size_t len) 1356{ 1357 struct hostapd_data *hapd = ctx; 1358 if (hapd == NULL) 1359 return; 1360 hostapd_ctrl_iface_send(hapd, level, txt, len); 1361} 1362 1363 1364int hostapd_ctrl_iface_init(struct hostapd_data *hapd) 1365{ 1366 struct sockaddr_un addr; 1367 int s = -1; 1368 char *fname = NULL; 1369 1370 if (hapd->ctrl_sock > -1) { 1371 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!"); 1372 return 0; 1373 } 1374 1375 if (hapd->conf->ctrl_interface == NULL) 1376 return 0; 1377 1378 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 1379 if (errno == EEXIST) { 1380 wpa_printf(MSG_DEBUG, "Using existing control " 1381 "interface directory."); 1382 } else { 1383 perror("mkdir[ctrl_interface]"); 1384 goto fail; 1385 } 1386 } 1387 1388 if (hapd->conf->ctrl_interface_gid_set && 1389 chown(hapd->conf->ctrl_interface, -1, 1390 hapd->conf->ctrl_interface_gid) < 0) { 1391 perror("chown[ctrl_interface]"); 1392 return -1; 1393 } 1394 1395 if (!hapd->conf->ctrl_interface_gid_set && 1396 hapd->iface->interfaces->ctrl_iface_group && 1397 chown(hapd->conf->ctrl_interface, -1, 1398 hapd->iface->interfaces->ctrl_iface_group) < 0) { 1399 perror("chown[ctrl_interface]"); 1400 return -1; 1401 } 1402 1403#ifdef ANDROID 1404 /* 1405 * Android is using umask 0077 which would leave the control interface 1406 * directory without group access. This breaks things since Wi-Fi 1407 * framework assumes that this directory can be accessed by other 1408 * applications in the wifi group. Fix this by adding group access even 1409 * if umask value would prevent this. 1410 */ 1411 if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 1412 wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", 1413 strerror(errno)); 1414 /* Try to continue anyway */ 1415 } 1416#endif /* ANDROID */ 1417 1418 if (os_strlen(hapd->conf->ctrl_interface) + 1 + 1419 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) 1420 goto fail; 1421 1422 s = socket(PF_UNIX, SOCK_DGRAM, 0); 1423 if (s < 0) { 1424 perror("socket(PF_UNIX)"); 1425 goto fail; 1426 } 1427 1428 os_memset(&addr, 0, sizeof(addr)); 1429#ifdef __FreeBSD__ 1430 addr.sun_len = sizeof(addr); 1431#endif /* __FreeBSD__ */ 1432 addr.sun_family = AF_UNIX; 1433 fname = hostapd_ctrl_iface_path(hapd); 1434 if (fname == NULL) 1435 goto fail; 1436 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 1437 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1438 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 1439 strerror(errno)); 1440 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1441 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 1442 " allow connections - assuming it was left" 1443 "over from forced program termination"); 1444 if (unlink(fname) < 0) { 1445 perror("unlink[ctrl_iface]"); 1446 wpa_printf(MSG_ERROR, "Could not unlink " 1447 "existing ctrl_iface socket '%s'", 1448 fname); 1449 goto fail; 1450 } 1451 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 1452 0) { 1453 perror("hostapd-ctrl-iface: bind(PF_UNIX)"); 1454 goto fail; 1455 } 1456 wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 1457 "ctrl_iface socket '%s'", fname); 1458 } else { 1459 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 1460 "be in use - cannot override it"); 1461 wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 1462 "not used anymore", fname); 1463 os_free(fname); 1464 fname = NULL; 1465 goto fail; 1466 } 1467 } 1468 1469 if (hapd->conf->ctrl_interface_gid_set && 1470 chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) { 1471 perror("chown[ctrl_interface/ifname]"); 1472 goto fail; 1473 } 1474 1475 if (!hapd->conf->ctrl_interface_gid_set && 1476 hapd->iface->interfaces->ctrl_iface_group && 1477 chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) { 1478 perror("chown[ctrl_interface/ifname]"); 1479 goto fail; 1480 } 1481 1482 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 1483 perror("chmod[ctrl_interface/ifname]"); 1484 goto fail; 1485 } 1486 os_free(fname); 1487 1488 hapd->ctrl_sock = s; 1489 eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, 1490 NULL); 1491 hapd->msg_ctx = hapd; 1492 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); 1493 1494 return 0; 1495 1496fail: 1497 if (s >= 0) 1498 close(s); 1499 if (fname) { 1500 unlink(fname); 1501 os_free(fname); 1502 } 1503 return -1; 1504} 1505 1506 1507void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) 1508{ 1509 struct wpa_ctrl_dst *dst, *prev; 1510 1511 if (hapd->ctrl_sock > -1) { 1512 char *fname; 1513 eloop_unregister_read_sock(hapd->ctrl_sock); 1514 close(hapd->ctrl_sock); 1515 hapd->ctrl_sock = -1; 1516 fname = hostapd_ctrl_iface_path(hapd); 1517 if (fname) 1518 unlink(fname); 1519 os_free(fname); 1520 1521 if (hapd->conf->ctrl_interface && 1522 rmdir(hapd->conf->ctrl_interface) < 0) { 1523 if (errno == ENOTEMPTY) { 1524 wpa_printf(MSG_DEBUG, "Control interface " 1525 "directory not empty - leaving it " 1526 "behind"); 1527 } else { 1528 wpa_printf(MSG_ERROR, 1529 "rmdir[ctrl_interface=%s]: %s", 1530 hapd->conf->ctrl_interface, 1531 strerror(errno)); 1532 } 1533 } 1534 } 1535 1536 dst = hapd->ctrl_dst; 1537 while (dst) { 1538 prev = dst; 1539 dst = dst->next; 1540 os_free(prev); 1541 } 1542} 1543 1544 1545static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces, 1546 char *buf) 1547{ 1548 if (hostapd_add_iface(interfaces, buf) < 0) { 1549 wpa_printf(MSG_ERROR, "Adding interface %s failed", buf); 1550 return -1; 1551 } 1552 return 0; 1553} 1554 1555 1556static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, 1557 char *buf) 1558{ 1559 if (hostapd_remove_iface(interfaces, buf) < 0) { 1560 wpa_printf(MSG_ERROR, "Removing interface %s failed", buf); 1561 return -1; 1562 } 1563 return 0; 1564} 1565 1566 1567static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, 1568 void *sock_ctx) 1569{ 1570 void *interfaces = eloop_ctx; 1571 char buf[256]; 1572 int res; 1573 struct sockaddr_un from; 1574 socklen_t fromlen = sizeof(from); 1575 char reply[24]; 1576 int reply_len; 1577 1578 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 1579 (struct sockaddr *) &from, &fromlen); 1580 if (res < 0) { 1581 perror("recvfrom(ctrl_iface)"); 1582 return; 1583 } 1584 buf[res] = '\0'; 1585 wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf); 1586 1587 os_memcpy(reply, "OK\n", 3); 1588 reply_len = 3; 1589 1590 if (os_strcmp(buf, "PING") == 0) { 1591 os_memcpy(reply, "PONG\n", 5); 1592 reply_len = 5; 1593 } else if (os_strncmp(buf, "RELOG", 5) == 0) { 1594 if (wpa_debug_reopen_file() < 0) 1595 reply_len = -1; 1596 } else if (os_strncmp(buf, "ADD ", 4) == 0) { 1597 if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0) 1598 reply_len = -1; 1599 } else if (os_strncmp(buf, "REMOVE ", 7) == 0) { 1600 if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0) 1601 reply_len = -1; 1602 } else { 1603 wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " 1604 "ignored"); 1605 reply_len = -1; 1606 } 1607 1608 if (reply_len < 0) { 1609 os_memcpy(reply, "FAIL\n", 5); 1610 reply_len = 5; 1611 } 1612 1613 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen); 1614} 1615 1616 1617static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) 1618{ 1619 char *buf; 1620 size_t len; 1621 1622 if (interface->global_iface_path == NULL) 1623 return NULL; 1624 1625 len = os_strlen(interface->global_iface_path) + 1626 os_strlen(interface->global_iface_name) + 2; 1627 buf = os_malloc(len); 1628 if (buf == NULL) 1629 return NULL; 1630 1631 os_snprintf(buf, len, "%s/%s", interface->global_iface_path, 1632 interface->global_iface_name); 1633 buf[len - 1] = '\0'; 1634 return buf; 1635} 1636 1637 1638int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) 1639{ 1640 struct sockaddr_un addr; 1641 int s = -1; 1642 char *fname = NULL; 1643 1644 if (interface->global_iface_path == NULL) { 1645 wpa_printf(MSG_DEBUG, "ctrl_iface not configured!"); 1646 return 0; 1647 } 1648 1649 if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) { 1650 if (errno == EEXIST) { 1651 wpa_printf(MSG_DEBUG, "Using existing control " 1652 "interface directory."); 1653 } else { 1654 perror("mkdir[ctrl_interface]"); 1655 goto fail; 1656 } 1657 } else if (interface->ctrl_iface_group && 1658 chown(interface->global_iface_path, -1, 1659 interface->ctrl_iface_group) < 0) { 1660 perror("chown[ctrl_interface]"); 1661 goto fail; 1662 } 1663 1664 if (os_strlen(interface->global_iface_path) + 1 + 1665 os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path)) 1666 goto fail; 1667 1668 s = socket(PF_UNIX, SOCK_DGRAM, 0); 1669 if (s < 0) { 1670 perror("socket(PF_UNIX)"); 1671 goto fail; 1672 } 1673 1674 os_memset(&addr, 0, sizeof(addr)); 1675#ifdef __FreeBSD__ 1676 addr.sun_len = sizeof(addr); 1677#endif /* __FreeBSD__ */ 1678 addr.sun_family = AF_UNIX; 1679 fname = hostapd_global_ctrl_iface_path(interface); 1680 if (fname == NULL) 1681 goto fail; 1682 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 1683 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1684 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 1685 strerror(errno)); 1686 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1687 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 1688 " allow connections - assuming it was left" 1689 "over from forced program termination"); 1690 if (unlink(fname) < 0) { 1691 perror("unlink[ctrl_iface]"); 1692 wpa_printf(MSG_ERROR, "Could not unlink " 1693 "existing ctrl_iface socket '%s'", 1694 fname); 1695 goto fail; 1696 } 1697 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 1698 0) { 1699 perror("bind(PF_UNIX)"); 1700 goto fail; 1701 } 1702 wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 1703 "ctrl_iface socket '%s'", fname); 1704 } else { 1705 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 1706 "be in use - cannot override it"); 1707 wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 1708 "not used anymore", fname); 1709 os_free(fname); 1710 fname = NULL; 1711 goto fail; 1712 } 1713 } 1714 1715 if (interface->ctrl_iface_group && 1716 chown(fname, -1, interface->ctrl_iface_group) < 0) { 1717 perror("chown[ctrl_interface]"); 1718 goto fail; 1719 } 1720 1721 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 1722 perror("chmod[ctrl_interface/ifname]"); 1723 goto fail; 1724 } 1725 os_free(fname); 1726 1727 interface->global_ctrl_sock = s; 1728 eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive, 1729 interface, NULL); 1730 1731 return 0; 1732 1733fail: 1734 if (s >= 0) 1735 close(s); 1736 if (fname) { 1737 unlink(fname); 1738 os_free(fname); 1739 } 1740 return -1; 1741} 1742 1743 1744void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) 1745{ 1746 char *fname = NULL; 1747 1748 if (interfaces->global_ctrl_sock > -1) { 1749 eloop_unregister_read_sock(interfaces->global_ctrl_sock); 1750 close(interfaces->global_ctrl_sock); 1751 interfaces->global_ctrl_sock = -1; 1752 fname = hostapd_global_ctrl_iface_path(interfaces); 1753 if (fname) { 1754 unlink(fname); 1755 os_free(fname); 1756 } 1757 1758 if (interfaces->global_iface_path && 1759 rmdir(interfaces->global_iface_path) < 0) { 1760 if (errno == ENOTEMPTY) { 1761 wpa_printf(MSG_DEBUG, "Control interface " 1762 "directory not empty - leaving it " 1763 "behind"); 1764 } else { 1765 wpa_printf(MSG_ERROR, 1766 "rmdir[ctrl_interface=%s]: %s", 1767 interfaces->global_iface_path, 1768 strerror(errno)); 1769 } 1770 } 1771 os_free(interfaces->global_iface_path); 1772 interfaces->global_iface_path = NULL; 1773 } 1774} 1775 1776 1777static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 1778 const char *buf, size_t len) 1779{ 1780 struct wpa_ctrl_dst *dst, *next; 1781 struct msghdr msg; 1782 int idx; 1783 struct iovec io[2]; 1784 char levelstr[10]; 1785 1786 dst = hapd->ctrl_dst; 1787 if (hapd->ctrl_sock < 0 || dst == NULL) 1788 return; 1789 1790 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 1791 io[0].iov_base = levelstr; 1792 io[0].iov_len = os_strlen(levelstr); 1793 io[1].iov_base = (char *) buf; 1794 io[1].iov_len = len; 1795 os_memset(&msg, 0, sizeof(msg)); 1796 msg.msg_iov = io; 1797 msg.msg_iovlen = 2; 1798 1799 idx = 0; 1800 while (dst) { 1801 next = dst->next; 1802 if (level >= dst->debug_level) { 1803 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", 1804 (u8 *) dst->addr.sun_path, dst->addrlen - 1805 offsetof(struct sockaddr_un, sun_path)); 1806 msg.msg_name = &dst->addr; 1807 msg.msg_namelen = dst->addrlen; 1808 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { 1809 int _errno = errno; 1810 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " 1811 "%d - %s", 1812 idx, errno, strerror(errno)); 1813 dst->errors++; 1814 if (dst->errors > 10 || _errno == ENOENT) { 1815 hostapd_ctrl_iface_detach( 1816 hapd, &dst->addr, 1817 dst->addrlen); 1818 } 1819 } else 1820 dst->errors = 0; 1821 } 1822 idx++; 1823 dst = next; 1824 } 1825} 1826 1827#endif /* CONFIG_NATIVE_WINDOWS */ 1828