Retry initial 20/40 MHz co-ex scan if the driver is busy
This makes the initial OBSS scans in AP mode before starting 40 MHz BSS more robust. In addition, HT20 can be used as a backup option if none of the scans succeed. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
587d60d2b7
commit
5f0bca77a8
4 changed files with 71 additions and 5 deletions
|
@ -1355,6 +1355,7 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
|
||||||
|
|
||||||
#ifdef CONFIG_IEEE80211N
|
#ifdef CONFIG_IEEE80211N
|
||||||
#ifdef NEED_AP_MLME
|
#ifdef NEED_AP_MLME
|
||||||
|
hostapd_stop_setup_timers(iface);
|
||||||
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
|
eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
|
||||||
#endif /* NEED_AP_MLME */
|
#endif /* NEED_AP_MLME */
|
||||||
#endif /* CONFIG_IEEE80211N */
|
#endif /* CONFIG_IEEE80211N */
|
||||||
|
|
|
@ -363,6 +363,7 @@ struct hostapd_iface {
|
||||||
#endif /* CONFIG_ACS */
|
#endif /* CONFIG_ACS */
|
||||||
|
|
||||||
void (*scan_cb)(struct hostapd_iface *iface);
|
void (*scan_cb)(struct hostapd_iface *iface);
|
||||||
|
int num_ht40_scan_tries;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* hostapd.c */
|
/* hostapd.c */
|
||||||
|
|
|
@ -602,9 +602,55 @@ static void ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
|
||||||
|
{
|
||||||
|
#define HT2040_COEX_SCAN_RETRY 15
|
||||||
|
struct hostapd_iface *iface = eloop_data;
|
||||||
|
struct wpa_driver_scan_params params;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
os_memset(¶ms, 0, sizeof(params));
|
||||||
|
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
|
||||||
|
ieee80211n_scan_channels_2g4(iface, ¶ms);
|
||||||
|
else
|
||||||
|
ieee80211n_scan_channels_5g(iface, ¶ms);
|
||||||
|
|
||||||
|
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
|
||||||
|
iface->num_ht40_scan_tries++;
|
||||||
|
os_free(params.freqs);
|
||||||
|
|
||||||
|
if (ret == -EBUSY &&
|
||||||
|
iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
|
||||||
|
ret, strerror(-ret), iface->num_ht40_scan_tries);
|
||||||
|
eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
iface->scan_cb = ieee80211n_check_scan;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Failed to request a scan in device, bringing up in HT20 mode");
|
||||||
|
iface->conf->secondary_channel = 0;
|
||||||
|
iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
|
||||||
|
hostapd_setup_interface_complete(iface, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hostapd_stop_setup_timers(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
|
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
|
||||||
{
|
{
|
||||||
struct wpa_driver_scan_params params;
|
struct wpa_driver_scan_params params;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!iface->conf->secondary_channel)
|
if (!iface->conf->secondary_channel)
|
||||||
return 0; /* HT40 not used */
|
return 0; /* HT40 not used */
|
||||||
|
@ -617,13 +663,26 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
|
||||||
ieee80211n_scan_channels_2g4(iface, ¶ms);
|
ieee80211n_scan_channels_2g4(iface, ¶ms);
|
||||||
else
|
else
|
||||||
ieee80211n_scan_channels_5g(iface, ¶ms);
|
ieee80211n_scan_channels_5g(iface, ¶ms);
|
||||||
if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
|
|
||||||
wpa_printf(MSG_ERROR, "Failed to request a scan of "
|
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
|
||||||
"neighboring BSSes");
|
|
||||||
os_free(params.freqs);
|
os_free(params.freqs);
|
||||||
|
|
||||||
|
if (ret == -EBUSY) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
|
||||||
|
ret, strerror(-ret));
|
||||||
|
iface->num_ht40_scan_tries = 1;
|
||||||
|
eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
|
||||||
|
eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
wpa_printf(MSG_ERROR,
|
||||||
|
"Failed to request a scan of neighboring BSSes ret=%d (%s)",
|
||||||
|
ret, strerror(-ret));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
os_free(params.freqs);
|
|
||||||
|
|
||||||
iface->scan_cb = ieee80211n_check_scan;
|
iface->scan_cb = ieee80211n_check_scan;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -23,6 +23,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
|
||||||
int hostapd_check_ht_capab(struct hostapd_iface *iface);
|
int hostapd_check_ht_capab(struct hostapd_iface *iface);
|
||||||
int hostapd_prepare_rates(struct hostapd_iface *iface,
|
int hostapd_prepare_rates(struct hostapd_iface *iface,
|
||||||
struct hostapd_hw_modes *mode);
|
struct hostapd_hw_modes *mode);
|
||||||
|
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
|
||||||
#else /* NEED_AP_MLME */
|
#else /* NEED_AP_MLME */
|
||||||
static inline void
|
static inline void
|
||||||
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
|
||||||
|
@ -61,6 +62,10 @@ static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* NEED_AP_MLME */
|
#endif /* NEED_AP_MLME */
|
||||||
|
|
||||||
#endif /* HW_FEATURES_H */
|
#endif /* HW_FEATURES_H */
|
||||||
|
|
Loading…
Reference in a new issue