cfg80211: make regulatory_hint() remove REGULATORY_CUSTOM_REG
[deliverable/linux.git] / net / wireless / reg.c
index b622ab0be5529a5f289ffd0ea45cfae02adab4cf..9b897fca7487dd4fe8d8364368e8516ab8f369c0 100644 (file)
@@ -120,6 +120,48 @@ static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
        return rtnl_dereference(wiphy->regd);
 }
 
+static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region)
+{
+       switch (dfs_region) {
+       case NL80211_DFS_UNSET:
+               return "unset";
+       case NL80211_DFS_FCC:
+               return "FCC";
+       case NL80211_DFS_ETSI:
+               return "ETSI";
+       case NL80211_DFS_JP:
+               return "JP";
+       }
+       return "Unknown";
+}
+
+enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
+{
+       const struct ieee80211_regdomain *regd = NULL;
+       const struct ieee80211_regdomain *wiphy_regd = NULL;
+
+       regd = get_cfg80211_regdom();
+       if (!wiphy)
+               goto out;
+
+       wiphy_regd = get_wiphy_regdom(wiphy);
+       if (!wiphy_regd)
+               goto out;
+
+       if (wiphy_regd->dfs_region == regd->dfs_region)
+               goto out;
+
+       REG_DBG_PRINT("%s: device specific dfs_region "
+                     "(%s) disagrees with cfg80211's "
+                     "central dfs_region (%s)\n",
+                     dev_name(&wiphy->dev),
+                     reg_dfs_region_str(wiphy_regd->dfs_region),
+                     reg_dfs_region_str(regd->dfs_region));
+
+out:
+       return regd->dfs_region;
+}
+
 static void rcu_free_regdom(const struct ieee80211_regdomain *r)
 {
        if (!r)
@@ -570,6 +612,20 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
 #undef ONE_GHZ_IN_KHZ
 }
 
+/*
+ * Later on we can perhaps use the more restrictive DFS
+ * region but we don't have information for that yet so
+ * for now simply disallow conflicts.
+ */
+static enum nl80211_dfs_regions
+reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
+                        const enum nl80211_dfs_regions dfs_region2)
+{
+       if (dfs_region1 != dfs_region2)
+               return NL80211_DFS_UNSET;
+       return dfs_region1;
+}
+
 /*
  * Helper for regdom_intersect(), this does the real
  * mathematical intersection fun
@@ -701,6 +757,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
        rd->n_reg_rules = num_rules;
        rd->alpha2[0] = '9';
        rd->alpha2[1] = '8';
+       rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,
+                                                 rd2->dfs_region);
 
        return rd;
 }
@@ -868,7 +926,7 @@ static void handle_channel(struct wiphy *wiphy,
 
                if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
                    request_wiphy && request_wiphy == wiphy &&
-                   request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
+                   request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
                        REG_DBG_PRINT("Disabling freq %d MHz for good\n",
                                      chan->center_freq);
                        chan->orig_flags |= IEEE80211_CHAN_DISABLED;
@@ -895,7 +953,7 @@ static void handle_channel(struct wiphy *wiphy,
 
        if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
            request_wiphy && request_wiphy == wiphy &&
-           request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
+           request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
                /*
                 * This guarantees the driver's requested regulatory domain
                 * will always be used as a base for further regulatory
@@ -921,13 +979,11 @@ static void handle_channel(struct wiphy *wiphy,
        chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
        if (chan->orig_mpwr) {
                /*
-                * Devices that have their own custom regulatory domain
-                * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the
-                * passed country IE power settings.
+                * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
+                * will always follow the passed country IE power settings.
                 */
                if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
-                   wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+                   wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER)
                        chan->max_power = chan->max_reg_power;
                else
                        chan->max_power = min(chan->orig_mpwr,
@@ -997,8 +1053,8 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
 
 static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy)
 {
-       if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY &&
-           !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY))
+       if (wiphy->regulatory_flags & REGULATORY_STRICT_REG &&
+           !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG))
                return true;
        return false;
 }
@@ -1016,7 +1072,7 @@ static bool ignore_reg_update(struct wiphy *wiphy,
        }
 
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {
+           wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
                REG_DBG_PRINT("Ignoring regulatory request set by %s "
                              "since the driver uses its own custom "
                              "regulatory domain\n",
@@ -1054,7 +1110,7 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
                return true;
 
        if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
-           wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+           wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)
                return true;
 
        return false;
@@ -1082,7 +1138,7 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
        if (!reg_is_world_roaming(wiphy))
                return;
 
-       if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)
+       if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS)
                return;
 
        chan_before.center_freq = chan->center_freq;
@@ -1242,7 +1298,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
                 * as some drivers used this to restore its orig_* reg domain.
                 */
                if (initiator == NL80211_REGDOM_SET_BY_CORE &&
-                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+                   wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)
                        reg_call_notifier(wiphy, lr);
                return;
        }
@@ -1328,9 +1384,9 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy,
        enum ieee80211_band band;
        unsigned int bands_set = 0;
 
-       WARN(!(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY),
-            "wiphy should have WIPHY_FLAG_CUSTOM_REGULATORY\n");
-       wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+       WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG),
+            "wiphy should have REGULATORY_CUSTOM_REG\n");
+       wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
 
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (!wiphy->bands[band])
@@ -1545,6 +1601,9 @@ __reg_process_hint_country_ie(struct wiphy *wiphy,
                if (regdom_changes(country_ie_request->alpha2))
                        return REG_REQ_IGNORE;
                return REG_REQ_ALREADY_SET;
+       } else {
+               if (wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE)
+                       return REG_REQ_IGNORE;
        }
 
        if (unlikely(!is_an_alpha2(country_ie_request->alpha2)))
@@ -1659,7 +1718,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
 
        /* This is required so that the orig_* parameters are saved */
        if (treatment == REG_REQ_ALREADY_SET && wiphy &&
-           wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+           wiphy->regulatory_flags & REGULATORY_STRICT_REG)
                wiphy_update_regulatory(wiphy, reg_request->initiator);
 }
 
@@ -1794,6 +1853,8 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
        if (WARN_ON(!alpha2 || !wiphy))
                return -EINVAL;
 
+       wiphy->regulatory_flags &= ~REGULATORY_CUSTOM_REG;
+
        request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
        if (!request)
                return -ENOMEM;
@@ -1986,7 +2047,7 @@ static void restore_regulatory_settings(bool reset_user)
        world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
-               if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY)
+               if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
                        restore_custom_reg_settings(&rdev->wiphy);
        }
 
@@ -2114,7 +2175,7 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
        }
 }
 
-bool reg_supported_dfs_region(u8 dfs_region)
+bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
 {
        switch (dfs_region) {
        case NL80211_DFS_UNSET:
@@ -2129,27 +2190,6 @@ bool reg_supported_dfs_region(u8 dfs_region)
        }
 }
 
-static void print_dfs_region(u8 dfs_region)
-{
-       if (!dfs_region)
-               return;
-
-       switch (dfs_region) {
-       case NL80211_DFS_FCC:
-               pr_info(" DFS Master region FCC");
-               break;
-       case NL80211_DFS_ETSI:
-               pr_info(" DFS Master region ETSI");
-               break;
-       case NL80211_DFS_JP:
-               pr_info(" DFS Master region JP");
-               break;
-       default:
-               pr_info(" DFS Master region Unknown");
-               break;
-       }
-}
-
 static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
        struct regulatory_request *lr = get_last_request();
@@ -2181,7 +2221,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
                }
        }
 
-       print_dfs_region(rd->dfs_region);
+       pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region));
        print_rd_rules(rd);
 }
 
@@ -2291,9 +2331,8 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
        return 0;
 }
 
-/* Takes ownership of rd only if it doesn't fail */
-static int __set_regdom(const struct ieee80211_regdomain *rd,
-                       struct regulatory_request *lr)
+static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
+                                struct regulatory_request *country_ie_request)
 {
        struct wiphy *request_wiphy;
 
@@ -2313,13 +2352,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd,
                return -EINVAL;
        }
 
-       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+       request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx);
        if (!request_wiphy) {
                schedule_delayed_work(&reg_timeout, 0);
                return -ENODEV;
        }
 
-       if (lr->intersect)
+       if (country_ie_request->intersect)
                return -EINVAL;
 
        reset_regdomains(false, rd);
@@ -2355,7 +2394,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
                r = reg_set_rd_driver(rd, lr);
                break;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
-               r = __set_regdom(rd, lr);
+               r = reg_set_rd_country_ie(rd, lr);
                break;
        default:
                WARN(1, "invalid initiator %d\n", lr->initiator);
This page took 0.03739 seconds and 5 git commands to generate.