aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/reg.c')
-rw-r--r--net/wireless/reg.c145
1 files changed, 96 insertions, 49 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 48dfc7b4e981..0e347f888fe9 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -82,17 +82,12 @@
82 * be intersected with the current one. 82 * be intersected with the current one.
83 * @REG_REQ_ALREADY_SET: the regulatory request will not change the current 83 * @REG_REQ_ALREADY_SET: the regulatory request will not change the current
84 * regulatory settings, and no further processing is required. 84 * regulatory settings, and no further processing is required.
85 * @REG_REQ_USER_HINT_HANDLED: a non alpha2 user hint was handled and no
86 * further processing is required, i.e., not need to update last_request
87 * etc. This should be used for user hints that do not provide an alpha2
88 * but some other type of regulatory hint, i.e., indoor operation.
89 */ 85 */
90enum reg_request_treatment { 86enum reg_request_treatment {
91 REG_REQ_OK, 87 REG_REQ_OK,
92 REG_REQ_IGNORE, 88 REG_REQ_IGNORE,
93 REG_REQ_INTERSECT, 89 REG_REQ_INTERSECT,
94 REG_REQ_ALREADY_SET, 90 REG_REQ_ALREADY_SET,
95 REG_REQ_USER_HINT_HANDLED,
96}; 91};
97 92
98static struct regulatory_request core_request_world = { 93static struct regulatory_request core_request_world = {
@@ -133,9 +128,17 @@ static int reg_num_devs_support_basehint;
133 * State variable indicating if the platform on which the devices 128 * State variable indicating if the platform on which the devices
134 * are attached is operating in an indoor environment. The state variable 129 * are attached is operating in an indoor environment. The state variable
135 * is relevant for all registered devices. 130 * is relevant for all registered devices.
136 * (protected by RTNL)
137 */ 131 */
138static bool reg_is_indoor; 132static bool reg_is_indoor;
133static spinlock_t reg_indoor_lock;
134
135/* Used to track the userspace process controlling the indoor setting */
136static u32 reg_is_indoor_portid;
137
138/* Max number of consecutive attempts to communicate with CRDA */
139#define REG_MAX_CRDA_TIMEOUTS 10
140
141static u32 reg_crda_timeouts;
139 142
140static const struct ieee80211_regdomain *get_cfg80211_regdom(void) 143static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
141{ 144{
@@ -487,7 +490,7 @@ static void reg_regdb_search(struct work_struct *work)
487 mutex_unlock(&reg_regdb_search_mutex); 490 mutex_unlock(&reg_regdb_search_mutex);
488 491
489 if (!IS_ERR_OR_NULL(regdom)) 492 if (!IS_ERR_OR_NULL(regdom))
490 set_regdom(regdom); 493 set_regdom(regdom, REGD_SOURCE_INTERNAL_DB);
491 494
492 rtnl_unlock(); 495 rtnl_unlock();
493} 496}
@@ -537,15 +540,20 @@ static int call_crda(const char *alpha2)
537 snprintf(country, sizeof(country), "COUNTRY=%c%c", 540 snprintf(country, sizeof(country), "COUNTRY=%c%c",
538 alpha2[0], alpha2[1]); 541 alpha2[0], alpha2[1]);
539 542
543 /* query internal regulatory database (if it exists) */
544 reg_regdb_query(alpha2);
545
546 if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) {
547 pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n");
548 return -EINVAL;
549 }
550
540 if (!is_world_regdom((char *) alpha2)) 551 if (!is_world_regdom((char *) alpha2))
541 pr_info("Calling CRDA for country: %c%c\n", 552 pr_info("Calling CRDA for country: %c%c\n",
542 alpha2[0], alpha2[1]); 553 alpha2[0], alpha2[1]);
543 else 554 else
544 pr_info("Calling CRDA to update world regulatory domain\n"); 555 pr_info("Calling CRDA to update world regulatory domain\n");
545 556
546 /* query internal regulatory database (if it exists) */
547 reg_regdb_query(alpha2);
548
549 return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env); 557 return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
550} 558}
551 559
@@ -554,6 +562,9 @@ reg_call_crda(struct regulatory_request *request)
554{ 562{
555 if (call_crda(request->alpha2)) 563 if (call_crda(request->alpha2))
556 return REG_REQ_IGNORE; 564 return REG_REQ_IGNORE;
565
566 queue_delayed_work(system_power_efficient_wq,
567 &reg_timeout, msecs_to_jiffies(3142));
557 return REG_REQ_OK; 568 return REG_REQ_OK;
558} 569}
559 570
@@ -1248,13 +1259,6 @@ static bool reg_request_cell_base(struct regulatory_request *request)
1248 return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE; 1259 return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
1249} 1260}
1250 1261
1251static bool reg_request_indoor(struct regulatory_request *request)
1252{
1253 if (request->initiator != NL80211_REGDOM_SET_BY_USER)
1254 return false;
1255 return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
1256}
1257
1258bool reg_last_request_cell_base(void) 1262bool reg_last_request_cell_base(void)
1259{ 1263{
1260 return reg_request_cell_base(get_last_request()); 1264 return reg_request_cell_base(get_last_request());
@@ -1800,8 +1804,7 @@ static void reg_set_request_processed(void)
1800 need_more_processing = true; 1804 need_more_processing = true;
1801 spin_unlock(&reg_requests_lock); 1805 spin_unlock(&reg_requests_lock);
1802 1806
1803 if (lr->initiator == NL80211_REGDOM_SET_BY_USER) 1807 cancel_delayed_work(&reg_timeout);
1804 cancel_delayed_work(&reg_timeout);
1805 1808
1806 if (need_more_processing) 1809 if (need_more_processing)
1807 schedule_work(&reg_work); 1810 schedule_work(&reg_work);
@@ -1833,11 +1836,6 @@ __reg_process_hint_user(struct regulatory_request *user_request)
1833{ 1836{
1834 struct regulatory_request *lr = get_last_request(); 1837 struct regulatory_request *lr = get_last_request();
1835 1838
1836 if (reg_request_indoor(user_request)) {
1837 reg_is_indoor = true;
1838 return REG_REQ_USER_HINT_HANDLED;
1839 }
1840
1841 if (reg_request_cell_base(user_request)) 1839 if (reg_request_cell_base(user_request))
1842 return reg_ignore_cell_hint(user_request); 1840 return reg_ignore_cell_hint(user_request);
1843 1841
@@ -1885,8 +1883,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
1885 1883
1886 treatment = __reg_process_hint_user(user_request); 1884 treatment = __reg_process_hint_user(user_request);
1887 if (treatment == REG_REQ_IGNORE || 1885 if (treatment == REG_REQ_IGNORE ||
1888 treatment == REG_REQ_ALREADY_SET || 1886 treatment == REG_REQ_ALREADY_SET) {
1889 treatment == REG_REQ_USER_HINT_HANDLED) {
1890 reg_free_request(user_request); 1887 reg_free_request(user_request);
1891 return treatment; 1888 return treatment;
1892 } 1889 }
@@ -1947,7 +1944,6 @@ reg_process_hint_driver(struct wiphy *wiphy,
1947 case REG_REQ_OK: 1944 case REG_REQ_OK:
1948 break; 1945 break;
1949 case REG_REQ_IGNORE: 1946 case REG_REQ_IGNORE:
1950 case REG_REQ_USER_HINT_HANDLED:
1951 reg_free_request(driver_request); 1947 reg_free_request(driver_request);
1952 return treatment; 1948 return treatment;
1953 case REG_REQ_INTERSECT: 1949 case REG_REQ_INTERSECT:
@@ -2047,7 +2043,6 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
2047 case REG_REQ_OK: 2043 case REG_REQ_OK:
2048 break; 2044 break;
2049 case REG_REQ_IGNORE: 2045 case REG_REQ_IGNORE:
2050 case REG_REQ_USER_HINT_HANDLED:
2051 /* fall through */ 2046 /* fall through */
2052 case REG_REQ_ALREADY_SET: 2047 case REG_REQ_ALREADY_SET:
2053 reg_free_request(country_ie_request); 2048 reg_free_request(country_ie_request);
@@ -2086,11 +2081,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
2086 case NL80211_REGDOM_SET_BY_USER: 2081 case NL80211_REGDOM_SET_BY_USER:
2087 treatment = reg_process_hint_user(reg_request); 2082 treatment = reg_process_hint_user(reg_request);
2088 if (treatment == REG_REQ_IGNORE || 2083 if (treatment == REG_REQ_IGNORE ||
2089 treatment == REG_REQ_ALREADY_SET || 2084 treatment == REG_REQ_ALREADY_SET)
2090 treatment == REG_REQ_USER_HINT_HANDLED)
2091 return; 2085 return;
2092 queue_delayed_work(system_power_efficient_wq,
2093 &reg_timeout, msecs_to_jiffies(3142));
2094 return; 2086 return;
2095 case NL80211_REGDOM_SET_BY_DRIVER: 2087 case NL80211_REGDOM_SET_BY_DRIVER:
2096 if (!wiphy) 2088 if (!wiphy)
@@ -2177,6 +2169,13 @@ static void reg_process_pending_hints(void)
2177 } 2169 }
2178 2170
2179 reg_process_hint(reg_request); 2171 reg_process_hint(reg_request);
2172
2173 lr = get_last_request();
2174
2175 spin_lock(&reg_requests_lock);
2176 if (!list_empty(&reg_requests_list) && lr && lr->processed)
2177 schedule_work(&reg_work);
2178 spin_unlock(&reg_requests_lock);
2180} 2179}
2181 2180
2182/* Processes beacon hints -- this has nothing to do with country IEs */ 2181/* Processes beacon hints -- this has nothing to do with country IEs */
@@ -2304,27 +2303,58 @@ int regulatory_hint_user(const char *alpha2,
2304 request->initiator = NL80211_REGDOM_SET_BY_USER; 2303 request->initiator = NL80211_REGDOM_SET_BY_USER;
2305 request->user_reg_hint_type = user_reg_hint_type; 2304 request->user_reg_hint_type = user_reg_hint_type;
2306 2305
2306 /* Allow calling CRDA again */
2307 reg_crda_timeouts = 0;
2308
2307 queue_regulatory_request(request); 2309 queue_regulatory_request(request);
2308 2310
2309 return 0; 2311 return 0;
2310} 2312}
2311 2313
2312int regulatory_hint_indoor_user(void) 2314int regulatory_hint_indoor(bool is_indoor, u32 portid)
2313{ 2315{
2314 struct regulatory_request *request; 2316 spin_lock(&reg_indoor_lock);
2315 2317
2316 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); 2318 /* It is possible that more than one user space process is trying to
2317 if (!request) 2319 * configure the indoor setting. To handle such cases, clear the indoor
2318 return -ENOMEM; 2320 * setting in case that some process does not think that the device
2321 * is operating in an indoor environment. In addition, if a user space
2322 * process indicates that it is controlling the indoor setting, save its
2323 * portid, i.e., make it the owner.
2324 */
2325 reg_is_indoor = is_indoor;
2326 if (reg_is_indoor) {
2327 if (!reg_is_indoor_portid)
2328 reg_is_indoor_portid = portid;
2329 } else {
2330 reg_is_indoor_portid = 0;
2331 }
2319 2332
2320 request->wiphy_idx = WIPHY_IDX_INVALID; 2333 spin_unlock(&reg_indoor_lock);
2321 request->initiator = NL80211_REGDOM_SET_BY_USER; 2334
2322 request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR; 2335 if (!is_indoor)
2323 queue_regulatory_request(request); 2336 reg_check_channels();
2324 2337
2325 return 0; 2338 return 0;
2326} 2339}
2327 2340
2341void regulatory_netlink_notify(u32 portid)
2342{
2343 spin_lock(&reg_indoor_lock);
2344
2345 if (reg_is_indoor_portid != portid) {
2346 spin_unlock(&reg_indoor_lock);
2347 return;
2348 }
2349
2350 reg_is_indoor = false;
2351 reg_is_indoor_portid = 0;
2352
2353 spin_unlock(&reg_indoor_lock);
2354
2355 reg_check_channels();
2356}
2357
2328/* Driver hints */ 2358/* Driver hints */
2329int regulatory_hint(struct wiphy *wiphy, const char *alpha2) 2359int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
2330{ 2360{
@@ -2345,6 +2375,9 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
2345 request->alpha2[1] = alpha2[1]; 2375 request->alpha2[1] = alpha2[1];
2346 request->initiator = NL80211_REGDOM_SET_BY_DRIVER; 2376 request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
2347 2377
2378 /* Allow calling CRDA again */
2379 reg_crda_timeouts = 0;
2380
2348 queue_regulatory_request(request); 2381 queue_regulatory_request(request);
2349 2382
2350 return 0; 2383 return 0;
@@ -2398,6 +2431,9 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band,
2398 request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; 2431 request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE;
2399 request->country_ie_env = env; 2432 request->country_ie_env = env;
2400 2433
2434 /* Allow calling CRDA again */
2435 reg_crda_timeouts = 0;
2436
2401 queue_regulatory_request(request); 2437 queue_regulatory_request(request);
2402 request = NULL; 2438 request = NULL;
2403out: 2439out:
@@ -2486,13 +2522,22 @@ static void restore_regulatory_settings(bool reset_user)
2486 char alpha2[2]; 2522 char alpha2[2];
2487 char world_alpha2[2]; 2523 char world_alpha2[2];
2488 struct reg_beacon *reg_beacon, *btmp; 2524 struct reg_beacon *reg_beacon, *btmp;
2489 struct regulatory_request *reg_request, *tmp;
2490 LIST_HEAD(tmp_reg_req_list); 2525 LIST_HEAD(tmp_reg_req_list);
2491 struct cfg80211_registered_device *rdev; 2526 struct cfg80211_registered_device *rdev;
2492 2527
2493 ASSERT_RTNL(); 2528 ASSERT_RTNL();
2494 2529
2495 reg_is_indoor = false; 2530 /*
2531 * Clear the indoor setting in case that it is not controlled by user
2532 * space, as otherwise there is no guarantee that the device is still
2533 * operating in an indoor environment.
2534 */
2535 spin_lock(&reg_indoor_lock);
2536 if (reg_is_indoor && !reg_is_indoor_portid) {
2537 reg_is_indoor = false;
2538 reg_check_channels();
2539 }
2540 spin_unlock(&reg_indoor_lock);
2496 2541
2497 reset_regdomains(true, &world_regdom); 2542 reset_regdomains(true, &world_regdom);
2498 restore_alpha2(alpha2, reset_user); 2543 restore_alpha2(alpha2, reset_user);
@@ -2504,11 +2549,7 @@ static void restore_regulatory_settings(bool reset_user)
2504 * settings. 2549 * settings.
2505 */ 2550 */
2506 spin_lock(&reg_requests_lock); 2551 spin_lock(&reg_requests_lock);
2507 list_for_each_entry_safe(reg_request, tmp, &reg_requests_list, list) { 2552 list_splice_tail_init(&reg_requests_list, &tmp_reg_req_list);
2508 if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER)
2509 continue;
2510 list_move_tail(&reg_request->list, &tmp_reg_req_list);
2511 }
2512 spin_unlock(&reg_requests_lock); 2553 spin_unlock(&reg_requests_lock);
2513 2554
2514 /* Clear beacon hints */ 2555 /* Clear beacon hints */
@@ -2871,7 +2912,8 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
2871 * multiple drivers can be ironed out later. Caller must've already 2912 * multiple drivers can be ironed out later. Caller must've already
2872 * kmalloc'd the rd structure. 2913 * kmalloc'd the rd structure.
2873 */ 2914 */
2874int set_regdom(const struct ieee80211_regdomain *rd) 2915int set_regdom(const struct ieee80211_regdomain *rd,
2916 enum ieee80211_regd_source regd_src)
2875{ 2917{
2876 struct regulatory_request *lr; 2918 struct regulatory_request *lr;
2877 bool user_reset = false; 2919 bool user_reset = false;
@@ -2882,6 +2924,9 @@ int set_regdom(const struct ieee80211_regdomain *rd)
2882 return -EINVAL; 2924 return -EINVAL;
2883 } 2925 }
2884 2926
2927 if (regd_src == REGD_SOURCE_CRDA)
2928 reg_crda_timeouts = 0;
2929
2885 lr = get_last_request(); 2930 lr = get_last_request();
2886 2931
2887 /* Note that this doesn't update the wiphys, this is done below */ 2932 /* Note that this doesn't update the wiphys, this is done below */
@@ -3041,6 +3086,7 @@ static void reg_timeout_work(struct work_struct *work)
3041{ 3086{
3042 REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); 3087 REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
3043 rtnl_lock(); 3088 rtnl_lock();
3089 reg_crda_timeouts++;
3044 restore_regulatory_settings(true); 3090 restore_regulatory_settings(true);
3045 rtnl_unlock(); 3091 rtnl_unlock();
3046} 3092}
@@ -3089,6 +3135,7 @@ int __init regulatory_init(void)
3089 3135
3090 spin_lock_init(&reg_requests_lock); 3136 spin_lock_init(&reg_requests_lock);
3091 spin_lock_init(&reg_pending_beacons_lock); 3137 spin_lock_init(&reg_pending_beacons_lock);
3138 spin_lock_init(&reg_indoor_lock);
3092 3139
3093 reg_regdb_size_check(); 3140 reg_regdb_size_check();
3094 3141