mac80211: allow disable FAT in specific configurations
This patch allows to disable FAT channel in specific configurations.
For example the configuration (8, +1), (primary channel 8, extension
channel 12) isn't permitted in U.S., but (8, -1), (primary channel 8,
extension channel 4) is. When FAT channel configuration is not
permitted, FAT channel should be reported as not supported in the
capabilities of the HT IE in association request. And sssociation is
performed on 20Mhz channel.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3f8601c..432011c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -92,6 +92,8 @@
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
+ u8 *ht_add_ie;
+ size_t ht_add_ie_len;
#ifdef CONFIG_MAC80211_MESH
u8 *mesh_id;
size_t mesh_id_len;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6faa700..d30c113 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -808,8 +808,29 @@
/* wmm support is a must to HT */
if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
- sband->ht_info.ht_supported) {
- __le16 tmp = cpu_to_le16(sband->ht_info.cap);
+ sband->ht_info.ht_supported && bss->ht_add_ie) {
+ struct ieee80211_ht_addt_info *ht_add_info =
+ (struct ieee80211_ht_addt_info *)bss->ht_add_ie;
+ u16 cap = sband->ht_info.cap;
+ __le16 tmp;
+ u32 flags = local->hw.conf.channel->flags;
+
+ switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+ if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ case IEEE80211_HT_IE_CHA_SEC_BELOW:
+ if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ }
+
+ tmp = cpu_to_le16(cap);
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
@@ -2264,6 +2285,7 @@
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
+ kfree(bss->ht_add_ie);
kfree(bss_mesh_id(bss));
kfree(bss_mesh_cfg(bss));
kfree(bss);
@@ -2640,6 +2662,26 @@
bss->ht_ie_len = 0;
}
+ if (elems.ht_info_elem &&
+ (!bss->ht_add_ie ||
+ bss->ht_add_ie_len != elems.ht_info_elem_len ||
+ memcmp(bss->ht_add_ie, elems.ht_info_elem,
+ elems.ht_info_elem_len))) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie =
+ kmalloc(elems.ht_info_elem_len + 2, GFP_ATOMIC);
+ if (bss->ht_add_ie) {
+ memcpy(bss->ht_add_ie, elems.ht_info_elem - 2,
+ elems.ht_info_elem_len + 2);
+ bss->ht_add_ie_len = elems.ht_info_elem_len + 2;
+ } else
+ bss->ht_add_ie_len = 0;
+ } else if (!elems.ht_info_elem && bss->ht_add_ie) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie = NULL;
+ bss->ht_add_ie_len = 0;
+ }
+
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);