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