From cf65c58fd4be282c92a221ff293c15fb6a73f5e5 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 4 Mar 2014 16:50:13 +0200 Subject: [PATCH] UPSTREAM: cfg80211/mac80211: ignore signal if the frame was heard on wrong channel On 2.4Ghz band, the channels overlap since the delta between different channels is 5Mhz while the width of the receiver is 20Mhz (at least). This means that we can hear beacons or probe responses from adjacent channels. These frames will have a significant lower RSSI which will feed all kinds of logic with inaccurate data. An obvious example is the roaming algorithm that will think our AP is getting weak and will try to move to another AP. In order to avoid this, update the signal only if the frame has been heard on the same channel as the one advertised by the AP in its DS / HT IEs. We refrain from updating the values only if the AP is already in the BSS list so that we will still have a valid (but inaccurate) value if the AP was heard on an adjacent channel only. To achieve this, stop taking the channel from DS / HT IEs in mac80211. The DS / HT IEs is taken into account to discard the frame if it was received on a disabled channel. This can happen due to the same phenomenon: the frame is sent on channel 12, but heard on channel 11 while channel 12 can be disabled on certain devices. Since this check is done in cfg80211, stop even checking this in mac80211. Cherry-picked from commit 3afc2167f60a3 upstream. BUG=scanning may produce cross-channel RX with invalid RSSI TEST=scan and check that RSSI doesn't wildly fluctuate Change-Id: Id913e83de08436f879e6b259965542173f362606 Signed-off-by: Emmanuel Grumbach [remove unused rx_freq variable] Signed-off-by: Johannes Berg Reviewed-on: https://chromium-review.googlesource.com/201571 Reviewed-by: Paul Stewart Reviewed-on: https://chromium-review.googlesource.com/225171 --- include/wireless-3.8/net/cfg80211.h | 8 ++++---- net/mac80211-3.8/ibss.c | 9 +-------- net/mac80211-3.8/mlme.c | 9 +-------- net/wireless-3.8/scan.c | 28 +++++++++++++++++++--------- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/include/wireless-3.8/net/cfg80211.h b/include/wireless-3.8/net/cfg80211.h index 47f9ffc0bce6..725707d9c8a0 100644 --- a/include/wireless-3.8/net/cfg80211.h +++ b/include/wireless-3.8/net/cfg80211.h @@ -3050,7 +3050,7 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame * * @wiphy: the wiphy reporting the BSS - * @channel: The channel the frame was received on + * @rx_channel: The channel the frame was received on * @mgmt: the management frame (probe response or beacon) * @len: length of the management frame * @signal: the signal strength, type depends on the wiphy's signal_type @@ -3063,7 +3063,7 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); */ struct cfg80211_bss * __must_check cfg80211_inform_bss_frame(struct wiphy *wiphy, - struct ieee80211_channel *channel, + struct ieee80211_channel *rx_channel, struct ieee80211_mgmt *mgmt, size_t len, s32 signal, gfp_t gfp); @@ -3071,7 +3071,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, * cfg80211_inform_bss - inform cfg80211 of a new BSS * * @wiphy: the wiphy reporting the BSS - * @channel: The channel the frame was received on + * @rx_channel: The channel the frame was received on * @bssid: the BSSID of the BSS * @tsf: the TSF sent by the peer in the beacon/probe response (or 0) * @capability: the capability field sent by the peer @@ -3088,7 +3088,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, */ struct cfg80211_bss * __must_check cfg80211_inform_bss(struct wiphy *wiphy, - struct ieee80211_channel *channel, + struct ieee80211_channel *rx_channel, const u8 *bssid, u64 tsf, u16 capability, u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp); diff --git a/net/mac80211-3.8/ibss.c b/net/mac80211-3.8/ibss.c index 25109e0c61f9..429318058b1c 100644 --- a/net/mac80211-3.8/ibss.c +++ b/net/mac80211-3.8/ibss.c @@ -438,7 +438,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bool beacon) { struct ieee80211_local *local = sdata->local; - int freq; struct cfg80211_bss *cbss; struct ieee80211_bss *bss; struct sta_info *sta; @@ -449,13 +448,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; bool rates_updated = false; - if (elems->ds_params && elems->ds_params_len == 1) - freq = ieee80211_channel_to_frequency(elems->ds_params[0], - band); - else - freq = rx_status->freq; - - channel = ieee80211_get_channel(local->hw.wiphy, freq); + channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; diff --git a/net/mac80211-3.8/mlme.c b/net/mac80211-3.8/mlme.c index 490f96e33e67..d6d83afee99e 100644 --- a/net/mac80211-3.8/mlme.c +++ b/net/mac80211-3.8/mlme.c @@ -2338,7 +2338,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bool beacon) { struct ieee80211_local *local = sdata->local; - int freq; struct ieee80211_bss *bss; struct ieee80211_channel *channel; bool need_ps = false; @@ -2359,13 +2358,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, } } - if (elems->ds_params && elems->ds_params_len == 1) - freq = ieee80211_channel_to_frequency(elems->ds_params[0], - rx_status->band); - else - freq = rx_status->freq; - - channel = ieee80211_get_channel(local->hw.wiphy, freq); + channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) return; diff --git a/net/wireless-3.8/scan.c b/net/wireless-3.8/scan.c index 5e6a0f937ee1..9c15ef995ce4 100644 --- a/net/wireless-3.8/scan.c +++ b/net/wireless-3.8/scan.c @@ -675,7 +675,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, static struct cfg80211_internal_bss * cfg80211_bss_update(struct cfg80211_registered_device *dev, - struct cfg80211_internal_bss *tmp) + struct cfg80211_internal_bss *tmp, + bool signal_valid) { struct cfg80211_internal_bss *found = NULL; @@ -695,7 +696,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, if (found) { found->pub.beacon_interval = tmp->pub.beacon_interval; - found->pub.signal = tmp->pub.signal; + /* + * don't update the signal if beacon was heard on + * adjacent channel. + */ + if (signal_valid) + found->pub.signal = tmp->pub.signal; found->pub.capability = tmp->pub.capability; found->ts = tmp->ts; @@ -857,12 +863,13 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, struct cfg80211_bss* cfg80211_inform_bss(struct wiphy *wiphy, - struct ieee80211_channel *channel, + struct ieee80211_channel *rx_channel, const u8 *bssid, u64 tsf, u16 capability, u16 beacon_interval, const u8 *ie, size_t ielen, s32 signal, gfp_t gfp) { struct cfg80211_bss_ies *ies; + struct ieee80211_channel *channel; struct cfg80211_internal_bss tmp = {}, *res; if (WARN_ON(!wiphy)) @@ -872,7 +879,7 @@ cfg80211_inform_bss(struct wiphy *wiphy, (signal < 0 || signal > 100))) return NULL; - channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel); + channel = cfg80211_get_bss_channel(wiphy, ie, ielen, rx_channel); if (!channel) return NULL; @@ -899,7 +906,8 @@ cfg80211_inform_bss(struct wiphy *wiphy, rcu_assign_pointer(tmp.pub.beacon_ies, ies); rcu_assign_pointer(tmp.pub.ies, ies); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); + res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp, + rx_channel == channel); if (!res) return NULL; @@ -914,19 +922,20 @@ EXPORT_SYMBOL(cfg80211_inform_bss); struct cfg80211_bss * cfg80211_inform_bss_frame(struct wiphy *wiphy, - struct ieee80211_channel *channel, + struct ieee80211_channel *rx_channel, struct ieee80211_mgmt *mgmt, size_t len, s32 signal, gfp_t gfp) { struct cfg80211_internal_bss tmp = {}, *res; struct cfg80211_bss_ies *ies; + struct ieee80211_channel *channel; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != offsetof(struct ieee80211_mgmt, u.beacon.variable)); - trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal); + trace_cfg80211_inform_bss_frame(wiphy, rx_channel, mgmt, len, signal); if (WARN_ON(!mgmt)) return NULL; @@ -942,7 +951,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, return NULL; channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, - ielen, channel); + ielen, rx_channel); if (!channel) return NULL; @@ -965,7 +974,8 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); - res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); + res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp, + rx_channel == channel); if (!res) return NULL;