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