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