hostapd: Add feature to start all interfaces at the same time in sync
When multiple interfaces across mutiple radios are started using a single instance of hostapd, they all come up at different times depending upon how long the ACS and HT scan take on each radio. This will result in stations (that already have the AP profile) associating with the first interfaces that comes up. For example in a dual band radio case (2G and 5G) with ACS enabled, 2G always comes up first because the ACS scan takes less time on 2G and this results in all stations associating with the 2G interface first. This feature brings up all the interfaces at the same time. The list of interfaces specified via hostapd.conf files on the command line are all marked as sync interfaces. All the interfaces are synchronized in hostapd_setup_interface_complete(). This feature is turned on with '-S' commmand line option. Signed-off-by: Srinivasa Duvvuri <sduvvuri@chromium.org>
This commit is contained in:
parent
9578413455
commit
053693d266
3 changed files with 102 additions and 10 deletions
|
@ -456,6 +456,7 @@ static void usage(void)
|
||||||
" -T = record to Linux tracing in addition to logging\n"
|
" -T = record to Linux tracing in addition to logging\n"
|
||||||
" (records all messages regardless of debug verbosity)\n"
|
" (records all messages regardless of debug verbosity)\n"
|
||||||
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
||||||
|
" -S start all the interfaces synchronously\n"
|
||||||
" -t include timestamps in some debug messages\n"
|
" -t include timestamps in some debug messages\n"
|
||||||
" -v show hostapd version\n");
|
" -v show hostapd version\n");
|
||||||
|
|
||||||
|
@ -570,6 +571,7 @@ int main(int argc, char *argv[])
|
||||||
#ifdef CONFIG_DEBUG_LINUX_TRACING
|
#ifdef CONFIG_DEBUG_LINUX_TRACING
|
||||||
int enable_trace_dbg = 0;
|
int enable_trace_dbg = 0;
|
||||||
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
||||||
|
int start_ifaces_in_sync = 0;
|
||||||
|
|
||||||
if (os_program_init())
|
if (os_program_init())
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -587,7 +589,7 @@ int main(int argc, char *argv[])
|
||||||
interfaces.global_ctrl_dst = NULL;
|
interfaces.global_ctrl_dst = NULL;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
|
c = getopt(argc, argv, "b:Bde:f:hKP:STtu:vg:G:");
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
break;
|
break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -644,6 +646,9 @@ int main(int argc, char *argv[])
|
||||||
bss_config = tmp_bss;
|
bss_config = tmp_bss;
|
||||||
bss_config[num_bss_configs++] = optarg;
|
bss_config[num_bss_configs++] = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
start_ifaces_in_sync = 1;
|
||||||
|
break;
|
||||||
#ifdef CONFIG_WPS
|
#ifdef CONFIG_WPS
|
||||||
case 'u':
|
case 'u':
|
||||||
return gen_uuid(optarg);
|
return gen_uuid(optarg);
|
||||||
|
@ -712,6 +717,8 @@ int main(int argc, char *argv[])
|
||||||
wpa_printf(MSG_ERROR, "Failed to initialize interface");
|
wpa_printf(MSG_ERROR, "Failed to initialize interface");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (start_ifaces_in_sync)
|
||||||
|
interfaces.iface[i]->need_to_start_in_sync = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and parse configuration for per-BSS files */
|
/* Allocate and parse configuration for per-BSS files */
|
||||||
|
|
|
@ -1510,15 +1510,8 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
|
||||||
#endif /* CONFIG_FST */
|
#endif /* CONFIG_FST */
|
||||||
|
|
||||||
|
|
||||||
/**
|
static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
|
||||||
* hostapd_setup_interface_complete - Complete interface setup
|
int err)
|
||||||
*
|
|
||||||
* This function is called when previous steps in the interface setup has been
|
|
||||||
* completed. This can also start operations, e.g., DFS, that will require
|
|
||||||
* additional processing before interface is ready to be enabled. Such
|
|
||||||
* operations will call this function from eloop callbacks when finished.
|
|
||||||
*/
|
|
||||||
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
|
||||||
{
|
{
|
||||||
struct hostapd_data *hapd = iface->bss[0];
|
struct hostapd_data *hapd = iface->bss[0];
|
||||||
size_t j;
|
size_t j;
|
||||||
|
@ -1720,6 +1713,89 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hostapd_setup_interface_complete - Complete interface setup
|
||||||
|
*
|
||||||
|
* This function is called when previous steps in the interface setup has been
|
||||||
|
* completed. This can also start operations, e.g., DFS, that will require
|
||||||
|
* additional processing before interface is ready to be enabled. Such
|
||||||
|
* operations will call this function from eloop callbacks when finished.
|
||||||
|
*/
|
||||||
|
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
|
||||||
|
{
|
||||||
|
struct hapd_interfaces *interfaces = iface->interfaces;
|
||||||
|
struct hostapd_data *hapd = iface->bss[0];
|
||||||
|
unsigned int i;
|
||||||
|
int not_ready_in_sync_ifaces = 0;
|
||||||
|
|
||||||
|
if (!iface->need_to_start_in_sync)
|
||||||
|
return hostapd_setup_interface_complete_sync(iface, err);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
wpa_printf(MSG_ERROR, "Interface initialization failed");
|
||||||
|
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
|
||||||
|
iface->need_to_start_in_sync = 0;
|
||||||
|
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
|
||||||
|
if (interfaces && interfaces->terminate_on_error)
|
||||||
|
eloop_terminate();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iface->ready_to_start_in_sync) {
|
||||||
|
/* Already in ready and waiting. should never happpen */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < interfaces->count; i++) {
|
||||||
|
if (interfaces->iface[i]->need_to_start_in_sync &&
|
||||||
|
!interfaces->iface[i]->ready_to_start_in_sync)
|
||||||
|
not_ready_in_sync_ifaces++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if this is the last interface, if yes then start all the other
|
||||||
|
* waiting interfaces. If not, add this interface to the waiting list.
|
||||||
|
*/
|
||||||
|
if (not_ready_in_sync_ifaces > 1 && iface->state == HAPD_IFACE_DFS) {
|
||||||
|
/*
|
||||||
|
* If this interface went through CAC, do not synchronize, just
|
||||||
|
* start immediately.
|
||||||
|
*/
|
||||||
|
iface->need_to_start_in_sync = 0;
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"%s: Finished CAC - bypass sync and start interface",
|
||||||
|
iface->bss[0]->conf->iface);
|
||||||
|
return hostapd_setup_interface_complete_sync(iface, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not_ready_in_sync_ifaces > 1) {
|
||||||
|
/* need to wait as there are other interfaces still coming up */
|
||||||
|
iface->ready_to_start_in_sync = 1;
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"%s: Interface waiting to sync with other interfaces",
|
||||||
|
iface->bss[0]->conf->iface);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"%s: Last interface to sync - starting all interfaces",
|
||||||
|
iface->bss[0]->conf->iface);
|
||||||
|
iface->need_to_start_in_sync = 0;
|
||||||
|
hostapd_setup_interface_complete_sync(iface, err);
|
||||||
|
for (i = 0; i < interfaces->count; i++) {
|
||||||
|
if (interfaces->iface[i]->need_to_start_in_sync &&
|
||||||
|
interfaces->iface[i]->ready_to_start_in_sync) {
|
||||||
|
hostapd_setup_interface_complete_sync(
|
||||||
|
interfaces->iface[i], 0);
|
||||||
|
/* Only once the interfaces are sync started */
|
||||||
|
interfaces->iface[i]->need_to_start_in_sync = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hostapd_setup_interface - Setup of an interface
|
* hostapd_setup_interface - Setup of an interface
|
||||||
* @iface: Pointer to interface data.
|
* @iface: Pointer to interface data.
|
||||||
|
|
|
@ -329,6 +329,15 @@ struct hostapd_iface {
|
||||||
*/
|
*/
|
||||||
unsigned int driver_ap_teardown:1;
|
unsigned int driver_ap_teardown:1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When set, indicates that this interface is part of list of
|
||||||
|
* interfaces that need to be started together (synchronously).
|
||||||
|
*/
|
||||||
|
unsigned int need_to_start_in_sync:1;
|
||||||
|
|
||||||
|
/* Ready to start but waiting for other interfaces to become ready. */
|
||||||
|
unsigned int ready_to_start_in_sync:1;
|
||||||
|
|
||||||
int num_ap; /* number of entries in ap_list */
|
int num_ap; /* number of entries in ap_list */
|
||||||
struct ap_info *ap_list; /* AP info list head */
|
struct ap_info *ap_list; /* AP info list head */
|
||||||
struct ap_info *ap_hash[STA_HASH_SIZE];
|
struct ap_info *ap_hash[STA_HASH_SIZE];
|
||||||
|
|
Loading…
Reference in a new issue