18dbcf02cSchristos /* 28dbcf02cSchristos * hostapd / main() 3*45d3cc13Schristos * Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> 48dbcf02cSchristos * 5e604d861Schristos * This software may be distributed under the terms of the BSD license. 6e604d861Schristos * See README for more details. 78dbcf02cSchristos */ 88dbcf02cSchristos 98dbcf02cSchristos #include "utils/includes.h" 108dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 118dbcf02cSchristos #include <syslog.h> 123c260e60Schristos #include <grp.h> 138dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 148dbcf02cSchristos 158dbcf02cSchristos #include "utils/common.h" 168dbcf02cSchristos #include "utils/eloop.h" 173c260e60Schristos #include "utils/uuid.h" 18*45d3cc13Schristos #include "crypto/crypto.h" 19111b9fd8Schristos #include "crypto/random.h" 208dbcf02cSchristos #include "crypto/tls.h" 218dbcf02cSchristos #include "common/version.h" 22460bb4fcSchristos #include "common/dpp.h" 238dbcf02cSchristos #include "drivers/driver.h" 248dbcf02cSchristos #include "eap_server/eap.h" 258dbcf02cSchristos #include "eap_server/tncs.h" 268dbcf02cSchristos #include "ap/hostapd.h" 278dbcf02cSchristos #include "ap/ap_config.h" 28e604d861Schristos #include "ap/ap_drv_ops.h" 29be6b3c4dSchristos #include "ap/dpp_hostapd.h" 30ecc36642Schristos #include "fst/fst.h" 318dbcf02cSchristos #include "config_file.h" 328dbcf02cSchristos #include "eap_register.h" 338dbcf02cSchristos #include "ctrl_iface.h" 348dbcf02cSchristos 358dbcf02cSchristos 36111b9fd8Schristos struct hapd_global { 37111b9fd8Schristos void **drv_priv; 38111b9fd8Schristos size_t drv_count; 39111b9fd8Schristos }; 40111b9fd8Schristos 41111b9fd8Schristos static struct hapd_global global; 42111b9fd8Schristos 438dbcf02cSchristos 448dbcf02cSchristos #ifndef CONFIG_NO_HOSTAPD_LOGGER 458dbcf02cSchristos static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, 468dbcf02cSchristos int level, const char *txt, size_t len) 478dbcf02cSchristos { 488dbcf02cSchristos struct hostapd_data *hapd = ctx; 498dbcf02cSchristos char *format, *module_str; 508dbcf02cSchristos int maxlen; 518dbcf02cSchristos int conf_syslog_level, conf_stdout_level; 528dbcf02cSchristos unsigned int conf_syslog, conf_stdout; 538dbcf02cSchristos 548dbcf02cSchristos maxlen = len + 100; 558dbcf02cSchristos format = os_malloc(maxlen); 568dbcf02cSchristos if (!format) 578dbcf02cSchristos return; 588dbcf02cSchristos 598dbcf02cSchristos if (hapd && hapd->conf) { 608dbcf02cSchristos conf_syslog_level = hapd->conf->logger_syslog_level; 618dbcf02cSchristos conf_stdout_level = hapd->conf->logger_stdout_level; 628dbcf02cSchristos conf_syslog = hapd->conf->logger_syslog; 638dbcf02cSchristos conf_stdout = hapd->conf->logger_stdout; 648dbcf02cSchristos } else { 658dbcf02cSchristos conf_syslog_level = conf_stdout_level = 0; 668dbcf02cSchristos conf_syslog = conf_stdout = (unsigned int) -1; 678dbcf02cSchristos } 688dbcf02cSchristos 698dbcf02cSchristos switch (module) { 708dbcf02cSchristos case HOSTAPD_MODULE_IEEE80211: 718dbcf02cSchristos module_str = "IEEE 802.11"; 728dbcf02cSchristos break; 738dbcf02cSchristos case HOSTAPD_MODULE_IEEE8021X: 748dbcf02cSchristos module_str = "IEEE 802.1X"; 758dbcf02cSchristos break; 768dbcf02cSchristos case HOSTAPD_MODULE_RADIUS: 778dbcf02cSchristos module_str = "RADIUS"; 788dbcf02cSchristos break; 798dbcf02cSchristos case HOSTAPD_MODULE_WPA: 808dbcf02cSchristos module_str = "WPA"; 818dbcf02cSchristos break; 828dbcf02cSchristos case HOSTAPD_MODULE_DRIVER: 838dbcf02cSchristos module_str = "DRIVER"; 848dbcf02cSchristos break; 858dbcf02cSchristos case HOSTAPD_MODULE_MLME: 868dbcf02cSchristos module_str = "MLME"; 878dbcf02cSchristos break; 888dbcf02cSchristos default: 898dbcf02cSchristos module_str = NULL; 908dbcf02cSchristos break; 918dbcf02cSchristos } 928dbcf02cSchristos 938dbcf02cSchristos if (hapd && hapd->conf && addr) 948dbcf02cSchristos os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s", 958dbcf02cSchristos hapd->conf->iface, MAC2STR(addr), 963c260e60Schristos module_str ? " " : "", module_str ? module_str : "", 973c260e60Schristos txt); 988dbcf02cSchristos else if (hapd && hapd->conf) 998dbcf02cSchristos os_snprintf(format, maxlen, "%s:%s%s %s", 1008dbcf02cSchristos hapd->conf->iface, module_str ? " " : "", 1013c260e60Schristos module_str ? module_str : "", txt); 1028dbcf02cSchristos else if (addr) 1038dbcf02cSchristos os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s", 1048dbcf02cSchristos MAC2STR(addr), module_str ? " " : "", 1053c260e60Schristos module_str ? module_str : "", txt); 1068dbcf02cSchristos else 1078dbcf02cSchristos os_snprintf(format, maxlen, "%s%s%s", 1083c260e60Schristos module_str ? module_str : "", 1093c260e60Schristos module_str ? ": " : "", txt); 1108dbcf02cSchristos 111be6b3c4dSchristos #ifdef CONFIG_DEBUG_SYSLOG 112be6b3c4dSchristos if (wpa_debug_syslog) 113be6b3c4dSchristos conf_stdout = 0; 114be6b3c4dSchristos #endif /* CONFIG_DEBUG_SYSLOG */ 1158dbcf02cSchristos if ((conf_stdout & module) && level >= conf_stdout_level) { 1168dbcf02cSchristos wpa_debug_print_timestamp(); 1173c260e60Schristos wpa_printf(MSG_INFO, "%s", format); 1188dbcf02cSchristos } 1198dbcf02cSchristos 1208dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 1218dbcf02cSchristos if ((conf_syslog & module) && level >= conf_syslog_level) { 1228dbcf02cSchristos int priority; 1238dbcf02cSchristos switch (level) { 1248dbcf02cSchristos case HOSTAPD_LEVEL_DEBUG_VERBOSE: 1258dbcf02cSchristos case HOSTAPD_LEVEL_DEBUG: 1268dbcf02cSchristos priority = LOG_DEBUG; 1278dbcf02cSchristos break; 1288dbcf02cSchristos case HOSTAPD_LEVEL_INFO: 1298dbcf02cSchristos priority = LOG_INFO; 1308dbcf02cSchristos break; 1318dbcf02cSchristos case HOSTAPD_LEVEL_NOTICE: 1328dbcf02cSchristos priority = LOG_NOTICE; 1338dbcf02cSchristos break; 1348dbcf02cSchristos case HOSTAPD_LEVEL_WARNING: 1358dbcf02cSchristos priority = LOG_WARNING; 1368dbcf02cSchristos break; 1378dbcf02cSchristos default: 1388dbcf02cSchristos priority = LOG_INFO; 1398dbcf02cSchristos break; 1408dbcf02cSchristos } 1418dbcf02cSchristos syslog(priority, "%s", format); 1428dbcf02cSchristos } 1438dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 1448dbcf02cSchristos 1458dbcf02cSchristos os_free(format); 1468dbcf02cSchristos } 1478dbcf02cSchristos #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 1488dbcf02cSchristos 1498dbcf02cSchristos 1508dbcf02cSchristos /** 1513c260e60Schristos * hostapd_driver_init - Preparate driver interface 1528dbcf02cSchristos */ 1538dbcf02cSchristos static int hostapd_driver_init(struct hostapd_iface *iface) 1548dbcf02cSchristos { 1558dbcf02cSchristos struct wpa_init_params params; 1568dbcf02cSchristos size_t i; 1578dbcf02cSchristos struct hostapd_data *hapd = iface->bss[0]; 1588dbcf02cSchristos struct hostapd_bss_config *conf = hapd->conf; 1598dbcf02cSchristos u8 *b = conf->bssid; 160111b9fd8Schristos struct wpa_driver_capa capa; 161*45d3cc13Schristos #ifdef CONFIG_IEEE80211BE 162*45d3cc13Schristos struct hostapd_data *h_hapd = NULL; 163*45d3cc13Schristos #endif /* CONFIG_IEEE80211BE */ 1648dbcf02cSchristos 1658dbcf02cSchristos if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) { 1668dbcf02cSchristos wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); 1678dbcf02cSchristos return -1; 1688dbcf02cSchristos } 1698dbcf02cSchristos 170*45d3cc13Schristos #ifdef CONFIG_IEEE80211BE 171*45d3cc13Schristos if (conf->mld_ap) 172*45d3cc13Schristos h_hapd = hostapd_mld_get_first_bss(hapd); 173*45d3cc13Schristos 174*45d3cc13Schristos if (h_hapd) { 175*45d3cc13Schristos hapd->drv_priv = h_hapd->drv_priv; 176*45d3cc13Schristos hapd->interface_added = h_hapd->interface_added; 177*45d3cc13Schristos 178*45d3cc13Schristos /* 179*45d3cc13Schristos * All interfaces participating in the AP MLD would have 180*45d3cc13Schristos * the same MLD address, which is the interface hardware 181*45d3cc13Schristos * address, while the interface address would be 182*45d3cc13Schristos * derived from the original interface address if BSSID 183*45d3cc13Schristos * is not configured, and otherwise it would be the 184*45d3cc13Schristos * configured BSSID. 185*45d3cc13Schristos */ 186*45d3cc13Schristos if (is_zero_ether_addr(b)) { 187*45d3cc13Schristos os_memcpy(hapd->own_addr, h_hapd->mld->mld_addr, 188*45d3cc13Schristos ETH_ALEN); 189*45d3cc13Schristos random_mac_addr_keep_oui(hapd->own_addr); 190*45d3cc13Schristos } else { 191*45d3cc13Schristos os_memcpy(hapd->own_addr, b, ETH_ALEN); 192*45d3cc13Schristos } 193*45d3cc13Schristos 194*45d3cc13Schristos hostapd_mld_add_link(hapd); 195*45d3cc13Schristos wpa_printf(MSG_DEBUG, 196*45d3cc13Schristos "Setup of non first link (%d) BSS of MLD %s", 197*45d3cc13Schristos hapd->mld_link_id, hapd->conf->iface); 198*45d3cc13Schristos 199*45d3cc13Schristos goto setup_mld; 200*45d3cc13Schristos } 201*45d3cc13Schristos #endif /* CONFIG_IEEE80211BE */ 202*45d3cc13Schristos 2038dbcf02cSchristos /* Initialize the driver interface */ 204*45d3cc13Schristos if (is_zero_ether_addr(b)) 2058dbcf02cSchristos b = NULL; 2068dbcf02cSchristos 2078dbcf02cSchristos os_memset(¶ms, 0, sizeof(params)); 208111b9fd8Schristos for (i = 0; wpa_drivers[i]; i++) { 209111b9fd8Schristos if (wpa_drivers[i] != hapd->driver) 210111b9fd8Schristos continue; 211111b9fd8Schristos 212111b9fd8Schristos if (global.drv_priv[i] == NULL && 213111b9fd8Schristos wpa_drivers[i]->global_init) { 2140d1d60ceSroy global.drv_priv[i] = 2150d1d60ceSroy wpa_drivers[i]->global_init(iface->interfaces); 216111b9fd8Schristos if (global.drv_priv[i] == NULL) { 217111b9fd8Schristos wpa_printf(MSG_ERROR, "Failed to initialize " 218111b9fd8Schristos "driver '%s'", 219111b9fd8Schristos wpa_drivers[i]->name); 220111b9fd8Schristos return -1; 221111b9fd8Schristos } 222111b9fd8Schristos } 223111b9fd8Schristos 224111b9fd8Schristos params.global_priv = global.drv_priv[i]; 225111b9fd8Schristos break; 226111b9fd8Schristos } 2278dbcf02cSchristos params.bssid = b; 228*45d3cc13Schristos #ifdef CONFIG_IEEE80211BE 229*45d3cc13Schristos /* 230*45d3cc13Schristos * Use the configured MLD MAC address as the interface hardware address 231*45d3cc13Schristos * if this AP is a part of an AP MLD. 232*45d3cc13Schristos */ 233*45d3cc13Schristos if (hapd->conf->mld_ap) { 234*45d3cc13Schristos if (!is_zero_ether_addr(hapd->conf->mld_addr)) 235*45d3cc13Schristos params.bssid = hapd->conf->mld_addr; 236*45d3cc13Schristos else 237*45d3cc13Schristos params.bssid = NULL; 238*45d3cc13Schristos } 239*45d3cc13Schristos #endif /* CONFIG_IEEE80211BE */ 240*45d3cc13Schristos 2418dbcf02cSchristos params.ifname = hapd->conf->iface; 242bb610346Schristos params.driver_params = hapd->iconf->driver_params; 2438dbcf02cSchristos params.use_pae_group_addr = hapd->conf->use_pae_group_addr; 2448dbcf02cSchristos 2458dbcf02cSchristos params.num_bridge = hapd->iface->num_bss; 246e604d861Schristos params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *)); 2478dbcf02cSchristos if (params.bridge == NULL) 2488dbcf02cSchristos return -1; 2498dbcf02cSchristos for (i = 0; i < hapd->iface->num_bss; i++) { 2508dbcf02cSchristos struct hostapd_data *bss = hapd->iface->bss[i]; 2518dbcf02cSchristos if (bss->conf->bridge[0]) 2528dbcf02cSchristos params.bridge[i] = bss->conf->bridge; 2538dbcf02cSchristos } 2548dbcf02cSchristos 2558dbcf02cSchristos params.own_addr = hapd->own_addr; 2568dbcf02cSchristos 2578dbcf02cSchristos hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms); 2588dbcf02cSchristos os_free(params.bridge); 2598dbcf02cSchristos if (hapd->drv_priv == NULL) { 2608dbcf02cSchristos wpa_printf(MSG_ERROR, "%s driver initialization failed.", 2618dbcf02cSchristos hapd->driver->name); 2628dbcf02cSchristos hapd->driver = NULL; 2638dbcf02cSchristos return -1; 2648dbcf02cSchristos } 2658dbcf02cSchristos 266*45d3cc13Schristos #ifdef CONFIG_IEEE80211BE 267*45d3cc13Schristos /* 268*45d3cc13Schristos * This is the first interface added to the AP MLD, so have the 269*45d3cc13Schristos * interface hardware address be the MLD address, while the link address 270*45d3cc13Schristos * would be derived from the original interface address if BSSID is not 271*45d3cc13Schristos * configured, and otherwise it would be the configured BSSID. 272*45d3cc13Schristos */ 273*45d3cc13Schristos if (hapd->conf->mld_ap) { 274*45d3cc13Schristos os_memcpy(hapd->mld->mld_addr, hapd->own_addr, ETH_ALEN); 275*45d3cc13Schristos 276*45d3cc13Schristos if (!b) 277*45d3cc13Schristos random_mac_addr_keep_oui(hapd->own_addr); 278*45d3cc13Schristos else 279*45d3cc13Schristos os_memcpy(hapd->own_addr, b, ETH_ALEN); 280*45d3cc13Schristos 281*45d3cc13Schristos hostapd_mld_add_link(hapd); 282*45d3cc13Schristos wpa_printf(MSG_DEBUG, "Setup of first link (%d) BSS of MLD %s", 283*45d3cc13Schristos hapd->mld_link_id, hapd->conf->iface); 284*45d3cc13Schristos } 285*45d3cc13Schristos 286*45d3cc13Schristos setup_mld: 287*45d3cc13Schristos #endif /* CONFIG_IEEE80211BE */ 288*45d3cc13Schristos 289111b9fd8Schristos if (hapd->driver->get_capa && 290e604d861Schristos hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { 291bb610346Schristos struct wowlan_triggers *triggs; 292bb610346Schristos 293111b9fd8Schristos iface->drv_flags = capa.flags; 294*45d3cc13Schristos iface->drv_flags2 = capa.flags2; 295*45d3cc13Schristos iface->drv_rrm_flags = capa.rrm_flags; 296e604d861Schristos iface->probe_resp_offloads = capa.probe_resp_offloads; 297ecc36642Schristos /* 298ecc36642Schristos * Use default extended capa values from per-radio information 299ecc36642Schristos */ 3003c260e60Schristos iface->extended_capa = capa.extended_capa; 3013c260e60Schristos iface->extended_capa_mask = capa.extended_capa_mask; 3023c260e60Schristos iface->extended_capa_len = capa.extended_capa_len; 3033c260e60Schristos iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; 304bb610346Schristos 305ecc36642Schristos /* 306ecc36642Schristos * Override extended capa with per-interface type (AP), if 307ecc36642Schristos * available from the driver. 308ecc36642Schristos */ 309ecc36642Schristos hostapd_get_ext_capa(iface); 310ecc36642Schristos 311*45d3cc13Schristos hostapd_get_mld_capa(iface); 312*45d3cc13Schristos 313bb610346Schristos triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); 314bb610346Schristos if (triggs && hapd->driver->set_wowlan) { 315bb610346Schristos if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) 316bb610346Schristos wpa_printf(MSG_ERROR, "set_wowlan failed"); 317bb610346Schristos } 318bb610346Schristos os_free(triggs); 319*45d3cc13Schristos 320*45d3cc13Schristos iface->mbssid_max_interfaces = capa.mbssid_max_interfaces; 321*45d3cc13Schristos iface->ema_max_periodicity = capa.ema_max_periodicity; 3228dbcf02cSchristos } 3238dbcf02cSchristos 324*45d3cc13Schristos #ifdef CONFIG_IEEE80211BE 325*45d3cc13Schristos if (hapd->conf->mld_ap) { 326*45d3cc13Schristos if (!(iface->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) { 327*45d3cc13Schristos wpa_printf(MSG_INFO, 328*45d3cc13Schristos "MLD: Not supported by the driver"); 329*45d3cc13Schristos return -1; 330*45d3cc13Schristos } 331*45d3cc13Schristos 332*45d3cc13Schristos /* Initialize the BSS parameter change to 1 */ 333*45d3cc13Schristos hapd->eht_mld_bss_param_change = 1; 334*45d3cc13Schristos 335*45d3cc13Schristos wpa_printf(MSG_DEBUG, 336*45d3cc13Schristos "MLD: Set link_id=%u, mld_addr=" MACSTR 337*45d3cc13Schristos ", own_addr=" MACSTR, 338*45d3cc13Schristos hapd->mld_link_id, MAC2STR(hapd->mld->mld_addr), 339*45d3cc13Schristos MAC2STR(hapd->own_addr)); 340*45d3cc13Schristos 341*45d3cc13Schristos hostapd_drv_link_add(hapd, hapd->mld_link_id, 342*45d3cc13Schristos hapd->own_addr); 343*45d3cc13Schristos } 344*45d3cc13Schristos #endif /* CONFIG_IEEE80211BE */ 345*45d3cc13Schristos 346e604d861Schristos return 0; 3478dbcf02cSchristos } 3488dbcf02cSchristos 3498dbcf02cSchristos 3503c260e60Schristos /** 3513c260e60Schristos * hostapd_interface_init - Read configuration file and init BSS data 3523c260e60Schristos * 3533c260e60Schristos * This function is used to parse configuration file for a full interface (one 3543c260e60Schristos * or more BSSes sharing the same radio) and allocate memory for the BSS 355be6b3c4dSchristos * interfaces. No actual driver operations are started. 3563c260e60Schristos */ 3578dbcf02cSchristos static struct hostapd_iface * 358ecc36642Schristos hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name, 3598dbcf02cSchristos const char *config_fname, int debug) 3608dbcf02cSchristos { 3618dbcf02cSchristos struct hostapd_iface *iface; 3628dbcf02cSchristos int k; 3638dbcf02cSchristos 364*45d3cc13Schristos wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname); 3653c260e60Schristos iface = hostapd_init(interfaces, config_fname); 3668dbcf02cSchristos if (!iface) 3678dbcf02cSchristos return NULL; 368ecc36642Schristos 369ecc36642Schristos if (if_name) { 370ecc36642Schristos os_strlcpy(iface->conf->bss[0]->iface, if_name, 371ecc36642Schristos sizeof(iface->conf->bss[0]->iface)); 372ecc36642Schristos } 373ecc36642Schristos 3748dbcf02cSchristos iface->interfaces = interfaces; 3758dbcf02cSchristos 3768dbcf02cSchristos for (k = 0; k < debug; k++) { 3778dbcf02cSchristos if (iface->bss[0]->conf->logger_stdout_level > 0) 3788dbcf02cSchristos iface->bss[0]->conf->logger_stdout_level--; 3798dbcf02cSchristos } 3808dbcf02cSchristos 3813c260e60Schristos if (iface->conf->bss[0]->iface[0] == '\0' && 3823c260e60Schristos !hostapd_drv_none(iface->bss[0])) { 383ecc36642Schristos wpa_printf(MSG_ERROR, 384ecc36642Schristos "Interface name not specified in %s, nor by '-i' parameter", 3853c260e60Schristos config_fname); 3868dbcf02cSchristos hostapd_interface_deinit_free(iface); 3878dbcf02cSchristos return NULL; 3888dbcf02cSchristos } 3898dbcf02cSchristos 3908dbcf02cSchristos return iface; 3918dbcf02cSchristos } 3928dbcf02cSchristos 3938dbcf02cSchristos 3948dbcf02cSchristos /** 3958dbcf02cSchristos * handle_term - SIGINT and SIGTERM handler to terminate hostapd process 3968dbcf02cSchristos */ 3978dbcf02cSchristos static void handle_term(int sig, void *signal_ctx) 3988dbcf02cSchristos { 3998dbcf02cSchristos wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig); 4008dbcf02cSchristos eloop_terminate(); 4018dbcf02cSchristos } 4028dbcf02cSchristos 4038dbcf02cSchristos 4048dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 4058dbcf02cSchristos 4068dbcf02cSchristos static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) 4078dbcf02cSchristos { 4088dbcf02cSchristos if (hostapd_reload_config(iface) < 0) { 4098dbcf02cSchristos wpa_printf(MSG_WARNING, "Failed to read new configuration " 4108dbcf02cSchristos "file - continuing with old."); 4118dbcf02cSchristos } 4128dbcf02cSchristos return 0; 4138dbcf02cSchristos } 4148dbcf02cSchristos 4158dbcf02cSchristos 4168dbcf02cSchristos /** 4178dbcf02cSchristos * handle_reload - SIGHUP handler to reload configuration 4188dbcf02cSchristos */ 4198dbcf02cSchristos static void handle_reload(int sig, void *signal_ctx) 4208dbcf02cSchristos { 4218dbcf02cSchristos struct hapd_interfaces *interfaces = signal_ctx; 4228dbcf02cSchristos wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", 4238dbcf02cSchristos sig); 4248dbcf02cSchristos hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); 4258dbcf02cSchristos } 4268dbcf02cSchristos 4278dbcf02cSchristos 4288dbcf02cSchristos static void handle_dump_state(int sig, void *signal_ctx) 4298dbcf02cSchristos { 4303c260e60Schristos /* Not used anymore - ignore signal */ 4318dbcf02cSchristos } 4328dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 4338dbcf02cSchristos 4348dbcf02cSchristos 435111b9fd8Schristos static int hostapd_global_init(struct hapd_interfaces *interfaces, 436111b9fd8Schristos const char *entropy_file) 4378dbcf02cSchristos { 438111b9fd8Schristos int i; 439111b9fd8Schristos 440111b9fd8Schristos os_memset(&global, 0, sizeof(global)); 441111b9fd8Schristos 4428dbcf02cSchristos hostapd_logger_register_cb(hostapd_logger_cb); 4438dbcf02cSchristos 4448dbcf02cSchristos if (eap_server_register_methods()) { 4458dbcf02cSchristos wpa_printf(MSG_ERROR, "Failed to register EAP methods"); 4468dbcf02cSchristos return -1; 4478dbcf02cSchristos } 4488dbcf02cSchristos 4498dbcf02cSchristos if (eloop_init()) { 4508dbcf02cSchristos wpa_printf(MSG_ERROR, "Failed to initialize event loop"); 4518dbcf02cSchristos return -1; 4528dbcf02cSchristos } 453ecc36642Schristos interfaces->eloop_initialized = 1; 4548dbcf02cSchristos 455111b9fd8Schristos random_init(entropy_file); 456111b9fd8Schristos 4578dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 4588dbcf02cSchristos eloop_register_signal(SIGHUP, handle_reload, interfaces); 4598dbcf02cSchristos eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); 4608dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 4618dbcf02cSchristos eloop_register_signal_terminate(handle_term, interfaces); 4628dbcf02cSchristos 4638dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 4648dbcf02cSchristos openlog("hostapd", 0, LOG_DAEMON); 4658dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 4668dbcf02cSchristos 467111b9fd8Schristos for (i = 0; wpa_drivers[i]; i++) 468111b9fd8Schristos global.drv_count++; 469111b9fd8Schristos if (global.drv_count == 0) { 470111b9fd8Schristos wpa_printf(MSG_ERROR, "No drivers enabled"); 471111b9fd8Schristos return -1; 472111b9fd8Schristos } 473e604d861Schristos global.drv_priv = os_calloc(global.drv_count, sizeof(void *)); 474111b9fd8Schristos if (global.drv_priv == NULL) 475111b9fd8Schristos return -1; 476111b9fd8Schristos 4778dbcf02cSchristos return 0; 4788dbcf02cSchristos } 4798dbcf02cSchristos 4808dbcf02cSchristos 481ecc36642Schristos static void hostapd_global_deinit(const char *pid_file, int eloop_initialized) 4828dbcf02cSchristos { 483111b9fd8Schristos int i; 484111b9fd8Schristos 485111b9fd8Schristos for (i = 0; wpa_drivers[i] && global.drv_priv; i++) { 486111b9fd8Schristos if (!global.drv_priv[i]) 487111b9fd8Schristos continue; 488111b9fd8Schristos wpa_drivers[i]->global_deinit(global.drv_priv[i]); 489111b9fd8Schristos } 490111b9fd8Schristos os_free(global.drv_priv); 491111b9fd8Schristos global.drv_priv = NULL; 492111b9fd8Schristos 4938dbcf02cSchristos #ifdef EAP_SERVER_TNC 4948dbcf02cSchristos tncs_global_deinit(); 4958dbcf02cSchristos #endif /* EAP_SERVER_TNC */ 4968dbcf02cSchristos 497111b9fd8Schristos random_deinit(); 498111b9fd8Schristos 499ecc36642Schristos if (eloop_initialized) 5008dbcf02cSchristos eloop_destroy(); 5018dbcf02cSchristos 5028dbcf02cSchristos #ifndef CONFIG_NATIVE_WINDOWS 5038dbcf02cSchristos closelog(); 5048dbcf02cSchristos #endif /* CONFIG_NATIVE_WINDOWS */ 5058dbcf02cSchristos 5068dbcf02cSchristos eap_server_unregister_methods(); 5078dbcf02cSchristos 5088dbcf02cSchristos os_daemonize_terminate(pid_file); 5098dbcf02cSchristos } 5108dbcf02cSchristos 5118dbcf02cSchristos 5128dbcf02cSchristos static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, 5138dbcf02cSchristos const char *pid_file) 5148dbcf02cSchristos { 5158dbcf02cSchristos #ifdef EAP_SERVER_TNC 5168dbcf02cSchristos int tnc = 0; 5178dbcf02cSchristos size_t i, k; 5188dbcf02cSchristos 5198dbcf02cSchristos for (i = 0; !tnc && i < ifaces->count; i++) { 5208dbcf02cSchristos for (k = 0; k < ifaces->iface[i]->num_bss; k++) { 5218dbcf02cSchristos if (ifaces->iface[i]->bss[0]->conf->tnc) { 5228dbcf02cSchristos tnc++; 5238dbcf02cSchristos break; 5248dbcf02cSchristos } 5258dbcf02cSchristos } 5268dbcf02cSchristos } 5278dbcf02cSchristos 5288dbcf02cSchristos if (tnc && tncs_global_init() < 0) { 5298dbcf02cSchristos wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); 5308dbcf02cSchristos return -1; 5318dbcf02cSchristos } 5328dbcf02cSchristos #endif /* EAP_SERVER_TNC */ 5338dbcf02cSchristos 534d2b81c07Sroy if (daemonize) { 535d2b81c07Sroy if (os_daemonize(pid_file)) { 536bb610346Schristos wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); 5378dbcf02cSchristos return -1; 5388dbcf02cSchristos } 539d2b81c07Sroy if (eloop_sock_requeue()) { 540d2b81c07Sroy wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s", 541d2b81c07Sroy strerror(errno)); 542d2b81c07Sroy return -1; 543d2b81c07Sroy } 544d2b81c07Sroy } 5458dbcf02cSchristos 5468dbcf02cSchristos eloop_run(); 5478dbcf02cSchristos 5488dbcf02cSchristos return 0; 5498dbcf02cSchristos } 5508dbcf02cSchristos 5518dbcf02cSchristos 5528dbcf02cSchristos static void show_version(void) 5538dbcf02cSchristos { 5548dbcf02cSchristos fprintf(stderr, 555*45d3cc13Schristos "hostapd v%s\n" 5568dbcf02cSchristos "User space daemon for IEEE 802.11 AP management,\n" 5578dbcf02cSchristos "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" 558*45d3cc13Schristos "Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi> " 559*45d3cc13Schristos "and contributors\n", 560*45d3cc13Schristos VERSION_STR); 5618dbcf02cSchristos } 5628dbcf02cSchristos 5638dbcf02cSchristos 5648dbcf02cSchristos static void usage(void) 5658dbcf02cSchristos { 5668dbcf02cSchristos show_version(); 5678dbcf02cSchristos fprintf(stderr, 5688dbcf02cSchristos "\n" 569*45d3cc13Schristos "usage: hostapd [-hdBKtvq] [-P <PID file>] [-e <entropy file>] " 570e604d861Schristos "\\\n" 5713c260e60Schristos " [-g <global ctrl_iface>] [-G <group>]\\\n" 572ecc36642Schristos " [-i <comma-separated list of interface names>]\\\n" 5733c260e60Schristos " <configuration file(s)>\n" 5748dbcf02cSchristos "\n" 5758dbcf02cSchristos "options:\n" 5768dbcf02cSchristos " -h show this usage\n" 5778dbcf02cSchristos " -d show more debug messages (-dd for even more)\n" 5788dbcf02cSchristos " -B run daemon in the background\n" 579111b9fd8Schristos " -e entropy file\n" 580e604d861Schristos " -g global control interface path\n" 5813c260e60Schristos " -G group for control interfaces\n" 5828dbcf02cSchristos " -P PID file\n" 5838dbcf02cSchristos " -K include key data in debug messages\n" 584111b9fd8Schristos #ifdef CONFIG_DEBUG_FILE 585111b9fd8Schristos " -f log output to debug file instead of stdout\n" 586111b9fd8Schristos #endif /* CONFIG_DEBUG_FILE */ 5873c260e60Schristos #ifdef CONFIG_DEBUG_LINUX_TRACING 588be6b3c4dSchristos " -T record to Linux tracing in addition to logging\n" 5893c260e60Schristos " (records all messages regardless of debug verbosity)\n" 5903c260e60Schristos #endif /* CONFIG_DEBUG_LINUX_TRACING */ 591ecc36642Schristos " -i list of interface names to use\n" 592be6b3c4dSchristos #ifdef CONFIG_DEBUG_SYSLOG 593be6b3c4dSchristos " -s log output to syslog instead of stdout\n" 594be6b3c4dSchristos #endif /* CONFIG_DEBUG_SYSLOG */ 595ecc36642Schristos " -S start all the interfaces synchronously\n" 5968dbcf02cSchristos " -t include timestamps in some debug messages\n" 597*45d3cc13Schristos " -v show hostapd version\n" 598*45d3cc13Schristos " -q show less debug messages (-qq for even less)\n"); 5998dbcf02cSchristos 6008dbcf02cSchristos exit(1); 6018dbcf02cSchristos } 6028dbcf02cSchristos 6038dbcf02cSchristos 604111b9fd8Schristos static const char * hostapd_msg_ifname_cb(void *ctx) 605111b9fd8Schristos { 606111b9fd8Schristos struct hostapd_data *hapd = ctx; 607ecc36642Schristos if (hapd && hapd->conf) 608ecc36642Schristos return hapd->conf->iface; 609111b9fd8Schristos return NULL; 610111b9fd8Schristos } 611111b9fd8Schristos 612111b9fd8Schristos 613e604d861Schristos static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces, 614e604d861Schristos const char *path) 615e604d861Schristos { 616ecc36642Schristos #ifndef CONFIG_CTRL_IFACE_UDP 617e604d861Schristos char *pos; 618ecc36642Schristos #endif /* !CONFIG_CTRL_IFACE_UDP */ 619ecc36642Schristos 620e604d861Schristos os_free(interfaces->global_iface_path); 621e604d861Schristos interfaces->global_iface_path = os_strdup(path); 622e604d861Schristos if (interfaces->global_iface_path == NULL) 623e604d861Schristos return -1; 624ecc36642Schristos 625ecc36642Schristos #ifndef CONFIG_CTRL_IFACE_UDP 626e604d861Schristos pos = os_strrchr(interfaces->global_iface_path, '/'); 627e604d861Schristos if (pos == NULL) { 6283c260e60Schristos wpa_printf(MSG_ERROR, "No '/' in the global control interface " 6293c260e60Schristos "file"); 630e604d861Schristos os_free(interfaces->global_iface_path); 631e604d861Schristos interfaces->global_iface_path = NULL; 632e604d861Schristos return -1; 633e604d861Schristos } 634e604d861Schristos 635e604d861Schristos *pos = '\0'; 636e604d861Schristos interfaces->global_iface_name = pos + 1; 637ecc36642Schristos #endif /* !CONFIG_CTRL_IFACE_UDP */ 638e604d861Schristos 639e604d861Schristos return 0; 640e604d861Schristos } 641e604d861Schristos 642e604d861Schristos 6433c260e60Schristos static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces, 6443c260e60Schristos const char *group) 6453c260e60Schristos { 6463c260e60Schristos #ifndef CONFIG_NATIVE_WINDOWS 6473c260e60Schristos struct group *grp; 6483c260e60Schristos grp = getgrnam(group); 6493c260e60Schristos if (grp == NULL) { 6503c260e60Schristos wpa_printf(MSG_ERROR, "Unknown group '%s'", group); 6513c260e60Schristos return -1; 6523c260e60Schristos } 6533c260e60Schristos interfaces->ctrl_iface_group = grp->gr_gid; 6543c260e60Schristos #endif /* CONFIG_NATIVE_WINDOWS */ 6553c260e60Schristos return 0; 6563c260e60Schristos } 6573c260e60Schristos 6583c260e60Schristos 659ecc36642Schristos static int hostapd_get_interface_names(char ***if_names, 660ecc36642Schristos size_t *if_names_size, 661be6b3c4dSchristos char *arg) 662ecc36642Schristos { 663ecc36642Schristos char *if_name, *tmp, **nnames; 664ecc36642Schristos size_t i; 665ecc36642Schristos 666be6b3c4dSchristos if (!arg) 667ecc36642Schristos return -1; 668be6b3c4dSchristos if_name = strtok_r(arg, ",", &tmp); 669ecc36642Schristos 670ecc36642Schristos while (if_name) { 671ecc36642Schristos nnames = os_realloc_array(*if_names, 1 + *if_names_size, 672ecc36642Schristos sizeof(char *)); 673ecc36642Schristos if (!nnames) 674ecc36642Schristos goto fail; 675ecc36642Schristos *if_names = nnames; 676ecc36642Schristos 677ecc36642Schristos (*if_names)[*if_names_size] = os_strdup(if_name); 678ecc36642Schristos if (!(*if_names)[*if_names_size]) 679ecc36642Schristos goto fail; 680ecc36642Schristos (*if_names_size)++; 681ecc36642Schristos if_name = strtok_r(NULL, ",", &tmp); 682ecc36642Schristos } 683ecc36642Schristos 684ecc36642Schristos return 0; 685ecc36642Schristos 686ecc36642Schristos fail: 687ecc36642Schristos for (i = 0; i < *if_names_size; i++) 688ecc36642Schristos os_free((*if_names)[i]); 689ecc36642Schristos os_free(*if_names); 690ecc36642Schristos *if_names = NULL; 691ecc36642Schristos *if_names_size = 0; 692ecc36642Schristos return -1; 693ecc36642Schristos } 694ecc36642Schristos 695ecc36642Schristos 6963c260e60Schristos #ifdef CONFIG_WPS 6973c260e60Schristos static int gen_uuid(const char *txt_addr) 6983c260e60Schristos { 6993c260e60Schristos u8 addr[ETH_ALEN]; 7003c260e60Schristos u8 uuid[UUID_LEN]; 7013c260e60Schristos char buf[100]; 7023c260e60Schristos 7033c260e60Schristos if (hwaddr_aton(txt_addr, addr) < 0) 7043c260e60Schristos return -1; 7053c260e60Schristos 7063c260e60Schristos uuid_gen_mac_addr(addr, uuid); 7073c260e60Schristos if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0) 7083c260e60Schristos return -1; 7093c260e60Schristos 7103c260e60Schristos printf("%s\n", buf); 7113c260e60Schristos 7123c260e60Schristos return 0; 7133c260e60Schristos } 7143c260e60Schristos #endif /* CONFIG_WPS */ 7153c260e60Schristos 7163c260e60Schristos 717ecc36642Schristos #ifndef HOSTAPD_CLEANUP_INTERVAL 718ecc36642Schristos #define HOSTAPD_CLEANUP_INTERVAL 10 719ecc36642Schristos #endif /* HOSTAPD_CLEANUP_INTERVAL */ 720ecc36642Schristos 721ecc36642Schristos static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx) 722ecc36642Schristos { 723ecc36642Schristos hostapd_periodic_iface(iface); 724ecc36642Schristos return 0; 725ecc36642Schristos } 726ecc36642Schristos 727ecc36642Schristos 728ecc36642Schristos /* Periodic cleanup tasks */ 729ecc36642Schristos static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx) 730ecc36642Schristos { 731ecc36642Schristos struct hapd_interfaces *interfaces = eloop_ctx; 732ecc36642Schristos 733ecc36642Schristos eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0, 734ecc36642Schristos hostapd_periodic, interfaces, NULL); 735ecc36642Schristos hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL); 736ecc36642Schristos } 737ecc36642Schristos 738ecc36642Schristos 739*45d3cc13Schristos static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) 740*45d3cc13Schristos { 741*45d3cc13Schristos #ifdef CONFIG_IEEE80211BE 742*45d3cc13Schristos size_t i; 743*45d3cc13Schristos 744*45d3cc13Schristos if (!interfaces || !interfaces->mld) 745*45d3cc13Schristos return; 746*45d3cc13Schristos 747*45d3cc13Schristos for (i = 0; i < interfaces->mld_count; i++) { 748*45d3cc13Schristos if (!interfaces->mld[i]) 749*45d3cc13Schristos continue; 750*45d3cc13Schristos 751*45d3cc13Schristos os_free(interfaces->mld[i]); 752*45d3cc13Schristos interfaces->mld[i] = NULL; 753*45d3cc13Schristos } 754*45d3cc13Schristos 755*45d3cc13Schristos os_free(interfaces->mld); 756*45d3cc13Schristos interfaces->mld = NULL; 757*45d3cc13Schristos interfaces->mld_count = 0; 758*45d3cc13Schristos #endif /* CONFIG_IEEE80211BE */ 759*45d3cc13Schristos } 760*45d3cc13Schristos 761*45d3cc13Schristos 7628dbcf02cSchristos int main(int argc, char *argv[]) 7638dbcf02cSchristos { 7648dbcf02cSchristos struct hapd_interfaces interfaces; 7658dbcf02cSchristos int ret = 1; 7663c260e60Schristos size_t i, j; 7678dbcf02cSchristos int c, debug = 0, daemonize = 0; 7688dbcf02cSchristos char *pid_file = NULL; 769111b9fd8Schristos const char *log_file = NULL; 770111b9fd8Schristos const char *entropy_file = NULL; 7713c260e60Schristos char **bss_config = NULL, **tmp_bss; 7723c260e60Schristos size_t num_bss_configs = 0; 7733c260e60Schristos #ifdef CONFIG_DEBUG_LINUX_TRACING 7743c260e60Schristos int enable_trace_dbg = 0; 7753c260e60Schristos #endif /* CONFIG_DEBUG_LINUX_TRACING */ 776ecc36642Schristos int start_ifaces_in_sync = 0; 777ecc36642Schristos char **if_names = NULL; 778ecc36642Schristos size_t if_names_size = 0; 779460bb4fcSchristos #ifdef CONFIG_DPP 780460bb4fcSchristos struct dpp_global_config dpp_conf; 781460bb4fcSchristos #endif /* CONFIG_DPP */ 7828dbcf02cSchristos 7838dbcf02cSchristos if (os_program_init()) 7848dbcf02cSchristos return -1; 7858dbcf02cSchristos 786e604d861Schristos os_memset(&interfaces, 0, sizeof(interfaces)); 787e604d861Schristos interfaces.reload_config = hostapd_reload_config; 788e604d861Schristos interfaces.config_read_cb = hostapd_config_read; 789e604d861Schristos interfaces.for_each_interface = hostapd_for_each_interface; 790e604d861Schristos interfaces.ctrl_iface_init = hostapd_ctrl_iface_init; 791e604d861Schristos interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit; 792e604d861Schristos interfaces.driver_init = hostapd_driver_init; 793e604d861Schristos interfaces.global_iface_path = NULL; 794e604d861Schristos interfaces.global_iface_name = NULL; 795e604d861Schristos interfaces.global_ctrl_sock = -1; 796ecc36642Schristos dl_list_init(&interfaces.global_ctrl_dst); 797be6b3c4dSchristos #ifdef CONFIG_ETH_P_OUI 798be6b3c4dSchristos dl_list_init(&interfaces.eth_p_oui); 799be6b3c4dSchristos #endif /* CONFIG_ETH_P_OUI */ 800be6b3c4dSchristos #ifdef CONFIG_DPP 801460bb4fcSchristos os_memset(&dpp_conf, 0, sizeof(dpp_conf)); 802*45d3cc13Schristos dpp_conf.cb_ctx = &interfaces; 803*45d3cc13Schristos #ifdef CONFIG_DPP2 804*45d3cc13Schristos dpp_conf.remove_bi = hostapd_dpp_remove_bi; 805*45d3cc13Schristos #endif /* CONFIG_DPP2 */ 806460bb4fcSchristos interfaces.dpp = dpp_global_init(&dpp_conf); 807460bb4fcSchristos if (!interfaces.dpp) 808460bb4fcSchristos return -1; 809be6b3c4dSchristos #endif /* CONFIG_DPP */ 810e604d861Schristos 8118dbcf02cSchristos for (;;) { 812*45d3cc13Schristos c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q"); 8138dbcf02cSchristos if (c < 0) 8148dbcf02cSchristos break; 8158dbcf02cSchristos switch (c) { 8168dbcf02cSchristos case 'h': 8178dbcf02cSchristos usage(); 8188dbcf02cSchristos break; 8198dbcf02cSchristos case 'd': 8208dbcf02cSchristos debug++; 8218dbcf02cSchristos if (wpa_debug_level > 0) 8228dbcf02cSchristos wpa_debug_level--; 8238dbcf02cSchristos break; 8248dbcf02cSchristos case 'B': 8258dbcf02cSchristos daemonize++; 8268dbcf02cSchristos break; 827111b9fd8Schristos case 'e': 828111b9fd8Schristos entropy_file = optarg; 829111b9fd8Schristos break; 830111b9fd8Schristos case 'f': 831111b9fd8Schristos log_file = optarg; 832111b9fd8Schristos break; 8338dbcf02cSchristos case 'K': 8348dbcf02cSchristos wpa_debug_show_keys++; 8358dbcf02cSchristos break; 8368dbcf02cSchristos case 'P': 8378dbcf02cSchristos os_free(pid_file); 8388dbcf02cSchristos pid_file = os_rel2abs_path(optarg); 8398dbcf02cSchristos break; 8408dbcf02cSchristos case 't': 8418dbcf02cSchristos wpa_debug_timestamp++; 8428dbcf02cSchristos break; 8433c260e60Schristos #ifdef CONFIG_DEBUG_LINUX_TRACING 8443c260e60Schristos case 'T': 8453c260e60Schristos enable_trace_dbg = 1; 8463c260e60Schristos break; 8473c260e60Schristos #endif /* CONFIG_DEBUG_LINUX_TRACING */ 8488dbcf02cSchristos case 'v': 8498dbcf02cSchristos show_version(); 8508dbcf02cSchristos exit(1); 851e604d861Schristos case 'g': 8523c260e60Schristos if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) 8533c260e60Schristos return -1; 854e604d861Schristos break; 8553c260e60Schristos case 'G': 8563c260e60Schristos if (hostapd_get_ctrl_iface_group(&interfaces, optarg)) 8573c260e60Schristos return -1; 8583c260e60Schristos break; 8593c260e60Schristos case 'b': 8603c260e60Schristos tmp_bss = os_realloc_array(bss_config, 8613c260e60Schristos num_bss_configs + 1, 8623c260e60Schristos sizeof(char *)); 8633c260e60Schristos if (tmp_bss == NULL) 8643c260e60Schristos goto out; 8653c260e60Schristos bss_config = tmp_bss; 8663c260e60Schristos bss_config[num_bss_configs++] = optarg; 8673c260e60Schristos break; 868be6b3c4dSchristos #ifdef CONFIG_DEBUG_SYSLOG 869be6b3c4dSchristos case 's': 870be6b3c4dSchristos wpa_debug_syslog = 1; 871be6b3c4dSchristos break; 872be6b3c4dSchristos #endif /* CONFIG_DEBUG_SYSLOG */ 873ecc36642Schristos case 'S': 874ecc36642Schristos start_ifaces_in_sync = 1; 875ecc36642Schristos break; 8763c260e60Schristos #ifdef CONFIG_WPS 8773c260e60Schristos case 'u': 8783c260e60Schristos return gen_uuid(optarg); 8793c260e60Schristos #endif /* CONFIG_WPS */ 880ecc36642Schristos case 'i': 881ecc36642Schristos if (hostapd_get_interface_names(&if_names, 882ecc36642Schristos &if_names_size, optarg)) 883ecc36642Schristos goto out; 884ecc36642Schristos break; 885*45d3cc13Schristos case 'q': 886*45d3cc13Schristos wpa_debug_level++; 887*45d3cc13Schristos break; 8888dbcf02cSchristos default: 8898dbcf02cSchristos usage(); 8908dbcf02cSchristos break; 8918dbcf02cSchristos } 8928dbcf02cSchristos } 8938dbcf02cSchristos 8943c260e60Schristos if (optind == argc && interfaces.global_iface_path == NULL && 8953c260e60Schristos num_bss_configs == 0) 8968dbcf02cSchristos usage(); 8978dbcf02cSchristos 898111b9fd8Schristos wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb); 899111b9fd8Schristos 900111b9fd8Schristos if (log_file) 901111b9fd8Schristos wpa_debug_open_file(log_file); 902*45d3cc13Schristos if (!log_file && !wpa_debug_syslog) 903bb610346Schristos wpa_debug_setup_stdout(); 904be6b3c4dSchristos #ifdef CONFIG_DEBUG_SYSLOG 905be6b3c4dSchristos if (wpa_debug_syslog) 906be6b3c4dSchristos wpa_debug_open_syslog(); 907be6b3c4dSchristos #endif /* CONFIG_DEBUG_SYSLOG */ 9083c260e60Schristos #ifdef CONFIG_DEBUG_LINUX_TRACING 9093c260e60Schristos if (enable_trace_dbg) { 9103c260e60Schristos int tret = wpa_debug_open_linux_tracing(); 9113c260e60Schristos if (tret) { 9123c260e60Schristos wpa_printf(MSG_ERROR, "Failed to enable trace logging"); 9133c260e60Schristos return -1; 9143c260e60Schristos } 9153c260e60Schristos } 9163c260e60Schristos #endif /* CONFIG_DEBUG_LINUX_TRACING */ 917111b9fd8Schristos 9188dbcf02cSchristos interfaces.count = argc - optind; 9193c260e60Schristos if (interfaces.count || num_bss_configs) { 9203c260e60Schristos interfaces.iface = os_calloc(interfaces.count + num_bss_configs, 9218dbcf02cSchristos sizeof(struct hostapd_iface *)); 9228dbcf02cSchristos if (interfaces.iface == NULL) { 923111b9fd8Schristos wpa_printf(MSG_ERROR, "malloc failed"); 9248dbcf02cSchristos return -1; 9258dbcf02cSchristos } 926e604d861Schristos } 9278dbcf02cSchristos 9283c260e60Schristos if (hostapd_global_init(&interfaces, entropy_file)) { 929ecc36642Schristos wpa_printf(MSG_ERROR, "Failed to initialize global context"); 9308dbcf02cSchristos return -1; 9313c260e60Schristos } 9328dbcf02cSchristos 933ecc36642Schristos eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0, 934ecc36642Schristos hostapd_periodic, &interfaces, NULL); 935ecc36642Schristos 936ecc36642Schristos if (fst_global_init()) { 937ecc36642Schristos wpa_printf(MSG_ERROR, 938ecc36642Schristos "Failed to initialize global FST context"); 939ecc36642Schristos goto out; 940ecc36642Schristos } 941ecc36642Schristos 942ecc36642Schristos #if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE) 943ecc36642Schristos if (!fst_global_add_ctrl(fst_ctrl_cli)) 944ecc36642Schristos wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl"); 945ecc36642Schristos #endif /* CONFIG_FST && CONFIG_CTRL_IFACE */ 946ecc36642Schristos 9473c260e60Schristos /* Allocate and parse configuration for full interface files */ 9488dbcf02cSchristos for (i = 0; i < interfaces.count; i++) { 949ecc36642Schristos char *if_name = NULL; 950ecc36642Schristos 951ecc36642Schristos if (i < if_names_size) 952ecc36642Schristos if_name = if_names[i]; 953ecc36642Schristos 9548dbcf02cSchristos interfaces.iface[i] = hostapd_interface_init(&interfaces, 955ecc36642Schristos if_name, 9568dbcf02cSchristos argv[optind + i], 9578dbcf02cSchristos debug); 9583c260e60Schristos if (!interfaces.iface[i]) { 9593c260e60Schristos wpa_printf(MSG_ERROR, "Failed to initialize interface"); 9603c260e60Schristos goto out; 9613c260e60Schristos } 962ecc36642Schristos if (start_ifaces_in_sync) 963ecc36642Schristos interfaces.iface[i]->need_to_start_in_sync = 1; 9643c260e60Schristos } 9653c260e60Schristos 9663c260e60Schristos /* Allocate and parse configuration for per-BSS files */ 9673c260e60Schristos for (i = 0; i < num_bss_configs; i++) { 9683c260e60Schristos struct hostapd_iface *iface; 9693c260e60Schristos char *fname; 9703c260e60Schristos 9713c260e60Schristos wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]); 9723c260e60Schristos fname = os_strchr(bss_config[i], ':'); 9733c260e60Schristos if (fname == NULL) { 9743c260e60Schristos wpa_printf(MSG_ERROR, 9753c260e60Schristos "Invalid BSS config identifier '%s'", 9763c260e60Schristos bss_config[i]); 9773c260e60Schristos goto out; 9783c260e60Schristos } 9793c260e60Schristos *fname++ = '\0'; 9803c260e60Schristos iface = hostapd_interface_init_bss(&interfaces, bss_config[i], 9813c260e60Schristos fname, debug); 9823c260e60Schristos if (iface == NULL) 9833c260e60Schristos goto out; 9843c260e60Schristos for (j = 0; j < interfaces.count; j++) { 9853c260e60Schristos if (interfaces.iface[j] == iface) 9863c260e60Schristos break; 9873c260e60Schristos } 9883c260e60Schristos if (j == interfaces.count) { 9893c260e60Schristos struct hostapd_iface **tmp; 9903c260e60Schristos tmp = os_realloc_array(interfaces.iface, 9913c260e60Schristos interfaces.count + 1, 9923c260e60Schristos sizeof(struct hostapd_iface *)); 9933c260e60Schristos if (tmp == NULL) { 9943c260e60Schristos hostapd_interface_deinit_free(iface); 9953c260e60Schristos goto out; 9963c260e60Schristos } 9973c260e60Schristos interfaces.iface = tmp; 9983c260e60Schristos interfaces.iface[interfaces.count++] = iface; 9993c260e60Schristos } 10003c260e60Schristos } 10013c260e60Schristos 10023c260e60Schristos /* 10033c260e60Schristos * Enable configured interfaces. Depending on channel configuration, 10043c260e60Schristos * this may complete full initialization before returning or use a 10053c260e60Schristos * callback mechanism to complete setup in case of operations like HT 10063c260e60Schristos * co-ex scans, ACS, or DFS are needed to determine channel parameters. 10073c260e60Schristos * In such case, the interface will be enabled from eloop context within 10083c260e60Schristos * hostapd_global_run(). 10093c260e60Schristos */ 10103c260e60Schristos interfaces.terminate_on_error = interfaces.count; 10113c260e60Schristos for (i = 0; i < interfaces.count; i++) { 10123c260e60Schristos if (hostapd_driver_init(interfaces.iface[i]) || 10133c260e60Schristos hostapd_setup_interface(interfaces.iface[i])) 10148dbcf02cSchristos goto out; 10158dbcf02cSchristos } 10168dbcf02cSchristos 1017e604d861Schristos hostapd_global_ctrl_iface_init(&interfaces); 1018e604d861Schristos 10193c260e60Schristos if (hostapd_global_run(&interfaces, daemonize, pid_file)) { 10203c260e60Schristos wpa_printf(MSG_ERROR, "Failed to start eloop"); 10218dbcf02cSchristos goto out; 10223c260e60Schristos } 10238dbcf02cSchristos 10248dbcf02cSchristos ret = 0; 10258dbcf02cSchristos 10268dbcf02cSchristos out: 1027e604d861Schristos hostapd_global_ctrl_iface_deinit(&interfaces); 10288dbcf02cSchristos /* Deinitialize all interfaces */ 10293c260e60Schristos for (i = 0; i < interfaces.count; i++) { 10303c260e60Schristos if (!interfaces.iface[i]) 10313c260e60Schristos continue; 10323c260e60Schristos interfaces.iface[i]->driver_ap_teardown = 10333c260e60Schristos !!(interfaces.iface[i]->drv_flags & 10343c260e60Schristos WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); 10358dbcf02cSchristos hostapd_interface_deinit_free(interfaces.iface[i]); 1036*45d3cc13Schristos interfaces.iface[i] = NULL; 10373c260e60Schristos } 10388dbcf02cSchristos os_free(interfaces.iface); 1039*45d3cc13Schristos interfaces.iface = NULL; 1040*45d3cc13Schristos interfaces.count = 0; 1041*45d3cc13Schristos 1042*45d3cc13Schristos hostapd_global_cleanup_mld(&interfaces); 10438dbcf02cSchristos 1044be6b3c4dSchristos #ifdef CONFIG_DPP 1045460bb4fcSchristos dpp_global_deinit(interfaces.dpp); 1046be6b3c4dSchristos #endif /* CONFIG_DPP */ 1047be6b3c4dSchristos 1048ecc36642Schristos if (interfaces.eloop_initialized) 1049ecc36642Schristos eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL); 1050ecc36642Schristos hostapd_global_deinit(pid_file, interfaces.eloop_initialized); 10518dbcf02cSchristos os_free(pid_file); 10528dbcf02cSchristos 1053be6b3c4dSchristos wpa_debug_close_syslog(); 1054111b9fd8Schristos if (log_file) 1055111b9fd8Schristos wpa_debug_close_file(); 10563c260e60Schristos wpa_debug_close_linux_tracing(); 10573c260e60Schristos 10583c260e60Schristos os_free(bss_config); 1059111b9fd8Schristos 1060ecc36642Schristos for (i = 0; i < if_names_size; i++) 1061ecc36642Schristos os_free(if_names[i]); 1062ecc36642Schristos os_free(if_names); 1063ecc36642Schristos 1064ecc36642Schristos fst_global_deinit(); 1065ecc36642Schristos 1066*45d3cc13Schristos crypto_unload(); 10678dbcf02cSchristos os_program_deinit(); 10688dbcf02cSchristos 10698dbcf02cSchristos return ret; 10708dbcf02cSchristos } 1071