Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / hostapd / main.c
index 9c532d4..6c7406a 100644 (file)
@@ -1,24 +1,21 @@
 /*
  * hostapd / main()
- * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 #ifndef CONFIG_NATIVE_WINDOWS
 #include <syslog.h>
+#include <grp.h>
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "utils/uuid.h"
+#include "crypto/random.h"
 #include "crypto/tls.h"
 #include "common/version.h"
 #include "drivers/driver.h"
 #include "eap_server/tncs.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#include "fst/fst.h"
 #include "config_file.h"
 #include "eap_register.h"
-#include "dump_state.h"
 #include "ctrl_iface.h"
 
 
-extern int wpa_debug_level;
-extern int wpa_debug_show_keys;
-extern int wpa_debug_timestamp;
-
-
-struct hapd_interfaces {
-       size_t count;
-       struct hostapd_iface **iface;
+struct hapd_global {
+       void **drv_priv;
+       size_t drv_count;
 };
 
-
-static int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
-                                     int (*cb)(struct hostapd_iface *iface,
-                                               void *ctx), void *ctx)
-{
-       size_t i;
-       int ret;
-
-       for (i = 0; i < interfaces->count; i++) {
-               ret = cb(interfaces->iface[i], ctx);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
+static struct hapd_global global;
 
 
 #ifndef CONFIG_NO_HOSTAPD_LOGGER
@@ -115,22 +93,24 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
        if (hapd && hapd->conf && addr)
                os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
                            hapd->conf->iface, MAC2STR(addr),
-                           module_str ? " " : "", module_str, txt);
+                           module_str ? " " : "", module_str ? module_str : "",
+                           txt);
        else if (hapd && hapd->conf)
                os_snprintf(format, maxlen, "%s:%s%s %s",
                            hapd->conf->iface, module_str ? " " : "",
-                           module_str, txt);
+                           module_str ? module_str : "", txt);
        else if (addr)
                os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
                            MAC2STR(addr), module_str ? " " : "",
-                           module_str, txt);
+                           module_str ? module_str : "", txt);
        else
                os_snprintf(format, maxlen, "%s%s%s",
-                           module_str, module_str ? ": " : "", txt);
+                           module_str ? module_str : "",
+                           module_str ? ": " : "", txt);
 
        if ((conf_stdout & module) && level >= conf_stdout_level) {
                wpa_debug_print_timestamp();
-               printf("%s\n", format);
+               wpa_printf(MSG_INFO, "%s", format);
        }
 
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -164,68 +144,8 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
 
 
 /**
- * hostapd_init - Allocate and initialize per-interface data
- * @config_file: Path to the configuration file
- * Returns: Pointer to the allocated interface data or %NULL on failure
- *
- * This function is used to allocate main data structures for per-interface
- * data. The allocated data buffer will be freed by calling
- * hostapd_cleanup_iface().
+ * hostapd_driver_init - Preparate driver interface
  */
-static struct hostapd_iface * hostapd_init(const char *config_file)
-{
-       struct hostapd_iface *hapd_iface = NULL;
-       struct hostapd_config *conf = NULL;
-       struct hostapd_data *hapd;
-       size_t i;
-
-       hapd_iface = os_zalloc(sizeof(*hapd_iface));
-       if (hapd_iface == NULL)
-               goto fail;
-
-       hapd_iface->reload_config = hostapd_reload_config;
-       hapd_iface->config_read_cb = hostapd_config_read;
-       hapd_iface->config_fname = os_strdup(config_file);
-       if (hapd_iface->config_fname == NULL)
-               goto fail;
-       hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
-       hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
-       hapd_iface->for_each_interface = hostapd_for_each_interface;
-
-       conf = hostapd_config_read(hapd_iface->config_fname);
-       if (conf == NULL)
-               goto fail;
-       hapd_iface->conf = conf;
-
-       hapd_iface->num_bss = conf->num_bss;
-       hapd_iface->bss = os_zalloc(conf->num_bss *
-                                   sizeof(struct hostapd_data *));
-       if (hapd_iface->bss == NULL)
-               goto fail;
-
-       for (i = 0; i < conf->num_bss; i++) {
-               hapd = hapd_iface->bss[i] =
-                       hostapd_alloc_bss_data(hapd_iface, conf,
-                                              &conf->bss[i]);
-               if (hapd == NULL)
-                       goto fail;
-               hapd->msg_ctx = hapd;
-       }
-
-       return hapd_iface;
-
-fail:
-       if (conf)
-               hostapd_config_free(conf);
-       if (hapd_iface) {
-               os_free(hapd_iface->config_fname);
-               os_free(hapd_iface->bss);
-               os_free(hapd_iface);
-       }
-       return NULL;
-}
-
-
 static int hostapd_driver_init(struct hostapd_iface *iface)
 {
        struct wpa_init_params params;
@@ -233,6 +153,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
        struct hostapd_data *hapd = iface->bss[0];
        struct hostapd_bss_config *conf = hapd->conf;
        u8 *b = conf->bssid;
+       struct wpa_driver_capa capa;
 
        if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
                wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
@@ -244,15 +165,31 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
                b = NULL;
 
        os_memset(&params, 0, sizeof(params));
+       for (i = 0; wpa_drivers[i]; i++) {
+               if (wpa_drivers[i] != hapd->driver)
+                       continue;
+
+               if (global.drv_priv[i] == NULL &&
+                   wpa_drivers[i]->global_init) {
+                       global.drv_priv[i] = wpa_drivers[i]->global_init();
+                       if (global.drv_priv[i] == NULL) {
+                               wpa_printf(MSG_ERROR, "Failed to initialize "
+                                          "driver '%s'",
+                                          wpa_drivers[i]->name);
+                               return -1;
+                       }
+               }
+
+               params.global_priv = global.drv_priv[i];
+               break;
+       }
        params.bssid = b;
        params.ifname = hapd->conf->iface;
-       params.ssid = (const u8 *) hapd->conf->ssid.ssid;
-       params.ssid_len = hapd->conf->ssid.ssid_len;
-       params.test_socket = hapd->conf->test_socket;
+       params.driver_params = hapd->iconf->driver_params;
        params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
 
        params.num_bridge = hapd->iface->num_bss;
-       params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
+       params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
        if (params.bridge == NULL)
                return -1;
        for (i = 0; i < hapd->iface->num_bss; i++) {
@@ -272,25 +209,37 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
                return -1;
        }
 
-       return 0;
-}
-
+       if (hapd->driver->get_capa &&
+           hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
+               struct wowlan_triggers *triggs;
+
+               iface->drv_flags = capa.flags;
+               iface->smps_modes = capa.smps_modes;
+               iface->probe_resp_offloads = capa.probe_resp_offloads;
+               iface->extended_capa = capa.extended_capa;
+               iface->extended_capa_mask = capa.extended_capa_mask;
+               iface->extended_capa_len = capa.extended_capa_len;
+               iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
+
+               triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa);
+               if (triggs && hapd->driver->set_wowlan) {
+                       if (hapd->driver->set_wowlan(hapd->drv_priv, triggs))
+                               wpa_printf(MSG_ERROR, "set_wowlan failed");
+               }
+               os_free(triggs);
+       }
 
-static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
-{
-       const struct wpa_driver_ops *driver;
-       void *drv_priv;
-       if (iface == NULL)
-               return;
-       driver = iface->bss[0]->driver;
-       drv_priv = iface->bss[0]->drv_priv;
-       hostapd_interface_deinit(iface);
-       if (driver && driver->hapd_deinit)
-               driver->hapd_deinit(drv_priv);
-       hostapd_interface_free(iface);
+       return 0;
 }
 
 
+/**
+ * hostapd_interface_init - Read configuration file and init BSS data
+ *
+ * This function is used to parse configuration file for a full interface (one
+ * or more BSSes sharing the same radio) and allocate memory for the BSS
+ * interfaces. No actiual driver operations are started.
+ */
 static struct hostapd_iface *
 hostapd_interface_init(struct hapd_interfaces *interfaces,
                       const char *config_fname, int debug)
@@ -299,7 +248,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
        int k;
 
        wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
-       iface = hostapd_init(config_fname);
+       iface = hostapd_init(interfaces, config_fname);
        if (!iface)
                return NULL;
        iface->interfaces = interfaces;
@@ -309,8 +258,10 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
                        iface->bss[0]->conf->logger_stdout_level--;
        }
 
-       if (hostapd_driver_init(iface) ||
-           hostapd_setup_interface(iface)) {
+       if (iface->conf->bss[0]->iface[0] == '\0' &&
+           !hostapd_drv_none(iface->bss[0])) {
+               wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+                          config_fname);
                hostapd_interface_deinit_free(iface);
                return NULL;
        }
@@ -355,16 +306,18 @@ static void handle_reload(int sig, void *signal_ctx)
 
 static void handle_dump_state(int sig, void *signal_ctx)
 {
-#ifdef HOSTAPD_DUMP_STATE
-       struct hapd_interfaces *interfaces = signal_ctx;
-       hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
-#endif /* HOSTAPD_DUMP_STATE */
+       /* Not used anymore - ignore signal */
 }
 #endif /* CONFIG_NATIVE_WINDOWS */
 
 
-static int hostapd_global_init(struct hapd_interfaces *interfaces)
+static int hostapd_global_init(struct hapd_interfaces *interfaces,
+                              const char *entropy_file)
 {
+       int i;
+
+       os_memset(&global, 0, sizeof(global));
+
        hostapd_logger_register_cb(hostapd_logger_cb);
 
        if (eap_server_register_methods()) {
@@ -377,6 +330,8 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces)
                return -1;
        }
 
+       random_init(entropy_file);
+
 #ifndef CONFIG_NATIVE_WINDOWS
        eloop_register_signal(SIGHUP, handle_reload, interfaces);
        eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
@@ -387,16 +342,38 @@ static int hostapd_global_init(struct hapd_interfaces *interfaces)
        openlog("hostapd", 0, LOG_DAEMON);
 #endif /* CONFIG_NATIVE_WINDOWS */
 
+       for (i = 0; wpa_drivers[i]; i++)
+               global.drv_count++;
+       if (global.drv_count == 0) {
+               wpa_printf(MSG_ERROR, "No drivers enabled");
+               return -1;
+       }
+       global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
+       if (global.drv_priv == NULL)
+               return -1;
+
        return 0;
 }
 
 
 static void hostapd_global_deinit(const char *pid_file)
 {
+       int i;
+
+       for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
+               if (!global.drv_priv[i])
+                       continue;
+               wpa_drivers[i]->global_deinit(global.drv_priv[i]);
+       }
+       os_free(global.drv_priv);
+       global.drv_priv = NULL;
+
 #ifdef EAP_SERVER_TNC
        tncs_global_deinit();
 #endif /* EAP_SERVER_TNC */
 
+       random_deinit();
+
        eloop_destroy();
 
 #ifndef CONFIG_NATIVE_WINDOWS
@@ -432,7 +409,7 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
 #endif /* EAP_SERVER_TNC */
 
        if (daemonize && os_daemonize(pid_file)) {
-               perror("daemon");
+               wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
                return -1;
        }
 
@@ -448,7 +425,7 @@ static void show_version(void)
                "hostapd v" VERSION_STR "\n"
                "User space daemon for IEEE 802.11 AP management,\n"
                "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
-               "Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> "
+               "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
                "and contributors\n");
 }
 
@@ -458,15 +435,27 @@ static void usage(void)
        show_version();
        fprintf(stderr,
                "\n"
-               "usage: hostapd [-hdBKtv] [-P <PID file>] "
-               "<configuration file(s)>\n"
+               "usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
+               "\\\n"
+               "         [-g <global ctrl_iface>] [-G <group>] \\\n"
+               "         <configuration file(s)>\n"
                "\n"
                "options:\n"
                "   -h   show this usage\n"
                "   -d   show more debug messages (-dd for even more)\n"
                "   -B   run daemon in the background\n"
+               "   -e   entropy file\n"
+               "   -g   global control interface path\n"
+               "   -G   group for control interfaces\n"
                "   -P   PID file\n"
                "   -K   include key data in debug messages\n"
+#ifdef CONFIG_DEBUG_FILE
+               "   -f   log output to debug file instead of stdout\n"
+#endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+               "   -T = record to Linux tracing in addition to logging\n"
+               "        (records all messages regardless of debug verbosity)\n"
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
                "   -t   include timestamps in some debug messages\n"
                "   -v   show hostapd version\n");
 
@@ -474,19 +463,131 @@ static void usage(void)
 }
 
 
+static const char * hostapd_msg_ifname_cb(void *ctx)
+{
+       struct hostapd_data *hapd = ctx;
+       if (hapd && hapd->iconf && hapd->iconf->bss &&
+           hapd->iconf->num_bss > 0 && hapd->iconf->bss[0])
+               return hapd->iconf->bss[0]->iface;
+       return NULL;
+}
+
+
+static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
+                                        const char *path)
+{
+       char *pos;
+       os_free(interfaces->global_iface_path);
+       interfaces->global_iface_path = os_strdup(path);
+       if (interfaces->global_iface_path == NULL)
+               return -1;
+       pos = os_strrchr(interfaces->global_iface_path, '/');
+       if (pos == NULL) {
+               wpa_printf(MSG_ERROR, "No '/' in the global control interface "
+                          "file");
+               os_free(interfaces->global_iface_path);
+               interfaces->global_iface_path = NULL;
+               return -1;
+       }
+
+       *pos = '\0';
+       interfaces->global_iface_name = pos + 1;
+
+       return 0;
+}
+
+
+static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
+                                       const char *group)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+       struct group *grp;
+       grp = getgrnam(group);
+       if (grp == NULL) {
+               wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
+               return -1;
+       }
+       interfaces->ctrl_iface_group = grp->gr_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+       return 0;
+}
+
+
+#ifdef CONFIG_WPS
+static int gen_uuid(const char *txt_addr)
+{
+       u8 addr[ETH_ALEN];
+       u8 uuid[UUID_LEN];
+       char buf[100];
+
+       if (hwaddr_aton(txt_addr, addr) < 0)
+               return -1;
+
+       uuid_gen_mac_addr(addr, uuid);
+       if (uuid_bin2str(uuid, buf, sizeof(buf)) < 0)
+               return -1;
+
+       printf("%s\n", buf);
+
+       return 0;
+}
+#endif /* CONFIG_WPS */
+
+
+#ifndef HOSTAPD_CLEANUP_INTERVAL
+#define HOSTAPD_CLEANUP_INTERVAL 10
+#endif /* HOSTAPD_CLEANUP_INTERVAL */
+
+static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
+{
+       hostapd_periodic_iface(iface);
+       return 0;
+}
+
+
+/* Periodic cleanup tasks */
+static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
+{
+       struct hapd_interfaces *interfaces = eloop_ctx;
+
+       eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
+                              hostapd_periodic, interfaces, NULL);
+       hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL);
+}
+
+
 int main(int argc, char *argv[])
 {
        struct hapd_interfaces interfaces;
        int ret = 1;
-       size_t i;
+       size_t i, j;
        int c, debug = 0, daemonize = 0;
        char *pid_file = NULL;
+       const char *log_file = NULL;
+       const char *entropy_file = NULL;
+       char **bss_config = NULL, **tmp_bss;
+       size_t num_bss_configs = 0;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+       int enable_trace_dbg = 0;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
 
        if (os_program_init())
                return -1;
 
+       os_memset(&interfaces, 0, sizeof(interfaces));
+       interfaces.reload_config = hostapd_reload_config;
+       interfaces.config_read_cb = hostapd_config_read;
+       interfaces.for_each_interface = hostapd_for_each_interface;
+       interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
+       interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
+       interfaces.driver_init = hostapd_driver_init;
+       interfaces.global_iface_path = NULL;
+       interfaces.global_iface_name = NULL;
+       interfaces.global_ctrl_sock = -1;
+       interfaces.global_ctrl_dst = NULL;
+
        for (;;) {
-               c = getopt(argc, argv, "BdhKP:tv");
+               c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
                if (c < 0)
                        break;
                switch (c) {
@@ -501,6 +602,12 @@ int main(int argc, char *argv[])
                case 'B':
                        daemonize++;
                        break;
+               case 'e':
+                       entropy_file = optarg;
+                       break;
+               case 'f':
+                       log_file = optarg;
+                       break;
                case 'K':
                        wpa_debug_show_keys++;
                        break;
@@ -511,54 +618,187 @@ int main(int argc, char *argv[])
                case 't':
                        wpa_debug_timestamp++;
                        break;
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+               case 'T':
+                       enable_trace_dbg = 1;
+                       break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
                case 'v':
                        show_version();
                        exit(1);
                        break;
-
+               case 'g':
+                       if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
+                               return -1;
+                       break;
+               case 'G':
+                       if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
+                               return -1;
+                       break;
+               case 'b':
+                       tmp_bss = os_realloc_array(bss_config,
+                                                  num_bss_configs + 1,
+                                                  sizeof(char *));
+                       if (tmp_bss == NULL)
+                               goto out;
+                       bss_config = tmp_bss;
+                       bss_config[num_bss_configs++] = optarg;
+                       break;
+#ifdef CONFIG_WPS
+               case 'u':
+                       return gen_uuid(optarg);
+#endif /* CONFIG_WPS */
                default:
                        usage();
                        break;
                }
        }
 
-       if (optind == argc)
+       if (optind == argc && interfaces.global_iface_path == NULL &&
+           num_bss_configs == 0)
                usage();
 
+       wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
+
+       if (log_file)
+               wpa_debug_open_file(log_file);
+       else
+               wpa_debug_setup_stdout();
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+       if (enable_trace_dbg) {
+               int tret = wpa_debug_open_linux_tracing();
+               if (tret) {
+                       wpa_printf(MSG_ERROR, "Failed to enable trace logging");
+                       return -1;
+               }
+       }
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
        interfaces.count = argc - optind;
-       interfaces.iface = os_malloc(interfaces.count *
-                                    sizeof(struct hostapd_iface *));
-       if (interfaces.iface == NULL) {
-               wpa_printf(MSG_ERROR, "malloc failed\n");
-               return -1;
+       if (interfaces.count || num_bss_configs) {
+               interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
+                                            sizeof(struct hostapd_iface *));
+               if (interfaces.iface == NULL) {
+                       wpa_printf(MSG_ERROR, "malloc failed");
+                       return -1;
+               }
        }
 
-       if (hostapd_global_init(&interfaces))
+       if (hostapd_global_init(&interfaces, entropy_file)) {
+               wpa_printf(MSG_ERROR, "Failed to initialize global context");
                return -1;
+       }
+
+       eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
+                              hostapd_periodic, &interfaces, NULL);
 
-       /* Initialize interfaces */
+       if (fst_global_init()) {
+               wpa_printf(MSG_ERROR,
+                          "Failed to initialize global FST context");
+               goto out;
+       }
+
+#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
+       if (!fst_global_add_ctrl(fst_ctrl_cli))
+               wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
+#endif /* CONFIG_FST && CONFIG_CTRL_IFACE */
+
+       /* Allocate and parse configuration for full interface files */
        for (i = 0; i < interfaces.count; i++) {
                interfaces.iface[i] = hostapd_interface_init(&interfaces,
                                                             argv[optind + i],
                                                             debug);
-               if (!interfaces.iface[i])
+               if (!interfaces.iface[i]) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize interface");
+                       goto out;
+               }
+       }
+
+       /* Allocate and parse configuration for per-BSS files */
+       for (i = 0; i < num_bss_configs; i++) {
+               struct hostapd_iface *iface;
+               char *fname;
+
+               wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
+               fname = os_strchr(bss_config[i], ':');
+               if (fname == NULL) {
+                       wpa_printf(MSG_ERROR,
+                                  "Invalid BSS config identifier '%s'",
+                                  bss_config[i]);
+                       goto out;
+               }
+               *fname++ = '\0';
+               iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
+                                                  fname, debug);
+               if (iface == NULL)
+                       goto out;
+               for (j = 0; j < interfaces.count; j++) {
+                       if (interfaces.iface[j] == iface)
+                               break;
+               }
+               if (j == interfaces.count) {
+                       struct hostapd_iface **tmp;
+                       tmp = os_realloc_array(interfaces.iface,
+                                              interfaces.count + 1,
+                                              sizeof(struct hostapd_iface *));
+                       if (tmp == NULL) {
+                               hostapd_interface_deinit_free(iface);
+                               goto out;
+                       }
+                       interfaces.iface = tmp;
+                       interfaces.iface[interfaces.count++] = iface;
+               }
+       }
+
+       /*
+        * Enable configured interfaces. Depending on channel configuration,
+        * this may complete full initialization before returning or use a
+        * callback mechanism to complete setup in case of operations like HT
+        * co-ex scans, ACS, or DFS are needed to determine channel parameters.
+        * In such case, the interface will be enabled from eloop context within
+        * hostapd_global_run().
+        */
+       interfaces.terminate_on_error = interfaces.count;
+       for (i = 0; i < interfaces.count; i++) {
+               if (hostapd_driver_init(interfaces.iface[i]) ||
+                   hostapd_setup_interface(interfaces.iface[i]))
                        goto out;
        }
 
-       if (hostapd_global_run(&interfaces, daemonize, pid_file))
+       hostapd_global_ctrl_iface_init(&interfaces);
+
+       if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
+               wpa_printf(MSG_ERROR, "Failed to start eloop");
                goto out;
+       }
 
        ret = 0;
 
  out:
+       hostapd_global_ctrl_iface_deinit(&interfaces);
        /* Deinitialize all interfaces */
-       for (i = 0; i < interfaces.count; i++)
+       for (i = 0; i < interfaces.count; i++) {
+               if (!interfaces.iface[i])
+                       continue;
+               interfaces.iface[i]->driver_ap_teardown =
+                       !!(interfaces.iface[i]->drv_flags &
+                          WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
                hostapd_interface_deinit_free(interfaces.iface[i]);
+       }
        os_free(interfaces.iface);
 
+       eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
        hostapd_global_deinit(pid_file);
        os_free(pid_file);
 
+       if (log_file)
+               wpa_debug_close_file();
+       wpa_debug_close_linux_tracing();
+
+       os_free(bss_config);
+
+       fst_global_deinit();
+
        os_program_deinit();
 
        return ret;