summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2016-02-01 10:40:55 +0100
committerJohannes Berg <johannes.berg@intel.com>2016-02-24 09:04:32 +0100
commit23665aaf9170ae6328cc4f68250c529a628af2ab (patch)
treecd4cefd66e788a04d15ebc4bc4ca92863eac3011
parentmac80211: add API to allow filtering frames in BA sessions (diff)
downloadlinux-23665aaf9170ae6328cc4f68250c529a628af2ab.tar.xz
linux-23665aaf9170ae6328cc4f68250c529a628af2ab.zip
mac80211: Interoperability workaround for 80+80 and 160 MHz channels
Number of deployed 80 MHz capable VHT stations that do not support 80+80 and 160 MHz bandwidths seem to misbehave when trying to connect to an AP that advertises 80+80 or 160 MHz channel bandwidth in the VHT Operation element. To avoid such issues with deployed devices, modify the design based on recently accepted IEEE 802.11 standard changes (*). This allows poorly implemented VHT 80 MHz stations to connect with the AP in 80 MHz mode. 80+80 and 160 MHz capable stations need to support the new workaround mechanism to allow full bandwidth to be used. However, there are more or less no impacted station with 80+80/160 capability deployed. The rebased version of this patch is based on the updated version from Johannes Berg to take the HT/VHT chandef refactoring into account. (*) Changes in https://mentor.ieee.org/802.11/dcn/15/11-15-1530-04-000m-vht160-operation-signaling-through-non-zero-ccfs1.docx were accepted during the IEEE 802.11 January 2016 meeting. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/util.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 091f3dd62ad1..f1e5b76eda70 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2364,10 +2364,23 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
switch (chandef->width) {
case NL80211_CHAN_WIDTH_160:
- vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
+ /*
+ * Convert 160 MHz channel width to new style as interop
+ * workaround.
+ */
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
+ vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx;
+ if (chandef->chan->center_freq < chandef->center_freq1)
+ vht_oper->center_freq_seg1_idx -= 8;
+ else
+ vht_oper->center_freq_seg1_idx += 8;
break;
case NL80211_CHAN_WIDTH_80P80:
- vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+ /*
+ * Convert 80+80 MHz channel width to new style as interop
+ * workaround.
+ */
+ vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
break;
case NL80211_CHAN_WIDTH_80:
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
@@ -2430,6 +2443,20 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
case IEEE80211_VHT_CHANWIDTH_80MHZ:
new.width = NL80211_CHAN_WIDTH_80;
new.center_freq1 = cf1;
+ /* If needed, adjust based on the newer interop workaround. */
+ if (oper->center_freq_seg2_idx) {
+ unsigned int diff;
+
+ diff = abs(oper->center_freq_seg2_idx -
+ oper->center_freq_seg1_idx);
+ if (diff == 8) {
+ new.width = NL80211_CHAN_WIDTH_160;
+ new.center_freq1 = cf2;
+ } else if (diff > 8) {
+ new.width = NL80211_CHAN_WIDTH_80P80;
+ new.center_freq2 = cf2;
+ }
+ }
break;
case IEEE80211_VHT_CHANWIDTH_160MHZ:
new.width = NL80211_CHAN_WIDTH_160;