hostapd: Allow per-BSS (vif) configuration files
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>
This commit is contained in:
parent
ebd79f07c4
commit
5afaa067d9
3 changed files with 180 additions and 9 deletions
177
hostapd/main.c
177
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue