{
int min_diff, diff;
int to_5ghz, to_6ghz;
- int cur_level;
+ int cur_level, sel_level;
unsigned int cur_est, sel_est;
struct wpa_signal_info si;
int cur_snr = 0;
int ret = 0;
+ const u8 *cur_ies = wpa_bss_ie_ptr(current_bss);
+ const u8 *sel_ies = wpa_bss_ie_ptr(selected);
+ size_t cur_ie_len = current_bss->ie_len ? current_bss->ie_len :
+ current_bss->beacon_ie_len;
+ size_t sel_ie_len = selected->ie_len ? selected->ie_len :
+ selected->beacon_ie_len;
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR
return 1;
}
- cur_level = current_bss->level;
- cur_est = current_bss->est_throughput;
- sel_est = selected->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
*/
if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
(si.data.avg_beacon_signal || si.data.avg_signal)) {
+ /*
+ * Normalize avg_signal to the RSSI over 20 MHz, as the
+ * throughput is estimated based on the RSSI over 20 MHz
+ */
cur_level = si.data.avg_beacon_signal ?
- si.data.avg_beacon_signal : si.data.avg_signal;
+ si.data.avg_beacon_signal :
+ (si.data.avg_signal -
+ wpas_channel_width_rssi_bump(cur_ies, cur_ie_len,
+ si.chanwidth));
cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level,
si.current_noise);
wpa_dbg(wpa_s, MSG_DEBUG,
"Using signal poll values for the current BSS: level=%d snr=%d est_throughput=%u",
cur_level, cur_snr, cur_est);
+ } else {
+ /* Level and SNR are measured over 20 MHz channel */
+ cur_level = current_bss->level;
+ cur_snr = current_bss->snr;
+ cur_est = current_bss->est_throughput;
}
+ /* Adjust the SNR of BSSes based on the channel width. */
+ cur_level += wpas_channel_width_rssi_bump(cur_ies, cur_ie_len,
+ current_bss->max_cw);
+ cur_snr = wpas_adjust_snr_by_chanwidth(cur_ies, cur_ie_len,
+ current_bss->max_cw, cur_snr);
+
+ sel_est = selected->est_throughput;
+ sel_level = selected->level +
+ wpas_channel_width_rssi_bump(sel_ies, sel_ie_len,
+ selected->max_cw);
+
if (sel_est > cur_est + 5000) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Allow reassociation - selected BSS has better estimated throughput");
!is_6ghz_freq(current_bss->freq);
if (cur_level < 0 &&
- cur_level > selected->level + to_5ghz * 2 + to_6ghz * 2 &&
+ cur_level > sel_level + to_5ghz * 2 + to_6ghz * 2 &&
sel_est < cur_est * 1.2) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
"signal level");
min_diff -= 2;
if (to_6ghz)
min_diff -= 2;
- diff = selected->level - cur_level;
+ diff = sel_level - cur_level;
if (diff < min_diff) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Skip roam - too small difference in signal level (%d < %d)",
MAC2STR(current_bss->bssid),
current_bss->freq, cur_level, cur_est,
MAC2STR(selected->bssid),
- selected->freq, selected->level, sel_est);
+ selected->freq, sel_level, sel_est);
return ret;
}
struct hostapd_hw_modes *hw_mode;
unsigned int est, tmp;
const u8 *ie;
+ /*
+ * No need to apply a bump to the noise here because the
+ * minsnr_bitrate_entry tables are based on MCS tables where this has
+ * been taken into account.
+ */
+ int adjusted_snr;
/* Limit based on estimated SNR */
if (rate > 1 * 2 && snr < 1)
if (ie && ie[1] >= 2 &&
(ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
*max_cw = CHAN_WIDTH_40;
- tmp = max_ht40_rate(snr, false);
+ adjusted_snr = snr +
+ wpas_channel_width_rssi_bump(ies, ies_len,
+ CHAN_WIDTH_40);
+ tmp = max_ht40_rate(adjusted_snr, false);
if (tmp > est)
est = tmp;
}
(ie[3] &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
*max_cw = CHAN_WIDTH_40;
- tmp = max_ht40_rate(snr, true) + 1;
+ adjusted_snr = snr +
+ wpas_channel_width_rssi_bump(
+ ies, ies_len, CHAN_WIDTH_40);
+ tmp = max_ht40_rate(adjusted_snr, true) + 1;
if (tmp > est)
est = tmp;
}
if (vht80) {
*max_cw = CHAN_WIDTH_80;
- tmp = max_vht80_rate(snr) + 1;
+ adjusted_snr = snr +
+ wpas_channel_width_rssi_bump(
+ ies, ies_len, CHAN_WIDTH_80);
+ tmp = max_vht80_rate(adjusted_snr) + 1;
if (tmp > est)
est = tmp;
}
(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
*max_cw = CHAN_WIDTH_160;
- tmp = max_vht160_rate(snr) + 1;
+ adjusted_snr = snr +
+ wpas_channel_width_rssi_bump(
+ ies, ies_len, CHAN_WIDTH_160);
+ tmp = max_vht160_rate(adjusted_snr) + 1;
if (tmp > est)
est = tmp;
}
if (*max_cw == CHAN_WIDTH_UNKNOWN ||
*max_cw < CHAN_WIDTH_40)
*max_cw = CHAN_WIDTH_40;
- tmp = max_he_eht_rate(he40_table, snr, is_eht) + boost;
+ adjusted_snr = snr + wpas_channel_width_rssi_bump(
+ ies, ies_len, CHAN_WIDTH_40);
+ tmp = max_he_eht_rate(he40_table, adjusted_snr,
+ is_eht) + boost;
if (tmp > est)
est = tmp;
}
if (*max_cw == CHAN_WIDTH_UNKNOWN ||
*max_cw < CHAN_WIDTH_80)
*max_cw = CHAN_WIDTH_80;
- tmp = max_he_eht_rate(he80_table, snr, is_eht) + boost;
+ adjusted_snr = snr + wpas_channel_width_rssi_bump(
+ ies, ies_len, CHAN_WIDTH_80);
+ tmp = max_he_eht_rate(he80_table, adjusted_snr,
+ is_eht) + boost;
if (tmp > est)
est = tmp;
}
if (*max_cw == CHAN_WIDTH_UNKNOWN ||
*max_cw < CHAN_WIDTH_160)
*max_cw = CHAN_WIDTH_160;
- tmp = max_he_eht_rate(he160_table, snr, is_eht) + boost;
+ adjusted_snr = snr + wpas_channel_width_rssi_bump(
+ ies, ies_len, CHAN_WIDTH_160);
+ tmp = max_he_eht_rate(he160_table, adjusted_snr,
+ is_eht) + boost;
if (tmp > est)
est = tmp;
}
if (*max_cw == CHAN_WIDTH_UNKNOWN ||
*max_cw < CHAN_WIDTH_320)
*max_cw = CHAN_WIDTH_320;
- tmp = max_he_eht_rate(eht320_table, snr, true);
+ adjusted_snr = snr + wpas_channel_width_rssi_bump(
+ ies, ies_len, CHAN_WIDTH_320);
+ tmp = max_he_eht_rate(eht320_table, adjusted_snr, true);
if (tmp > est)
est = tmp;
}