nl80211: Parse channel type attribute in an ibss join request
authorAlexander Simon <an.alexsimon@googlemail.com>
Wed, 30 Nov 2011 15:56:32 +0000 (16:56 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 6 Dec 2011 21:05:24 +0000 (16:05 -0500)
Prepare cfg80211 for IBSS HT:
 * extend cfg80211 ibss struct with channel_type
 * Check if extension channel can be used
 * Export can_beacon_sec_chan for use in mac80211 (will be called
   from ibss.c later).

Signed-off-by: Alexander Simon <an.alexsimon@googlemail.com>
[siwu@hrz.tu-chemnitz.de: Updates]
* fix cfg80211_can_beacon_ext_chan comment
* remove implicit channel_type enum assumptions
* remove radar channel flags check
* add HT IBSS feature flag
* reword commit message

Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/linux/nl80211.h
include/net/cfg80211.h
net/wireless/chan.c
net/wireless/nl80211.c

index f51e3bf93a9640a107345866fc3391bb1a7d81d1..a18760684fc90628420e339e3215b9ff3d0a5eb4 100644 (file)
@@ -2785,9 +2785,11 @@ enum nl80211_ap_sme_features {
  * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
  *     TX status to the socket error queue when requested with the
  *     socket option.
+ * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
+       NL80211_FEATURE_HT_IBSS         = 1 << 1,
 };
 
 /**
index f0e82b2e42276372f747e277dd767dd70b8edac3..3de1c39d03e5d62fd00d87a8fddcb0adc42098b1 100644 (file)
@@ -1149,6 +1149,7 @@ struct cfg80211_ibss_params {
        u8 *ssid;
        u8 *bssid;
        struct ieee80211_channel *channel;
+       enum nl80211_channel_type channel_type;
        u8 *ie;
        u8 ssid_len, ie_len;
        u16 beacon_interval;
@@ -3267,6 +3268,16 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
                                 const u8 *frame, size_t len,
                                 int freq, gfp_t gfp);
 
+/*
+ * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
+ * @wiphy: the wiphy
+ * @chan: main channel
+ * @channel_type: HT mode
+ */
+int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
+                                struct ieee80211_channel *chan,
+                                enum nl80211_channel_type channel_type);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index 17cd0c04d139045bbb0802a74d9628731d9428dc..2fcfe0993ca221cb20e0739d4c1774fa22593cbd 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright 2009      Johannes Berg <johannes@sipsolutions.net>
  */
 
+#include <linux/export.h>
 #include <net/cfg80211.h>
 #include "core.h"
 
@@ -44,9 +45,9 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
        return chan;
 }
 
-static bool can_beacon_sec_chan(struct wiphy *wiphy,
-                               struct ieee80211_channel *chan,
-                               enum nl80211_channel_type channel_type)
+int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
+                                 struct ieee80211_channel *chan,
+                                 enum nl80211_channel_type channel_type)
 {
        struct ieee80211_channel *sec_chan;
        int diff;
@@ -75,6 +76,7 @@ static bool can_beacon_sec_chan(struct wiphy *wiphy,
 
        return true;
 }
+EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
 
 int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
                      struct wireless_dev *wdev, int freq,
@@ -109,8 +111,8 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
                switch (channel_type) {
                case NL80211_CHAN_HT40PLUS:
                case NL80211_CHAN_HT40MINUS:
-                       if (!can_beacon_sec_chan(&rdev->wiphy, chan,
-                                                channel_type)) {
+                       if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
+                                                         channel_type)) {
                                printk(KERN_DEBUG
                                       "cfg80211: Secondary channel not "
                                       "allowed to initiate communication\n");
index 8a9b4d817ae6dec9c85fd44472ba7403c287b631..ba439664c2e0d33428e008473e1fcf3c86b70247 100644 (file)
@@ -4682,13 +4682,41 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       ibss.channel = ieee80211_get_channel(wiphy,
-               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+               enum nl80211_channel_type channel_type;
+
+               channel_type = nla_get_u32(
+                               info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+               if (channel_type != NL80211_CHAN_NO_HT &&
+                   channel_type != NL80211_CHAN_HT20 &&
+                   channel_type != NL80211_CHAN_HT40MINUS &&
+                   channel_type != NL80211_CHAN_HT40PLUS)
+                       return -EINVAL;
+
+               if (channel_type != NL80211_CHAN_NO_HT &&
+                   !(wiphy->features & NL80211_FEATURE_HT_IBSS))
+                       return -EINVAL;
+
+               ibss.channel_type = channel_type;
+       } else {
+               ibss.channel_type = NL80211_CHAN_NO_HT;
+       }
+
+       ibss.channel = rdev_freq_to_chan(rdev,
+               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+               ibss.channel_type);
        if (!ibss.channel ||
            ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
            ibss.channel->flags & IEEE80211_CHAN_DISABLED)
                return -EINVAL;
 
+       /* Both channels should be able to initiate communication */
+       if ((ibss.channel_type == NL80211_CHAN_HT40PLUS ||
+            ibss.channel_type == NL80211_CHAN_HT40MINUS) &&
+           !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel,
+                                         ibss.channel_type))
+               return -EINVAL;
+
        ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
        ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];