]> err.no Git - linux-2.6/commitdiff
mac80211: allow disable FAT in specific configurations
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Thu, 29 May 2008 08:35:23 +0000 (16:35 +0800)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 3 Jun 2008 19:00:26 +0000 (15:00 -0400)
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>
include/linux/ieee80211.h
include/net/wireless.h
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c

index 3c2ac0c37aa8f5362ba4b456f97428dcf28bc142..9300f37cd7e8429104b27024dc00df6b657e526c 100644 (file)
@@ -320,6 +320,8 @@ struct ieee80211_ht_addt_info {
 #define IEEE80211_HT_CAP_MCS_TX_UEQM           0x10
 /* 802.11n HT IE masks */
 #define IEEE80211_HT_IE_CHA_SEC_OFFSET         0x03
+#define IEEE80211_HT_IE_CHA_SEC_ABOVE          0x01
+#define IEEE80211_HT_IE_CHA_SEC_BELOW          0x03
 #define IEEE80211_HT_IE_CHA_WIDTH              0x04
 #define IEEE80211_HT_IE_HT_PROTECTION          0x0003
 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT       0x0004
index 667b4080d30fe27eee5949a4c9e846ea6b3384ef..9324f8dd183eac07d299269fdf0f836bd6c8f193 100644 (file)
@@ -39,12 +39,18 @@ enum ieee80211_band {
  *     on this channel.
  * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
  * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
+ *     is not permitted.
+ * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
+ *     is not permitted.
  */
 enum ieee80211_channel_flags {
        IEEE80211_CHAN_DISABLED         = 1<<0,
        IEEE80211_CHAN_PASSIVE_SCAN     = 1<<1,
        IEEE80211_CHAN_NO_IBSS          = 1<<2,
        IEEE80211_CHAN_RADAR            = 1<<3,
+       IEEE80211_CHAN_NO_FAT_ABOVE     = 1<<4,
+       IEEE80211_CHAN_NO_FAT_BELOW     = 1<<5,
 };
 
 /**
index 3f8601cafffb4a940c841e298275b8a7c13429cd..432011cd3647227e9d86bdf281bc582688545b74 100644 (file)
@@ -92,6 +92,8 @@ struct ieee80211_sta_bss {
        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;
index 6faa7006681a7e6cc28c7e54215038d6c3e6507c..d30c11337b047d0364b5a58b02ffd14ede7c2f2b 100644 (file)
@@ -808,8 +808,29 @@ static void ieee80211_send_assoc(struct net_device *dev,
 
        /* 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 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
        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 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                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);