cfg80211: process driver regulatory requests on its own
authorLuis R. Rodriguez <mcgrof@do-not-panic.com>
Tue, 5 Nov 2013 17:18:05 +0000 (09:18 -0800)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 25 Nov 2013 19:51:10 +0000 (20:51 +0100)
This makes the code easier to read and follow.

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 1bd590c2ed7fd083ce37199704d411b61557c422..7188ef9f07b6b3ec041a052d5793dce8410bdeee 100644 (file)
@@ -1338,6 +1338,7 @@ get_reg_request_treatment(struct wiphy *wiphy,
        switch (pending_request->initiator) {
        case NL80211_REGDOM_SET_BY_CORE:
        case NL80211_REGDOM_SET_BY_USER:
+       case NL80211_REGDOM_SET_BY_DRIVER:
                return REG_REQ_IGNORE;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
                if (reg_request_cell_base(lr)) {
@@ -1372,23 +1373,6 @@ get_reg_request_treatment(struct wiphy *wiphy,
                        return REG_REQ_ALREADY_SET;
                }
                return REG_REQ_OK;
-       case NL80211_REGDOM_SET_BY_DRIVER:
-               if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
-                       if (regdom_changes(pending_request->alpha2))
-                               return REG_REQ_OK;
-                       return REG_REQ_ALREADY_SET;
-               }
-
-               /*
-                * This would happen if you unplug and plug your card
-                * back in or if you add a new device for which the previously
-                * loaded card also agrees on the regulatory domain.
-                */
-               if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
-                   !regdom_changes(pending_request->alpha2))
-                       return REG_REQ_ALREADY_SET;
-
-               return REG_REQ_INTERSECT;
        }
 
        return REG_REQ_IGNORE;
@@ -1514,6 +1498,89 @@ reg_process_hint_user(struct regulatory_request *user_request)
        return REG_REQ_OK;
 }
 
+static enum reg_request_treatment
+__reg_process_hint_driver(struct regulatory_request *driver_request)
+{
+       struct regulatory_request *lr = get_last_request();
+
+       if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
+               if (regdom_changes(driver_request->alpha2))
+                       return REG_REQ_OK;
+               return REG_REQ_ALREADY_SET;
+       }
+
+       /*
+        * This would happen if you unplug and plug your card
+        * back in or if you add a new device for which the previously
+        * loaded card also agrees on the regulatory domain.
+        */
+       if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+           !regdom_changes(driver_request->alpha2))
+               return REG_REQ_ALREADY_SET;
+
+       return REG_REQ_INTERSECT;
+}
+
+/**
+ * reg_process_hint_driver - process driver regulatory requests
+ * @driver_request: a pending driver regulatory request
+ *
+ * The wireless subsystem can use this function to process
+ * a regulatory request issued by an 802.11 driver.
+ *
+ * Returns one of the different reg request treatment values.
+ */
+static enum reg_request_treatment
+reg_process_hint_driver(struct wiphy *wiphy,
+                       struct regulatory_request *driver_request)
+{
+       const struct ieee80211_regdomain *regd;
+       enum reg_request_treatment treatment;
+       struct regulatory_request *lr;
+
+       treatment = __reg_process_hint_driver(driver_request);
+
+       switch (treatment) {
+       case REG_REQ_OK:
+               break;
+       case REG_REQ_IGNORE:
+               kfree(driver_request);
+               return treatment;
+       case REG_REQ_INTERSECT:
+               /* fall through */
+       case REG_REQ_ALREADY_SET:
+               regd = reg_copy_regd(get_cfg80211_regdom());
+               if (IS_ERR(regd)) {
+                       kfree(driver_request);
+                       return REG_REQ_IGNORE;
+               }
+               rcu_assign_pointer(wiphy->regd, regd);
+       }
+
+       lr = get_last_request();
+       if (lr != &core_request_world && lr)
+               kfree_rcu(lr, rcu_head);
+
+       driver_request->intersect = treatment == REG_REQ_INTERSECT;
+       driver_request->processed = false;
+       rcu_assign_pointer(last_request, driver_request);
+
+       /*
+        * Since CRDA will not be called in this case as we already
+        * have applied the requested regulatory domain before we just
+        * inform userspace we have processed the request
+        */
+       if (treatment == REG_REQ_ALREADY_SET) {
+               nl80211_send_reg_change_event(driver_request);
+               reg_set_request_processed();
+               return treatment;
+       }
+
+       if (call_crda(driver_request->alpha2))
+               return REG_REQ_IGNORE;
+       return REG_REQ_OK;
+}
+
 /**
  * __regulatory_hint - hint to the wireless core a regulatory domain
  * @wiphy: if the hint comes from country information from an AP, this
@@ -1637,6 +1704,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
                schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
                return;
        case NL80211_REGDOM_SET_BY_DRIVER:
+               treatment = reg_process_hint_driver(wiphy, reg_request);
+               break;
        case NL80211_REGDOM_SET_BY_COUNTRY_IE:
                treatment = __regulatory_hint(wiphy, reg_request);
                break;