cfg80211: set driver regulatory updates on its own
authorLuis R. Rodriguez <mcgrof@do-not-panic.com>
Tue, 5 Nov 2013 17:18:16 +0000 (09:18 -0800)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 25 Nov 2013 19:51:36 +0000 (20:51 +0100)
This splits up the driver regulatory update on its
own, this helps simplify the reading the case.

Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/reg.c

index 1f6abba602743f13db76e93f1b174ef406dc988c..b622ab0be5529a5f289ffd0ea45cfae02adab4cf 100644 (file)
@@ -2232,38 +2232,19 @@ static int reg_set_rd_user(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_driver(const struct ieee80211_regdomain *rd,
+                            struct regulatory_request *driver_request)
 {
        const struct ieee80211_regdomain *regd;
        const struct ieee80211_regdomain *intersected_rd = NULL;
+       const struct ieee80211_regdomain *tmp;
        struct wiphy *request_wiphy;
 
-       if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
-           !is_unknown_alpha2(rd->alpha2))
+       if (is_world_regdom(rd->alpha2))
                return -EINVAL;
 
-       /*
-        * Lets only bother proceeding on the same alpha2 if the current
-        * rd is non static (it means CRDA was present and was used last)
-        * and the pending request came in from a country IE
-        */
-       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-               /*
-                * If someone else asked us to change the rd lets only bother
-                * checking if the alpha2 changes if CRDA was already called
-                */
-               if (!regdom_changes(rd->alpha2))
-                       return -EALREADY;
-       }
-
-       /*
-        * Now lets set the regulatory domain, update all driver channels
-        * and finally inform them of what we have done, in case they want
-        * to review or adjust their own settings based on their own
-        * internal EEPROM data
-        */
+       if (!regdom_changes(rd->alpha2))
+               return -EALREADY;
 
        if (!is_valid_rd(rd)) {
                pr_err("Invalid regulatory domain detected:\n");
@@ -2271,29 +2252,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd,
                return -EINVAL;
        }
 
-       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
-       if (!request_wiphy &&
-           (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
-            lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+       request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);
+       if (!request_wiphy) {
                schedule_delayed_work(&reg_timeout, 0);
                return -ENODEV;
        }
 
-       if (!lr->intersect) {
-               if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
-                       reset_regdomains(false, rd);
-                       return 0;
-               }
-
-               /*
-                * For a driver hint, lets copy the regulatory domain the
-                * driver wanted to the wiphy to deal with conflicts
-                */
-
-               /*
-                * Userspace could have sent two replies with only
-                * one kernel request.
-                */
+       if (!driver_request->intersect) {
                if (request_wiphy->regd)
                        return -EALREADY;
 
@@ -2306,38 +2271,60 @@ static int __set_regdom(const struct ieee80211_regdomain *rd,
                return 0;
        }
 
-       /* Intersection requires a bit more work */
+       intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
+       if (!intersected_rd)
+               return -EINVAL;
 
-       if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
-               intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
-               if (!intersected_rd)
-                       return -EINVAL;
+       /*
+        * We can trash what CRDA provided now.
+        * However if a driver requested this specific regulatory
+        * domain we keep it for its private use
+        */
+       tmp = get_wiphy_regdom(request_wiphy);
+       rcu_assign_pointer(request_wiphy->regd, rd);
+       rcu_free_regdom(tmp);
 
-               /*
-                * We can trash what CRDA provided now.
-                * However if a driver requested this specific regulatory
-                * domain we keep it for its private use
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
-                       const struct ieee80211_regdomain *tmp;
+       rd = NULL;
 
-                       tmp = get_wiphy_regdom(request_wiphy);
-                       rcu_assign_pointer(request_wiphy->regd, rd);
-                       rcu_free_regdom(tmp);
-               } else {
-                       kfree(rd);
-               }
+       reset_regdomains(false, intersected_rd);
 
-               rd = NULL;
+       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)
+{
+       struct wiphy *request_wiphy;
 
-               reset_regdomains(false, intersected_rd);
+       if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
+           !is_unknown_alpha2(rd->alpha2))
+               return -EINVAL;
 
-               return 0;
+       /*
+        * Lets only bother proceeding on the same alpha2 if the current
+        * rd is non static (it means CRDA was present and was used last)
+        * and the pending request came in from a country IE
+        */
+
+       if (!is_valid_rd(rd)) {
+               pr_err("Invalid regulatory domain detected:\n");
+               print_regdomain_info(rd);
+               return -EINVAL;
        }
 
-       return -EINVAL;
-}
+       request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
+       if (!request_wiphy) {
+               schedule_delayed_work(&reg_timeout, 0);
+               return -ENODEV;
+       }
 
+       if (lr->intersect)
+               return -EINVAL;
+
+       reset_regdomains(false, rd);
+       return 0;
+}
 
 /*
  * Use this call to set the current regulatory domain. Conflicts with
@@ -2365,6 +2352,8 @@ int set_regdom(const struct ieee80211_regdomain *rd)
                r = reg_set_rd_user(rd, lr);
                break;
        case NL80211_REGDOM_SET_BY_DRIVER:
+               r = reg_set_rd_driver(rd, lr);
+               break;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
                r = __set_regdom(rd, lr);
                break;