]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - net/wireless/reg.c
Merge tag 'mac80211-next-for-davem-2015-10-05' of git://git.kernel.org/pub/scm/linux...
[mirror_ubuntu-zesty-kernel.git] / net / wireless / reg.c
index aa2d75482017e1a258eb0cdb7271b2d615d8782e..7258246b7458713eb14230c906246e230972b1b4 100644 (file)
@@ -1004,7 +1004,7 @@ static u32 map_regdom_flags(u32 rd_flags)
 
 static const struct ieee80211_reg_rule *
 freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
-                  const struct ieee80211_regdomain *regd)
+                  const struct ieee80211_regdomain *regd, u32 bw)
 {
        int i;
        bool band_rule_found = false;
@@ -1028,7 +1028,7 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
                if (!band_rule_found)
                        band_rule_found = freq_in_rule_band(fr, center_freq);
 
-               bw_fits = reg_does_bw_fit(fr, center_freq, MHZ_TO_KHZ(20));
+               bw_fits = reg_does_bw_fit(fr, center_freq, bw);
 
                if (band_rule_found && bw_fits)
                        return rr;
@@ -1040,14 +1040,26 @@ freq_reg_info_regd(struct wiphy *wiphy, u32 center_freq,
        return ERR_PTR(-EINVAL);
 }
 
-const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
-                                              u32 center_freq)
+static const struct ieee80211_reg_rule *
+__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
 {
-       const struct ieee80211_regdomain *regd;
+       const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
+       const struct ieee80211_reg_rule *reg_rule = NULL;
+       u32 bw;
 
-       regd = reg_get_regdomain(wiphy);
+       for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
+               reg_rule = freq_reg_info_regd(wiphy, center_freq, regd, bw);
+               if (!IS_ERR(reg_rule))
+                       return reg_rule;
+       }
+
+       return reg_rule;
+}
 
-       return freq_reg_info_regd(wiphy, center_freq, regd);
+const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
+                                              u32 center_freq)
+{
+       return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(20));
 }
 EXPORT_SYMBOL(freq_reg_info);
 
@@ -1176,8 +1188,20 @@ static void handle_channel(struct wiphy *wiphy,
        if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
+       /* If we get a reg_rule we can assume that at least 5Mhz fit */
+       if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
+                            MHZ_TO_KHZ(10)))
+               bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+       if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
+                            MHZ_TO_KHZ(20)))
+               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+
+       if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+               bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
-               bw_flags = IEEE80211_CHAN_NO_HT40;
+               bw_flags |= IEEE80211_CHAN_NO_HT40;
        if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(160))
@@ -1695,9 +1719,15 @@ static void handle_channel_custom(struct wiphy *wiphy,
        const struct ieee80211_power_rule *power_rule = NULL;
        const struct ieee80211_freq_range *freq_range = NULL;
        u32 max_bandwidth_khz;
+       u32 bw;
 
-       reg_rule = freq_reg_info_regd(wiphy, MHZ_TO_KHZ(chan->center_freq),
-                                     regd);
+       for (bw = MHZ_TO_KHZ(20); bw >= MHZ_TO_KHZ(5); bw = bw / 2) {
+               reg_rule = freq_reg_info_regd(wiphy,
+                                             MHZ_TO_KHZ(chan->center_freq),
+                                             regd, bw);
+               if (!IS_ERR(reg_rule))
+                       break;
+       }
 
        if (IS_ERR(reg_rule)) {
                REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
@@ -1721,8 +1751,20 @@ static void handle_channel_custom(struct wiphy *wiphy,
        if (reg_rule->flags & NL80211_RRF_AUTO_BW)
                max_bandwidth_khz = reg_get_max_bandwidth(regd, reg_rule);
 
+       /* If we get a reg_rule we can assume that at least 5Mhz fit */
+       if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
+                            MHZ_TO_KHZ(10)))
+               bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+       if (!reg_does_bw_fit(freq_range, MHZ_TO_KHZ(chan->center_freq),
+                            MHZ_TO_KHZ(20)))
+               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
+
+       if (max_bandwidth_khz < MHZ_TO_KHZ(10))
+               bw_flags |= IEEE80211_CHAN_NO_10MHZ;
+       if (max_bandwidth_khz < MHZ_TO_KHZ(20))
+               bw_flags |= IEEE80211_CHAN_NO_20MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(40))
-               bw_flags = IEEE80211_CHAN_NO_HT40;
+               bw_flags |= IEEE80211_CHAN_NO_HT40;
        if (max_bandwidth_khz < MHZ_TO_KHZ(80))
                bw_flags |= IEEE80211_CHAN_NO_80MHZ;
        if (max_bandwidth_khz < MHZ_TO_KHZ(160))
@@ -2079,10 +2121,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
                reg_process_hint_core(reg_request);
                return;
        case NL80211_REGDOM_SET_BY_USER:
-               treatment = reg_process_hint_user(reg_request);
-               if (treatment == REG_REQ_IGNORE ||
-                   treatment == REG_REQ_ALREADY_SET)
-                       return;
+               reg_process_hint_user(reg_request);
                return;
        case NL80211_REGDOM_SET_BY_DRIVER:
                if (!wiphy)
@@ -2099,7 +2138,9 @@ static void reg_process_hint(struct regulatory_request *reg_request)
                goto out_free;
        }
 
-       /* This is required so that the orig_* parameters are saved */
+       /* This is required so that the orig_* parameters are saved.
+        * NOTE: treatment must be set for any case that reaches here!
+        */
        if (treatment == REG_REQ_ALREADY_SET && wiphy &&
            wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
                wiphy_update_regulatory(wiphy, reg_request->initiator);
@@ -2584,7 +2625,7 @@ static void restore_regulatory_settings(bool reset_user)
         * settings, user regulatory settings takes precedence.
         */
        if (is_an_alpha2(alpha2))
-               regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER);
+               regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER);
 
        spin_lock(&reg_requests_lock);
        list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list);