Home | History | Annotate | Download | only in hostapd
      1 /*
      2  * hostapd / main()
      3  * Copyright (c) 2002-2011, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "utils/includes.h"
     10 #ifndef CONFIG_NATIVE_WINDOWS
     11 #include <syslog.h>
     12 #include <grp.h>
     13 #endif /* CONFIG_NATIVE_WINDOWS */
     14 
     15 #include "utils/common.h"
     16 #include "utils/eloop.h"
     17 #include "crypto/random.h"
     18 #include "crypto/tls.h"
     19 #include "common/version.h"
     20 #include "drivers/driver.h"
     21 #include "eap_server/eap.h"
     22 #include "eap_server/tncs.h"
     23 #include "ap/hostapd.h"
     24 #include "ap/ap_config.h"
     25 #include "ap/ap_drv_ops.h"
     26 #include "config_file.h"
     27 #include "eap_register.h"
     28 #include "dump_state.h"
     29 #include "ctrl_iface.h"
     30 
     31 
     32 extern int wpa_debug_level;
     33 extern int wpa_debug_show_keys;
     34 extern int wpa_debug_timestamp;
     35 
     36 extern struct wpa_driver_ops *wpa_drivers[];
     37 
     38 
     39 struct hapd_global {
     40 	void **drv_priv;
     41 	size_t drv_count;
     42 };
     43 
     44 static struct hapd_global global;
     45 
     46 
     47 #ifndef CONFIG_NO_HOSTAPD_LOGGER
     48 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
     49 			      int level, const char *txt, size_t len)
     50 {
     51 	struct hostapd_data *hapd = ctx;
     52 	char *format, *module_str;
     53 	int maxlen;
     54 	int conf_syslog_level, conf_stdout_level;
     55 	unsigned int conf_syslog, conf_stdout;
     56 
     57 	maxlen = len + 100;
     58 	format = os_malloc(maxlen);
     59 	if (!format)
     60 		return;
     61 
     62 	if (hapd && hapd->conf) {
     63 		conf_syslog_level = hapd->conf->logger_syslog_level;
     64 		conf_stdout_level = hapd->conf->logger_stdout_level;
     65 		conf_syslog = hapd->conf->logger_syslog;
     66 		conf_stdout = hapd->conf->logger_stdout;
     67 	} else {
     68 		conf_syslog_level = conf_stdout_level = 0;
     69 		conf_syslog = conf_stdout = (unsigned int) -1;
     70 	}
     71 
     72 	switch (module) {
     73 	case HOSTAPD_MODULE_IEEE80211:
     74 		module_str = "IEEE 802.11";
     75 		break;
     76 	case HOSTAPD_MODULE_IEEE8021X:
     77 		module_str = "IEEE 802.1X";
     78 		break;
     79 	case HOSTAPD_MODULE_RADIUS:
     80 		module_str = "RADIUS";
     81 		break;
     82 	case HOSTAPD_MODULE_WPA:
     83 		module_str = "WPA";
     84 		break;
     85 	case HOSTAPD_MODULE_DRIVER:
     86 		module_str = "DRIVER";
     87 		break;
     88 	case HOSTAPD_MODULE_IAPP:
     89 		module_str = "IAPP";
     90 		break;
     91 	case HOSTAPD_MODULE_MLME:
     92 		module_str = "MLME";
     93 		break;
     94 	default:
     95 		module_str = NULL;
     96 		break;
     97 	}
     98 
     99 	if (hapd && hapd->conf && addr)
    100 		os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
    101 			    hapd->conf->iface, MAC2STR(addr),
    102 			    module_str ? " " : "", module_str, txt);
    103 	else if (hapd && hapd->conf)
    104 		os_snprintf(format, maxlen, "%s:%s%s %s",
    105 			    hapd->conf->iface, module_str ? " " : "",
    106 			    module_str, txt);
    107 	else if (addr)
    108 		os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
    109 			    MAC2STR(addr), module_str ? " " : "",
    110 			    module_str, txt);
    111 	else
    112 		os_snprintf(format, maxlen, "%s%s%s",
    113 			    module_str, module_str ? ": " : "", txt);
    114 
    115 	if ((conf_stdout & module) && level >= conf_stdout_level) {
    116 		wpa_debug_print_timestamp();
    117 		printf("%s\n", format);
    118 	}
    119 
    120 #ifndef CONFIG_NATIVE_WINDOWS
    121 	if ((conf_syslog & module) && level >= conf_syslog_level) {
    122 		int priority;
    123 		switch (level) {
    124 		case HOSTAPD_LEVEL_DEBUG_VERBOSE:
    125 		case HOSTAPD_LEVEL_DEBUG:
    126 			priority = LOG_DEBUG;
    127 			break;
    128 		case HOSTAPD_LEVEL_INFO:
    129 			priority = LOG_INFO;
    130 			break;
    131 		case HOSTAPD_LEVEL_NOTICE:
    132 			priority = LOG_NOTICE;
    133 			break;
    134 		case HOSTAPD_LEVEL_WARNING:
    135 			priority = LOG_WARNING;
    136 			break;
    137 		default:
    138 			priority = LOG_INFO;
    139 			break;
    140 		}
    141 		syslog(priority, "%s", format);
    142 	}
    143 #endif /* CONFIG_NATIVE_WINDOWS */
    144 
    145 	os_free(format);
    146 }
    147 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
    148 
    149 
    150 /**
    151  * hostapd_init - Allocate and initialize per-interface data
    152  * @config_file: Path to the configuration file
    153  * Returns: Pointer to the allocated interface data or %NULL on failure
    154  *
    155  * This function is used to allocate main data structures for per-interface
    156  * data. The allocated data buffer will be freed by calling
    157  * hostapd_cleanup_iface().
    158  */
    159 static struct hostapd_iface * hostapd_init(const char *config_file)
    160 {
    161 	struct hostapd_iface *hapd_iface = NULL;
    162 	struct hostapd_config *conf = NULL;
    163 	struct hostapd_data *hapd;
    164 	size_t i;
    165 
    166 	hapd_iface = os_zalloc(sizeof(*hapd_iface));
    167 	if (hapd_iface == NULL)
    168 		goto fail;
    169 
    170 	hapd_iface->config_fname = os_strdup(config_file);
    171 	if (hapd_iface->config_fname == NULL)
    172 		goto fail;
    173 
    174 	conf = hostapd_config_read(hapd_iface->config_fname);
    175 	if (conf == NULL)
    176 		goto fail;
    177 	hapd_iface->conf = conf;
    178 
    179 	hapd_iface->num_bss = conf->num_bss;
    180 	hapd_iface->bss = os_calloc(conf->num_bss,
    181 				    sizeof(struct hostapd_data *));
    182 	if (hapd_iface->bss == NULL)
    183 		goto fail;
    184 
    185 	for (i = 0; i < conf->num_bss; i++) {
    186 		hapd = hapd_iface->bss[i] =
    187 			hostapd_alloc_bss_data(hapd_iface, conf,
    188 					       &conf->bss[i]);
    189 		if (hapd == NULL)
    190 			goto fail;
    191 		hapd->msg_ctx = hapd;
    192 	}
    193 
    194 	return hapd_iface;
    195 
    196 fail:
    197 	if (conf)
    198 		hostapd_config_free(conf);
    199 	if (hapd_iface) {
    200 		os_free(hapd_iface->config_fname);
    201 		os_free(hapd_iface->bss);
    202 		os_free(hapd_iface);
    203 	}
    204 	return NULL;
    205 }
    206 
    207 
    208 static int hostapd_driver_init(struct hostapd_iface *iface)
    209 {
    210 	struct wpa_init_params params;
    211 	size_t i;
    212 	struct hostapd_data *hapd = iface->bss[0];
    213 	struct hostapd_bss_config *conf = hapd->conf;
    214 	u8 *b = conf->bssid;
    215 	struct wpa_driver_capa capa;
    216 
    217 	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
    218 		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
    219 		return -1;
    220 	}
    221 
    222 	/* Initialize the driver interface */
    223 	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
    224 		b = NULL;
    225 
    226 	os_memset(&params, 0, sizeof(params));
    227 	for (i = 0; wpa_drivers[i]; i++) {
    228 		if (wpa_drivers[i] != hapd->driver)
    229 			continue;
    230 
    231 		if (global.drv_priv[i] == NULL &&
    232 		    wpa_drivers[i]->global_init) {
    233 			global.drv_priv[i] = wpa_drivers[i]->global_init();
    234 			if (global.drv_priv[i] == NULL) {
    235 				wpa_printf(MSG_ERROR, "Failed to initialize "
    236 					   "driver '%s'",
    237 					   wpa_drivers[i]->name);
    238 				return -1;
    239 			}
    240 		}
    241 
    242 		params.global_priv = global.drv_priv[i];
    243 		break;
    244 	}
    245 	params.bssid = b;
    246 	params.ifname = hapd->conf->iface;
    247 	params.ssid = hapd->conf->ssid.ssid;
    248 	params.ssid_len = hapd->conf->ssid.ssid_len;
    249 	params.test_socket = hapd->conf->test_socket;
    250 	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
    251 
    252 	params.num_bridge = hapd->iface->num_bss;
    253 	params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
    254 	if (params.bridge == NULL)
    255 		return -1;
    256 	for (i = 0; i < hapd->iface->num_bss; i++) {
    257 		struct hostapd_data *bss = hapd->iface->bss[i];
    258 		if (bss->conf->bridge[0])
    259 			params.bridge[i] = bss->conf->bridge;
    260 	}
    261 
    262 	params.own_addr = hapd->own_addr;
    263 
    264 	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
    265 	os_free(params.bridge);
    266 	if (hapd->drv_priv == NULL) {
    267 		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
    268 			   hapd->driver->name);
    269 		hapd->driver = NULL;
    270 		return -1;
    271 	}
    272 
    273 	if (hapd->driver->get_capa &&
    274 	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
    275 		iface->drv_flags = capa.flags;
    276 		iface->probe_resp_offloads = capa.probe_resp_offloads;
    277 		iface->extended_capa = capa.extended_capa;
    278 		iface->extended_capa_mask = capa.extended_capa_mask;
    279 		iface->extended_capa_len = capa.extended_capa_len;
    280 	}
    281 
    282 	return 0;
    283 }
    284 
    285 
    286 static struct hostapd_iface *
    287 hostapd_interface_init(struct hapd_interfaces *interfaces,
    288 		       const char *config_fname, int debug)
    289 {
    290 	struct hostapd_iface *iface;
    291 	int k;
    292 
    293 	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
    294 	iface = hostapd_init(config_fname);
    295 	if (!iface)
    296 		return NULL;
    297 	iface->interfaces = interfaces;
    298 
    299 	for (k = 0; k < debug; k++) {
    300 		if (iface->bss[0]->conf->logger_stdout_level > 0)
    301 			iface->bss[0]->conf->logger_stdout_level--;
    302 	}
    303 
    304 	if (iface->conf->bss[0].iface[0] != 0 ||
    305 	    hostapd_drv_none(iface->bss[0])) {
    306 		if (hostapd_driver_init(iface) ||
    307 			hostapd_setup_interface(iface)) {
    308 			hostapd_interface_deinit_free(iface);
    309 			return NULL;
    310 		}
    311 	}
    312 
    313 	return iface;
    314 }
    315 
    316 
    317 /**
    318  * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
    319  */
    320 static void handle_term(int sig, void *signal_ctx)
    321 {
    322 	wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
    323 	eloop_terminate();
    324 }
    325 
    326 
    327 #ifndef CONFIG_NATIVE_WINDOWS
    328 
    329 static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
    330 {
    331 	if (hostapd_reload_config(iface) < 0) {
    332 		wpa_printf(MSG_WARNING, "Failed to read new configuration "
    333 			   "file - continuing with old.");
    334 	}
    335 	return 0;
    336 }
    337 
    338 
    339 /**
    340  * handle_reload - SIGHUP handler to reload configuration
    341  */
    342 static void handle_reload(int sig, void *signal_ctx)
    343 {
    344 	struct hapd_interfaces *interfaces = signal_ctx;
    345 	wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
    346 		   sig);
    347 	hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
    348 }
    349 
    350 
    351 static void handle_dump_state(int sig, void *signal_ctx)
    352 {
    353 #ifdef HOSTAPD_DUMP_STATE
    354 	struct hapd_interfaces *interfaces = signal_ctx;
    355 	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
    356 #endif /* HOSTAPD_DUMP_STATE */
    357 }
    358 #endif /* CONFIG_NATIVE_WINDOWS */
    359 
    360 
    361 static int hostapd_global_init(struct hapd_interfaces *interfaces,
    362 			       const char *entropy_file)
    363 {
    364 	int i;
    365 
    366 	os_memset(&global, 0, sizeof(global));
    367 
    368 	hostapd_logger_register_cb(hostapd_logger_cb);
    369 
    370 	if (eap_server_register_methods()) {
    371 		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
    372 		return -1;
    373 	}
    374 
    375 	if (eloop_init()) {
    376 		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
    377 		return -1;
    378 	}
    379 
    380 	random_init(entropy_file);
    381 
    382 #ifndef CONFIG_NATIVE_WINDOWS
    383 	eloop_register_signal(SIGHUP, handle_reload, interfaces);
    384 	eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
    385 #endif /* CONFIG_NATIVE_WINDOWS */
    386 	eloop_register_signal_terminate(handle_term, interfaces);
    387 
    388 #ifndef CONFIG_NATIVE_WINDOWS
    389 	openlog("hostapd", 0, LOG_DAEMON);
    390 #endif /* CONFIG_NATIVE_WINDOWS */
    391 
    392 	for (i = 0; wpa_drivers[i]; i++)
    393 		global.drv_count++;
    394 	if (global.drv_count == 0) {
    395 		wpa_printf(MSG_ERROR, "No drivers enabled");
    396 		return -1;
    397 	}
    398 	global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
    399 	if (global.drv_priv == NULL)
    400 		return -1;
    401 
    402 	return 0;
    403 }
    404 
    405 
    406 static void hostapd_global_deinit(const char *pid_file)
    407 {
    408 	int i;
    409 
    410 	for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
    411 		if (!global.drv_priv[i])
    412 			continue;
    413 		wpa_drivers[i]->global_deinit(global.drv_priv[i]);
    414 	}
    415 	os_free(global.drv_priv);
    416 	global.drv_priv = NULL;
    417 
    418 #ifdef EAP_SERVER_TNC
    419 	tncs_global_deinit();
    420 #endif /* EAP_SERVER_TNC */
    421 
    422 	random_deinit();
    423 
    424 	eloop_destroy();
    425 
    426 #ifndef CONFIG_NATIVE_WINDOWS
    427 	closelog();
    428 #endif /* CONFIG_NATIVE_WINDOWS */
    429 
    430 	eap_server_unregister_methods();
    431 
    432 	os_daemonize_terminate(pid_file);
    433 }
    434 
    435 
    436 static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
    437 			      const char *pid_file)
    438 {
    439 #ifdef EAP_SERVER_TNC
    440 	int tnc = 0;
    441 	size_t i, k;
    442 
    443 	for (i = 0; !tnc && i < ifaces->count; i++) {
    444 		for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
    445 			if (ifaces->iface[i]->bss[0]->conf->tnc) {
    446 				tnc++;
    447 				break;
    448 			}
    449 		}
    450 	}
    451 
    452 	if (tnc && tncs_global_init() < 0) {
    453 		wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
    454 		return -1;
    455 	}
    456 #endif /* EAP_SERVER_TNC */
    457 
    458 	if (daemonize && os_daemonize(pid_file)) {
    459 		perror("daemon");
    460 		return -1;
    461 	}
    462 
    463 	eloop_run();
    464 
    465 	return 0;
    466 }
    467 
    468 
    469 static void show_version(void)
    470 {
    471 	fprintf(stderr,
    472 		"hostapd v" VERSION_STR "\n"
    473 		"User space daemon for IEEE 802.11 AP management,\n"
    474 		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
    475 		"Copyright (c) 2002-2013, Jouni Malinen <j (at) w1.fi> "
    476 		"and contributors\n");
    477 }
    478 
    479 
    480 static void usage(void)
    481 {
    482 	show_version();
    483 	fprintf(stderr,
    484 		"\n"
    485 		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
    486 		"\\\n"
    487 		"         [-g <global ctrl_iface>] [-G <group>] \\\n"
    488 		"         <configuration file(s)>\n"
    489 		"\n"
    490 		"options:\n"
    491 		"   -h   show this usage\n"
    492 		"   -d   show more debug messages (-dd for even more)\n"
    493 		"   -B   run daemon in the background\n"
    494 		"   -e   entropy file\n"
    495 		"   -g   global control interface path\n"
    496 		"   -G   group for control interfaces\n"
    497 		"   -P   PID file\n"
    498 		"   -K   include key data in debug messages\n"
    499 #ifdef CONFIG_DEBUG_FILE
    500 		"   -f   log output to debug file instead of stdout\n"
    501 #endif /* CONFIG_DEBUG_FILE */
    502 		"   -t   include timestamps in some debug messages\n"
    503 		"   -v   show hostapd version\n");
    504 
    505 	exit(1);
    506 }
    507 
    508 
    509 static const char * hostapd_msg_ifname_cb(void *ctx)
    510 {
    511 	struct hostapd_data *hapd = ctx;
    512 	if (hapd && hapd->iconf && hapd->iconf->bss)
    513 		return hapd->iconf->bss->iface;
    514 	return NULL;
    515 }
    516 
    517 
    518 static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
    519 					 const char *path)
    520 {
    521 	char *pos;
    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 	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 
    538 	return 0;
    539 }
    540 
    541 
    542 static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
    543 					const char *group)
    544 {
    545 #ifndef CONFIG_NATIVE_WINDOWS
    546 	struct group *grp;
    547 	grp = getgrnam(group);
    548 	if (grp == NULL) {
    549 		wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
    550 		return -1;
    551 	}
    552 	interfaces->ctrl_iface_group = grp->gr_gid;
    553 #endif /* CONFIG_NATIVE_WINDOWS */
    554 	return 0;
    555 }
    556 
    557 
    558 int main(int argc, char *argv[])
    559 {
    560 	struct hapd_interfaces interfaces;
    561 	int ret = 1;
    562 	size_t i;
    563 	int c, debug = 0, daemonize = 0;
    564 	char *pid_file = NULL;
    565 	const char *log_file = NULL;
    566 	const char *entropy_file = NULL;
    567 
    568 	if (os_program_init())
    569 		return -1;
    570 
    571 	os_memset(&interfaces, 0, sizeof(interfaces));
    572 	interfaces.reload_config = hostapd_reload_config;
    573 	interfaces.config_read_cb = hostapd_config_read;
    574 	interfaces.for_each_interface = hostapd_for_each_interface;
    575 	interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
    576 	interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
    577 	interfaces.driver_init = hostapd_driver_init;
    578 	interfaces.global_iface_path = NULL;
    579 	interfaces.global_iface_name = NULL;
    580 	interfaces.global_ctrl_sock = -1;
    581 
    582 	for (;;) {
    583 		c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
    584 		if (c < 0)
    585 			break;
    586 		switch (c) {
    587 		case 'h':
    588 			usage();
    589 			break;
    590 		case 'd':
    591 			debug++;
    592 			if (wpa_debug_level > 0)
    593 				wpa_debug_level--;
    594 			break;
    595 		case 'B':
    596 			daemonize++;
    597 			break;
    598 		case 'e':
    599 			entropy_file = optarg;
    600 			break;
    601 		case 'f':
    602 			log_file = optarg;
    603 			break;
    604 		case 'K':
    605 			wpa_debug_show_keys++;
    606 			break;
    607 		case 'P':
    608 			os_free(pid_file);
    609 			pid_file = os_rel2abs_path(optarg);
    610 			break;
    611 		case 't':
    612 			wpa_debug_timestamp++;
    613 			break;
    614 		case 'v':
    615 			show_version();
    616 			exit(1);
    617 			break;
    618 		case 'g':
    619 			if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
    620 				return -1;
    621 			break;
    622 		case 'G':
    623 			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
    624 				return -1;
    625 			break;
    626 		default:
    627 			usage();
    628 			break;
    629 		}
    630 	}
    631 
    632 	if (optind == argc && interfaces.global_iface_path == NULL)
    633 		usage();
    634 
    635 	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
    636 
    637 	if (log_file)
    638 		wpa_debug_open_file(log_file);
    639 
    640 	interfaces.count = argc - optind;
    641 	if (interfaces.count) {
    642 		interfaces.iface = os_calloc(interfaces.count,
    643 					     sizeof(struct hostapd_iface *));
    644 		if (interfaces.iface == NULL) {
    645 			wpa_printf(MSG_ERROR, "malloc failed");
    646 			return -1;
    647 		}
    648 	}
    649 
    650 	if (hostapd_global_init(&interfaces, entropy_file))
    651 		return -1;
    652 
    653 	/* Initialize interfaces */
    654 	for (i = 0; i < interfaces.count; i++) {
    655 		interfaces.iface[i] = hostapd_interface_init(&interfaces,
    656 							     argv[optind + i],
    657 							     debug);
    658 		if (!interfaces.iface[i])
    659 			goto out;
    660 	}
    661 
    662 	hostapd_global_ctrl_iface_init(&interfaces);
    663 
    664 	if (hostapd_global_run(&interfaces, daemonize, pid_file))
    665 		goto out;
    666 
    667 	ret = 0;
    668 
    669  out:
    670 	hostapd_global_ctrl_iface_deinit(&interfaces);
    671 	/* Deinitialize all interfaces */
    672 	for (i = 0; i < interfaces.count; i++)
    673 		hostapd_interface_deinit_free(interfaces.iface[i]);
    674 	os_free(interfaces.iface);
    675 
    676 	hostapd_global_deinit(pid_file);
    677 	os_free(pid_file);
    678 
    679 	if (log_file)
    680 		wpa_debug_close_file();
    681 
    682 	os_program_deinit();
    683 
    684 	return ret;
    685 }
    686