hostapd: Allow per-BSS (vif) configuration files
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 17 Oct 2013 14:41:26 +0000 (17:41 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 29 Oct 2013 14:58:21 +0000 (16:58 +0200)
This provides a new option for configuring multiple virtual interfaces
(BSS) that share a single radio. The new command line parameter
-b<phyname>:<config file name> is used to define one or more virtual
interfaces for each PHY. The first such entry for a new PHY is used to
initialize the interface structure and all consecutive parameters that
have the same PHY name will be added as virtual BSS entries to that
interface. The radio parameters in the configuration files have to be
identical.

This can be used as an alternative for the bss=<ifname> separator and
multiple BSSes in a single configuration file design while still
allowing hostapd to control the PHY (struct hostapd_iface) as a group of
virtual interfaces (struct hostapd_data) so that common radio operations
like OLBC detection and HT40 co-ex scans can be done only once per real
radio.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

hostapd/main.c
src/ap/ap_config.c
src/ap/hostapd.h

index ab75b5f..23eef1a 100644 (file)
@@ -327,10 +327,123 @@ hostapd_interface_init(struct hapd_interfaces *interfaces,
                return NULL;
        }
 
+       iface->init_done = 1;
+
        return iface;
 }
 
 
+static struct hostapd_iface *
+hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
+                          const char *config_fname, int debug)
+{
+       struct hostapd_iface *new_iface = NULL, *iface = NULL;
+       struct hostapd_data *hapd;
+       int k;
+       size_t i, bss_idx;
+
+       if (!phy || !*phy)
+               return NULL;
+
+       for (i = 0; i < interfaces->count; i++) {
+               if (os_strcmp(interfaces->iface[i]->phy, phy) == 0) {
+                       iface = interfaces->iface[i];
+                       break;
+               }
+       }
+
+       wpa_printf(MSG_ERROR, "Configuration file: %s (phy %s)%s",
+                  config_fname, phy, iface ? "" : " --> new PHY");
+       if (iface) {
+               struct hostapd_config *conf;
+               struct hostapd_bss_config **tmp_conf;
+               struct hostapd_data **tmp_bss;
+               struct hostapd_bss_config *bss;
+
+               /* Add new BSS to existing iface */
+               conf = hostapd_config_read(config_fname);
+               if (conf == NULL)
+                       return NULL;
+               if (conf->num_bss > 1) {
+                       wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
+                       hostapd_config_free(conf);
+                       return NULL;
+               }
+
+               tmp_conf = os_realloc_array(
+                       iface->conf->bss, iface->conf->num_bss + 1,
+                       sizeof(struct hostapd_bss_config *));
+               tmp_bss = os_realloc_array(iface->bss, iface->num_bss + 1,
+                                          sizeof(struct hostapd_data *));
+               if (tmp_bss)
+                       iface->bss = tmp_bss;
+               if (tmp_conf) {
+                       iface->conf->bss = tmp_conf;
+                       iface->conf->last_bss = tmp_conf[0];
+               }
+               if (tmp_bss == NULL || tmp_conf == NULL) {
+                       hostapd_config_free(conf);
+                       return NULL;
+               }
+               bss = iface->conf->bss[iface->conf->num_bss] = conf->bss[0];
+               iface->conf->num_bss++;
+
+               hapd = hostapd_alloc_bss_data(iface, iface->conf, bss);
+               if (hapd == NULL) {
+                       iface->conf->num_bss--;
+                       hostapd_config_free(conf);
+                       return NULL;
+               }
+               iface->conf->last_bss = bss;
+               iface->bss[iface->num_bss] = hapd;
+               hapd->msg_ctx = hapd;
+
+               bss_idx = iface->num_bss++;
+               conf->num_bss--;
+               conf->bss[0] = NULL;
+               hostapd_config_free(conf);
+       } else {
+               /* Add a new iface with the first BSS */
+               new_iface = iface = hostapd_init(config_fname);
+               if (!iface)
+                       return NULL;
+               os_strlcpy(iface->phy, phy, sizeof(iface->phy));
+               iface->interfaces = interfaces;
+               bss_idx = 0;
+       }
+
+       for (k = 0; k < debug; k++) {
+               if (iface->bss[bss_idx]->conf->logger_stdout_level > 0)
+                       iface->bss[bss_idx]->conf->logger_stdout_level--;
+       }
+
+       if (iface->conf->bss[bss_idx]->iface[0] == '\0' &&
+           !hostapd_drv_none(iface->bss[bss_idx])) {
+               wpa_printf(MSG_ERROR, "Interface name not specified in %s",
+                          config_fname);
+               if (new_iface)
+                       hostapd_interface_deinit_free(new_iface);
+               return NULL;
+       }
+
+       return iface;
+}
+
+
+static int hostapd_interface_init2(struct hostapd_iface *iface)
+{
+       if (iface->init_done)
+               return 0;
+
+       if (hostapd_driver_init(iface) ||
+           hostapd_setup_interface(iface))
+               return -1;
+       iface->init_done = 1;
+
+       return 0;
+}
+
+
 /**
  * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
  */
@@ -577,11 +690,13 @@ 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;
 
        if (os_program_init())
                return -1;
@@ -598,7 +713,7 @@ int main(int argc, char *argv[])
        interfaces.global_ctrl_sock = -1;
 
        for (;;) {
-               c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
+               c = getopt(argc, argv, "b:Bde:f:hKP:tvg:G:");
                if (c < 0)
                        break;
                switch (c) {
@@ -641,13 +756,23 @@ int main(int argc, char *argv[])
                        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;
                default:
                        usage();
                        break;
                }
        }
 
-       if (optind == argc && interfaces.global_iface_path == NULL)
+       if (optind == argc && interfaces.global_iface_path == NULL &&
+           num_bss_configs == 0)
                usage();
 
        wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
@@ -656,8 +781,8 @@ int main(int argc, char *argv[])
                wpa_debug_open_file(log_file);
 
        interfaces.count = argc - optind;
-       if (interfaces.count) {
-               interfaces.iface = os_calloc(interfaces.count,
+       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");
@@ -681,6 +806,46 @@ int main(int argc, char *argv[])
                }
        }
 
+       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;
+               }
+       }
+
+       for (i = 0; i < interfaces.count; i++) {
+               if (hostapd_interface_init2(interfaces.iface[i]) < 0)
+                       goto out;
+       }
+
        hostapd_global_ctrl_iface_init(&interfaces);
 
        if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
@@ -703,6 +868,8 @@ int main(int argc, char *argv[])
        if (log_file)
                wpa_debug_close_file();
 
+       os_free(bss_config);
+
        os_program_deinit();
 
        return ret;
index 7295bed..698a632 100644 (file)
@@ -438,10 +438,12 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->accept_mac);
        os_free(conf->deny_mac);
        os_free(conf->nas_identifier);
-       hostapd_config_free_radius(conf->radius->auth_servers,
-                                  conf->radius->num_auth_servers);
-       hostapd_config_free_radius(conf->radius->acct_servers,
-                                  conf->radius->num_acct_servers);
+       if (conf->radius) {
+               hostapd_config_free_radius(conf->radius->auth_servers,
+                                          conf->radius->num_auth_servers);
+               hostapd_config_free_radius(conf->radius->acct_servers,
+                                          conf->radius->num_acct_servers);
+       }
        hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
        hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
        os_free(conf->rsn_preauth_interfaces);
index d79c3e5..1afe327 100644 (file)
@@ -250,6 +250,8 @@ struct hostapd_iface {
        void *owner;
        char *config_fname;
        struct hostapd_config *conf;
+       char phy[16]; /* Name of the PHY (radio) */
+       int init_done;
 
        size_t num_bss;
        struct hostapd_data **bss;