aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-03-04 09:50:13 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-03-19 16:29:56 -0400
commit3afc2167f60a327a2c1e1e2600ef209a3c2b75b7 (patch)
tree2588b9503edc6b574126f54eee64ccb00aceb863 /net
parent2316d7b0544c4601cc852c801c93d1f451378740 (diff)
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. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> [remove unused rx_freq variable] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ibss.c12
-rw-r--r--net/mac80211/mlme.c12
-rw-r--r--net/wireless/scan.c28
3 files changed, 23 insertions, 29 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index e458ca0dffec..06d28787945b 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -991,7 +991,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
991 struct ieee802_11_elems *elems) 991 struct ieee802_11_elems *elems)
992{ 992{
993 struct ieee80211_local *local = sdata->local; 993 struct ieee80211_local *local = sdata->local;
994 int freq;
995 struct cfg80211_bss *cbss; 994 struct cfg80211_bss *cbss;
996 struct ieee80211_bss *bss; 995 struct ieee80211_bss *bss;
997 struct sta_info *sta; 996 struct sta_info *sta;
@@ -1003,15 +1002,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
1003 struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; 1002 struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
1004 bool rates_updated = false; 1003 bool rates_updated = false;
1005 1004
1006 if (elems->ds_params) 1005 channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
1007 freq = ieee80211_channel_to_frequency(elems->ds_params[0], 1006 if (!channel)
1008 band);
1009 else
1010 freq = rx_status->freq;
1011
1012 channel = ieee80211_get_channel(local->hw.wiphy, freq);
1013
1014 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
1015 return; 1007 return;
1016 1008
1017 if (sdata->vif.type == NL80211_IFTYPE_ADHOC && 1009 if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6d24e6c8f320..bbc2175e4bfe 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2760,21 +2760,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
2760 struct ieee802_11_elems *elems) 2760 struct ieee802_11_elems *elems)
2761{ 2761{
2762 struct ieee80211_local *local = sdata->local; 2762 struct ieee80211_local *local = sdata->local;
2763 int freq;
2764 struct ieee80211_bss *bss; 2763 struct ieee80211_bss *bss;
2765 struct ieee80211_channel *channel; 2764 struct ieee80211_channel *channel;
2766 2765
2767 sdata_assert_lock(sdata); 2766 sdata_assert_lock(sdata);
2768 2767
2769 if (elems->ds_params) 2768 channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
2770 freq = ieee80211_channel_to_frequency(elems->ds_params[0], 2769 if (!channel)
2771 rx_status->band);
2772 else
2773 freq = rx_status->freq;
2774
2775 channel = ieee80211_get_channel(local->hw.wiphy, freq);
2776
2777 if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
2778 return; 2770 return;
2779 2771
2780 bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, 2772 bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index d1ed4aebbbb7..7d9f5264a63c 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -680,7 +680,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
680/* Returned bss is reference counted and must be cleaned up appropriately. */ 680/* Returned bss is reference counted and must be cleaned up appropriately. */
681static struct cfg80211_internal_bss * 681static struct cfg80211_internal_bss *
682cfg80211_bss_update(struct cfg80211_registered_device *dev, 682cfg80211_bss_update(struct cfg80211_registered_device *dev,
683 struct cfg80211_internal_bss *tmp) 683 struct cfg80211_internal_bss *tmp,
684 bool signal_valid)
684{ 685{
685 struct cfg80211_internal_bss *found = NULL; 686 struct cfg80211_internal_bss *found = NULL;
686 687
@@ -765,7 +766,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
765 } 766 }
766 767
767 found->pub.beacon_interval = tmp->pub.beacon_interval; 768 found->pub.beacon_interval = tmp->pub.beacon_interval;
768 found->pub.signal = tmp->pub.signal; 769 /*
770 * don't update the signal if beacon was heard on
771 * adjacent channel.
772 */
773 if (signal_valid)
774 found->pub.signal = tmp->pub.signal;
769 found->pub.capability = tmp->pub.capability; 775 found->pub.capability = tmp->pub.capability;
770 found->ts = tmp->ts; 776 found->ts = tmp->ts;
771 } else { 777 } else {
@@ -869,13 +875,14 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
869/* Returned bss is reference counted and must be cleaned up appropriately. */ 875/* Returned bss is reference counted and must be cleaned up appropriately. */
870struct cfg80211_bss* 876struct cfg80211_bss*
871cfg80211_inform_bss_width(struct wiphy *wiphy, 877cfg80211_inform_bss_width(struct wiphy *wiphy,
872 struct ieee80211_channel *channel, 878 struct ieee80211_channel *rx_channel,
873 enum nl80211_bss_scan_width scan_width, 879 enum nl80211_bss_scan_width scan_width,
874 const u8 *bssid, u64 tsf, u16 capability, 880 const u8 *bssid, u64 tsf, u16 capability,
875 u16 beacon_interval, const u8 *ie, size_t ielen, 881 u16 beacon_interval, const u8 *ie, size_t ielen,
876 s32 signal, gfp_t gfp) 882 s32 signal, gfp_t gfp)
877{ 883{
878 struct cfg80211_bss_ies *ies; 884 struct cfg80211_bss_ies *ies;
885 struct ieee80211_channel *channel;
879 struct cfg80211_internal_bss tmp = {}, *res; 886 struct cfg80211_internal_bss tmp = {}, *res;
880 887
881 if (WARN_ON(!wiphy)) 888 if (WARN_ON(!wiphy))
@@ -885,7 +892,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
885 (signal < 0 || signal > 100))) 892 (signal < 0 || signal > 100)))
886 return NULL; 893 return NULL;
887 894
888 channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel); 895 channel = cfg80211_get_bss_channel(wiphy, ie, ielen, rx_channel);
889 if (!channel) 896 if (!channel)
890 return NULL; 897 return NULL;
891 898
@@ -913,7 +920,8 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
913 rcu_assign_pointer(tmp.pub.beacon_ies, ies); 920 rcu_assign_pointer(tmp.pub.beacon_ies, ies);
914 rcu_assign_pointer(tmp.pub.ies, ies); 921 rcu_assign_pointer(tmp.pub.ies, ies);
915 922
916 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); 923 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
924 rx_channel == channel);
917 if (!res) 925 if (!res)
918 return NULL; 926 return NULL;
919 927
@@ -929,20 +937,21 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width);
929/* Returned bss is reference counted and must be cleaned up appropriately. */ 937/* Returned bss is reference counted and must be cleaned up appropriately. */
930struct cfg80211_bss * 938struct cfg80211_bss *
931cfg80211_inform_bss_width_frame(struct wiphy *wiphy, 939cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
932 struct ieee80211_channel *channel, 940 struct ieee80211_channel *rx_channel,
933 enum nl80211_bss_scan_width scan_width, 941 enum nl80211_bss_scan_width scan_width,
934 struct ieee80211_mgmt *mgmt, size_t len, 942 struct ieee80211_mgmt *mgmt, size_t len,
935 s32 signal, gfp_t gfp) 943 s32 signal, gfp_t gfp)
936{ 944{
937 struct cfg80211_internal_bss tmp = {}, *res; 945 struct cfg80211_internal_bss tmp = {}, *res;
938 struct cfg80211_bss_ies *ies; 946 struct cfg80211_bss_ies *ies;
947 struct ieee80211_channel *channel;
939 size_t ielen = len - offsetof(struct ieee80211_mgmt, 948 size_t ielen = len - offsetof(struct ieee80211_mgmt,
940 u.probe_resp.variable); 949 u.probe_resp.variable);
941 950
942 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != 951 BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
943 offsetof(struct ieee80211_mgmt, u.beacon.variable)); 952 offsetof(struct ieee80211_mgmt, u.beacon.variable));
944 953
945 trace_cfg80211_inform_bss_width_frame(wiphy, channel, scan_width, mgmt, 954 trace_cfg80211_inform_bss_width_frame(wiphy, rx_channel, scan_width, mgmt,
946 len, signal); 955 len, signal);
947 956
948 if (WARN_ON(!mgmt)) 957 if (WARN_ON(!mgmt))
@@ -959,7 +968,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
959 return NULL; 968 return NULL;
960 969
961 channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, 970 channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
962 ielen, channel); 971 ielen, rx_channel);
963 if (!channel) 972 if (!channel)
964 return NULL; 973 return NULL;
965 974
@@ -983,7 +992,8 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
983 tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); 992 tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
984 tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); 993 tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
985 994
986 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); 995 res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
996 rx_channel == channel);
987 if (!res) 997 if (!res)
988 return NULL; 998 return NULL;
989 999