diff --git a/hostapd/main.c b/hostapd/main.c index ab75b5fe6..23eef1a58 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -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; diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 7295bedb6..698a63206 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -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); diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index d79c3e53d..1afe327f2 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -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;