xref: /freebsd/contrib/wpa/hostapd/main.c (revision e8e8c939350bdf3c228a411caa9660c607c27a11)
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 && os_daemonize(pid_file)) {
411 		wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
412 		return -1;
413 	}
414 
415 	eloop_run();
416 
417 	return 0;
418 }
419 
420 
421 static void show_version(void)
422 {
423 	fprintf(stderr,
424 		"hostapd v" VERSION_STR "\n"
425 		"User space daemon for IEEE 802.11 AP management,\n"
426 		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
427 		"Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
428 		"and contributors\n");
429 }
430 
431 
432 static void usage(void)
433 {
434 	show_version();
435 	fprintf(stderr,
436 		"\n"
437 		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
438 		"\\\n"
439 		"         [-g <global ctrl_iface>] [-G <group>] \\\n"
440 		"         <configuration file(s)>\n"
441 		"\n"
442 		"options:\n"
443 		"   -h   show this usage\n"
444 		"   -d   show more debug messages (-dd for even more)\n"
445 		"   -B   run daemon in the background\n"
446 		"   -e   entropy file\n"
447 		"   -g   global control interface path\n"
448 		"   -G   group for control interfaces\n"
449 		"   -P   PID file\n"
450 		"   -K   include key data in debug messages\n"
451 #ifdef CONFIG_DEBUG_FILE
452 		"   -f   log output to debug file instead of stdout\n"
453 #endif /* CONFIG_DEBUG_FILE */
454 #ifdef CONFIG_DEBUG_LINUX_TRACING
455 		"   -T = record to Linux tracing in addition to logging\n"
456 		"        (records all messages regardless of debug verbosity)\n"
457 #endif /* CONFIG_DEBUG_LINUX_TRACING */
458 		"   -t   include timestamps in some debug messages\n"
459 		"   -v   show hostapd version\n");
460 
461 	exit(1);
462 }
463 
464 
465 static const char * hostapd_msg_ifname_cb(void *ctx)
466 {
467 	struct hostapd_data *hapd = ctx;
468 	if (hapd && hapd->iconf && hapd->iconf->bss &&
469 	    hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
470 		return hapd->iconf->bss[0]->iface;
471 	return NULL;
472 }
473 
474 
475 static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
476 					 const char *path)
477 {
478 	char *pos;
479 	os_free(interfaces->global_iface_path);
480 	interfaces->global_iface_path = os_strdup(path);
481 	if (interfaces->global_iface_path == NULL)
482 		return -1;
483 	pos = os_strrchr(interfaces->global_iface_path, '/');
484 	if (pos == NULL) {
485 		wpa_printf(MSG_ERROR, "No '/' in the global control interface "
486 			   "file");
487 		os_free(interfaces->global_iface_path);
488 		interfaces->global_iface_path = NULL;
489 		return -1;
490 	}
491 
492 	*pos = '\0';
493 	interfaces->global_iface_name = pos + 1;
494 
495 	return 0;
496 }
497 
498 
499 static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
500 					const char *group)
501 {
502 #ifndef CONFIG_NATIVE_WINDOWS
503 	struct group *grp;
504 	grp = getgrnam(group);
505 	if (grp == NULL) {
506 		wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
507 		return -1;
508 	}
509 	interfaces->ctrl_iface_group = grp->gr_gid;
510 #endif /* CONFIG_NATIVE_WINDOWS */
511 	return 0;
512 }
513 
514 
515 #ifdef CONFIG_WPS
516 static int gen_uuid(const char *txt_addr)
517 {
518 	u8 addr[ETH_ALEN];
519 	u8 uuid[UUID_LEN];
520 	char buf[100];
521 
522 	if (hwaddr_aton(txt_addr, addr) < 0)
523 		return -1;
524 
525 	uuid_gen_mac_addr(addr, uuid);
526 	if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0)
527 		return -1;
528 
529 	printf("%s\n", buf);
530 
531 	return 0;
532 }
533 #endif /* CONFIG_WPS */
534 
535 
536 int main(int argc, char *argv[])
537 {
538 	struct hapd_interfaces interfaces;
539 	int ret = 1;
540 	size_t i, j;
541 	int c, debug = 0, daemonize = 0;
542 	char *pid_file = NULL;
543 	const char *log_file = NULL;
544 	const char *entropy_file = NULL;
545 	char **bss_config = NULL, **tmp_bss;
546 	size_t num_bss_configs = 0;
547 #ifdef CONFIG_DEBUG_LINUX_TRACING
548 	int enable_trace_dbg = 0;
549 #endif /* CONFIG_DEBUG_LINUX_TRACING */
550 
551 	if (os_program_init())
552 		return -1;
553 
554 	os_memset(&interfaces, 0, sizeof(interfaces));
555 	interfaces.reload_config = hostapd_reload_config;
556 	interfaces.config_read_cb = hostapd_config_read;
557 	interfaces.for_each_interface = hostapd_for_each_interface;
558 	interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
559 	interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
560 	interfaces.driver_init = hostapd_driver_init;
561 	interfaces.global_iface_path = NULL;
562 	interfaces.global_iface_name = NULL;
563 	interfaces.global_ctrl_sock = -1;
564 
565 	for (;;) {
566 		c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
567 		if (c < 0)
568 			break;
569 		switch (c) {
570 		case 'h':
571 			usage();
572 			break;
573 		case 'd':
574 			debug++;
575 			if (wpa_debug_level > 0)
576 				wpa_debug_level--;
577 			break;
578 		case 'B':
579 			daemonize++;
580 			break;
581 		case 'e':
582 			entropy_file = optarg;
583 			break;
584 		case 'f':
585 			log_file = optarg;
586 			break;
587 		case 'K':
588 			wpa_debug_show_keys++;
589 			break;
590 		case 'P':
591 			os_free(pid_file);
592 			pid_file = os_rel2abs_path(optarg);
593 			break;
594 		case 't':
595 			wpa_debug_timestamp++;
596 			break;
597 #ifdef CONFIG_DEBUG_LINUX_TRACING
598 		case 'T':
599 			enable_trace_dbg = 1;
600 			break;
601 #endif /* CONFIG_DEBUG_LINUX_TRACING */
602 		case 'v':
603 			show_version();
604 			exit(1);
605 			break;
606 		case 'g':
607 			if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
608 				return -1;
609 			break;
610 		case 'G':
611 			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
612 				return -1;
613 			break;
614 		case 'b':
615 			tmp_bss = os_realloc_array(bss_config,
616 						   num_bss_configs + 1,
617 						   sizeof(char *));
618 			if (tmp_bss == NULL)
619 				goto out;
620 			bss_config = tmp_bss;
621 			bss_config[num_bss_configs++] = optarg;
622 			break;
623 #ifdef CONFIG_WPS
624 		case 'u':
625 			return gen_uuid(optarg);
626 #endif /* CONFIG_WPS */
627 		default:
628 			usage();
629 			break;
630 		}
631 	}
632 
633 	if (optind == argc && interfaces.global_iface_path == NULL &&
634 	    num_bss_configs == 0)
635 		usage();
636 
637 	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
638 
639 	if (log_file)
640 		wpa_debug_open_file(log_file);
641 	else
642 		wpa_debug_setup_stdout();
643 #ifdef CONFIG_DEBUG_LINUX_TRACING
644 	if (enable_trace_dbg) {
645 		int tret = wpa_debug_open_linux_tracing();
646 		if (tret) {
647 			wpa_printf(MSG_ERROR, "Failed to enable trace logging");
648 			return -1;
649 		}
650 	}
651 #endif /* CONFIG_DEBUG_LINUX_TRACING */
652 
653 	interfaces.count = argc - optind;
654 	if (interfaces.count || num_bss_configs) {
655 		interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
656 					     sizeof(struct hostapd_iface *));
657 		if (interfaces.iface == NULL) {
658 			wpa_printf(MSG_ERROR, "malloc failed");
659 			return -1;
660 		}
661 	}
662 
663 	if (hostapd_global_init(&interfaces, entropy_file)) {
664 		wpa_printf(MSG_ERROR, "Failed to initilize global context");
665 		return -1;
666 	}
667 
668 	/* Allocate and parse configuration for full interface files */
669 	for (i = 0; i < interfaces.count; i++) {
670 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
671 							     argv[optind + i],
672 							     debug);
673 		if (!interfaces.iface[i]) {
674 			wpa_printf(MSG_ERROR, "Failed to initialize interface");
675 			goto out;
676 		}
677 	}
678 
679 	/* Allocate and parse configuration for per-BSS files */
680 	for (i = 0; i < num_bss_configs; i++) {
681 		struct hostapd_iface *iface;
682 		char *fname;
683 
684 		wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
685 		fname = os_strchr(bss_config[i], ':');
686 		if (fname == NULL) {
687 			wpa_printf(MSG_ERROR,
688 				   "Invalid BSS config identifier '%s'",
689 				   bss_config[i]);
690 			goto out;
691 		}
692 		*fname++ = '\0';
693 		iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
694 						   fname, debug);
695 		if (iface == NULL)
696 			goto out;
697 		for (j = 0; j < interfaces.count; j++) {
698 			if (interfaces.iface[j] == iface)
699 				break;
700 		}
701 		if (j == interfaces.count) {
702 			struct hostapd_iface **tmp;
703 			tmp = os_realloc_array(interfaces.iface,
704 					       interfaces.count + 1,
705 					       sizeof(struct hostapd_iface *));
706 			if (tmp == NULL) {
707 				hostapd_interface_deinit_free(iface);
708 				goto out;
709 			}
710 			interfaces.iface = tmp;
711 			interfaces.iface[interfaces.count++] = iface;
712 		}
713 	}
714 
715 	/*
716 	 * Enable configured interfaces. Depending on channel configuration,
717 	 * this may complete full initialization before returning or use a
718 	 * callback mechanism to complete setup in case of operations like HT
719 	 * co-ex scans, ACS, or DFS are needed to determine channel parameters.
720 	 * In such case, the interface will be enabled from eloop context within
721 	 * hostapd_global_run().
722 	 */
723 	interfaces.terminate_on_error = interfaces.count;
724 	for (i = 0; i < interfaces.count; i++) {
725 		if (hostapd_driver_init(interfaces.iface[i]) ||
726 		    hostapd_setup_interface(interfaces.iface[i]))
727 			goto out;
728 	}
729 
730 	hostapd_global_ctrl_iface_init(&interfaces);
731 
732 	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
733 		wpa_printf(MSG_ERROR, "Failed to start eloop");
734 		goto out;
735 	}
736 
737 	ret = 0;
738 
739  out:
740 	hostapd_global_ctrl_iface_deinit(&interfaces);
741 	/* Deinitialize all interfaces */
742 	for (i = 0; i < interfaces.count; i++) {
743 		if (!interfaces.iface[i])
744 			continue;
745 		interfaces.iface[i]->driver_ap_teardown =
746 			!!(interfaces.iface[i]->drv_flags &
747 			   WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
748 		hostapd_interface_deinit_free(interfaces.iface[i]);
749 	}
750 	os_free(interfaces.iface);
751 
752 	hostapd_global_deinit(pid_file);
753 	os_free(pid_file);
754 
755 	if (log_file)
756 		wpa_debug_close_file();
757 	wpa_debug_close_linux_tracing();
758 
759 	os_free(bss_config);
760 
761 	os_program_deinit();
762 
763 	return ret;
764 }
765