aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorLuis R. Rodriguez <mcgrof@do-not-panic.com>2013-11-05 12:18:16 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-11-25 14:51:36 -0500
commitf5fe3247809815153e9fe88a989c251bd17059b9 (patch)
treedb2eda5d95dbcb78f0a9705a9b6b5d9c5732c883 /net/wireless
parent84721d44906f9a4ee8b0d41b31fcc9f45295c3a6 (diff)
cfg80211: set driver regulatory updates on its own
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>
Diffstat (limited to 'net/wireless')
-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,
2232 return 0; 2232 return 0;
2233} 2233}
2234 2234
2235/* Takes ownership of rd only if it doesn't fail */ 2235static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
2236static int __set_regdom(const struct ieee80211_regdomain *rd, 2236 struct regulatory_request *driver_request)
2237 struct regulatory_request *lr)
2238{ 2237{
2239 const struct ieee80211_regdomain *regd; 2238 const struct ieee80211_regdomain *regd;
2240 const struct ieee80211_regdomain *intersected_rd = NULL; 2239 const struct ieee80211_regdomain *intersected_rd = NULL;
2240 const struct ieee80211_regdomain *tmp;
2241 struct wiphy *request_wiphy; 2241 struct wiphy *request_wiphy;
2242 2242
2243 if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) && 2243 if (is_world_regdom(rd->alpha2))
2244 !is_unknown_alpha2(rd->alpha2))
2245 return -EINVAL; 2244 return -EINVAL;
2246 2245
2247 /* 2246 if (!regdom_changes(rd->alpha2))
2248 * Lets only bother proceeding on the same alpha2 if the current 2247 return -EALREADY;
2249 * rd is non static (it means CRDA was present and was used last)
2250 * and the pending request came in from a country IE
2251 */
2252 if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
2253 /*
2254 * If someone else asked us to change the rd lets only bother
2255 * checking if the alpha2 changes if CRDA was already called
2256 */
2257 if (!regdom_changes(rd->alpha2))
2258 return -EALREADY;
2259 }
2260
2261 /*
2262 * Now lets set the regulatory domain, update all driver channels
2263 * and finally inform them of what we have done, in case they want
2264 * to review or adjust their own settings based on their own
2265 * internal EEPROM data
2266 */
2267 2248
2268 if (!is_valid_rd(rd)) { 2249 if (!is_valid_rd(rd)) {
2269 pr_err("Invalid regulatory domain detected:\n"); 2250 pr_err("Invalid regulatory domain detected:\n");
@@ -2271,29 +2252,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd,
2271 return -EINVAL; 2252 return -EINVAL;
2272 } 2253 }
2273 2254
2274 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); 2255 request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);
2275 if (!request_wiphy && 2256 if (!request_wiphy) {
2276 (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
2277 lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
2278 schedule_delayed_work(&reg_timeout, 0); 2257 schedule_delayed_work(&reg_timeout, 0);
2279 return -ENODEV; 2258 return -ENODEV;
2280 } 2259 }
2281 2260
2282 if (!lr->intersect) { 2261 if (!driver_request->intersect) {
2283 if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
2284 reset_regdomains(false, rd);
2285 return 0;
2286 }
2287
2288 /*
2289 * For a driver hint, lets copy the regulatory domain the
2290 * driver wanted to the wiphy to deal with conflicts
2291 */
2292
2293 /*
2294 * Userspace could have sent two replies with only
2295 * one kernel request.
2296 */
2297 if (request_wiphy->regd) 2262 if (request_wiphy->regd)
2298 return -EALREADY; 2263 return -EALREADY;
2299 2264
@@ -2306,38 +2271,60 @@ static int __set_regdom(const struct ieee80211_regdomain *rd,
2306 return 0; 2271 return 0;
2307 } 2272 }
2308 2273
2309 /* Intersection requires a bit more work */ 2274 intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
2275 if (!intersected_rd)
2276 return -EINVAL;
2310 2277
2311 if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { 2278 /*
2312 intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); 2279 * We can trash what CRDA provided now.
2313 if (!intersected_rd) 2280 * However if a driver requested this specific regulatory
2314 return -EINVAL; 2281 * domain we keep it for its private use
2282 */
2283 tmp = get_wiphy_regdom(request_wiphy);
2284 rcu_assign_pointer(request_wiphy->regd, rd);
2285 rcu_free_regdom(tmp);
2315 2286
2316 /* 2287 rd = NULL;
2317 * We can trash what CRDA provided now.
2318 * However if a driver requested this specific regulatory
2319 * domain we keep it for its private use
2320 */
2321 if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) {
2322 const struct ieee80211_regdomain *tmp;
2323 2288
2324 tmp = get_wiphy_regdom(request_wiphy); 2289 reset_regdomains(false, intersected_rd);
2325 rcu_assign_pointer(request_wiphy->regd, rd);
2326 rcu_free_regdom(tmp);
2327 } else {
2328 kfree(rd);
2329 }
2330 2290
2331 rd = NULL; 2291 return 0;
2292}
2293
2294/* Takes ownership of rd only if it doesn't fail */
2295static int __set_regdom(const struct ieee80211_regdomain *rd,
2296 struct regulatory_request *lr)
2297{
2298 struct wiphy *request_wiphy;
2332 2299
2333 reset_regdomains(false, intersected_rd); 2300 if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&
2301 !is_unknown_alpha2(rd->alpha2))
2302 return -EINVAL;
2334 2303
2335 return 0; 2304 /*
2305 * Lets only bother proceeding on the same alpha2 if the current
2306 * rd is non static (it means CRDA was present and was used last)
2307 * and the pending request came in from a country IE
2308 */
2309
2310 if (!is_valid_rd(rd)) {
2311 pr_err("Invalid regulatory domain detected:\n");
2312 print_regdomain_info(rd);
2313 return -EINVAL;
2336 } 2314 }
2337 2315
2338 return -EINVAL; 2316 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
2339} 2317 if (!request_wiphy) {
2318 schedule_delayed_work(&reg_timeout, 0);
2319 return -ENODEV;
2320 }
2340 2321
2322 if (lr->intersect)
2323 return -EINVAL;
2324
2325 reset_regdomains(false, rd);
2326 return 0;
2327}
2341 2328
2342/* 2329/*
2343 * Use this call to set the current regulatory domain. Conflicts with 2330 * Use this call to set the current regulatory domain. Conflicts with
@@ -2365,6 +2352,8 @@ int set_regdom(const struct ieee80211_regdomain *rd)
2365 r = reg_set_rd_user(rd, lr); 2352 r = reg_set_rd_user(rd, lr);
2366 break; 2353 break;
2367 case NL80211_REGDOM_SET_BY_DRIVER: 2354 case NL80211_REGDOM_SET_BY_DRIVER:
2355 r = reg_set_rd_driver(rd, lr);
2356 break;
2368 case NL80211_REGDOM_SET_BY_COUNTRY_IE: 2357 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
2369 r = __set_regdom(rd, lr); 2358 r = __set_regdom(rd, lr);
2370 break; 2359 break;