I do certainly remember the patch, I once used it and long though that it was upstreamed. While looking through it, please take a look on https://www.spinics.net/lists/hostap/msg05792.html Roaming behaviour in a dense office environment is borderline unusable unless you sit right underneath an AP with Intel AX200 NIC. It seems that background scan settings have no effect on roaming since a few major versions ago. For me, even a person passing by a corridor 10 metres away can cause a reassociation. Adding a simple hysteresis mechanism should at least solve that. On Mon, Dec 9, 2019 at 1:42 PM Otcheretianski, Andrei <andrei.otcheretianski@xxxxxxxxx> wrote: > > Hi Jouni, > > We sent this patch about a year ago and it was unanswered. > As we still get complaints about constant roaming in the described scenario, I'd like to ask to you to take another look if possible. > We'd like to get any feedback, and if you think it may work - we'll rebase and resubmit. > > Thanks, > Andrei > > > -----Original Message----- > > From: Hostap <hostap-bounces@xxxxxxxxxxxxxxxxxxx> On Behalf Of Andrei > > Otcheretianski > > Sent: Wednesday, September 05, 2018 20:45 > > To: hostap@xxxxxxxxxxxxxxxxxxx > > Cc: Grumbach, Emmanuel <emmanuel.grumbach@xxxxxxxxx> > > Subject: [PATCH 2/2] wpa_supplicant: fix the constant roaming problem > > > > From: Emmanuel Grumbach <emmanuel.grumbach@xxxxxxxxx> > > > > We saw that on certain platforms in certain places we keep switching between > > two APs and eventually get the same RSSI. > > Debugging showed that we have a very big difference between the two > > antennas. > > > > Ant A can hear AP A very well (-60) but AP B very bad (-80) Ant B can hear AP B > > very well (-60) but AP A very bad (-80) > > > > When the device associates to AP A, it'll learn to use Ant A. > > If the device uses one single antenna to receive the scan results, it may hear the > > AP it is currently associated to on the second antenna and get bad results. > > Because of that, the wpa_supplicant will roam to the other AP and the same > > scenario will repeat itself: > > > > Association to AP A (Ant A reports -60). > > Scan on Ant A: AP A: -60, AP B: -80 > > Scan on Ant B: AP A: -80, AP A: -60 ==> ROAM. > > > > Association to AP B (Ant B reports -60) > > Scan on Ant A: AP A: -60, AP B: -80 ==> ROAM > > > > Etc... > > > > Fix this by querying the signal of the current AP using > > drv_signal_poll() instead of relying on the signal that we get from the scan > > results. > > > > Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@xxxxxxxxx> > > --- > > wpa_supplicant/events.c | 83 +++++++++++++++++++++++++++++++++---- > > -- > > wpa_supplicant/scan.c | 57 +++++++++++++-------------- > > wpa_supplicant/scan.h | 4 ++ > > wpa_supplicant/wpa_supplicant_i.h | 9 +++++ > > 4 files changed, 112 insertions(+), 41 deletions(-) > > > > diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index > > 4cdca34..a814041 100644 > > --- a/wpa_supplicant/events.c > > +++ b/wpa_supplicant/events.c > > @@ -1617,6 +1617,33 @@ static void > > wpa_supplicant_rsn_preauth_scan_results( > > } > > > > > > +static int wpas_get_snr_signal_info(const struct wpa_signal_info *si) { > > + int noise = IS_5GHZ(si->frequency) ? > > + DEFAULT_NOISE_FLOOR_5GHZ : > > + DEFAULT_NOISE_FLOOR_2GHZ; > > + > > + /* > > + * Since we take the average beacon signal, we can't use > > + * the current noise measurement (average vs. snapshot), > > + * so use the default values instead. > > + */ > > + return si->avg_beacon_signal - noise; > > +} > > + > > + > > +static unsigned int > > +wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s, > > + const struct wpa_bss *bss, int snr) { > > + int rate = wpa_bss_get_max_rate(bss); > > + const u8 *ies = (void *)(bss + 1); > > + size_t ie_len = bss->ie_len ?: bss->beacon_ie_len; > > + > > + return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr); } > > + > > + > > static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, > > struct wpa_bss *selected, > > struct wpa_ssid *ssid) > > @@ -1625,7 +1652,9 @@ static int wpa_supplicant_need_to_roam(struct > > wpa_supplicant *wpa_s, #ifndef CONFIG_NO_ROAMING > > int min_diff, diff; > > int to_5ghz; > > - int cur_est, sel_est; > > + int cur_level; > > + unsigned int cur_est, sel_est; > > + struct wpa_signal_info si; > > #endif /* CONFIG_NO_ROAMING */ > > > > if (wpa_s->reassociate) > > @@ -1676,7 +1705,39 @@ static int wpa_supplicant_need_to_roam(struct > > wpa_supplicant *wpa_s, > > return 1; > > } > > > > - if (selected->est_throughput > current_bss->est_throughput + 5000) { > > + cur_level = current_bss->level; > > + cur_est = current_bss->est_throughput; > > + > > + /* > > + * Try to poll the signal from the driver since this will allow to get > > + * more accurate values. In some cases, there can be big differences > > + * between the RSSI of the probe response of the AP we are associated > > + * to and the beacons we hear from the same AP after association. This > > + * can happen when there are two antennas that hear the AP very > > + * differently. If the driver chooses to hear the probe responses > > + * during the scan on the "bad" antenna because it wants to save power, > > + * but knows to choose the other antenna after association, we will > > + * hear our AP with a low RSSI as part of the scan, even we can hear > > + * it decently on the other antenna. > > + * To cope with this, ask the driver to teach us how it hears the AP. > > + * Also, the scan results may be a bit old, since we can very quickly > > + * get fresh information about our own AP, do that. > > + */ > > + if (!wpa_drv_signal_poll(wpa_s, &si)) { > > + if (si.avg_beacon_signal) { > > + int snr = wpas_get_snr_signal_info(&si); > > + > > + cur_level = si.avg_beacon_signal; > > + cur_est = > > wpas_get_est_throughput_from_bss_snr(wpa_s, > > + > > current_bss, > > + snr); > > + wpa_dbg(wpa_s, MSG_DEBUG, > > + "Using poll to get accurate level and est > > throughput: level=%d snr=%d est_throughput=%u", > > + cur_level, snr, cur_est); > > + } > > + } > > + > > + if (selected->est_throughput > cur_est + 5000) { > > wpa_dbg(wpa_s, MSG_DEBUG, > > "Allow reassociation - selected BSS has better > > estimated throughput"); > > return 1; > > @@ -1684,30 +1745,28 @@ static int wpa_supplicant_need_to_roam(struct > > wpa_supplicant *wpa_s, > > > > to_5ghz = selected->freq > 4000 && current_bss->freq < 4000; > > > > - if (current_bss->level < 0 && > > - current_bss->level > selected->level + to_5ghz * 2) { > > + if (cur_level < 0 && cur_level > selected->level + to_5ghz * 2) { > > wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has > > better " > > "signal level"); > > return 0; > > } > > > > - if (current_bss->est_throughput > selected->est_throughput + 5000) { > > + if (cur_est > selected->est_throughput + 5000) { > > wpa_dbg(wpa_s, MSG_DEBUG, > > "Skip roam - Current BSS has better estimated > > throughput"); > > return 0; > > } > > > > - cur_est = current_bss->est_throughput; > > sel_est = selected->est_throughput; > > min_diff = 2; > > - if (current_bss->level < 0) { > > - if (current_bss->level < -85) > > + if (cur_level < 0) { > > + if (cur_level < -85) > > min_diff = 1; > > - else if (current_bss->level < -80) > > + else if (cur_level < -80) > > min_diff = 2; > > - else if (current_bss->level < -75) > > + else if (cur_level < -75) > > min_diff = 3; > > - else if (current_bss->level < -70) > > + else if (cur_level < -70) > > min_diff = 4; > > else > > min_diff = 5; > > @@ -1736,7 +1795,7 @@ static int wpa_supplicant_need_to_roam(struct > > wpa_supplicant *wpa_s, > > else > > min_diff = 0; > > } > > - diff = abs(current_bss->level - selected->level); > > + diff = abs(cur_level - selected->level); > > if (diff < min_diff) { > > wpa_dbg(wpa_s, MSG_DEBUG, > > "Skip roam - too small difference in signal level (%d < > > %d)", diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index > > 56d53fb..030e7ac 100644 > > --- a/wpa_supplicant/scan.c > > +++ b/wpa_supplicant/scan.c > > @@ -1869,8 +1869,6 @@ struct wpabuf * > > wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, > > */ > > #define GREAT_SNR 25 > > > > -#define IS_5GHZ(n) (n > 4000) > > - > > /* Compare function for sorting scan results. Return >0 if @b is considered > > * better. */ > > static int wpa_scan_result_compar(const void *a, const void *b) @@ -2078,14 > > +2076,6 @@ void filter_scan_res(struct wpa_supplicant *wpa_s, } > > > > > > -/* > > - * Noise floor values to use when we have signal strength > > - * measurements, but no noise floor measurements. These values were > > - * measured in an office environment with many APs. > > - */ > > -#define DEFAULT_NOISE_FLOOR_2GHZ (-89) > > -#define DEFAULT_NOISE_FLOOR_5GHZ (-92) > > - > > void scan_snr(struct wpa_scan_res *res) { > > if (res->flags & WPA_SCAN_NOISE_INVALID) { @@ -2169,21 +2159,13 > > @@ static unsigned int max_vht80_rate(int snr) > > return 390000; /* VHT80 MCS9 */ > > } > > > > - > > -void scan_est_throughput(struct wpa_supplicant *wpa_s, > > - struct wpa_scan_res *res) > > +unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, > > + const u8 *ies, size_t ies_len, int rate, > > + int snr) > > { > > enum local_hw_capab capab = wpa_s->hw_capab; > > - int rate; /* max legacy rate in 500 kb/s units */ > > - const u8 *ie; > > unsigned int est, tmp; > > - int snr = res->snr; > > - > > - if (res->est_throughput) > > - return; > > - > > - /* Get maximum legacy rate */ > > - rate = wpa_scan_get_max_rate(res); > > + const u8 *ie; > > > > /* Limit based on estimated SNR */ > > if (rate > 1 * 2 && snr < 1) > > @@ -2209,7 +2191,7 @@ void scan_est_throughput(struct wpa_supplicant > > *wpa_s, > > est = rate * 500; > > > > if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == > > CAPAB_VHT) { > > - ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP); > > + ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP); > > if (ie) { > > tmp = max_ht20_rate(snr); > > if (tmp > est) > > @@ -2218,7 +2200,7 @@ void scan_est_throughput(struct wpa_supplicant > > *wpa_s, > > } > > > > if (capab == CAPAB_HT40 || capab == CAPAB_VHT) { > > - ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION); > > + ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); > > if (ie && ie[1] >= 2 && > > (ie[3] & > > HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { > > tmp = max_ht40_rate(snr); > > @@ -2229,13 +2211,13 @@ void scan_est_throughput(struct wpa_supplicant > > *wpa_s, > > > > if (capab == CAPAB_VHT) { > > /* Use +1 to assume VHT is always faster than HT */ > > - ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP); > > + ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP); > > if (ie) { > > tmp = max_ht20_rate(snr) + 1; > > if (tmp > est) > > est = tmp; > > > > - ie = wpa_scan_get_ie(res, > > WLAN_EID_HT_OPERATION); > > + ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); > > if (ie && ie[1] >= 2 && > > (ie[3] & > > > > HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { @@ -2244,7 +2226,7 > > @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, > > est = tmp; > > } > > > > - ie = wpa_scan_get_ie(res, > > WLAN_EID_VHT_OPERATION); > > + ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); > > if (ie && ie[1] >= 1 && > > (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) { > > tmp = max_vht80_rate(snr) + 1; > > @@ -2254,9 +2236,26 @@ void scan_est_throughput(struct wpa_supplicant > > *wpa_s, > > } > > } > > > > - /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ > > + return est; > > +} > > + > > +void scan_est_throughput(struct wpa_supplicant *wpa_s, > > + struct wpa_scan_res *res) > > +{ > > + int rate; /* max legacy rate in 500 kb/s units */ > > + int snr = res->snr; > > + const u8 *ies = (void *)(res + 1); > > > > - res->est_throughput = est; > > + if (res->est_throughput) > > + return; > > + > > + /* Get maximum legacy rate */ > > + rate = wpa_scan_get_max_rate(res); > > + > > + res->est_throughput = > > + wpas_get_est_tpt(wpa_s, ies, res->ie_len, rate, snr); > > + > > + /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ > > } > > > > > > diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index > > 2aa0a8b..204332a 100644 > > --- a/wpa_supplicant/scan.h > > +++ b/wpa_supplicant/scan.h > > @@ -58,6 +58,10 @@ void filter_scan_res(struct wpa_supplicant *wpa_s, void > > scan_snr(struct wpa_scan_res *res); void scan_est_throughput(struct > > wpa_supplicant *wpa_s, > > struct wpa_scan_res *res); > > + > > +unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, > > + const u8 *ies, size_t ies_len, int rate, > > + int snr); > > void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s); > > > > #endif /* SCAN_H */ > > diff --git a/wpa_supplicant/wpa_supplicant_i.h > > b/wpa_supplicant/wpa_supplicant_i.h > > index 9b8d1fa..9255b2c 100644 > > --- a/wpa_supplicant/wpa_supplicant_i.h > > +++ b/wpa_supplicant/wpa_supplicant_i.h > > @@ -1487,4 +1487,13 @@ int > > wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, int > > wpa_is_fils_supported(struct wpa_supplicant *wpa_s); int > > wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s); > > > > +/* > > + * Noise floor values to use when we have signal strength > > + * measurements, but no noise floor measurements. These values were > > + * measured in an office environment with many APs. > > + */ > > +#define DEFAULT_NOISE_FLOOR_2GHZ (-89) > > +#define DEFAULT_NOISE_FLOOR_5GHZ (-92) > > +#define IS_5GHZ(n) (n > 4000) > > + > > #endif /* WPA_SUPPLICANT_I_H */ > > -- > > 2.7.4 > > > > > > _______________________________________________ > > Hostap mailing list > > Hostap@xxxxxxxxxxxxxxxxxxx > > http://lists.infradead.org/mailman/listinfo/hostap > > _______________________________________________ > Hostap mailing list > Hostap@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/hostap _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap