cfg80211: introduce regulatory flags controlling bw
authorArik Nemtsov <arik@wizery.com>
Thu, 23 Oct 2014 06:37:33 +0000 (09:37 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 10 Nov 2014 09:36:21 +0000 (10:36 +0100)
Allow setting bandwidth related regulatory flags. These flags are mapped
to the corresponding channel flags in the specified range.
Make sure the new flags are consulted when calculating the maximum
bandwidth allowed by a regulatory-rule.

Also allow propagating the GO_CONCURRENT modifier from a reg-rule to a
channel.

Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: Luis R. Rodriguez <mcgrof@suse.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/uapi/linux/nl80211.h
net/wireless/reg.c

index a552736c3e59c04d8314b4114078b019fcb90d38..442369f69b4fa74b806107c9602b6da82997d30b 100644 (file)
@@ -2665,6 +2665,11 @@ enum nl80211_sched_scan_match_attr {
  * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
  *     base on contiguous rules and wider channels will be allowed to cross
  *     multiple contiguous/overlapping frequency ranges.
+ * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
+ * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
+ * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
+ * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
  */
 enum nl80211_reg_rule_flags {
        NL80211_RRF_NO_OFDM             = 1<<0,
@@ -2677,11 +2682,18 @@ enum nl80211_reg_rule_flags {
        NL80211_RRF_NO_IR               = 1<<7,
        __NL80211_RRF_NO_IBSS           = 1<<8,
        NL80211_RRF_AUTO_BW             = 1<<11,
+       NL80211_RRF_GO_CONCURRENT       = 1<<12,
+       NL80211_RRF_NO_HT40MINUS        = 1<<13,
+       NL80211_RRF_NO_HT40PLUS         = 1<<14,
+       NL80211_RRF_NO_80MHZ            = 1<<15,
+       NL80211_RRF_NO_160MHZ           = 1<<16,
 };
 
 #define NL80211_RRF_PASSIVE_SCAN       NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_IBSS            NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_IR              NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_HT40            (NL80211_RRF_NO_HT40MINUS |\
+                                        NL80211_RRF_NO_HT40PLUS)
 
 /* For backport compatibility with older userspace */
 #define NL80211_RRF_NO_IR_ALL          (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
index b725a31a475178ec99de0e9aabc4d89e2ebb7d40..7449a8c0f9fd2e4f475bc4d9090f7b68be29edbc 100644 (file)
@@ -573,8 +573,9 @@ static const struct ieee80211_regdomain *reg_get_regdomain(struct wiphy *wiphy)
        return get_cfg80211_regdom();
 }
 
-unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
-                                  const struct ieee80211_reg_rule *rule)
+static unsigned int
+reg_get_max_bandwidth_from_range(const struct ieee80211_regdomain *rd,
+                                const struct ieee80211_reg_rule *rule)
 {
        const struct ieee80211_freq_range *freq_range = &rule->freq_range;
        const struct ieee80211_freq_range *freq_range_tmp;
@@ -622,6 +623,27 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
        return end_freq - start_freq;
 }
 
+unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
+                                  const struct ieee80211_reg_rule *rule)
+{
+       unsigned int bw = reg_get_max_bandwidth_from_range(rd, rule);
+
+       if (rule->flags & NL80211_RRF_NO_160MHZ)
+               bw = min_t(unsigned int, bw, MHZ_TO_KHZ(80));
+       if (rule->flags & NL80211_RRF_NO_80MHZ)
+               bw = min_t(unsigned int, bw, MHZ_TO_KHZ(40));
+
+       /*
+        * HT40+/HT40- limits are handled per-channel. Only limit BW if both
+        * are not allowed.
+        */
+       if (rule->flags & NL80211_RRF_NO_HT40MINUS &&
+           rule->flags & NL80211_RRF_NO_HT40PLUS)
+               bw = min_t(unsigned int, bw, MHZ_TO_KHZ(20));
+
+       return bw;
+}
+
 /* Sanity check on a regulatory rule */
 static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
 {
@@ -946,6 +968,16 @@ static u32 map_regdom_flags(u32 rd_flags)
                channel_flags |= IEEE80211_CHAN_NO_OFDM;
        if (rd_flags & NL80211_RRF_NO_OUTDOOR)
                channel_flags |= IEEE80211_CHAN_INDOOR_ONLY;
+       if (rd_flags & NL80211_RRF_GO_CONCURRENT)
+               channel_flags |= IEEE80211_CHAN_GO_CONCURRENT;
+       if (rd_flags & NL80211_RRF_NO_HT40MINUS)
+               channel_flags |= IEEE80211_CHAN_NO_HT40MINUS;
+       if (rd_flags & NL80211_RRF_NO_HT40PLUS)
+               channel_flags |= IEEE80211_CHAN_NO_HT40PLUS;
+       if (rd_flags & NL80211_RRF_NO_80MHZ)
+               channel_flags |= IEEE80211_CHAN_NO_80MHZ;
+       if (rd_flags & NL80211_RRF_NO_160MHZ)
+               channel_flags |= IEEE80211_CHAN_NO_160MHZ;
        return channel_flags;
 }