diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 33988598a..391d77460 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1355,6 +1355,7 @@ void hostapd_interface_deinit(struct hostapd_iface *iface) #ifdef CONFIG_IEEE80211N #ifdef NEED_AP_MLME + hostapd_stop_setup_timers(iface); eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL); #endif /* NEED_AP_MLME */ #endif /* CONFIG_IEEE80211N */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index dba9bb29c..bd85c54a2 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -363,6 +363,7 @@ struct hostapd_iface { #endif /* CONFIG_ACS */ void (*scan_cb)(struct hostapd_iface *iface); + int num_ht40_scan_tries; }; /* hostapd.c */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 43cb243b9..b36183452 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.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) { struct wpa_driver_scan_params params; + int ret; if (!iface->conf->secondary_channel) return 0; /* HT40 not used */ @@ -617,13 +663,26 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) ieee80211n_scan_channels_2g4(iface, ¶ms); else 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 " - "neighboring BSSes"); - os_free(params.freqs); + + ret = hostapd_driver_scan(iface->bss[0], ¶ms); + 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; } - os_free(params.freqs); iface->scan_cb = ieee80211n_check_scan; return 1; diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index 783ae5e12..0f67ab8e5 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -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_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode); +void hostapd_stop_setup_timers(struct hostapd_iface *iface); #else /* NEED_AP_MLME */ static inline void 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; } +static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface) +{ +} + #endif /* NEED_AP_MLME */ #endif /* HW_FEATURES_H */