ACS: Handle scan start request failure with error code -EBUSY

Currently, if ACS scan request fails, states are cleared and returned.
However, in case of MLO, there is a possibilty of getting return value
of -EBUSY. In this case, ACS can retry the scan request after some time
similary to the HT40 scan.

Hence, retry the scan after 5 seconds if -EBUSY is returned. Maximum of
15 re-attempts are made before giving up.

Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
Co-developed-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
This commit is contained in:
Harshitha Prem 2024-04-22 16:49:06 +05:30 committed by Jouni Malinen
parent 3cf7bf68f4
commit 3e52a90d34
3 changed files with 56 additions and 9 deletions

View file

@ -12,6 +12,7 @@
#include "utils/common.h" #include "utils/common.h"
#include "utils/list.h" #include "utils/list.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h" #include "common/ieee802_11_defs.h"
#include "common/hw_features_common.h" #include "common/hw_features_common.h"
#include "common/wpa_ctrl.h" #include "common/wpa_ctrl.h"
@ -307,6 +308,7 @@ static const struct bw_item *bw_desc[] = {
static int acs_request_scan(struct hostapd_iface *iface); static int acs_request_scan(struct hostapd_iface *iface);
static int acs_survey_is_sufficient(struct freq_survey *survey); static int acs_survey_is_sufficient(struct freq_survey *survey);
static void acs_scan_retry(void *eloop_data, void *user_data);
static void acs_clean_chan_surveys(struct hostapd_channel_data *chan) static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
@ -352,6 +354,8 @@ void acs_cleanup(struct hostapd_iface *iface)
iface->chans_surveyed = 0; iface->chans_surveyed = 0;
iface->acs_num_completed_scans = 0; iface->acs_num_completed_scans = 0;
iface->acs_num_retries = 0;
eloop_cancel_timeout(acs_scan_retry, iface, NULL);
} }
@ -1317,6 +1321,7 @@ static void acs_scan_complete(struct hostapd_iface *iface)
int err; int err;
iface->scan_cb = NULL; iface->scan_cb = NULL;
iface->acs_num_retries = 0;
wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)", wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)",
iface->conf->acs_num_scans); iface->conf->acs_num_scans);
@ -1329,7 +1334,7 @@ static void acs_scan_complete(struct hostapd_iface *iface)
if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) { if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) {
err = acs_request_scan(iface); err = acs_request_scan(iface);
if (err) { if (err && err != -EBUSY) {
wpa_printf(MSG_ERROR, "ACS: Failed to request scan"); wpa_printf(MSG_ERROR, "ACS: Failed to request scan");
goto fail; goto fail;
} }
@ -1382,7 +1387,7 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface,
static int acs_request_scan(struct hostapd_iface *iface) static int acs_request_scan(struct hostapd_iface *iface)
{ {
struct wpa_driver_scan_params params; struct wpa_driver_scan_params params;
int i, *freq; int i, *freq, ret;
int num_channels; int num_channels;
struct hostapd_hw_modes *mode; struct hostapd_hw_modes *mode;
@ -1415,21 +1420,59 @@ static int acs_request_scan(struct hostapd_iface *iface)
return -1; return -1;
} }
iface->scan_cb = acs_scan_complete; if (!iface->acs_num_retries)
wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d", wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d",
iface->acs_num_completed_scans + 1, iface->acs_num_completed_scans + 1,
iface->conf->acs_num_scans); iface->conf->acs_num_scans);
else
wpa_printf(MSG_DEBUG,
"ACS: Re-try scanning attempt %d (%d / %d)",
iface->acs_num_retries,
iface->acs_num_completed_scans + 1,
iface->conf->acs_num_scans);
if (hostapd_driver_scan(iface->bss[0], &params) < 0) { ret = hostapd_driver_scan(iface->bss[0], &params);
wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
acs_cleanup(iface);
os_free(params.freqs); os_free(params.freqs);
if (ret == -EBUSY) {
iface->acs_num_retries++;
if (iface->acs_num_retries >= ACS_SCAN_RETRY_MAX_COUNT) {
wpa_printf(MSG_ERROR,
"ACS: Failed to request initial scan (all re-attempts failed)");
acs_fail(iface);
return -1; return -1;
} }
os_free(params.freqs); wpa_printf(MSG_INFO,
"Failed to request acs scan ret=%d (%s) - try to scan after %d seconds",
ret, strerror(-ret), ACS_SCAN_RETRY_INTERVAL);
eloop_cancel_timeout(acs_scan_retry, iface, NULL);
eloop_register_timeout(ACS_SCAN_RETRY_INTERVAL, 0,
acs_scan_retry, iface, NULL);
return 0; return 0;
}
if (ret < 0) {
wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan");
acs_cleanup(iface);
return -1;
}
iface->scan_cb = acs_scan_complete;
return 0;
}
static void acs_scan_retry(void *eloop_data, void *user_data)
{
struct hostapd_iface *iface = eloop_data;
if (acs_request_scan(iface)) {
wpa_printf(MSG_ERROR,
"ACS: Failed to request re-try of initial scan");
acs_fail(iface);
}
} }

View file

@ -15,6 +15,9 @@
enum hostapd_chan_status acs_init(struct hostapd_iface *iface); enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
void acs_cleanup(struct hostapd_iface *iface); void acs_cleanup(struct hostapd_iface *iface);
#define ACS_SCAN_RETRY_MAX_COUNT 15
#define ACS_SCAN_RETRY_INTERVAL 5
#else /* CONFIG_ACS */ #else /* CONFIG_ACS */
static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface) static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface)

View file

@ -682,6 +682,7 @@ struct hostapd_iface {
#ifdef CONFIG_ACS #ifdef CONFIG_ACS
unsigned int acs_num_completed_scans; unsigned int acs_num_completed_scans;
unsigned int acs_num_retries;
#endif /* CONFIG_ACS */ #endif /* CONFIG_ACS */
void (*scan_cb)(struct hostapd_iface *iface); void (*scan_cb)(struct hostapd_iface *iface);