aboutsummaryrefslogtreecommitdiff
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c123
1 files changed, 56 insertions, 67 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 1f6abba60274..b622ab0be552 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -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;