summaryrefslogtreecommitdiff
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c103
1 files changed, 86 insertions, 17 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 1bd590c..7188ef9 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -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;