summaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2014-07-24 04:20:05 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-08-15 08:38:08 -0400
commit53b954ee4a71e782d7dfcdeee5bf4695caeeb112 (patch)
tree77468f7957d3bbcec2d745c2932225acf3bc7f00 /net/mac80211/mlme.c
parenta74a8c846fb699f3277c0c21278bd4c414074b4a (diff)
mac80211: disable 40MHz support in case of 20MHz AP
If the AP only advertises support for 20MHz (in the ht operation ie), disable 40MHz and VHT. This can improve interoperability with APs that don't like stations exceeding their own advertised capabilities. Signed-off-by: Eliad Peller <eliadx.peller@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0e8d59a0e17e..29fe91d6a094 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -149,6 +149,7 @@ static u32
149ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, 149ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
150 struct ieee80211_supported_band *sband, 150 struct ieee80211_supported_band *sband,
151 struct ieee80211_channel *channel, 151 struct ieee80211_channel *channel,
152 const struct ieee80211_ht_cap *ht_cap,
152 const struct ieee80211_ht_operation *ht_oper, 153 const struct ieee80211_ht_operation *ht_oper,
153 const struct ieee80211_vht_operation *vht_oper, 154 const struct ieee80211_vht_operation *vht_oper,
154 struct cfg80211_chan_def *chandef, bool tracking) 155 struct cfg80211_chan_def *chandef, bool tracking)
@@ -162,13 +163,19 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
162 chandef->center_freq1 = channel->center_freq; 163 chandef->center_freq1 = channel->center_freq;
163 chandef->center_freq2 = 0; 164 chandef->center_freq2 = 0;
164 165
165 if (!ht_oper || !sband->ht_cap.ht_supported) { 166 if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) {
166 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT; 167 ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
167 goto out; 168 goto out;
168 } 169 }
169 170
170 chandef->width = NL80211_CHAN_WIDTH_20; 171 chandef->width = NL80211_CHAN_WIDTH_20;
171 172
173 if (!(ht_cap->cap_info &
174 cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40))) {
175 ret = IEEE80211_STA_DISABLE_40MHZ | IEEE80211_STA_DISABLE_VHT;
176 goto out;
177 }
178
172 ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan, 179 ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
173 channel->band); 180 channel->band);
174 /* check that channel matches the right operating channel */ 181 /* check that channel matches the right operating channel */
@@ -328,6 +335,7 @@ out:
328 335
329static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata, 336static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
330 struct sta_info *sta, 337 struct sta_info *sta,
338 const struct ieee80211_ht_cap *ht_cap,
331 const struct ieee80211_ht_operation *ht_oper, 339 const struct ieee80211_ht_operation *ht_oper,
332 const struct ieee80211_vht_operation *vht_oper, 340 const struct ieee80211_vht_operation *vht_oper,
333 const u8 *bssid, u32 *changed) 341 const u8 *bssid, u32 *changed)
@@ -367,8 +375,9 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
367 sband = local->hw.wiphy->bands[chan->band]; 375 sband = local->hw.wiphy->bands[chan->band];
368 376
369 /* calculate new channel (type) based on HT/VHT operation IEs */ 377 /* calculate new channel (type) based on HT/VHT operation IEs */
370 flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper, 378 flags = ieee80211_determine_chantype(sdata, sband, chan,
371 vht_oper, &chandef, true); 379 ht_cap, ht_oper, vht_oper,
380 &chandef, true);
372 381
373 /* 382 /*
374 * Downgrade the new channel if we associated with restricted 383 * Downgrade the new channel if we associated with restricted
@@ -3173,7 +3182,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
3173 mutex_lock(&local->sta_mtx); 3182 mutex_lock(&local->sta_mtx);
3174 sta = sta_info_get(sdata, bssid); 3183 sta = sta_info_get(sdata, bssid);
3175 3184
3176 if (ieee80211_config_bw(sdata, sta, elems.ht_operation, 3185 if (ieee80211_config_bw(sdata, sta,
3186 elems.ht_cap_elem, elems.ht_operation,
3177 elems.vht_operation, bssid, &changed)) { 3187 elems.vht_operation, bssid, &changed)) {
3178 mutex_unlock(&local->sta_mtx); 3188 mutex_unlock(&local->sta_mtx);
3179 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, 3189 ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
@@ -3807,6 +3817,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3807{ 3817{
3808 struct ieee80211_local *local = sdata->local; 3818 struct ieee80211_local *local = sdata->local;
3809 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 3819 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3820 const struct ieee80211_ht_cap *ht_cap = NULL;
3810 const struct ieee80211_ht_operation *ht_oper = NULL; 3821 const struct ieee80211_ht_operation *ht_oper = NULL;
3811 const struct ieee80211_vht_operation *vht_oper = NULL; 3822 const struct ieee80211_vht_operation *vht_oper = NULL;
3812 struct ieee80211_supported_band *sband; 3823 struct ieee80211_supported_band *sband;
@@ -3823,14 +3834,17 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3823 3834
3824 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && 3835 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
3825 sband->ht_cap.ht_supported) { 3836 sband->ht_cap.ht_supported) {
3826 const u8 *ht_oper_ie, *ht_cap; 3837 const u8 *ht_oper_ie, *ht_cap_ie;
3827 3838
3828 ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION); 3839 ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
3829 if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper)) 3840 if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
3830 ht_oper = (void *)(ht_oper_ie + 2); 3841 ht_oper = (void *)(ht_oper_ie + 2);
3831 3842
3832 ht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY); 3843 ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
3833 if (!ht_cap || ht_cap[1] < sizeof(struct ieee80211_ht_cap)) { 3844 if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap))
3845 ht_cap = (void *)(ht_cap_ie + 2);
3846
3847 if (!ht_cap) {
3834 ifmgd->flags |= IEEE80211_STA_DISABLE_HT; 3848 ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
3835 ht_oper = NULL; 3849 ht_oper = NULL;
3836 } 3850 }
@@ -3861,7 +3875,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
3861 3875
3862 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, 3876 ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
3863 cbss->channel, 3877 cbss->channel,
3864 ht_oper, vht_oper, 3878 ht_cap, ht_oper, vht_oper,
3865 &chandef, false); 3879 &chandef, false);
3866 3880
3867 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss), 3881 sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),