Update throughput estimate for the current BSS based on signal poll

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...

Improve this by querying the signal level of the current AP using
drv_signal_poll() instead of relying on the signal level that we get
from the scan results. Also update the throughput estimate based on the
likely more accurate values for the current association.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This commit is contained in:
Emmanuel Grumbach 2019-12-06 14:27:47 -08:00 committed by Jouni Malinen
parent ad06ac0b04
commit 7e7b23e229

View file

@ -1672,6 +1672,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 = (const void *) (bss + 1);
size_t ie_len = bss->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, static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_bss *selected,
struct wpa_ssid *ssid) struct wpa_ssid *ssid)
@ -1682,6 +1709,7 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
int to_5ghz; int to_5ghz;
int cur_level; int cur_level;
unsigned int cur_est, sel_est; unsigned int cur_est, sel_est;
struct wpa_signal_info si;
#endif /* CONFIG_NO_ROAMING */ #endif /* CONFIG_NO_ROAMING */
if (wpa_s->reassociate) if (wpa_s->reassociate)
@ -1735,6 +1763,34 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
cur_level = current_bss->level; cur_level = current_bss->level;
cur_est = current_bss->est_throughput; 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 frames of the AP we are
* associated with and the Beacon frames we hear from the same AP after
* association. This can happen, e.g., when there are two antennas that
* hear the AP very differently. If the driver chooses to hear the
* Probe Response frames 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 when 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 currently associated AP.
*/
if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
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 signal poll values for the current BSS: level=%d snr=%d est_throughput=%u",
cur_level, snr, cur_est);
}
if (selected->est_throughput > cur_est + 5000) { if (selected->est_throughput > cur_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG, wpa_dbg(wpa_s, MSG_DEBUG,
"Allow reassociation - selected BSS has better estimated throughput"); "Allow reassociation - selected BSS has better estimated throughput");