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