diff --git a/hostapd/main.c b/hostapd/main.c index 6c7406af4..72b1d91d0 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -456,6 +456,7 @@ static void usage(void) " -T = record to Linux tracing in addition to logging\n" " (records all messages regardless of debug verbosity)\n" #endif /* CONFIG_DEBUG_LINUX_TRACING */ + " -S start all the interfaces synchronously\n" " -t include timestamps in some debug messages\n" " -v show hostapd version\n"); @@ -570,6 +571,7 @@ int main(int argc, char *argv[]) #ifdef CONFIG_DEBUG_LINUX_TRACING int enable_trace_dbg = 0; #endif /* CONFIG_DEBUG_LINUX_TRACING */ + int start_ifaces_in_sync = 0; if (os_program_init()) return -1; @@ -587,7 +589,7 @@ int main(int argc, char *argv[]) interfaces.global_ctrl_dst = NULL; 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) break; switch (c) { @@ -644,6 +646,9 @@ int main(int argc, char *argv[]) bss_config = tmp_bss; bss_config[num_bss_configs++] = optarg; break; + case 'S': + start_ifaces_in_sync = 1; + break; #ifdef CONFIG_WPS case 'u': return gen_uuid(optarg); @@ -712,6 +717,8 @@ int main(int argc, char *argv[]) wpa_printf(MSG_ERROR, "Failed to initialize interface"); goto out; } + if (start_ifaces_in_sync) + interfaces.iface[i]->need_to_start_in_sync = 1; } /* Allocate and parse configuration for per-BSS files */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 5b95989cf..b10b454e3 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1510,15 +1510,8 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, #endif /* CONFIG_FST */ -/** - * 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) +static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, + int err) { struct hostapd_data *hapd = iface->bss[0]; 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 * @iface: Pointer to interface data. diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 024d25fcb..8161a5933 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -329,6 +329,15 @@ struct hostapd_iface { */ 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 */ struct ap_info *ap_list; /* AP info list head */ struct ap_info *ap_hash[STA_HASH_SIZE];