• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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
hostapd_logger_cb(void * ctx,const u8 * addr,unsigned int module,int level,const char * txt,size_t len)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  */
hostapd_driver_init(struct hostapd_iface * iface)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 *
hostapd_interface_init(struct hapd_interfaces * interfaces,const char * if_name,const char * config_fname,int debug)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  */
handle_term(int sig,void * signal_ctx)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 
handle_reload_iface(struct hostapd_iface * iface,void * ctx)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  */
handle_reload(int sig,void * signal_ctx)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 
handle_dump_state(int sig,void * signal_ctx)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 
hostapd_global_init(struct hapd_interfaces * interfaces,const char * entropy_file)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 
hostapd_global_deinit(const char * pid_file,int eloop_initialized)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 
hostapd_global_run(struct hapd_interfaces * ifaces,int daemonize,const char * pid_file)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 
show_version(void)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@w1.fi> "
463 		"and contributors\n");
464 }
465 
466 
usage(void)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 
hostapd_msg_ifname_cb(void * ctx)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 
hostapd_get_global_ctrl_iface(struct hapd_interfaces * interfaces,const char * path)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 
hostapd_get_ctrl_iface_group(struct hapd_interfaces * interfaces,const char * group)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 
hostapd_get_interface_names(char *** if_names,size_t * if_names_size,char * arg)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
gen_uuid(const char * txt_addr)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 
hostapd_periodic_call(struct hostapd_iface * iface,void * ctx)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 */
hostapd_periodic(void * eloop_ctx,void * timeout_ctx)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 
main(int argc,char * argv[])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