1 /* 2 * hostapd / UNIX domain socket -based control interface 3 * Copyright (c) 2004-2015, 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 #ifdef CONFIG_TESTING_OPTIONS 14 #include <net/ethernet.h> 15 #include <netinet/ip.h> 16 #endif /* CONFIG_TESTING_OPTIONS */ 17 18 #include <sys/un.h> 19 #include <sys/stat.h> 20 #include <stddef.h> 21 22 #include "utils/common.h" 23 #include "utils/eloop.h" 24 #include "common/version.h" 25 #include "common/ieee802_11_defs.h" 26 #include "crypto/tls.h" 27 #include "drivers/driver.h" 28 #include "radius/radius_client.h" 29 #include "radius/radius_server.h" 30 #include "l2_packet/l2_packet.h" 31 #include "ap/hostapd.h" 32 #include "ap/ap_config.h" 33 #include "ap/ieee802_1x.h" 34 #include "ap/wpa_auth.h" 35 #include "ap/ieee802_11.h" 36 #include "ap/sta_info.h" 37 #include "ap/wps_hostapd.h" 38 #include "ap/ctrl_iface_ap.h" 39 #include "ap/ap_drv_ops.h" 40 #include "ap/hs20.h" 41 #include "ap/wnm_ap.h" 42 #include "ap/wpa_auth.h" 43 #include "ap/beacon.h" 44 #include "wps/wps_defs.h" 45 #include "wps/wps.h" 46 #include "config_file.h" 47 #include "ctrl_iface.h" 48 49 50 struct wpa_ctrl_dst { 51 struct wpa_ctrl_dst *next; 52 struct sockaddr_un addr; 53 socklen_t addrlen; 54 int debug_level; 55 int errors; 56 }; 57 58 59 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 60 const char *buf, size_t len); 61 62 63 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd, 64 struct sockaddr_un *from, 65 socklen_t fromlen) 66 { 67 struct wpa_ctrl_dst *dst; 68 69 dst = os_zalloc(sizeof(*dst)); 70 if (dst == NULL) 71 return -1; 72 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 73 dst->addrlen = fromlen; 74 dst->debug_level = MSG_INFO; 75 dst->next = hapd->ctrl_dst; 76 hapd->ctrl_dst = dst; 77 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", 78 (u8 *) from->sun_path, 79 fromlen - offsetof(struct sockaddr_un, sun_path)); 80 return 0; 81 } 82 83 84 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd, 85 struct sockaddr_un *from, 86 socklen_t fromlen) 87 { 88 struct wpa_ctrl_dst *dst, *prev = NULL; 89 90 dst = hapd->ctrl_dst; 91 while (dst) { 92 if (fromlen == dst->addrlen && 93 os_memcmp(from->sun_path, dst->addr.sun_path, 94 fromlen - offsetof(struct sockaddr_un, sun_path)) 95 == 0) { 96 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", 97 (u8 *) from->sun_path, 98 fromlen - 99 offsetof(struct sockaddr_un, sun_path)); 100 if (prev == NULL) 101 hapd->ctrl_dst = dst->next; 102 else 103 prev->next = dst->next; 104 os_free(dst); 105 return 0; 106 } 107 prev = dst; 108 dst = dst->next; 109 } 110 return -1; 111 } 112 113 114 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd, 115 struct sockaddr_un *from, 116 socklen_t fromlen, 117 char *level) 118 { 119 struct wpa_ctrl_dst *dst; 120 121 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 122 123 dst = hapd->ctrl_dst; 124 while (dst) { 125 if (fromlen == dst->addrlen && 126 os_memcmp(from->sun_path, dst->addr.sun_path, 127 fromlen - offsetof(struct sockaddr_un, sun_path)) 128 == 0) { 129 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " 130 "level", (u8 *) from->sun_path, fromlen - 131 offsetof(struct sockaddr_un, sun_path)); 132 dst->debug_level = atoi(level); 133 return 0; 134 } 135 dst = dst->next; 136 } 137 138 return -1; 139 } 140 141 142 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, 143 const char *txtaddr) 144 { 145 u8 addr[ETH_ALEN]; 146 struct sta_info *sta; 147 148 wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr); 149 150 if (hwaddr_aton(txtaddr, addr)) 151 return -1; 152 153 sta = ap_get_sta(hapd, addr); 154 if (sta) 155 return 0; 156 157 wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface " 158 "notification", MAC2STR(addr)); 159 sta = ap_sta_add(hapd, addr); 160 if (sta == NULL) 161 return -1; 162 163 hostapd_new_assoc_sta(hapd, sta, 0); 164 return 0; 165 } 166 167 168 #ifdef CONFIG_IEEE80211W 169 #ifdef NEED_AP_MLME 170 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, 171 const char *txtaddr) 172 { 173 u8 addr[ETH_ALEN]; 174 u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN]; 175 176 wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr); 177 178 if (hwaddr_aton(txtaddr, addr) || 179 os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) 180 return -1; 181 182 ieee802_11_send_sa_query_req(hapd, addr, trans_id); 183 184 return 0; 185 } 186 #endif /* NEED_AP_MLME */ 187 #endif /* CONFIG_IEEE80211W */ 188 189 190 #ifdef CONFIG_WPS 191 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt) 192 { 193 char *pin = os_strchr(txt, ' '); 194 char *timeout_txt; 195 int timeout; 196 u8 addr_buf[ETH_ALEN], *addr = NULL; 197 char *pos; 198 199 if (pin == NULL) 200 return -1; 201 *pin++ = '\0'; 202 203 timeout_txt = os_strchr(pin, ' '); 204 if (timeout_txt) { 205 *timeout_txt++ = '\0'; 206 timeout = atoi(timeout_txt); 207 pos = os_strchr(timeout_txt, ' '); 208 if (pos) { 209 *pos++ = '\0'; 210 if (hwaddr_aton(pos, addr_buf) == 0) 211 addr = addr_buf; 212 } 213 } else 214 timeout = 0; 215 216 return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout); 217 } 218 219 220 static int hostapd_ctrl_iface_wps_check_pin( 221 struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen) 222 { 223 char pin[9]; 224 size_t len; 225 char *pos; 226 int ret; 227 228 wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN", 229 (u8 *) cmd, os_strlen(cmd)); 230 for (pos = cmd, len = 0; *pos != '\0'; pos++) { 231 if (*pos < '0' || *pos > '9') 232 continue; 233 pin[len++] = *pos; 234 if (len == 9) { 235 wpa_printf(MSG_DEBUG, "WPS: Too long PIN"); 236 return -1; 237 } 238 } 239 if (len != 4 && len != 8) { 240 wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len); 241 return -1; 242 } 243 pin[len] = '\0'; 244 245 if (len == 8) { 246 unsigned int pin_val; 247 pin_val = atoi(pin); 248 if (!wps_pin_valid(pin_val)) { 249 wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit"); 250 ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n"); 251 if (os_snprintf_error(buflen, ret)) 252 return -1; 253 return ret; 254 } 255 } 256 257 ret = os_snprintf(buf, buflen, "%s", pin); 258 if (os_snprintf_error(buflen, ret)) 259 return -1; 260 261 return ret; 262 } 263 264 265 #ifdef CONFIG_WPS_NFC 266 static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd, 267 char *pos) 268 { 269 size_t len; 270 struct wpabuf *buf; 271 int ret; 272 273 len = os_strlen(pos); 274 if (len & 0x01) 275 return -1; 276 len /= 2; 277 278 buf = wpabuf_alloc(len); 279 if (buf == NULL) 280 return -1; 281 if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { 282 wpabuf_free(buf); 283 return -1; 284 } 285 286 ret = hostapd_wps_nfc_tag_read(hapd, buf); 287 wpabuf_free(buf); 288 289 return ret; 290 } 291 292 293 static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd, 294 char *cmd, char *reply, 295 size_t max_len) 296 { 297 int ndef; 298 struct wpabuf *buf; 299 int res; 300 301 if (os_strcmp(cmd, "WPS") == 0) 302 ndef = 0; 303 else if (os_strcmp(cmd, "NDEF") == 0) 304 ndef = 1; 305 else 306 return -1; 307 308 buf = hostapd_wps_nfc_config_token(hapd, ndef); 309 if (buf == NULL) 310 return -1; 311 312 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 313 wpabuf_len(buf)); 314 reply[res++] = '\n'; 315 reply[res] = '\0'; 316 317 wpabuf_free(buf); 318 319 return res; 320 } 321 322 323 static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd, 324 char *reply, size_t max_len, 325 int ndef) 326 { 327 struct wpabuf *buf; 328 int res; 329 330 buf = hostapd_wps_nfc_token_gen(hapd, ndef); 331 if (buf == NULL) 332 return -1; 333 334 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 335 wpabuf_len(buf)); 336 reply[res++] = '\n'; 337 reply[res] = '\0'; 338 339 wpabuf_free(buf); 340 341 return res; 342 } 343 344 345 static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd, 346 char *cmd, char *reply, 347 size_t max_len) 348 { 349 if (os_strcmp(cmd, "WPS") == 0) 350 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, 351 max_len, 0); 352 353 if (os_strcmp(cmd, "NDEF") == 0) 354 return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply, 355 max_len, 1); 356 357 if (os_strcmp(cmd, "enable") == 0) 358 return hostapd_wps_nfc_token_enable(hapd); 359 360 if (os_strcmp(cmd, "disable") == 0) { 361 hostapd_wps_nfc_token_disable(hapd); 362 return 0; 363 } 364 365 return -1; 366 } 367 368 369 static int hostapd_ctrl_iface_nfc_get_handover_sel(struct hostapd_data *hapd, 370 char *cmd, char *reply, 371 size_t max_len) 372 { 373 struct wpabuf *buf; 374 int res; 375 char *pos; 376 int ndef; 377 378 pos = os_strchr(cmd, ' '); 379 if (pos == NULL) 380 return -1; 381 *pos++ = '\0'; 382 383 if (os_strcmp(cmd, "WPS") == 0) 384 ndef = 0; 385 else if (os_strcmp(cmd, "NDEF") == 0) 386 ndef = 1; 387 else 388 return -1; 389 390 if (os_strcmp(pos, "WPS-CR") == 0) 391 buf = hostapd_wps_nfc_hs_cr(hapd, ndef); 392 else 393 buf = NULL; 394 if (buf == NULL) 395 return -1; 396 397 res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf), 398 wpabuf_len(buf)); 399 reply[res++] = '\n'; 400 reply[res] = '\0'; 401 402 wpabuf_free(buf); 403 404 return res; 405 } 406 407 408 static int hostapd_ctrl_iface_nfc_report_handover(struct hostapd_data *hapd, 409 char *cmd) 410 { 411 size_t len; 412 struct wpabuf *req, *sel; 413 int ret; 414 char *pos, *role, *type, *pos2; 415 416 role = cmd; 417 pos = os_strchr(role, ' '); 418 if (pos == NULL) 419 return -1; 420 *pos++ = '\0'; 421 422 type = pos; 423 pos = os_strchr(type, ' '); 424 if (pos == NULL) 425 return -1; 426 *pos++ = '\0'; 427 428 pos2 = os_strchr(pos, ' '); 429 if (pos2 == NULL) 430 return -1; 431 *pos2++ = '\0'; 432 433 len = os_strlen(pos); 434 if (len & 0x01) 435 return -1; 436 len /= 2; 437 438 req = wpabuf_alloc(len); 439 if (req == NULL) 440 return -1; 441 if (hexstr2bin(pos, wpabuf_put(req, len), len) < 0) { 442 wpabuf_free(req); 443 return -1; 444 } 445 446 len = os_strlen(pos2); 447 if (len & 0x01) { 448 wpabuf_free(req); 449 return -1; 450 } 451 len /= 2; 452 453 sel = wpabuf_alloc(len); 454 if (sel == NULL) { 455 wpabuf_free(req); 456 return -1; 457 } 458 if (hexstr2bin(pos2, wpabuf_put(sel, len), len) < 0) { 459 wpabuf_free(req); 460 wpabuf_free(sel); 461 return -1; 462 } 463 464 if (os_strcmp(role, "RESP") == 0 && os_strcmp(type, "WPS") == 0) { 465 ret = hostapd_wps_nfc_report_handover(hapd, req, sel); 466 } else { 467 wpa_printf(MSG_DEBUG, "NFC: Unsupported connection handover " 468 "reported: role=%s type=%s", role, type); 469 ret = -1; 470 } 471 wpabuf_free(req); 472 wpabuf_free(sel); 473 474 return ret; 475 } 476 477 #endif /* CONFIG_WPS_NFC */ 478 479 480 static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt, 481 char *buf, size_t buflen) 482 { 483 int timeout = 300; 484 char *pos; 485 const char *pin_txt; 486 487 pos = os_strchr(txt, ' '); 488 if (pos) 489 *pos++ = '\0'; 490 491 if (os_strcmp(txt, "disable") == 0) { 492 hostapd_wps_ap_pin_disable(hapd); 493 return os_snprintf(buf, buflen, "OK\n"); 494 } 495 496 if (os_strcmp(txt, "random") == 0) { 497 if (pos) 498 timeout = atoi(pos); 499 pin_txt = hostapd_wps_ap_pin_random(hapd, timeout); 500 if (pin_txt == NULL) 501 return -1; 502 return os_snprintf(buf, buflen, "%s", pin_txt); 503 } 504 505 if (os_strcmp(txt, "get") == 0) { 506 pin_txt = hostapd_wps_ap_pin_get(hapd); 507 if (pin_txt == NULL) 508 return -1; 509 return os_snprintf(buf, buflen, "%s", pin_txt); 510 } 511 512 if (os_strcmp(txt, "set") == 0) { 513 char *pin; 514 if (pos == NULL) 515 return -1; 516 pin = pos; 517 pos = os_strchr(pos, ' '); 518 if (pos) { 519 *pos++ = '\0'; 520 timeout = atoi(pos); 521 } 522 if (os_strlen(pin) > buflen) 523 return -1; 524 if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0) 525 return -1; 526 return os_snprintf(buf, buflen, "%s", pin); 527 } 528 529 return -1; 530 } 531 532 533 static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt) 534 { 535 char *pos; 536 char *ssid, *auth, *encr = NULL, *key = NULL; 537 538 ssid = txt; 539 pos = os_strchr(txt, ' '); 540 if (!pos) 541 return -1; 542 *pos++ = '\0'; 543 544 auth = pos; 545 pos = os_strchr(pos, ' '); 546 if (pos) { 547 *pos++ = '\0'; 548 encr = pos; 549 pos = os_strchr(pos, ' '); 550 if (pos) { 551 *pos++ = '\0'; 552 key = pos; 553 } 554 } 555 556 return hostapd_wps_config_ap(hapd, ssid, auth, encr, key); 557 } 558 559 560 static const char * pbc_status_str(enum pbc_status status) 561 { 562 switch (status) { 563 case WPS_PBC_STATUS_DISABLE: 564 return "Disabled"; 565 case WPS_PBC_STATUS_ACTIVE: 566 return "Active"; 567 case WPS_PBC_STATUS_TIMEOUT: 568 return "Timed-out"; 569 case WPS_PBC_STATUS_OVERLAP: 570 return "Overlap"; 571 default: 572 return "Unknown"; 573 } 574 } 575 576 577 static int hostapd_ctrl_iface_wps_get_status(struct hostapd_data *hapd, 578 char *buf, size_t buflen) 579 { 580 int ret; 581 char *pos, *end; 582 583 pos = buf; 584 end = buf + buflen; 585 586 ret = os_snprintf(pos, end - pos, "PBC Status: %s\n", 587 pbc_status_str(hapd->wps_stats.pbc_status)); 588 589 if (os_snprintf_error(end - pos, ret)) 590 return pos - buf; 591 pos += ret; 592 593 ret = os_snprintf(pos, end - pos, "Last WPS result: %s\n", 594 (hapd->wps_stats.status == WPS_STATUS_SUCCESS ? 595 "Success": 596 (hapd->wps_stats.status == WPS_STATUS_FAILURE ? 597 "Failed" : "None"))); 598 599 if (os_snprintf_error(end - pos, ret)) 600 return pos - buf; 601 pos += ret; 602 603 /* If status == Failure - Add possible Reasons */ 604 if(hapd->wps_stats.status == WPS_STATUS_FAILURE && 605 hapd->wps_stats.failure_reason > 0) { 606 ret = os_snprintf(pos, end - pos, 607 "Failure Reason: %s\n", 608 wps_ei_str(hapd->wps_stats.failure_reason)); 609 610 if (os_snprintf_error(end - pos, ret)) 611 return pos - buf; 612 pos += ret; 613 } 614 615 if (hapd->wps_stats.status) { 616 ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n", 617 MAC2STR(hapd->wps_stats.peer_addr)); 618 619 if (os_snprintf_error(end - pos, ret)) 620 return pos - buf; 621 pos += ret; 622 } 623 624 return pos - buf; 625 } 626 627 #endif /* CONFIG_WPS */ 628 629 #ifdef CONFIG_HS20 630 631 static int hostapd_ctrl_iface_hs20_wnm_notif(struct hostapd_data *hapd, 632 const char *cmd) 633 { 634 u8 addr[ETH_ALEN]; 635 const char *url; 636 637 if (hwaddr_aton(cmd, addr)) 638 return -1; 639 url = cmd + 17; 640 if (*url == '\0') { 641 url = NULL; 642 } else { 643 if (*url != ' ') 644 return -1; 645 url++; 646 if (*url == '\0') 647 url = NULL; 648 } 649 650 return hs20_send_wnm_notification(hapd, addr, 1, url); 651 } 652 653 654 static int hostapd_ctrl_iface_hs20_deauth_req(struct hostapd_data *hapd, 655 const char *cmd) 656 { 657 u8 addr[ETH_ALEN]; 658 int code, reauth_delay, ret; 659 const char *pos; 660 size_t url_len; 661 struct wpabuf *req; 662 663 /* <STA MAC Addr> <Code(0/1)> <Re-auth-Delay(sec)> [URL] */ 664 if (hwaddr_aton(cmd, addr)) 665 return -1; 666 667 pos = os_strchr(cmd, ' '); 668 if (pos == NULL) 669 return -1; 670 pos++; 671 code = atoi(pos); 672 673 pos = os_strchr(pos, ' '); 674 if (pos == NULL) 675 return -1; 676 pos++; 677 reauth_delay = atoi(pos); 678 679 url_len = 0; 680 pos = os_strchr(pos, ' '); 681 if (pos) { 682 pos++; 683 url_len = os_strlen(pos); 684 } 685 686 req = wpabuf_alloc(4 + url_len); 687 if (req == NULL) 688 return -1; 689 wpabuf_put_u8(req, code); 690 wpabuf_put_le16(req, reauth_delay); 691 wpabuf_put_u8(req, url_len); 692 if (pos) 693 wpabuf_put_data(req, pos, url_len); 694 695 wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " MACSTR 696 " to indicate imminent deauthentication (code=%d " 697 "reauth_delay=%d)", MAC2STR(addr), code, reauth_delay); 698 ret = hs20_send_wnm_notification_deauth_req(hapd, addr, req); 699 wpabuf_free(req); 700 return ret; 701 } 702 703 #endif /* CONFIG_HS20 */ 704 705 706 #ifdef CONFIG_INTERWORKING 707 708 static int hostapd_ctrl_iface_set_qos_map_set(struct hostapd_data *hapd, 709 const char *cmd) 710 { 711 u8 qos_map_set[16 + 2 * 21], count = 0; 712 const char *pos = cmd; 713 int val, ret; 714 715 for (;;) { 716 if (count == sizeof(qos_map_set)) { 717 wpa_printf(MSG_ERROR, "Too many qos_map_set parameters"); 718 return -1; 719 } 720 721 val = atoi(pos); 722 if (val < 0 || val > 255) { 723 wpa_printf(MSG_INFO, "Invalid QoS Map Set"); 724 return -1; 725 } 726 727 qos_map_set[count++] = val; 728 pos = os_strchr(pos, ','); 729 if (!pos) 730 break; 731 pos++; 732 } 733 734 if (count < 16 || count & 1) { 735 wpa_printf(MSG_INFO, "Invalid QoS Map Set"); 736 return -1; 737 } 738 739 ret = hostapd_drv_set_qos_map(hapd, qos_map_set, count); 740 if (ret) { 741 wpa_printf(MSG_INFO, "Failed to set QoS Map Set"); 742 return -1; 743 } 744 745 os_memcpy(hapd->conf->qos_map_set, qos_map_set, count); 746 hapd->conf->qos_map_set_len = count; 747 748 return 0; 749 } 750 751 752 static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd, 753 const char *cmd) 754 { 755 u8 addr[ETH_ALEN]; 756 struct sta_info *sta; 757 struct wpabuf *buf; 758 u8 *qos_map_set = hapd->conf->qos_map_set; 759 u8 qos_map_set_len = hapd->conf->qos_map_set_len; 760 int ret; 761 762 if (!qos_map_set_len) { 763 wpa_printf(MSG_INFO, "QoS Map Set is not set"); 764 return -1; 765 } 766 767 if (hwaddr_aton(cmd, addr)) 768 return -1; 769 770 sta = ap_get_sta(hapd, addr); 771 if (sta == NULL) { 772 wpa_printf(MSG_DEBUG, "Station " MACSTR " not found " 773 "for QoS Map Configuration message", 774 MAC2STR(addr)); 775 return -1; 776 } 777 778 if (!sta->qos_map_enabled) { 779 wpa_printf(MSG_DEBUG, "Station " MACSTR " did not indicate " 780 "support for QoS Map", MAC2STR(addr)); 781 return -1; 782 } 783 784 buf = wpabuf_alloc(2 + 2 + qos_map_set_len); 785 if (buf == NULL) 786 return -1; 787 788 wpabuf_put_u8(buf, WLAN_ACTION_QOS); 789 wpabuf_put_u8(buf, QOS_QOS_MAP_CONFIG); 790 791 /* QoS Map Set Element */ 792 wpabuf_put_u8(buf, WLAN_EID_QOS_MAP_SET); 793 wpabuf_put_u8(buf, qos_map_set_len); 794 wpabuf_put_data(buf, qos_map_set, qos_map_set_len); 795 796 ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, 797 wpabuf_head(buf), wpabuf_len(buf)); 798 wpabuf_free(buf); 799 800 return ret; 801 } 802 803 #endif /* CONFIG_INTERWORKING */ 804 805 806 #ifdef CONFIG_WNM 807 808 static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, 809 const char *cmd) 810 { 811 u8 addr[ETH_ALEN]; 812 int disassoc_timer; 813 struct sta_info *sta; 814 815 if (hwaddr_aton(cmd, addr)) 816 return -1; 817 if (cmd[17] != ' ') 818 return -1; 819 disassoc_timer = atoi(cmd + 17); 820 821 sta = ap_get_sta(hapd, addr); 822 if (sta == NULL) { 823 wpa_printf(MSG_DEBUG, "Station " MACSTR 824 " not found for disassociation imminent message", 825 MAC2STR(addr)); 826 return -1; 827 } 828 829 return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); 830 } 831 832 833 static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, 834 const char *cmd) 835 { 836 u8 addr[ETH_ALEN]; 837 const char *url, *timerstr; 838 int disassoc_timer; 839 struct sta_info *sta; 840 841 if (hwaddr_aton(cmd, addr)) 842 return -1; 843 844 sta = ap_get_sta(hapd, addr); 845 if (sta == NULL) { 846 wpa_printf(MSG_DEBUG, "Station " MACSTR 847 " not found for ESS disassociation imminent message", 848 MAC2STR(addr)); 849 return -1; 850 } 851 852 timerstr = cmd + 17; 853 if (*timerstr != ' ') 854 return -1; 855 timerstr++; 856 disassoc_timer = atoi(timerstr); 857 if (disassoc_timer < 0 || disassoc_timer > 65535) 858 return -1; 859 860 url = os_strchr(timerstr, ' '); 861 if (url == NULL) 862 return -1; 863 url++; 864 865 return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); 866 } 867 868 869 static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, 870 const char *cmd) 871 { 872 u8 addr[ETH_ALEN]; 873 const char *pos, *end; 874 int disassoc_timer = 0; 875 struct sta_info *sta; 876 u8 req_mode = 0, valid_int = 0x01; 877 u8 bss_term_dur[12]; 878 char *url = NULL; 879 int ret; 880 u8 nei_rep[1000]; 881 u8 *nei_pos = nei_rep; 882 883 if (hwaddr_aton(cmd, addr)) { 884 wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); 885 return -1; 886 } 887 888 sta = ap_get_sta(hapd, addr); 889 if (sta == NULL) { 890 wpa_printf(MSG_DEBUG, "Station " MACSTR 891 " not found for BSS TM Request message", 892 MAC2STR(addr)); 893 return -1; 894 } 895 896 pos = os_strstr(cmd, " disassoc_timer="); 897 if (pos) { 898 pos += 16; 899 disassoc_timer = atoi(pos); 900 if (disassoc_timer < 0 || disassoc_timer > 65535) { 901 wpa_printf(MSG_DEBUG, "Invalid disassoc_timer"); 902 return -1; 903 } 904 } 905 906 pos = os_strstr(cmd, " valid_int="); 907 if (pos) { 908 pos += 11; 909 valid_int = atoi(pos); 910 } 911 912 pos = os_strstr(cmd, " bss_term="); 913 if (pos) { 914 pos += 10; 915 req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED; 916 /* TODO: TSF configurable/learnable */ 917 bss_term_dur[0] = 4; /* Subelement ID */ 918 bss_term_dur[1] = 10; /* Length */ 919 os_memset(bss_term_dur, 2, 8); 920 end = os_strchr(pos, ','); 921 if (end == NULL) { 922 wpa_printf(MSG_DEBUG, "Invalid bss_term data"); 923 return -1; 924 } 925 end++; 926 WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); 927 } 928 929 930 /* 931 * BSS Transition Candidate List Entries - Neighbor Report elements 932 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>, 933 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>] 934 */ 935 pos = cmd; 936 while (pos) { 937 u8 *nei_start; 938 long int val; 939 char *endptr, *tmp; 940 941 pos = os_strstr(pos, " neighbor="); 942 if (!pos) 943 break; 944 if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) { 945 wpa_printf(MSG_DEBUG, 946 "Not enough room for additional neighbor"); 947 return -1; 948 } 949 pos += 10; 950 951 nei_start = nei_pos; 952 *nei_pos++ = WLAN_EID_NEIGHBOR_REPORT; 953 nei_pos++; /* length to be filled in */ 954 955 if (hwaddr_aton(pos, nei_pos)) { 956 wpa_printf(MSG_DEBUG, "Invalid BSSID"); 957 return -1; 958 } 959 nei_pos += ETH_ALEN; 960 pos += 17; 961 if (*pos != ',') { 962 wpa_printf(MSG_DEBUG, "Missing BSSID Information"); 963 return -1; 964 } 965 pos++; 966 967 val = strtol(pos, &endptr, 0); 968 WPA_PUT_LE32(nei_pos, val); 969 nei_pos += 4; 970 if (*endptr != ',') { 971 wpa_printf(MSG_DEBUG, "Missing Operating Class"); 972 return -1; 973 } 974 pos = endptr + 1; 975 976 *nei_pos++ = atoi(pos); /* Operating Class */ 977 pos = os_strchr(pos, ','); 978 if (pos == NULL) { 979 wpa_printf(MSG_DEBUG, "Missing Channel Number"); 980 return -1; 981 } 982 pos++; 983 984 *nei_pos++ = atoi(pos); /* Channel Number */ 985 pos = os_strchr(pos, ','); 986 if (pos == NULL) { 987 wpa_printf(MSG_DEBUG, "Missing PHY Type"); 988 return -1; 989 } 990 pos++; 991 992 *nei_pos++ = atoi(pos); /* PHY Type */ 993 end = os_strchr(pos, ' '); 994 tmp = os_strchr(pos, ','); 995 if (tmp && (!end || tmp < end)) { 996 /* Optional Subelements (hexdump) */ 997 size_t len; 998 999 pos = tmp + 1; 1000 end = os_strchr(pos, ' '); 1001 if (end) 1002 len = end - pos; 1003 else 1004 len = os_strlen(pos); 1005 if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) { 1006 wpa_printf(MSG_DEBUG, 1007 "Not enough room for neighbor subelements"); 1008 return -1; 1009 } 1010 if (len & 0x01 || 1011 hexstr2bin(pos, nei_pos, len / 2) < 0) { 1012 wpa_printf(MSG_DEBUG, 1013 "Invalid neighbor subelement info"); 1014 return -1; 1015 } 1016 nei_pos += len / 2; 1017 pos = end; 1018 } 1019 1020 nei_start[1] = nei_pos - nei_start - 2; 1021 } 1022 1023 pos = os_strstr(cmd, " url="); 1024 if (pos) { 1025 size_t len; 1026 pos += 5; 1027 end = os_strchr(pos, ' '); 1028 if (end) 1029 len = end - pos; 1030 else 1031 len = os_strlen(pos); 1032 url = os_malloc(len + 1); 1033 if (url == NULL) 1034 return -1; 1035 os_memcpy(url, pos, len); 1036 url[len] = '\0'; 1037 req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; 1038 } 1039 1040 if (os_strstr(cmd, " pref=1")) 1041 req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; 1042 if (os_strstr(cmd, " abridged=1")) 1043 req_mode |= WNM_BSS_TM_REQ_ABRIDGED; 1044 if (os_strstr(cmd, " disassoc_imminent=1")) 1045 req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; 1046 1047 ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, 1048 valid_int, bss_term_dur, url, 1049 nei_pos > nei_rep ? nei_rep : NULL, 1050 nei_pos - nei_rep); 1051 os_free(url); 1052 return ret; 1053 } 1054 1055 #endif /* CONFIG_WNM */ 1056 1057 1058 static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, 1059 char *buf, size_t buflen) 1060 { 1061 int ret; 1062 char *pos, *end; 1063 1064 pos = buf; 1065 end = buf + buflen; 1066 1067 ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n" 1068 "ssid=%s\n", 1069 MAC2STR(hapd->own_addr), 1070 wpa_ssid_txt(hapd->conf->ssid.ssid, 1071 hapd->conf->ssid.ssid_len)); 1072 if (os_snprintf_error(end - pos, ret)) 1073 return pos - buf; 1074 pos += ret; 1075 1076 #ifdef CONFIG_WPS 1077 ret = os_snprintf(pos, end - pos, "wps_state=%s\n", 1078 hapd->conf->wps_state == 0 ? "disabled" : 1079 (hapd->conf->wps_state == 1 ? "not configured" : 1080 "configured")); 1081 if (os_snprintf_error(end - pos, ret)) 1082 return pos - buf; 1083 pos += ret; 1084 1085 if (hapd->conf->wps_state && hapd->conf->wpa && 1086 hapd->conf->ssid.wpa_passphrase) { 1087 ret = os_snprintf(pos, end - pos, "passphrase=%s\n", 1088 hapd->conf->ssid.wpa_passphrase); 1089 if (os_snprintf_error(end - pos, ret)) 1090 return pos - buf; 1091 pos += ret; 1092 } 1093 1094 if (hapd->conf->wps_state && hapd->conf->wpa && 1095 hapd->conf->ssid.wpa_psk && 1096 hapd->conf->ssid.wpa_psk->group) { 1097 char hex[PMK_LEN * 2 + 1]; 1098 wpa_snprintf_hex(hex, sizeof(hex), 1099 hapd->conf->ssid.wpa_psk->psk, PMK_LEN); 1100 ret = os_snprintf(pos, end - pos, "psk=%s\n", hex); 1101 if (os_snprintf_error(end - pos, ret)) 1102 return pos - buf; 1103 pos += ret; 1104 } 1105 #endif /* CONFIG_WPS */ 1106 1107 if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) { 1108 ret = os_snprintf(pos, end - pos, "key_mgmt="); 1109 if (os_snprintf_error(end - pos, ret)) 1110 return pos - buf; 1111 pos += ret; 1112 1113 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) { 1114 ret = os_snprintf(pos, end - pos, "WPA-PSK "); 1115 if (os_snprintf_error(end - pos, ret)) 1116 return pos - buf; 1117 pos += ret; 1118 } 1119 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 1120 ret = os_snprintf(pos, end - pos, "WPA-EAP "); 1121 if (os_snprintf_error(end - pos, ret)) 1122 return pos - buf; 1123 pos += ret; 1124 } 1125 #ifdef CONFIG_IEEE80211R 1126 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) { 1127 ret = os_snprintf(pos, end - pos, "FT-PSK "); 1128 if (os_snprintf_error(end - pos, ret)) 1129 return pos - buf; 1130 pos += ret; 1131 } 1132 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) { 1133 ret = os_snprintf(pos, end - pos, "FT-EAP "); 1134 if (os_snprintf_error(end - pos, ret)) 1135 return pos - buf; 1136 pos += ret; 1137 } 1138 #ifdef CONFIG_SAE 1139 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) { 1140 ret = os_snprintf(pos, end - pos, "FT-SAE "); 1141 if (os_snprintf_error(end - pos, ret)) 1142 return pos - buf; 1143 pos += ret; 1144 } 1145 #endif /* CONFIG_SAE */ 1146 #endif /* CONFIG_IEEE80211R */ 1147 #ifdef CONFIG_IEEE80211W 1148 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { 1149 ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 "); 1150 if (os_snprintf_error(end - pos, ret)) 1151 return pos - buf; 1152 pos += ret; 1153 } 1154 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { 1155 ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 "); 1156 if (os_snprintf_error(end - pos, ret)) 1157 return pos - buf; 1158 pos += ret; 1159 } 1160 #endif /* CONFIG_IEEE80211W */ 1161 #ifdef CONFIG_SAE 1162 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { 1163 ret = os_snprintf(pos, end - pos, "SAE "); 1164 if (os_snprintf_error(end - pos, ret)) 1165 return pos - buf; 1166 pos += ret; 1167 } 1168 #endif /* CONFIG_SAE */ 1169 if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 1170 ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B "); 1171 if (os_snprintf_error(end - pos, ret)) 1172 return pos - buf; 1173 pos += ret; 1174 } 1175 if (hapd->conf->wpa_key_mgmt & 1176 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { 1177 ret = os_snprintf(pos, end - pos, 1178 "WPA-EAP-SUITE-B-192 "); 1179 if (os_snprintf_error(end - pos, ret)) 1180 return pos - buf; 1181 pos += ret; 1182 } 1183 1184 ret = os_snprintf(pos, end - pos, "\n"); 1185 if (os_snprintf_error(end - pos, ret)) 1186 return pos - buf; 1187 pos += ret; 1188 } 1189 1190 if (hapd->conf->wpa) { 1191 ret = os_snprintf(pos, end - pos, "group_cipher=%s\n", 1192 wpa_cipher_txt(hapd->conf->wpa_group)); 1193 if (os_snprintf_error(end - pos, ret)) 1194 return pos - buf; 1195 pos += ret; 1196 } 1197 1198 if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) { 1199 ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher="); 1200 if (os_snprintf_error(end - pos, ret)) 1201 return pos - buf; 1202 pos += ret; 1203 1204 ret = wpa_write_ciphers(pos, end, hapd->conf->rsn_pairwise, 1205 " "); 1206 if (ret < 0) 1207 return pos - buf; 1208 pos += ret; 1209 1210 ret = os_snprintf(pos, end - pos, "\n"); 1211 if (os_snprintf_error(end - pos, ret)) 1212 return pos - buf; 1213 pos += ret; 1214 } 1215 1216 if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) { 1217 ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher="); 1218 if (os_snprintf_error(end - pos, ret)) 1219 return pos - buf; 1220 pos += ret; 1221 1222 ret = wpa_write_ciphers(pos, end, hapd->conf->wpa_pairwise, 1223 " "); 1224 if (ret < 0) 1225 return pos - buf; 1226 pos += ret; 1227 1228 ret = os_snprintf(pos, end - pos, "\n"); 1229 if (os_snprintf_error(end - pos, ret)) 1230 return pos - buf; 1231 pos += ret; 1232 } 1233 1234 return pos - buf; 1235 } 1236 1237 1238 static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) 1239 { 1240 char *value; 1241 int ret = 0; 1242 1243 value = os_strchr(cmd, ' '); 1244 if (value == NULL) 1245 return -1; 1246 *value++ = '\0'; 1247 1248 wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value); 1249 if (0) { 1250 #ifdef CONFIG_WPS_TESTING 1251 } else if (os_strcasecmp(cmd, "wps_version_number") == 0) { 1252 long int val; 1253 val = strtol(value, NULL, 0); 1254 if (val < 0 || val > 0xff) { 1255 ret = -1; 1256 wpa_printf(MSG_DEBUG, "WPS: Invalid " 1257 "wps_version_number %ld", val); 1258 } else { 1259 wps_version_number = val; 1260 wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS " 1261 "version %u.%u", 1262 (wps_version_number & 0xf0) >> 4, 1263 wps_version_number & 0x0f); 1264 hostapd_wps_update_ie(hapd); 1265 } 1266 } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) { 1267 wps_testing_dummy_cred = atoi(value); 1268 wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d", 1269 wps_testing_dummy_cred); 1270 } else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) { 1271 wps_corrupt_pkhash = atoi(value); 1272 wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d", 1273 wps_corrupt_pkhash); 1274 #endif /* CONFIG_WPS_TESTING */ 1275 #ifdef CONFIG_INTERWORKING 1276 } else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) { 1277 int val = atoi(value); 1278 if (val <= 0) 1279 ret = -1; 1280 else 1281 hapd->gas_frag_limit = val; 1282 #endif /* CONFIG_INTERWORKING */ 1283 #ifdef CONFIG_TESTING_OPTIONS 1284 } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { 1285 hapd->ext_mgmt_frame_handling = atoi(value); 1286 } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { 1287 hapd->ext_eapol_frame_io = atoi(value); 1288 #endif /* CONFIG_TESTING_OPTIONS */ 1289 } else { 1290 struct sta_info *sta; 1291 int vlan_id; 1292 1293 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); 1294 if (ret) 1295 return ret; 1296 1297 if (os_strcasecmp(cmd, "deny_mac_file") == 0) { 1298 for (sta = hapd->sta_list; sta; sta = sta->next) { 1299 if (hostapd_maclist_found( 1300 hapd->conf->deny_mac, 1301 hapd->conf->num_deny_mac, sta->addr, 1302 &vlan_id) && 1303 (!vlan_id || vlan_id == sta->vlan_id)) 1304 ap_sta_disconnect( 1305 hapd, sta, sta->addr, 1306 WLAN_REASON_UNSPECIFIED); 1307 } 1308 } else if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED && 1309 os_strcasecmp(cmd, "accept_mac_file") == 0) { 1310 for (sta = hapd->sta_list; sta; sta = sta->next) { 1311 if (!hostapd_maclist_found( 1312 hapd->conf->accept_mac, 1313 hapd->conf->num_accept_mac, 1314 sta->addr, &vlan_id) || 1315 (vlan_id && vlan_id != sta->vlan_id)) 1316 ap_sta_disconnect( 1317 hapd, sta, sta->addr, 1318 WLAN_REASON_UNSPECIFIED); 1319 } 1320 } 1321 } 1322 1323 return ret; 1324 } 1325 1326 1327 static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd, 1328 char *buf, size_t buflen) 1329 { 1330 int res; 1331 1332 wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd); 1333 1334 if (os_strcmp(cmd, "version") == 0) { 1335 res = os_snprintf(buf, buflen, "%s", VERSION_STR); 1336 if (os_snprintf_error(buflen, res)) 1337 return -1; 1338 return res; 1339 } else if (os_strcmp(cmd, "tls_library") == 0) { 1340 res = tls_get_library_version(buf, buflen); 1341 if (os_snprintf_error(buflen, res)) 1342 return -1; 1343 return res; 1344 } 1345 1346 return -1; 1347 } 1348 1349 1350 static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface) 1351 { 1352 if (hostapd_enable_iface(iface) < 0) { 1353 wpa_printf(MSG_ERROR, "Enabling of interface failed"); 1354 return -1; 1355 } 1356 return 0; 1357 } 1358 1359 1360 static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface) 1361 { 1362 if (hostapd_reload_iface(iface) < 0) { 1363 wpa_printf(MSG_ERROR, "Reloading of interface failed"); 1364 return -1; 1365 } 1366 return 0; 1367 } 1368 1369 1370 static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) 1371 { 1372 if (hostapd_disable_iface(iface) < 0) { 1373 wpa_printf(MSG_ERROR, "Disabling of interface failed"); 1374 return -1; 1375 } 1376 return 0; 1377 } 1378 1379 1380 #ifdef CONFIG_TESTING_OPTIONS 1381 1382 static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) 1383 { 1384 union wpa_event_data data; 1385 char *pos, *param; 1386 enum wpa_event_type event; 1387 1388 wpa_printf(MSG_DEBUG, "RADAR TEST: %s", cmd); 1389 1390 os_memset(&data, 0, sizeof(data)); 1391 1392 param = os_strchr(cmd, ' '); 1393 if (param == NULL) 1394 return -1; 1395 *param++ = '\0'; 1396 1397 if (os_strcmp(cmd, "DETECTED") == 0) 1398 event = EVENT_DFS_RADAR_DETECTED; 1399 else if (os_strcmp(cmd, "CAC-FINISHED") == 0) 1400 event = EVENT_DFS_CAC_FINISHED; 1401 else if (os_strcmp(cmd, "CAC-ABORTED") == 0) 1402 event = EVENT_DFS_CAC_ABORTED; 1403 else if (os_strcmp(cmd, "NOP-FINISHED") == 0) 1404 event = EVENT_DFS_NOP_FINISHED; 1405 else { 1406 wpa_printf(MSG_DEBUG, "Unsupported RADAR test command: %s", 1407 cmd); 1408 return -1; 1409 } 1410 1411 pos = os_strstr(param, "freq="); 1412 if (pos) 1413 data.dfs_event.freq = atoi(pos + 5); 1414 1415 pos = os_strstr(param, "ht_enabled=1"); 1416 if (pos) 1417 data.dfs_event.ht_enabled = 1; 1418 1419 pos = os_strstr(param, "chan_offset="); 1420 if (pos) 1421 data.dfs_event.chan_offset = atoi(pos + 12); 1422 1423 pos = os_strstr(param, "chan_width="); 1424 if (pos) 1425 data.dfs_event.chan_width = atoi(pos + 11); 1426 1427 pos = os_strstr(param, "cf1="); 1428 if (pos) 1429 data.dfs_event.cf1 = atoi(pos + 4); 1430 1431 pos = os_strstr(param, "cf2="); 1432 if (pos) 1433 data.dfs_event.cf2 = atoi(pos + 4); 1434 1435 wpa_supplicant_event(hapd, event, &data); 1436 1437 return 0; 1438 } 1439 1440 1441 static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd) 1442 { 1443 size_t len; 1444 u8 *buf; 1445 int res; 1446 1447 wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); 1448 1449 len = os_strlen(cmd); 1450 if (len & 1) 1451 return -1; 1452 len /= 2; 1453 1454 buf = os_malloc(len); 1455 if (buf == NULL) 1456 return -1; 1457 1458 if (hexstr2bin(cmd, buf, len) < 0) { 1459 os_free(buf); 1460 return -1; 1461 } 1462 1463 res = hostapd_drv_send_mlme(hapd, buf, len, 0); 1464 os_free(buf); 1465 return res; 1466 } 1467 1468 1469 static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd) 1470 { 1471 char *pos; 1472 u8 src[ETH_ALEN], *buf; 1473 int used; 1474 size_t len; 1475 1476 wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd); 1477 1478 pos = cmd; 1479 used = hwaddr_aton2(pos, src); 1480 if (used < 0) 1481 return -1; 1482 pos += used; 1483 while (*pos == ' ') 1484 pos++; 1485 1486 len = os_strlen(pos); 1487 if (len & 1) 1488 return -1; 1489 len /= 2; 1490 1491 buf = os_malloc(len); 1492 if (buf == NULL) 1493 return -1; 1494 1495 if (hexstr2bin(pos, buf, len) < 0) { 1496 os_free(buf); 1497 return -1; 1498 } 1499 1500 ieee802_1x_receive(hapd, src, buf, len); 1501 os_free(buf); 1502 1503 return 0; 1504 } 1505 1506 1507 static u16 ipv4_hdr_checksum(const void *buf, size_t len) 1508 { 1509 size_t i; 1510 u32 sum = 0; 1511 const u16 *pos = buf; 1512 1513 for (i = 0; i < len / 2; i++) 1514 sum += *pos++; 1515 1516 while (sum >> 16) 1517 sum = (sum & 0xffff) + (sum >> 16); 1518 1519 return sum ^ 0xffff; 1520 } 1521 1522 1523 #define HWSIM_PACKETLEN 1500 1524 #define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header)) 1525 1526 void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, 1527 size_t len) 1528 { 1529 struct hostapd_data *hapd = ctx; 1530 const struct ether_header *eth; 1531 const struct iphdr *ip; 1532 const u8 *pos; 1533 unsigned int i; 1534 1535 if (len != HWSIM_PACKETLEN) 1536 return; 1537 1538 eth = (const struct ether_header *) buf; 1539 ip = (const struct iphdr *) (eth + 1); 1540 pos = (const u8 *) (ip + 1); 1541 1542 if (ip->ihl != 5 || ip->version != 4 || 1543 ntohs(ip->tot_len) != HWSIM_IP_LEN) 1544 return; 1545 1546 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) { 1547 if (*pos != (u8) i) 1548 return; 1549 pos++; 1550 } 1551 1552 wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR, 1553 MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost)); 1554 } 1555 1556 1557 static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd, 1558 char *cmd) 1559 { 1560 int enabled = atoi(cmd); 1561 char *pos; 1562 const char *ifname; 1563 1564 if (!enabled) { 1565 if (hapd->l2_test) { 1566 l2_packet_deinit(hapd->l2_test); 1567 hapd->l2_test = NULL; 1568 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, 1569 "test data: Disabled"); 1570 } 1571 return 0; 1572 } 1573 1574 if (hapd->l2_test) 1575 return 0; 1576 1577 pos = os_strstr(cmd, " ifname="); 1578 if (pos) 1579 ifname = pos + 8; 1580 else 1581 ifname = hapd->conf->iface; 1582 1583 hapd->l2_test = l2_packet_init(ifname, hapd->own_addr, 1584 ETHERTYPE_IP, hostapd_data_test_rx, 1585 hapd, 1); 1586 if (hapd->l2_test == NULL) 1587 return -1; 1588 1589 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled"); 1590 1591 return 0; 1592 } 1593 1594 1595 static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd) 1596 { 1597 u8 dst[ETH_ALEN], src[ETH_ALEN]; 1598 char *pos; 1599 int used; 1600 long int val; 1601 u8 tos; 1602 u8 buf[HWSIM_PACKETLEN]; 1603 struct ether_header *eth; 1604 struct iphdr *ip; 1605 u8 *dpos; 1606 unsigned int i; 1607 1608 if (hapd->l2_test == NULL) 1609 return -1; 1610 1611 /* format: <dst> <src> <tos> */ 1612 1613 pos = cmd; 1614 used = hwaddr_aton2(pos, dst); 1615 if (used < 0) 1616 return -1; 1617 pos += used; 1618 while (*pos == ' ') 1619 pos++; 1620 used = hwaddr_aton2(pos, src); 1621 if (used < 0) 1622 return -1; 1623 pos += used; 1624 1625 val = strtol(pos, NULL, 0); 1626 if (val < 0 || val > 0xff) 1627 return -1; 1628 tos = val; 1629 1630 eth = (struct ether_header *) buf; 1631 os_memcpy(eth->ether_dhost, dst, ETH_ALEN); 1632 os_memcpy(eth->ether_shost, src, ETH_ALEN); 1633 eth->ether_type = htons(ETHERTYPE_IP); 1634 ip = (struct iphdr *) (eth + 1); 1635 os_memset(ip, 0, sizeof(*ip)); 1636 ip->ihl = 5; 1637 ip->version = 4; 1638 ip->ttl = 64; 1639 ip->tos = tos; 1640 ip->tot_len = htons(HWSIM_IP_LEN); 1641 ip->protocol = 1; 1642 ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1); 1643 ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2); 1644 ip->check = ipv4_hdr_checksum(ip, sizeof(*ip)); 1645 dpos = (u8 *) (ip + 1); 1646 for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) 1647 *dpos++ = i; 1648 1649 if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, buf, 1650 HWSIM_PACKETLEN) < 0) 1651 return -1; 1652 1653 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR 1654 " src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos); 1655 1656 return 0; 1657 } 1658 1659 1660 static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd, 1661 char *cmd) 1662 { 1663 u8 *buf; 1664 struct ether_header *eth; 1665 struct l2_packet_data *l2 = NULL; 1666 size_t len; 1667 u16 ethertype; 1668 int res = -1; 1669 const char *ifname = hapd->conf->iface; 1670 1671 if (os_strncmp(cmd, "ifname=", 7) == 0) { 1672 cmd += 7; 1673 ifname = cmd; 1674 cmd = os_strchr(cmd, ' '); 1675 if (cmd == NULL) 1676 return -1; 1677 *cmd++ = '\0'; 1678 } 1679 1680 len = os_strlen(cmd); 1681 if (len & 1 || len < ETH_HLEN * 2) 1682 return -1; 1683 len /= 2; 1684 1685 buf = os_malloc(len); 1686 if (buf == NULL) 1687 return -1; 1688 1689 if (hexstr2bin(cmd, buf, len) < 0) 1690 goto done; 1691 1692 eth = (struct ether_header *) buf; 1693 ethertype = ntohs(eth->ether_type); 1694 1695 l2 = l2_packet_init(ifname, hapd->own_addr, ethertype, 1696 hostapd_data_test_rx, hapd, 1); 1697 if (l2 == NULL) 1698 goto done; 1699 1700 res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len); 1701 wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res); 1702 done: 1703 if (l2) 1704 l2_packet_deinit(l2); 1705 os_free(buf); 1706 1707 return res < 0 ? -1 : 0; 1708 } 1709 1710 1711 static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd) 1712 { 1713 #ifdef WPA_TRACE_BFD 1714 extern char wpa_trace_fail_func[256]; 1715 extern unsigned int wpa_trace_fail_after; 1716 char *pos; 1717 1718 wpa_trace_fail_after = atoi(cmd); 1719 pos = os_strchr(cmd, ':'); 1720 if (pos) { 1721 pos++; 1722 os_strlcpy(wpa_trace_fail_func, pos, 1723 sizeof(wpa_trace_fail_func)); 1724 } else { 1725 wpa_trace_fail_after = 0; 1726 } 1727 1728 return 0; 1729 #else /* WPA_TRACE_BFD */ 1730 return -1; 1731 #endif /* WPA_TRACE_BFD */ 1732 } 1733 1734 1735 static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd, 1736 char *buf, size_t buflen) 1737 { 1738 #ifdef WPA_TRACE_BFD 1739 extern char wpa_trace_fail_func[256]; 1740 extern unsigned int wpa_trace_fail_after; 1741 1742 return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, 1743 wpa_trace_fail_func); 1744 #else /* WPA_TRACE_BFD */ 1745 return -1; 1746 #endif /* WPA_TRACE_BFD */ 1747 } 1748 1749 #endif /* CONFIG_TESTING_OPTIONS */ 1750 1751 1752 static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, 1753 char *pos) 1754 { 1755 #ifdef NEED_AP_MLME 1756 struct csa_settings settings; 1757 int ret; 1758 unsigned int i; 1759 1760 ret = hostapd_parse_csa_settings(pos, &settings); 1761 if (ret) 1762 return ret; 1763 1764 for (i = 0; i < iface->num_bss; i++) { 1765 ret = hostapd_switch_channel(iface->bss[i], &settings); 1766 if (ret) { 1767 /* FIX: What do we do if CSA fails in the middle of 1768 * submitting multi-BSS CSA requests? */ 1769 return ret; 1770 } 1771 } 1772 1773 return 0; 1774 #else /* NEED_AP_MLME */ 1775 return -1; 1776 #endif /* NEED_AP_MLME */ 1777 } 1778 1779 1780 static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply, 1781 int reply_size, const char *param) 1782 { 1783 #ifdef RADIUS_SERVER 1784 if (os_strcmp(param, "radius_server") == 0) { 1785 return radius_server_get_mib(hapd->radius_srv, reply, 1786 reply_size); 1787 } 1788 #endif /* RADIUS_SERVER */ 1789 return -1; 1790 } 1791 1792 1793 static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd, 1794 char *buf, size_t buflen) 1795 { 1796 int ret; 1797 char *pos; 1798 u8 *data = NULL; 1799 unsigned int vendor_id, subcmd; 1800 struct wpabuf *reply; 1801 size_t data_len = 0; 1802 1803 /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ 1804 vendor_id = strtoul(cmd, &pos, 16); 1805 if (!isblank(*pos)) 1806 return -EINVAL; 1807 1808 subcmd = strtoul(pos, &pos, 10); 1809 1810 if (*pos != '\0') { 1811 if (!isblank(*pos++)) 1812 return -EINVAL; 1813 data_len = os_strlen(pos); 1814 } 1815 1816 if (data_len) { 1817 data_len /= 2; 1818 data = os_malloc(data_len); 1819 if (!data) 1820 return -ENOBUFS; 1821 1822 if (hexstr2bin(pos, data, data_len)) { 1823 wpa_printf(MSG_DEBUG, 1824 "Vendor command: wrong parameter format"); 1825 os_free(data); 1826 return -EINVAL; 1827 } 1828 } 1829 1830 reply = wpabuf_alloc((buflen - 1) / 2); 1831 if (!reply) { 1832 os_free(data); 1833 return -ENOBUFS; 1834 } 1835 1836 ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len, 1837 reply); 1838 1839 if (ret == 0) 1840 ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply), 1841 wpabuf_len(reply)); 1842 1843 wpabuf_free(reply); 1844 os_free(data); 1845 1846 return ret; 1847 } 1848 1849 1850 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, 1851 void *sock_ctx) 1852 { 1853 struct hostapd_data *hapd = eloop_ctx; 1854 char buf[4096]; 1855 int res; 1856 struct sockaddr_un from; 1857 socklen_t fromlen = sizeof(from); 1858 char *reply; 1859 const int reply_size = 4096; 1860 int reply_len; 1861 int level = MSG_DEBUG; 1862 1863 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 1864 (struct sockaddr *) &from, &fromlen); 1865 if (res < 0) { 1866 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 1867 strerror(errno)); 1868 return; 1869 } 1870 buf[res] = '\0'; 1871 if (os_strcmp(buf, "PING") == 0) 1872 level = MSG_EXCESSIVE; 1873 wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res); 1874 1875 reply = os_malloc(reply_size); 1876 if (reply == NULL) { 1877 if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 1878 fromlen) < 0) { 1879 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s", 1880 strerror(errno)); 1881 } 1882 return; 1883 } 1884 1885 os_memcpy(reply, "OK\n", 3); 1886 reply_len = 3; 1887 1888 if (os_strcmp(buf, "PING") == 0) { 1889 os_memcpy(reply, "PONG\n", 5); 1890 reply_len = 5; 1891 } else if (os_strncmp(buf, "RELOG", 5) == 0) { 1892 if (wpa_debug_reopen_file() < 0) 1893 reply_len = -1; 1894 } else if (os_strcmp(buf, "STATUS") == 0) { 1895 reply_len = hostapd_ctrl_iface_status(hapd, reply, 1896 reply_size); 1897 } else if (os_strcmp(buf, "STATUS-DRIVER") == 0) { 1898 reply_len = hostapd_drv_status(hapd, reply, reply_size); 1899 } else if (os_strcmp(buf, "MIB") == 0) { 1900 reply_len = ieee802_11_get_mib(hapd, reply, reply_size); 1901 if (reply_len >= 0) { 1902 res = wpa_get_mib(hapd->wpa_auth, reply + reply_len, 1903 reply_size - reply_len); 1904 if (res < 0) 1905 reply_len = -1; 1906 else 1907 reply_len += res; 1908 } 1909 if (reply_len >= 0) { 1910 res = ieee802_1x_get_mib(hapd, reply + reply_len, 1911 reply_size - reply_len); 1912 if (res < 0) 1913 reply_len = -1; 1914 else 1915 reply_len += res; 1916 } 1917 #ifndef CONFIG_NO_RADIUS 1918 if (reply_len >= 0) { 1919 res = radius_client_get_mib(hapd->radius, 1920 reply + reply_len, 1921 reply_size - reply_len); 1922 if (res < 0) 1923 reply_len = -1; 1924 else 1925 reply_len += res; 1926 } 1927 #endif /* CONFIG_NO_RADIUS */ 1928 } else if (os_strncmp(buf, "MIB ", 4) == 0) { 1929 reply_len = hostapd_ctrl_iface_mib(hapd, reply, reply_size, 1930 buf + 4); 1931 } else if (os_strcmp(buf, "STA-FIRST") == 0) { 1932 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply, 1933 reply_size); 1934 } else if (os_strncmp(buf, "STA ", 4) == 0) { 1935 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply, 1936 reply_size); 1937 } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { 1938 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply, 1939 reply_size); 1940 } else if (os_strcmp(buf, "ATTACH") == 0) { 1941 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen)) 1942 reply_len = -1; 1943 } else if (os_strcmp(buf, "DETACH") == 0) { 1944 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen)) 1945 reply_len = -1; 1946 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 1947 if (hostapd_ctrl_iface_level(hapd, &from, fromlen, 1948 buf + 6)) 1949 reply_len = -1; 1950 } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) { 1951 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8)) 1952 reply_len = -1; 1953 } else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) { 1954 if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15)) 1955 reply_len = -1; 1956 } else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) { 1957 if (hostapd_ctrl_iface_disassociate(hapd, buf + 13)) 1958 reply_len = -1; 1959 } else if (os_strcmp(buf, "STOP_AP") == 0) { 1960 if (hostapd_ctrl_iface_stop_ap(hapd)) 1961 reply_len = -1; 1962 #ifdef CONFIG_IEEE80211W 1963 #ifdef NEED_AP_MLME 1964 } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { 1965 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) 1966 reply_len = -1; 1967 #endif /* NEED_AP_MLME */ 1968 #endif /* CONFIG_IEEE80211W */ 1969 #ifdef CONFIG_WPS 1970 } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { 1971 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) 1972 reply_len = -1; 1973 } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) { 1974 reply_len = hostapd_ctrl_iface_wps_check_pin( 1975 hapd, buf + 14, reply, reply_size); 1976 } else if (os_strcmp(buf, "WPS_PBC") == 0) { 1977 if (hostapd_wps_button_pushed(hapd, NULL)) 1978 reply_len = -1; 1979 } else if (os_strcmp(buf, "WPS_CANCEL") == 0) { 1980 if (hostapd_wps_cancel(hapd)) 1981 reply_len = -1; 1982 } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) { 1983 reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11, 1984 reply, reply_size); 1985 } else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) { 1986 if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0) 1987 reply_len = -1; 1988 } else if (os_strncmp(buf, "WPS_GET_STATUS", 13) == 0) { 1989 reply_len = hostapd_ctrl_iface_wps_get_status(hapd, reply, 1990 reply_size); 1991 #ifdef CONFIG_WPS_NFC 1992 } else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) { 1993 if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17)) 1994 reply_len = -1; 1995 } else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) { 1996 reply_len = hostapd_ctrl_iface_wps_nfc_config_token( 1997 hapd, buf + 21, reply, reply_size); 1998 } else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) { 1999 reply_len = hostapd_ctrl_iface_wps_nfc_token( 2000 hapd, buf + 14, reply, reply_size); 2001 } else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) { 2002 reply_len = hostapd_ctrl_iface_nfc_get_handover_sel( 2003 hapd, buf + 21, reply, reply_size); 2004 } else if (os_strncmp(buf, "NFC_REPORT_HANDOVER ", 20) == 0) { 2005 if (hostapd_ctrl_iface_nfc_report_handover(hapd, buf + 20)) 2006 reply_len = -1; 2007 #endif /* CONFIG_WPS_NFC */ 2008 #endif /* CONFIG_WPS */ 2009 #ifdef CONFIG_INTERWORKING 2010 } else if (os_strncmp(buf, "SET_QOS_MAP_SET ", 16) == 0) { 2011 if (hostapd_ctrl_iface_set_qos_map_set(hapd, buf + 16)) 2012 reply_len = -1; 2013 } else if (os_strncmp(buf, "SEND_QOS_MAP_CONF ", 18) == 0) { 2014 if (hostapd_ctrl_iface_send_qos_map_conf(hapd, buf + 18)) 2015 reply_len = -1; 2016 #endif /* CONFIG_INTERWORKING */ 2017 #ifdef CONFIG_HS20 2018 } else if (os_strncmp(buf, "HS20_WNM_NOTIF ", 15) == 0) { 2019 if (hostapd_ctrl_iface_hs20_wnm_notif(hapd, buf + 15)) 2020 reply_len = -1; 2021 } else if (os_strncmp(buf, "HS20_DEAUTH_REQ ", 16) == 0) { 2022 if (hostapd_ctrl_iface_hs20_deauth_req(hapd, buf + 16)) 2023 reply_len = -1; 2024 #endif /* CONFIG_HS20 */ 2025 #ifdef CONFIG_WNM 2026 } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { 2027 if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18)) 2028 reply_len = -1; 2029 } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) { 2030 if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13)) 2031 reply_len = -1; 2032 } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) { 2033 if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11)) 2034 reply_len = -1; 2035 #endif /* CONFIG_WNM */ 2036 } else if (os_strcmp(buf, "GET_CONFIG") == 0) { 2037 reply_len = hostapd_ctrl_iface_get_config(hapd, reply, 2038 reply_size); 2039 } else if (os_strncmp(buf, "SET ", 4) == 0) { 2040 if (hostapd_ctrl_iface_set(hapd, buf + 4)) 2041 reply_len = -1; 2042 } else if (os_strncmp(buf, "GET ", 4) == 0) { 2043 reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply, 2044 reply_size); 2045 } else if (os_strncmp(buf, "ENABLE", 6) == 0) { 2046 if (hostapd_ctrl_iface_enable(hapd->iface)) 2047 reply_len = -1; 2048 } else if (os_strncmp(buf, "RELOAD", 6) == 0) { 2049 if (hostapd_ctrl_iface_reload(hapd->iface)) 2050 reply_len = -1; 2051 } else if (os_strncmp(buf, "DISABLE", 7) == 0) { 2052 if (hostapd_ctrl_iface_disable(hapd->iface)) 2053 reply_len = -1; 2054 } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) { 2055 if (ieee802_11_set_beacon(hapd)) 2056 reply_len = -1; 2057 #ifdef CONFIG_TESTING_OPTIONS 2058 } else if (os_strncmp(buf, "RADAR ", 6) == 0) { 2059 if (hostapd_ctrl_iface_radar(hapd, buf + 6)) 2060 reply_len = -1; 2061 } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { 2062 if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8)) 2063 reply_len = -1; 2064 } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { 2065 if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0) 2066 reply_len = -1; 2067 } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) { 2068 if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0) 2069 reply_len = -1; 2070 } else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) { 2071 if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0) 2072 reply_len = -1; 2073 } else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) { 2074 if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0) 2075 reply_len = -1; 2076 } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) { 2077 if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0) 2078 reply_len = -1; 2079 } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) { 2080 reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply, 2081 reply_size); 2082 #endif /* CONFIG_TESTING_OPTIONS */ 2083 } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { 2084 if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) 2085 reply_len = -1; 2086 } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { 2087 reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply, 2088 reply_size); 2089 } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { 2090 ieee802_1x_erp_flush(hapd); 2091 #ifdef RADIUS_SERVER 2092 radius_server_erp_flush(hapd->radius_srv); 2093 #endif /* RADIUS_SERVER */ 2094 } else { 2095 os_memcpy(reply, "UNKNOWN COMMAND\n", 16); 2096 reply_len = 16; 2097 } 2098 2099 if (reply_len < 0) { 2100 os_memcpy(reply, "FAIL\n", 5); 2101 reply_len = 5; 2102 } 2103 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 2104 fromlen) < 0) { 2105 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s", 2106 strerror(errno)); 2107 } 2108 os_free(reply); 2109 } 2110 2111 2112 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd) 2113 { 2114 char *buf; 2115 size_t len; 2116 2117 if (hapd->conf->ctrl_interface == NULL) 2118 return NULL; 2119 2120 len = os_strlen(hapd->conf->ctrl_interface) + 2121 os_strlen(hapd->conf->iface) + 2; 2122 buf = os_malloc(len); 2123 if (buf == NULL) 2124 return NULL; 2125 2126 os_snprintf(buf, len, "%s/%s", 2127 hapd->conf->ctrl_interface, hapd->conf->iface); 2128 buf[len - 1] = '\0'; 2129 return buf; 2130 } 2131 2132 2133 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global, 2134 const char *txt, size_t len) 2135 { 2136 struct hostapd_data *hapd = ctx; 2137 if (hapd == NULL) 2138 return; 2139 hostapd_ctrl_iface_send(hapd, level, txt, len); 2140 } 2141 2142 2143 int hostapd_ctrl_iface_init(struct hostapd_data *hapd) 2144 { 2145 struct sockaddr_un addr; 2146 int s = -1; 2147 char *fname = NULL; 2148 2149 if (hapd->ctrl_sock > -1) { 2150 wpa_printf(MSG_DEBUG, "ctrl_iface already exists!"); 2151 return 0; 2152 } 2153 2154 if (hapd->conf->ctrl_interface == NULL) 2155 return 0; 2156 2157 if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 2158 if (errno == EEXIST) { 2159 wpa_printf(MSG_DEBUG, "Using existing control " 2160 "interface directory."); 2161 } else { 2162 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", 2163 strerror(errno)); 2164 goto fail; 2165 } 2166 } 2167 2168 if (hapd->conf->ctrl_interface_gid_set && 2169 chown(hapd->conf->ctrl_interface, -1, 2170 hapd->conf->ctrl_interface_gid) < 0) { 2171 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", 2172 strerror(errno)); 2173 return -1; 2174 } 2175 2176 if (!hapd->conf->ctrl_interface_gid_set && 2177 hapd->iface->interfaces->ctrl_iface_group && 2178 chown(hapd->conf->ctrl_interface, -1, 2179 hapd->iface->interfaces->ctrl_iface_group) < 0) { 2180 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", 2181 strerror(errno)); 2182 return -1; 2183 } 2184 2185 #ifdef ANDROID 2186 /* 2187 * Android is using umask 0077 which would leave the control interface 2188 * directory without group access. This breaks things since Wi-Fi 2189 * framework assumes that this directory can be accessed by other 2190 * applications in the wifi group. Fix this by adding group access even 2191 * if umask value would prevent this. 2192 */ 2193 if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) { 2194 wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", 2195 strerror(errno)); 2196 /* Try to continue anyway */ 2197 } 2198 #endif /* ANDROID */ 2199 2200 if (os_strlen(hapd->conf->ctrl_interface) + 1 + 2201 os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path)) 2202 goto fail; 2203 2204 s = socket(PF_UNIX, SOCK_DGRAM, 0); 2205 if (s < 0) { 2206 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 2207 goto fail; 2208 } 2209 2210 os_memset(&addr, 0, sizeof(addr)); 2211 #ifdef __FreeBSD__ 2212 addr.sun_len = sizeof(addr); 2213 #endif /* __FreeBSD__ */ 2214 addr.sun_family = AF_UNIX; 2215 fname = hostapd_ctrl_iface_path(hapd); 2216 if (fname == NULL) 2217 goto fail; 2218 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 2219 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 2220 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 2221 strerror(errno)); 2222 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 2223 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 2224 " allow connections - assuming it was left" 2225 "over from forced program termination"); 2226 if (unlink(fname) < 0) { 2227 wpa_printf(MSG_ERROR, 2228 "Could not unlink existing ctrl_iface socket '%s': %s", 2229 fname, strerror(errno)); 2230 goto fail; 2231 } 2232 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 2233 0) { 2234 wpa_printf(MSG_ERROR, 2235 "hostapd-ctrl-iface: bind(PF_UNIX): %s", 2236 strerror(errno)); 2237 goto fail; 2238 } 2239 wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 2240 "ctrl_iface socket '%s'", fname); 2241 } else { 2242 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 2243 "be in use - cannot override it"); 2244 wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 2245 "not used anymore", fname); 2246 os_free(fname); 2247 fname = NULL; 2248 goto fail; 2249 } 2250 } 2251 2252 if (hapd->conf->ctrl_interface_gid_set && 2253 chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) { 2254 wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s", 2255 strerror(errno)); 2256 goto fail; 2257 } 2258 2259 if (!hapd->conf->ctrl_interface_gid_set && 2260 hapd->iface->interfaces->ctrl_iface_group && 2261 chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) { 2262 wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s", 2263 strerror(errno)); 2264 goto fail; 2265 } 2266 2267 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 2268 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", 2269 strerror(errno)); 2270 goto fail; 2271 } 2272 os_free(fname); 2273 2274 hapd->ctrl_sock = s; 2275 if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd, 2276 NULL) < 0) { 2277 hostapd_ctrl_iface_deinit(hapd); 2278 return -1; 2279 } 2280 hapd->msg_ctx = hapd; 2281 wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); 2282 2283 return 0; 2284 2285 fail: 2286 if (s >= 0) 2287 close(s); 2288 if (fname) { 2289 unlink(fname); 2290 os_free(fname); 2291 } 2292 return -1; 2293 } 2294 2295 2296 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd) 2297 { 2298 struct wpa_ctrl_dst *dst, *prev; 2299 2300 if (hapd->ctrl_sock > -1) { 2301 char *fname; 2302 eloop_unregister_read_sock(hapd->ctrl_sock); 2303 close(hapd->ctrl_sock); 2304 hapd->ctrl_sock = -1; 2305 fname = hostapd_ctrl_iface_path(hapd); 2306 if (fname) 2307 unlink(fname); 2308 os_free(fname); 2309 2310 if (hapd->conf->ctrl_interface && 2311 rmdir(hapd->conf->ctrl_interface) < 0) { 2312 if (errno == ENOTEMPTY) { 2313 wpa_printf(MSG_DEBUG, "Control interface " 2314 "directory not empty - leaving it " 2315 "behind"); 2316 } else { 2317 wpa_printf(MSG_ERROR, 2318 "rmdir[ctrl_interface=%s]: %s", 2319 hapd->conf->ctrl_interface, 2320 strerror(errno)); 2321 } 2322 } 2323 } 2324 2325 dst = hapd->ctrl_dst; 2326 hapd->ctrl_dst = NULL; 2327 while (dst) { 2328 prev = dst; 2329 dst = dst->next; 2330 os_free(prev); 2331 } 2332 2333 #ifdef CONFIG_TESTING_OPTIONS 2334 l2_packet_deinit(hapd->l2_test); 2335 hapd->l2_test = NULL; 2336 #endif /* CONFIG_TESTING_OPTIONS */ 2337 } 2338 2339 2340 static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces, 2341 char *buf) 2342 { 2343 if (hostapd_add_iface(interfaces, buf) < 0) { 2344 wpa_printf(MSG_ERROR, "Adding interface %s failed", buf); 2345 return -1; 2346 } 2347 return 0; 2348 } 2349 2350 2351 static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces, 2352 char *buf) 2353 { 2354 if (hostapd_remove_iface(interfaces, buf) < 0) { 2355 wpa_printf(MSG_ERROR, "Removing interface %s failed", buf); 2356 return -1; 2357 } 2358 return 0; 2359 } 2360 2361 2362 static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces) 2363 { 2364 #ifdef CONFIG_WPS_TESTING 2365 wps_version_number = 0x20; 2366 wps_testing_dummy_cred = 0; 2367 wps_corrupt_pkhash = 0; 2368 #endif /* CONFIG_WPS_TESTING */ 2369 } 2370 2371 2372 static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, 2373 void *sock_ctx) 2374 { 2375 void *interfaces = eloop_ctx; 2376 char buf[256]; 2377 int res; 2378 struct sockaddr_un from; 2379 socklen_t fromlen = sizeof(from); 2380 char reply[24]; 2381 int reply_len; 2382 2383 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 2384 (struct sockaddr *) &from, &fromlen); 2385 if (res < 0) { 2386 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 2387 strerror(errno)); 2388 return; 2389 } 2390 buf[res] = '\0'; 2391 wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf); 2392 2393 os_memcpy(reply, "OK\n", 3); 2394 reply_len = 3; 2395 2396 if (os_strcmp(buf, "PING") == 0) { 2397 os_memcpy(reply, "PONG\n", 5); 2398 reply_len = 5; 2399 } else if (os_strncmp(buf, "RELOG", 5) == 0) { 2400 if (wpa_debug_reopen_file() < 0) 2401 reply_len = -1; 2402 } else if (os_strcmp(buf, "FLUSH") == 0) { 2403 hostapd_ctrl_iface_flush(interfaces); 2404 } else if (os_strncmp(buf, "ADD ", 4) == 0) { 2405 if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0) 2406 reply_len = -1; 2407 } else if (os_strncmp(buf, "REMOVE ", 7) == 0) { 2408 if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0) 2409 reply_len = -1; 2410 #ifdef CONFIG_MODULE_TESTS 2411 } else if (os_strcmp(buf, "MODULE_TESTS") == 0) { 2412 int hapd_module_tests(void); 2413 if (hapd_module_tests() < 0) 2414 reply_len = -1; 2415 #endif /* CONFIG_MODULE_TESTS */ 2416 } else { 2417 wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command " 2418 "ignored"); 2419 reply_len = -1; 2420 } 2421 2422 if (reply_len < 0) { 2423 os_memcpy(reply, "FAIL\n", 5); 2424 reply_len = 5; 2425 } 2426 2427 if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 2428 fromlen) < 0) { 2429 wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s", 2430 strerror(errno)); 2431 } 2432 } 2433 2434 2435 static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface) 2436 { 2437 char *buf; 2438 size_t len; 2439 2440 if (interface->global_iface_path == NULL) 2441 return NULL; 2442 2443 len = os_strlen(interface->global_iface_path) + 2444 os_strlen(interface->global_iface_name) + 2; 2445 buf = os_malloc(len); 2446 if (buf == NULL) 2447 return NULL; 2448 2449 os_snprintf(buf, len, "%s/%s", interface->global_iface_path, 2450 interface->global_iface_name); 2451 buf[len - 1] = '\0'; 2452 return buf; 2453 } 2454 2455 2456 int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) 2457 { 2458 struct sockaddr_un addr; 2459 int s = -1; 2460 char *fname = NULL; 2461 2462 if (interface->global_iface_path == NULL) { 2463 wpa_printf(MSG_DEBUG, "ctrl_iface not configured!"); 2464 return 0; 2465 } 2466 2467 if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) { 2468 if (errno == EEXIST) { 2469 wpa_printf(MSG_DEBUG, "Using existing control " 2470 "interface directory."); 2471 } else { 2472 wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s", 2473 strerror(errno)); 2474 goto fail; 2475 } 2476 } else if (interface->ctrl_iface_group && 2477 chown(interface->global_iface_path, -1, 2478 interface->ctrl_iface_group) < 0) { 2479 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", 2480 strerror(errno)); 2481 goto fail; 2482 } 2483 2484 if (os_strlen(interface->global_iface_path) + 1 + 2485 os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path)) 2486 goto fail; 2487 2488 s = socket(PF_UNIX, SOCK_DGRAM, 0); 2489 if (s < 0) { 2490 wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 2491 goto fail; 2492 } 2493 2494 os_memset(&addr, 0, sizeof(addr)); 2495 #ifdef __FreeBSD__ 2496 addr.sun_len = sizeof(addr); 2497 #endif /* __FreeBSD__ */ 2498 addr.sun_family = AF_UNIX; 2499 fname = hostapd_global_ctrl_iface_path(interface); 2500 if (fname == NULL) 2501 goto fail; 2502 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 2503 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 2504 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 2505 strerror(errno)); 2506 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 2507 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 2508 " allow connections - assuming it was left" 2509 "over from forced program termination"); 2510 if (unlink(fname) < 0) { 2511 wpa_printf(MSG_ERROR, 2512 "Could not unlink existing ctrl_iface socket '%s': %s", 2513 fname, strerror(errno)); 2514 goto fail; 2515 } 2516 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 2517 0) { 2518 wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s", 2519 strerror(errno)); 2520 goto fail; 2521 } 2522 wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 2523 "ctrl_iface socket '%s'", fname); 2524 } else { 2525 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 2526 "be in use - cannot override it"); 2527 wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 2528 "not used anymore", fname); 2529 os_free(fname); 2530 fname = NULL; 2531 goto fail; 2532 } 2533 } 2534 2535 if (interface->ctrl_iface_group && 2536 chown(fname, -1, interface->ctrl_iface_group) < 0) { 2537 wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s", 2538 strerror(errno)); 2539 goto fail; 2540 } 2541 2542 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 2543 wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s", 2544 strerror(errno)); 2545 goto fail; 2546 } 2547 os_free(fname); 2548 2549 interface->global_ctrl_sock = s; 2550 eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive, 2551 interface, NULL); 2552 2553 return 0; 2554 2555 fail: 2556 if (s >= 0) 2557 close(s); 2558 if (fname) { 2559 unlink(fname); 2560 os_free(fname); 2561 } 2562 return -1; 2563 } 2564 2565 2566 void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces) 2567 { 2568 char *fname = NULL; 2569 2570 if (interfaces->global_ctrl_sock > -1) { 2571 eloop_unregister_read_sock(interfaces->global_ctrl_sock); 2572 close(interfaces->global_ctrl_sock); 2573 interfaces->global_ctrl_sock = -1; 2574 fname = hostapd_global_ctrl_iface_path(interfaces); 2575 if (fname) { 2576 unlink(fname); 2577 os_free(fname); 2578 } 2579 2580 if (interfaces->global_iface_path && 2581 rmdir(interfaces->global_iface_path) < 0) { 2582 if (errno == ENOTEMPTY) { 2583 wpa_printf(MSG_DEBUG, "Control interface " 2584 "directory not empty - leaving it " 2585 "behind"); 2586 } else { 2587 wpa_printf(MSG_ERROR, 2588 "rmdir[ctrl_interface=%s]: %s", 2589 interfaces->global_iface_path, 2590 strerror(errno)); 2591 } 2592 } 2593 os_free(interfaces->global_iface_path); 2594 interfaces->global_iface_path = NULL; 2595 } 2596 } 2597 2598 2599 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, 2600 const char *buf, size_t len) 2601 { 2602 struct wpa_ctrl_dst *dst, *next; 2603 struct msghdr msg; 2604 int idx; 2605 struct iovec io[2]; 2606 char levelstr[10]; 2607 2608 dst = hapd->ctrl_dst; 2609 if (hapd->ctrl_sock < 0 || dst == NULL) 2610 return; 2611 2612 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 2613 io[0].iov_base = levelstr; 2614 io[0].iov_len = os_strlen(levelstr); 2615 io[1].iov_base = (char *) buf; 2616 io[1].iov_len = len; 2617 os_memset(&msg, 0, sizeof(msg)); 2618 msg.msg_iov = io; 2619 msg.msg_iovlen = 2; 2620 2621 idx = 0; 2622 while (dst) { 2623 next = dst->next; 2624 if (level >= dst->debug_level) { 2625 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", 2626 (u8 *) dst->addr.sun_path, dst->addrlen - 2627 offsetof(struct sockaddr_un, sun_path)); 2628 msg.msg_name = &dst->addr; 2629 msg.msg_namelen = dst->addrlen; 2630 if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) { 2631 int _errno = errno; 2632 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " 2633 "%d - %s", 2634 idx, errno, strerror(errno)); 2635 dst->errors++; 2636 if (dst->errors > 10 || _errno == ENOENT) { 2637 hostapd_ctrl_iface_detach( 2638 hapd, &dst->addr, 2639 dst->addrlen); 2640 } 2641 } else 2642 dst->errors = 0; 2643 } 2644 idx++; 2645 dst = next; 2646 } 2647 } 2648 2649 #endif /* CONFIG_NATIVE_WINDOWS */ 2650