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