1 /* 2 * hostapd / main() 3 * Copyright (c) 2002-2022, 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 #ifndef CONFIG_NATIVE_WINDOWS 11 #include <syslog.h> 12 #include <grp.h> 13 #endif /* CONFIG_NATIVE_WINDOWS */ 14 15 #include "utils/common.h" 16 #include "utils/eloop.h" 17 #include "utils/uuid.h" 18 #include "crypto/crypto.h" 19 #include "crypto/random.h" 20 #include "crypto/tls.h" 21 #include "common/version.h" 22 #include "common/dpp.h" 23 #include "drivers/driver.h" 24 #include "eap_server/eap.h" 25 #include "eap_server/tncs.h" 26 #include "ap/hostapd.h" 27 #include "ap/ap_config.h" 28 #include "ap/ap_drv_ops.h" 29 #include "ap/dpp_hostapd.h" 30 #include "fst/fst.h" 31 #include "config_file.h" 32 #include "eap_register.h" 33 #include "ctrl_iface.h" 34 35 36 struct hapd_global { 37 void **drv_priv; 38 size_t drv_count; 39 }; 40 41 static struct hapd_global global; 42 43 44 #ifndef CONFIG_NO_HOSTAPD_LOGGER 45 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, 46 int level, const char *txt, size_t len) 47 { 48 struct hostapd_data *hapd = ctx; 49 char *format, *module_str; 50 int maxlen; 51 int conf_syslog_level, conf_stdout_level; 52 unsigned int conf_syslog, conf_stdout; 53 54 maxlen = len + 100; 55 format = os_malloc(maxlen); 56 if (!format) 57 return; 58 59 if (hapd && hapd->conf) { 60 conf_syslog_level = hapd->conf->logger_syslog_level; 61 conf_stdout_level = hapd->conf->logger_stdout_level; 62 conf_syslog = hapd->conf->logger_syslog; 63 conf_stdout = hapd->conf->logger_stdout; 64 } else { 65 conf_syslog_level = conf_stdout_level = 0; 66 conf_syslog = conf_stdout = (unsigned int) -1; 67 } 68 69 switch (module) { 70 case HOSTAPD_MODULE_IEEE80211: 71 module_str = "IEEE 802.11"; 72 break; 73 case HOSTAPD_MODULE_IEEE8021X: 74 module_str = "IEEE 802.1X"; 75 break; 76 case HOSTAPD_MODULE_RADIUS: 77 module_str = "RADIUS"; 78 break; 79 case HOSTAPD_MODULE_WPA: 80 module_str = "WPA"; 81 break; 82 case HOSTAPD_MODULE_DRIVER: 83 module_str = "DRIVER"; 84 break; 85 case HOSTAPD_MODULE_MLME: 86 module_str = "MLME"; 87 break; 88 default: 89 module_str = NULL; 90 break; 91 } 92 93 if (hapd && hapd->conf && addr) 94 os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", 95 hapd->conf->iface, MAC2STR(addr), 96 module_str ? " " : "", module_str ? module_str : "", 97 txt); 98 else if (hapd && hapd->conf) 99 os_snprintf(format, maxlen, "%s:%s%s %s", 100 hapd->conf->iface, module_str ? " " : "", 101 module_str ? module_str : "", txt); 102 else if (addr) 103 os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", 104 MAC2STR(addr), module_str ? " " : "", 105 module_str ? module_str : "", txt); 106 else 107 os_snprintf(format, maxlen, "%s%s%s", 108 module_str ? module_str : "", 109 module_str ? ": " : "", txt); 110 111 #ifdef CONFIG_DEBUG_SYSLOG 112 if (wpa_debug_syslog) 113 conf_stdout = 0; 114 #endif /* CONFIG_DEBUG_SYSLOG */ 115 if ((conf_stdout & module) && level >= conf_stdout_level) { 116 wpa_debug_print_timestamp(); 117 wpa_printf(MSG_INFO, "%s", format); 118 } 119 120 #ifndef CONFIG_NATIVE_WINDOWS 121 if ((conf_syslog & module) && level >= conf_syslog_level) { 122 int priority; 123 switch (level) { 124 case HOSTAPD_LEVEL_DEBUG_VERBOSE: 125 case HOSTAPD_LEVEL_DEBUG: 126 priority = LOG_DEBUG; 127 break; 128 case HOSTAPD_LEVEL_INFO: 129 priority = LOG_INFO; 130 break; 131 case HOSTAPD_LEVEL_NOTICE: 132 priority = LOG_NOTICE; 133 break; 134 case HOSTAPD_LEVEL_WARNING: 135 priority = LOG_WARNING; 136 break; 137 default: 138 priority = LOG_INFO; 139 break; 140 } 141 syslog(priority, "%s", format); 142 } 143 #endif /* CONFIG_NATIVE_WINDOWS */ 144 145 os_free(format); 146 } 147 #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 148 149 150 /** 151 * hostapd_driver_init - Preparate driver interface 152 */ 153 static int hostapd_driver_init(struct hostapd_iface *iface) 154 { 155 struct wpa_init_params params; 156 size_t i; 157 struct hostapd_data *hapd = iface->bss[0]; 158 struct hostapd_bss_config *conf = hapd->conf; 159 u8 *b = conf->bssid; 160 struct wpa_driver_capa capa; 161 #ifdef CONFIG_IEEE80211BE 162 struct hostapd_data *h_hapd = NULL; 163 #endif /* CONFIG_IEEE80211BE */ 164 165 if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) { 166 wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); 167 return -1; 168 } 169 170 #ifdef CONFIG_IEEE80211BE 171 if (conf->mld_ap) 172 h_hapd = hostapd_mld_get_first_bss(hapd); 173 174 if (h_hapd) { 175 hapd->drv_priv = h_hapd->drv_priv; 176 hapd->interface_added = h_hapd->interface_added; 177 178 /* 179 * All interfaces participating in the AP MLD would have 180 * the same MLD address, which is the interface hardware 181 * address, while the interface address would be 182 * derived from the original interface address if BSSID 183 * is not configured, and otherwise it would be the 184 * configured BSSID. 185 */ 186 if (is_zero_ether_addr(b)) { 187 os_memcpy(hapd->own_addr, h_hapd->mld->mld_addr, 188 ETH_ALEN); 189 random_mac_addr_keep_oui(hapd->own_addr); 190 } else { 191 os_memcpy(hapd->own_addr, b, ETH_ALEN); 192 } 193 194 hostapd_mld_add_link(hapd); 195 wpa_printf(MSG_DEBUG, 196 "Setup of non first link (%d) BSS of MLD %s", 197 hapd->mld_link_id, hapd->conf->iface); 198 199 goto setup_mld; 200 } 201 #endif /* CONFIG_IEEE80211BE */ 202 203 /* Initialize the driver interface */ 204 if (is_zero_ether_addr(b)) 205 b = NULL; 206 207 os_memset(¶ms, 0, sizeof(params)); 208 for (i = 0; wpa_drivers[i]; i++) { 209 if (wpa_drivers[i] != hapd->driver) 210 continue; 211 212 if (global.drv_priv[i] == NULL && 213 wpa_drivers[i]->global_init) { 214 global.drv_priv[i] = 215 wpa_drivers[i]->global_init(iface->interfaces); 216 if (global.drv_priv[i] == NULL) { 217 wpa_printf(MSG_ERROR, "Failed to initialize " 218 "driver '%s'", 219 wpa_drivers[i]->name); 220 return -1; 221 } 222 } 223 224 params.global_priv = global.drv_priv[i]; 225 break; 226 } 227 params.bssid = b; 228 #ifdef CONFIG_IEEE80211BE 229 /* 230 * Use the configured MLD MAC address as the interface hardware address 231 * if this AP is a part of an AP MLD. 232 */ 233 if (hapd->conf->mld_ap) { 234 if (!is_zero_ether_addr(hapd->conf->mld_addr)) 235 params.bssid = hapd->conf->mld_addr; 236 else 237 params.bssid = NULL; 238 } 239 #endif /* CONFIG_IEEE80211BE */ 240 241 params.ifname = hapd->conf->iface; 242 params.driver_params = hapd->iconf->driver_params; 243 params.use_pae_group_addr = hapd->conf->use_pae_group_addr; 244 245 params.num_bridge = hapd->iface->num_bss; 246 params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *)); 247 if (params.bridge == NULL) 248 return -1; 249 for (i = 0; i < hapd->iface->num_bss; i++) { 250 struct hostapd_data *bss = hapd->iface->bss[i]; 251 if (bss->conf->bridge[0]) 252 params.bridge[i] = bss->conf->bridge; 253 } 254 255 params.own_addr = hapd->own_addr; 256 257 hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms); 258 os_free(params.bridge); 259 if (hapd->drv_priv == NULL) { 260 wpa_printf(MSG_ERROR, "%s driver initialization failed.", 261 hapd->driver->name); 262 hapd->driver = NULL; 263 return -1; 264 } 265 266 #ifdef CONFIG_IEEE80211BE 267 /* 268 * This is the first interface added to the AP MLD, so have the 269 * interface hardware address be the MLD address, while the link address 270 * would be derived from the original interface address if BSSID is not 271 * configured, and otherwise it would be the configured BSSID. 272 */ 273 if (hapd->conf->mld_ap) { 274 os_memcpy(hapd->mld->mld_addr, hapd->own_addr, ETH_ALEN); 275 276 if (!b) 277 random_mac_addr_keep_oui(hapd->own_addr); 278 else 279 os_memcpy(hapd->own_addr, b, ETH_ALEN); 280 281 hostapd_mld_add_link(hapd); 282 wpa_printf(MSG_DEBUG, "Setup of first link (%d) BSS of MLD %s", 283 hapd->mld_link_id, hapd->conf->iface); 284 } 285 286 setup_mld: 287 #endif /* CONFIG_IEEE80211BE */ 288 289 if (hapd->driver->get_capa && 290 hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { 291 struct wowlan_triggers *triggs; 292 293 iface->drv_flags = capa.flags; 294 iface->drv_flags2 = capa.flags2; 295 iface->drv_rrm_flags = capa.rrm_flags; 296 iface->probe_resp_offloads = capa.probe_resp_offloads; 297 /* 298 * Use default extended capa values from per-radio information 299 */ 300 iface->extended_capa = capa.extended_capa; 301 iface->extended_capa_mask = capa.extended_capa_mask; 302 iface->extended_capa_len = capa.extended_capa_len; 303 iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; 304 305 /* 306 * Override extended capa with per-interface type (AP), if 307 * available from the driver. 308 */ 309 hostapd_get_ext_capa(iface); 310 311 hostapd_get_mld_capa(iface); 312 313 triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); 314 if (triggs && hapd->driver->set_wowlan) { 315 if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) 316 wpa_printf(MSG_ERROR, "set_wowlan failed"); 317 } 318 os_free(triggs); 319 320 iface->mbssid_max_interfaces = capa.mbssid_max_interfaces; 321 iface->ema_max_periodicity = capa.ema_max_periodicity; 322 } 323 324 #ifdef CONFIG_IEEE80211BE 325 if (hapd->conf->mld_ap) { 326 if (!(iface->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) { 327 wpa_printf(MSG_INFO, 328 "MLD: Not supported by the driver"); 329 return -1; 330 } 331 332 /* Initialize the BSS parameter change to 1 */ 333 hapd->eht_mld_bss_param_change = 1; 334 335 wpa_printf(MSG_DEBUG, 336 "MLD: Set link_id=%u, mld_addr=" MACSTR 337 ", own_addr=" MACSTR, 338 hapd->mld_link_id, MAC2STR(hapd->mld->mld_addr), 339 MAC2STR(hapd->own_addr)); 340 341 hostapd_drv_link_add(hapd, hapd->mld_link_id, 342 hapd->own_addr); 343 } 344 #endif /* CONFIG_IEEE80211BE */ 345 346 return 0; 347 } 348 349 350 /** 351 * hostapd_interface_init - Read configuration file and init BSS data 352 * 353 * This function is used to parse configuration file for a full interface (one 354 * or more BSSes sharing the same radio) and allocate memory for the BSS 355 * interfaces. No actual driver operations are started. 356 */ 357 static struct hostapd_iface * 358 hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name, 359 const char *config_fname, int debug) 360 { 361 struct hostapd_iface *iface; 362 int k; 363 364 wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname); 365 iface = hostapd_init(interfaces, config_fname); 366 if (!iface) 367 return NULL; 368 369 if (if_name) { 370 os_strlcpy(iface->conf->bss[0]->iface, if_name, 371 sizeof(iface->conf->bss[0]->iface)); 372 } 373 374 iface->interfaces = interfaces; 375 376 for (k = 0; k < debug; k++) { 377 if (iface->bss[0]->conf->logger_stdout_level > 0) 378 iface->bss[0]->conf->logger_stdout_level--; 379 } 380 381 if (iface->conf->bss[0]->iface[0] == '\0' && 382 !hostapd_drv_none(iface->bss[0])) { 383 wpa_printf(MSG_ERROR, 384 "Interface name not specified in %s, nor by '-i' parameter", 385 config_fname); 386 hostapd_interface_deinit_free(iface); 387 return NULL; 388 } 389 390 return iface; 391 } 392 393 394 /** 395 * handle_term - SIGINT and SIGTERM handler to terminate hostapd process 396 */ 397 static void handle_term(int sig, void *signal_ctx) 398 { 399 wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); 400 eloop_terminate(); 401 } 402 403 404 #ifndef CONFIG_NATIVE_WINDOWS 405 406 static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) 407 { 408 if (hostapd_reload_config(iface) < 0) { 409 wpa_printf(MSG_WARNING, "Failed to read new configuration " 410 "file - continuing with old."); 411 } 412 return 0; 413 } 414 415 416 /** 417 * handle_reload - SIGHUP handler to reload configuration 418 */ 419 static void handle_reload(int sig, void *signal_ctx) 420 { 421 struct hapd_interfaces *interfaces = signal_ctx; 422 wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", 423 sig); 424 hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); 425 } 426 427 428 static void handle_dump_state(int sig, void *signal_ctx) 429 { 430 /* Not used anymore - ignore signal */ 431 } 432 #endif /* CONFIG_NATIVE_WINDOWS */ 433 434 435 static int hostapd_global_init(struct hapd_interfaces *interfaces, 436 const char *entropy_file) 437 { 438 int i; 439 440 os_memset(&global, 0, sizeof(global)); 441 442 hostapd_logger_register_cb(hostapd_logger_cb); 443 444 if (eap_server_register_methods()) { 445 wpa_printf(MSG_ERROR, "Failed to register EAP methods"); 446 return -1; 447 } 448 449 if (eloop_init()) { 450 wpa_printf(MSG_ERROR, "Failed to initialize event loop"); 451 return -1; 452 } 453 interfaces->eloop_initialized = 1; 454 455 random_init(entropy_file); 456 457 #ifndef CONFIG_NATIVE_WINDOWS 458 eloop_register_signal(SIGHUP, handle_reload, interfaces); 459 eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); 460 #endif /* CONFIG_NATIVE_WINDOWS */ 461 eloop_register_signal_terminate(handle_term, interfaces); 462 463 #ifndef CONFIG_NATIVE_WINDOWS 464 openlog("hostapd", 0, LOG_DAEMON); 465 #endif /* CONFIG_NATIVE_WINDOWS */ 466 467 for (i = 0; wpa_drivers[i]; i++) 468 global.drv_count++; 469 if (global.drv_count == 0) { 470 wpa_printf(MSG_ERROR, "No drivers enabled"); 471 return -1; 472 } 473 global.drv_priv = os_calloc(global.drv_count, sizeof(void *)); 474 if (global.drv_priv == NULL) 475 return -1; 476 477 return 0; 478 } 479 480 481 static void hostapd_global_deinit(const char *pid_file, int eloop_initialized) 482 { 483 int i; 484 485 for (i = 0; wpa_drivers[i] && global.drv_priv; i++) { 486 if (!global.drv_priv[i]) 487 continue; 488 wpa_drivers[i]->global_deinit(global.drv_priv[i]); 489 } 490 os_free(global.drv_priv); 491 global.drv_priv = NULL; 492 493 #ifdef EAP_SERVER_TNC 494 tncs_global_deinit(); 495 #endif /* EAP_SERVER_TNC */ 496 497 random_deinit(); 498 499 if (eloop_initialized) 500 eloop_destroy(); 501 502 #ifndef CONFIG_NATIVE_WINDOWS 503 closelog(); 504 #endif /* CONFIG_NATIVE_WINDOWS */ 505 506 eap_server_unregister_methods(); 507 508 os_daemonize_terminate(pid_file); 509 } 510 511 512 static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, 513 const char *pid_file) 514 { 515 #ifdef EAP_SERVER_TNC 516 int tnc = 0; 517 size_t i, k; 518 519 for (i = 0; !tnc && i < ifaces->count; i++) { 520 for (k = 0; k < ifaces->iface[i]->num_bss; k++) { 521 if (ifaces->iface[i]->bss[0]->conf->tnc) { 522 tnc++; 523 break; 524 } 525 } 526 } 527 528 if (tnc && tncs_global_init() < 0) { 529 wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); 530 return -1; 531 } 532 #endif /* EAP_SERVER_TNC */ 533 534 if (daemonize) { 535 if (os_daemonize(pid_file)) { 536 wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); 537 return -1; 538 } 539 if (eloop_sock_requeue()) { 540 wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s", 541 strerror(errno)); 542 return -1; 543 } 544 } 545 546 eloop_run(); 547 548 return 0; 549 } 550 551 552 static void show_version(void) 553 { 554 fprintf(stderr, 555 "hostapd v%s\n" 556 "User space daemon for IEEE 802.11 AP management,\n" 557 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" 558 "Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi> " 559 "and contributors\n", 560 VERSION_STR); 561 } 562 563 564 static void usage(void) 565 { 566 show_version(); 567 fprintf(stderr, 568 "\n" 569 "usage: hostapd [-hdBKtvq] [-P <PID file>] [-e <entropy file>] " 570 "\\\n" 571 " [-g <global ctrl_iface>] [-G <group>]\\\n" 572 " [-i <comma-separated list of interface names>]\\\n" 573 " <configuration file(s)>\n" 574 "\n" 575 "options:\n" 576 " -h show this usage\n" 577 " -d show more debug messages (-dd for even more)\n" 578 " -B run daemon in the background\n" 579 " -e entropy file\n" 580 " -g global control interface path\n" 581 " -G group for control interfaces\n" 582 " -P PID file\n" 583 " -K include key data in debug messages\n" 584 #ifdef CONFIG_DEBUG_FILE 585 " -f log output to debug file instead of stdout\n" 586 #endif /* CONFIG_DEBUG_FILE */ 587 #ifdef CONFIG_DEBUG_LINUX_TRACING 588 " -T record to Linux tracing in addition to logging\n" 589 " (records all messages regardless of debug verbosity)\n" 590 #endif /* CONFIG_DEBUG_LINUX_TRACING */ 591 " -i list of interface names to use\n" 592 #ifdef CONFIG_DEBUG_SYSLOG 593 " -s log output to syslog instead of stdout\n" 594 #endif /* CONFIG_DEBUG_SYSLOG */ 595 " -S start all the interfaces synchronously\n" 596 " -t include timestamps in some debug messages\n" 597 " -v show hostapd version\n" 598 " -q show less debug messages (-qq for even less)\n"); 599 600 exit(1); 601 } 602 603 604 static const char * hostapd_msg_ifname_cb(void *ctx) 605 { 606 struct hostapd_data *hapd = ctx; 607 if (hapd && hapd->conf) 608 return hapd->conf->iface; 609 return NULL; 610 } 611 612 613 static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, 614 const char *path) 615 { 616 #ifndef CONFIG_CTRL_IFACE_UDP 617 char *pos; 618 #endif /* !CONFIG_CTRL_IFACE_UDP */ 619 620 os_free(interfaces->global_iface_path); 621 interfaces->global_iface_path = os_strdup(path); 622 if (interfaces->global_iface_path == NULL) 623 return -1; 624 625 #ifndef CONFIG_CTRL_IFACE_UDP 626 pos = os_strrchr(interfaces->global_iface_path, '/'); 627 if (pos == NULL) { 628 wpa_printf(MSG_ERROR, "No '/' in the global control interface " 629 "file"); 630 os_free(interfaces->global_iface_path); 631 interfaces->global_iface_path = NULL; 632 return -1; 633 } 634 635 *pos = '\0'; 636 interfaces->global_iface_name = pos + 1; 637 #endif /* !CONFIG_CTRL_IFACE_UDP */ 638 639 return 0; 640 } 641 642 643 static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces, 644 const char *group) 645 { 646 #ifndef CONFIG_NATIVE_WINDOWS 647 struct group *grp; 648 grp = getgrnam(group); 649 if (grp == NULL) { 650 wpa_printf(MSG_ERROR, "Unknown group '%s'", group); 651 return -1; 652 } 653 interfaces->ctrl_iface_group = grp->gr_gid; 654 #endif /* CONFIG_NATIVE_WINDOWS */ 655 return 0; 656 } 657 658 659 static int hostapd_get_interface_names(char ***if_names, 660 size_t *if_names_size, 661 char *arg) 662 { 663 char *if_name, *tmp, **nnames; 664 size_t i; 665 666 if (!arg) 667 return -1; 668 if_name = strtok_r(arg, ",", &tmp); 669 670 while (if_name) { 671 nnames = os_realloc_array(*if_names, 1 + *if_names_size, 672 sizeof(char *)); 673 if (!nnames) 674 goto fail; 675 *if_names = nnames; 676 677 (*if_names)[*if_names_size] = os_strdup(if_name); 678 if (!(*if_names)[*if_names_size]) 679 goto fail; 680 (*if_names_size)++; 681 if_name = strtok_r(NULL, ",", &tmp); 682 } 683 684 return 0; 685 686 fail: 687 for (i = 0; i < *if_names_size; i++) 688 os_free((*if_names)[i]); 689 os_free(*if_names); 690 *if_names = NULL; 691 *if_names_size = 0; 692 return -1; 693 } 694 695 696 #ifdef CONFIG_WPS 697 static int gen_uuid(const char *txt_addr) 698 { 699 u8 addr[ETH_ALEN]; 700 u8 uuid[UUID_LEN]; 701 char buf[100]; 702 703 if (hwaddr_aton(txt_addr, addr) < 0) 704 return -1; 705 706 uuid_gen_mac_addr(addr, uuid); 707 if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0) 708 return -1; 709 710 printf("%s\n", buf); 711 712 return 0; 713 } 714 #endif /* CONFIG_WPS */ 715 716 717 #ifndef HOSTAPD_CLEANUP_INTERVAL 718 #define HOSTAPD_CLEANUP_INTERVAL 10 719 #endif /* HOSTAPD_CLEANUP_INTERVAL */ 720 721 static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx) 722 { 723 hostapd_periodic_iface(iface); 724 return 0; 725 } 726 727 728 /* Periodic cleanup tasks */ 729 static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx) 730 { 731 struct hapd_interfaces *interfaces = eloop_ctx; 732 733 eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0, 734 hostapd_periodic, interfaces, NULL); 735 hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL); 736 } 737 738 739 static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) 740 { 741 #ifdef CONFIG_IEEE80211BE 742 size_t i; 743 744 if (!interfaces || !interfaces->mld) 745 return; 746 747 for (i = 0; i < interfaces->mld_count; i++) { 748 if (!interfaces->mld[i]) 749 continue; 750 751 os_free(interfaces->mld[i]); 752 interfaces->mld[i] = NULL; 753 } 754 755 os_free(interfaces->mld); 756 interfaces->mld = NULL; 757 interfaces->mld_count = 0; 758 #endif /* CONFIG_IEEE80211BE */ 759 } 760 761 762 int main(int argc, char *argv[]) 763 { 764 struct hapd_interfaces interfaces; 765 int ret = 1; 766 size_t i, j; 767 int c, debug = 0, daemonize = 0; 768 char *pid_file = NULL; 769 const char *log_file = NULL; 770 const char *entropy_file = NULL; 771 char **bss_config = NULL, **tmp_bss; 772 size_t num_bss_configs = 0; 773 #ifdef CONFIG_DEBUG_LINUX_TRACING 774 int enable_trace_dbg = 0; 775 #endif /* CONFIG_DEBUG_LINUX_TRACING */ 776 int start_ifaces_in_sync = 0; 777 char **if_names = NULL; 778 size_t if_names_size = 0; 779 #ifdef CONFIG_DPP 780 struct dpp_global_config dpp_conf; 781 #endif /* CONFIG_DPP */ 782 783 if (os_program_init()) 784 return -1; 785 786 os_memset(&interfaces, 0, sizeof(interfaces)); 787 interfaces.reload_config = hostapd_reload_config; 788 interfaces.config_read_cb = hostapd_config_read; 789 interfaces.for_each_interface = hostapd_for_each_interface; 790 interfaces.ctrl_iface_init = hostapd_ctrl_iface_init; 791 interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit; 792 interfaces.driver_init = hostapd_driver_init; 793 interfaces.global_iface_path = NULL; 794 interfaces.global_iface_name = NULL; 795 interfaces.global_ctrl_sock = -1; 796 dl_list_init(&interfaces.global_ctrl_dst); 797 #ifdef CONFIG_ETH_P_OUI 798 dl_list_init(&interfaces.eth_p_oui); 799 #endif /* CONFIG_ETH_P_OUI */ 800 #ifdef CONFIG_DPP 801 os_memset(&dpp_conf, 0, sizeof(dpp_conf)); 802 dpp_conf.cb_ctx = &interfaces; 803 #ifdef CONFIG_DPP2 804 dpp_conf.remove_bi = hostapd_dpp_remove_bi; 805 #endif /* CONFIG_DPP2 */ 806 interfaces.dpp = dpp_global_init(&dpp_conf); 807 if (!interfaces.dpp) 808 return -1; 809 #endif /* CONFIG_DPP */ 810 811 for (;;) { 812 c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q"); 813 if (c < 0) 814 break; 815 switch (c) { 816 case 'h': 817 usage(); 818 break; 819 case 'd': 820 debug++; 821 if (wpa_debug_level > 0) 822 wpa_debug_level--; 823 break; 824 case 'B': 825 daemonize++; 826 break; 827 case 'e': 828 entropy_file = optarg; 829 break; 830 case 'f': 831 log_file = optarg; 832 break; 833 case 'K': 834 wpa_debug_show_keys++; 835 break; 836 case 'P': 837 os_free(pid_file); 838 pid_file = os_rel2abs_path(optarg); 839 break; 840 case 't': 841 wpa_debug_timestamp++; 842 break; 843 #ifdef CONFIG_DEBUG_LINUX_TRACING 844 case 'T': 845 enable_trace_dbg = 1; 846 break; 847 #endif /* CONFIG_DEBUG_LINUX_TRACING */ 848 case 'v': 849 show_version(); 850 exit(1); 851 case 'g': 852 if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) 853 return -1; 854 break; 855 case 'G': 856 if (hostapd_get_ctrl_iface_group(&interfaces, optarg)) 857 return -1; 858 break; 859 case 'b': 860 tmp_bss = os_realloc_array(bss_config, 861 num_bss_configs + 1, 862 sizeof(char *)); 863 if (tmp_bss == NULL) 864 goto out; 865 bss_config = tmp_bss; 866 bss_config[num_bss_configs++] = optarg; 867 break; 868 #ifdef CONFIG_DEBUG_SYSLOG 869 case 's': 870 wpa_debug_syslog = 1; 871 break; 872 #endif /* CONFIG_DEBUG_SYSLOG */ 873 case 'S': 874 start_ifaces_in_sync = 1; 875 break; 876 #ifdef CONFIG_WPS 877 case 'u': 878 return gen_uuid(optarg); 879 #endif /* CONFIG_WPS */ 880 case 'i': 881 if (hostapd_get_interface_names(&if_names, 882 &if_names_size, optarg)) 883 goto out; 884 break; 885 case 'q': 886 wpa_debug_level++; 887 break; 888 default: 889 usage(); 890 break; 891 } 892 } 893 894 if (optind == argc && interfaces.global_iface_path == NULL && 895 num_bss_configs == 0) 896 usage(); 897 898 wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); 899 900 if (log_file) 901 wpa_debug_open_file(log_file); 902 if (!log_file && !wpa_debug_syslog) 903 wpa_debug_setup_stdout(); 904 #ifdef CONFIG_DEBUG_SYSLOG 905 if (wpa_debug_syslog) 906 wpa_debug_open_syslog(); 907 #endif /* CONFIG_DEBUG_SYSLOG */ 908 #ifdef CONFIG_DEBUG_LINUX_TRACING 909 if (enable_trace_dbg) { 910 int tret = wpa_debug_open_linux_tracing(); 911 if (tret) { 912 wpa_printf(MSG_ERROR, "Failed to enable trace logging"); 913 return -1; 914 } 915 } 916 #endif /* CONFIG_DEBUG_LINUX_TRACING */ 917 918 interfaces.count = argc - optind; 919 if (interfaces.count || num_bss_configs) { 920 interfaces.iface = os_calloc(interfaces.count + num_bss_configs, 921 sizeof(struct hostapd_iface *)); 922 if (interfaces.iface == NULL) { 923 wpa_printf(MSG_ERROR, "malloc failed"); 924 return -1; 925 } 926 } 927 928 if (hostapd_global_init(&interfaces, entropy_file)) { 929 wpa_printf(MSG_ERROR, "Failed to initialize global context"); 930 return -1; 931 } 932 933 eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0, 934 hostapd_periodic, &interfaces, NULL); 935 936 if (fst_global_init()) { 937 wpa_printf(MSG_ERROR, 938 "Failed to initialize global FST context"); 939 goto out; 940 } 941 942 #if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE) 943 if (!fst_global_add_ctrl(fst_ctrl_cli)) 944 wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl"); 945 #endif /* CONFIG_FST && CONFIG_CTRL_IFACE */ 946 947 /* Allocate and parse configuration for full interface files */ 948 for (i = 0; i < interfaces.count; i++) { 949 char *if_name = NULL; 950 951 if (i < if_names_size) 952 if_name = if_names[i]; 953 954 interfaces.iface[i] = hostapd_interface_init(&interfaces, 955 if_name, 956 argv[optind + i], 957 debug); 958 if (!interfaces.iface[i]) { 959 wpa_printf(MSG_ERROR, "Failed to initialize interface"); 960 goto out; 961 } 962 if (start_ifaces_in_sync) 963 interfaces.iface[i]->need_to_start_in_sync = 1; 964 } 965 966 /* Allocate and parse configuration for per-BSS files */ 967 for (i = 0; i < num_bss_configs; i++) { 968 struct hostapd_iface *iface; 969 char *fname; 970 971 wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]); 972 fname = os_strchr(bss_config[i], ':'); 973 if (fname == NULL) { 974 wpa_printf(MSG_ERROR, 975 "Invalid BSS config identifier '%s'", 976 bss_config[i]); 977 goto out; 978 } 979 *fname++ = '\0'; 980 iface = hostapd_interface_init_bss(&interfaces, bss_config[i], 981 fname, debug); 982 if (iface == NULL) 983 goto out; 984 for (j = 0; j < interfaces.count; j++) { 985 if (interfaces.iface[j] == iface) 986 break; 987 } 988 if (j == interfaces.count) { 989 struct hostapd_iface **tmp; 990 tmp = os_realloc_array(interfaces.iface, 991 interfaces.count + 1, 992 sizeof(struct hostapd_iface *)); 993 if (tmp == NULL) { 994 hostapd_interface_deinit_free(iface); 995 goto out; 996 } 997 interfaces.iface = tmp; 998 interfaces.iface[interfaces.count++] = iface; 999 } 1000 } 1001 1002 /* 1003 * Enable configured interfaces. Depending on channel configuration, 1004 * this may complete full initialization before returning or use a 1005 * callback mechanism to complete setup in case of operations like HT 1006 * co-ex scans, ACS, or DFS are needed to determine channel parameters. 1007 * In such case, the interface will be enabled from eloop context within 1008 * hostapd_global_run(). 1009 */ 1010 interfaces.terminate_on_error = interfaces.count; 1011 for (i = 0; i < interfaces.count; i++) { 1012 if (hostapd_driver_init(interfaces.iface[i]) || 1013 hostapd_setup_interface(interfaces.iface[i])) 1014 goto out; 1015 } 1016 1017 hostapd_global_ctrl_iface_init(&interfaces); 1018 1019 if (hostapd_global_run(&interfaces, daemonize, pid_file)) { 1020 wpa_printf(MSG_ERROR, "Failed to start eloop"); 1021 goto out; 1022 } 1023 1024 ret = 0; 1025 1026 out: 1027 hostapd_global_ctrl_iface_deinit(&interfaces); 1028 /* Deinitialize all interfaces */ 1029 for (i = 0; i < interfaces.count; i++) { 1030 if (!interfaces.iface[i]) 1031 continue; 1032 interfaces.iface[i]->driver_ap_teardown = 1033 !!(interfaces.iface[i]->drv_flags & 1034 WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 1035 hostapd_interface_deinit_free(interfaces.iface[i]); 1036 interfaces.iface[i] = NULL; 1037 } 1038 os_free(interfaces.iface); 1039 interfaces.iface = NULL; 1040 interfaces.count = 0; 1041 1042 hostapd_global_cleanup_mld(&interfaces); 1043 1044 #ifdef CONFIG_DPP 1045 dpp_global_deinit(interfaces.dpp); 1046 #endif /* CONFIG_DPP */ 1047 1048 if (interfaces.eloop_initialized) 1049 eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL); 1050 hostapd_global_deinit(pid_file, interfaces.eloop_initialized); 1051 os_free(pid_file); 1052 1053 wpa_debug_close_syslog(); 1054 if (log_file) 1055 wpa_debug_close_file(); 1056 wpa_debug_close_linux_tracing(); 1057 1058 os_free(bss_config); 1059 1060 for (i = 0; i < if_names_size; i++) 1061 os_free(if_names[i]); 1062 os_free(if_names); 1063 1064 fst_global_deinit(); 1065 1066 crypto_unload(); 1067 os_program_deinit(); 1068 1069 return ret; 1070 } 1071