aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-12-03 18:48:59 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-03 07:01:28 -0500
commit6913b49a5071064f49f7a74b432286fa735f7612 (patch)
tree15b54b8dd9d5eef07e8a9366b3f9e391043499f1 /net/wireless/reg.c
parent540f6f2cc545da9ae2baa9faa3152fc550bedb57 (diff)
regulatory: fix reg_is_valid_request handling
There's a bug with the world regulatory domain, it can be updated any time which is different from all other regdomains that can only be updated once after a request for them. Fix this by adding a check for "processed" to the reg_is_valid_request() function and clear that when doing a request. While looking at this I also found another locking bug, last_request is protected by the reg_mutex not the cfg80211_mutex so the code in nl80211 is racy. Remove that code as it only tries to prevent an allocation in an error case, which isn't necessary. Then the function can also become static and locking in nl80211 can have a smaller scope. Also change __set_regdom() to do the checks earlier and not different for world/other regdomains. Acked-by: Luis R. Rodriguez <mcgrof@do-not-panic.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 752729ecd701..b3f94c957d1d 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -425,12 +425,16 @@ static int call_crda(const char *alpha2)
425 return kobject_uevent(&reg_pdev->dev.kobj, KOBJ_CHANGE); 425 return kobject_uevent(&reg_pdev->dev.kobj, KOBJ_CHANGE);
426} 426}
427 427
428/* Used by nl80211 before kmalloc'ing our regulatory domain */ 428static bool reg_is_valid_request(const char *alpha2)
429bool reg_is_valid_request(const char *alpha2)
430{ 429{
430 assert_reg_lock();
431
431 if (!last_request) 432 if (!last_request)
432 return false; 433 return false;
433 434
435 if (last_request->processed)
436 return false;
437
434 return alpha2_equal(last_request->alpha2, alpha2); 438 return alpha2_equal(last_request->alpha2, alpha2);
435} 439}
436 440
@@ -1470,6 +1474,7 @@ new_request:
1470 1474
1471 last_request = pending_request; 1475 last_request = pending_request;
1472 last_request->intersect = intersect; 1476 last_request->intersect = intersect;
1477 last_request->processed = false;
1473 1478
1474 pending_request = NULL; 1479 pending_request = NULL;
1475 1480
@@ -2060,11 +2065,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2060 const struct ieee80211_regdomain *regd; 2065 const struct ieee80211_regdomain *regd;
2061 const struct ieee80211_regdomain *intersected_rd = NULL; 2066 const struct ieee80211_regdomain *intersected_rd = NULL;
2062 struct wiphy *request_wiphy; 2067 struct wiphy *request_wiphy;
2068
2063 /* Some basic sanity checks first */ 2069 /* Some basic sanity checks first */
2064 2070
2071 if (!reg_is_valid_request(rd->alpha2))
2072 return -EINVAL;
2073
2065 if (is_world_regdom(rd->alpha2)) { 2074 if (is_world_regdom(rd->alpha2)) {
2066 if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
2067 return -EINVAL;
2068 update_world_regdomain(rd); 2075 update_world_regdomain(rd);
2069 return 0; 2076 return 0;
2070 } 2077 }
@@ -2073,9 +2080,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2073 !is_unknown_alpha2(rd->alpha2)) 2080 !is_unknown_alpha2(rd->alpha2))
2074 return -EINVAL; 2081 return -EINVAL;
2075 2082
2076 if (!last_request)
2077 return -EINVAL;
2078
2079 /* 2083 /*
2080 * Lets only bother proceeding on the same alpha2 if the current 2084 * Lets only bother proceeding on the same alpha2 if the current
2081 * rd is non static (it means CRDA was present and was used last) 2085 * rd is non static (it means CRDA was present and was used last)
@@ -2097,9 +2101,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2097 * internal EEPROM data 2101 * internal EEPROM data
2098 */ 2102 */
2099 2103
2100 if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
2101 return -EINVAL;
2102
2103 if (!is_valid_rd(rd)) { 2104 if (!is_valid_rd(rd)) {
2104 pr_err("Invalid regulatory domain detected:\n"); 2105 pr_err("Invalid regulatory domain detected:\n");
2105 print_regdomain_info(rd); 2106 print_regdomain_info(rd);