diff options
author | Luis R. Rodriguez <mcgrof@do-not-panic.com> | 2013-11-05 12:18:16 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-11-25 14:51:36 -0500 |
commit | f5fe3247809815153e9fe88a989c251bd17059b9 (patch) | |
tree | db2eda5d95dbcb78f0a9705a9b6b5d9c5732c883 /net/wireless | |
parent | 84721d44906f9a4ee8b0d41b31fcc9f45295c3a6 (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.c | 123 |
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 */ | 2235 | static int reg_set_rd_driver(const struct ieee80211_regdomain *rd, |
2236 | static 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(®_timeout, 0); | 2257 | schedule_delayed_work(®_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 */ | ||
2295 | static 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(®_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; |