aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/reg.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-12-06 10:29:25 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-03 07:01:30 -0500
commitc492db370c17c428a0a58d3673294d4e99634b7d (patch)
treea350365e3cdb2f37c1249f6871eaeb36a811512b /net/wireless/reg.c
parent458f4f9e960b9a3b674c4b87d996eef186b1fe83 (diff)
regulatory: use RCU to protect last_request
This will allow making freq_reg_info() lock-free. 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.c199
1 files changed, 109 insertions, 90 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 9b64b201cdf1..2a7c3adf902f 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -82,7 +82,8 @@ static struct regulatory_request core_request_world = {
82}; 82};
83 83
84/* Receipt of information from last regulatory request */ 84/* Receipt of information from last regulatory request */
85static struct regulatory_request *last_request = &core_request_world; 85static struct regulatory_request __rcu *last_request =
86 (void __rcu *)&core_request_world;
86 87
87/* To trigger userspace events */ 88/* To trigger userspace events */
88static struct platform_device *reg_pdev; 89static struct platform_device *reg_pdev;
@@ -102,7 +103,7 @@ const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
102 * Protects static reg.c components: 103 * Protects static reg.c components:
103 * - cfg80211_regdomain (if not used with RCU) 104 * - cfg80211_regdomain (if not used with RCU)
104 * - cfg80211_world_regdom 105 * - cfg80211_world_regdom
105 * - last_request 106 * - last_request (if not used with RCU)
106 * - reg_num_devs_support_basehint 107 * - reg_num_devs_support_basehint
107 */ 108 */
108static DEFINE_MUTEX(reg_mutex); 109static DEFINE_MUTEX(reg_mutex);
@@ -137,6 +138,12 @@ static void rcu_free_regdom(const struct ieee80211_regdomain *r)
137 kfree_rcu((struct ieee80211_regdomain *)r, rcu_head); 138 kfree_rcu((struct ieee80211_regdomain *)r, rcu_head);
138} 139}
139 140
141static struct regulatory_request *get_last_request(void)
142{
143 return rcu_dereference_protected(last_request,
144 lockdep_is_held(&reg_mutex));
145}
146
140/* Used to queue up regulatory hints */ 147/* Used to queue up regulatory hints */
141static LIST_HEAD(reg_requests_list); 148static LIST_HEAD(reg_requests_list);
142static spinlock_t reg_requests_lock; 149static spinlock_t reg_requests_lock;
@@ -206,6 +213,7 @@ static void reset_regdomains(bool full_reset,
206 const struct ieee80211_regdomain *new_regdom) 213 const struct ieee80211_regdomain *new_regdom)
207{ 214{
208 const struct ieee80211_regdomain *r; 215 const struct ieee80211_regdomain *r;
216 struct regulatory_request *lr;
209 217
210 assert_reg_lock(); 218 assert_reg_lock();
211 219
@@ -228,9 +236,10 @@ static void reset_regdomains(bool full_reset,
228 if (!full_reset) 236 if (!full_reset)
229 return; 237 return;
230 238
231 if (last_request != &core_request_world) 239 lr = get_last_request();
232 kfree(last_request); 240 if (lr != &core_request_world && lr)
233 last_request = &core_request_world; 241 kfree_rcu(lr, rcu_head);
242 rcu_assign_pointer(last_request, &core_request_world);
234} 243}
235 244
236/* 245/*
@@ -239,9 +248,11 @@ static void reset_regdomains(bool full_reset,
239 */ 248 */
240static void update_world_regdomain(const struct ieee80211_regdomain *rd) 249static void update_world_regdomain(const struct ieee80211_regdomain *rd)
241{ 250{
242 WARN_ON(!last_request); 251 struct regulatory_request *lr;
243 252
244 assert_reg_lock(); 253 lr = get_last_request();
254
255 WARN_ON(!lr);
245 256
246 reset_regdomains(false, rd); 257 reset_regdomains(false, rd);
247 258
@@ -448,15 +459,12 @@ static int call_crda(const char *alpha2)
448 459
449static bool reg_is_valid_request(const char *alpha2) 460static bool reg_is_valid_request(const char *alpha2)
450{ 461{
451 assert_reg_lock(); 462 struct regulatory_request *lr = get_last_request();
452 463
453 if (!last_request) 464 if (!lr || lr->processed)
454 return false; 465 return false;
455 466
456 if (last_request->processed) 467 return alpha2_equal(lr->alpha2, alpha2);
457 return false;
458
459 return alpha2_equal(last_request->alpha2, alpha2);
460} 468}
461 469
462/* Sanity check on a regulatory rule */ 470/* Sanity check on a regulatory rule */
@@ -746,15 +754,14 @@ int freq_reg_info(struct wiphy *wiphy, u32 center_freq,
746 const struct ieee80211_reg_rule **reg_rule) 754 const struct ieee80211_reg_rule **reg_rule)
747{ 755{
748 const struct ieee80211_regdomain *regd; 756 const struct ieee80211_regdomain *regd;
749 757 struct regulatory_request *lr = get_last_request();
750 assert_reg_lock();
751 758
752 /* 759 /*
753 * Follow the driver's regulatory domain, if present, unless a country 760 * Follow the driver's regulatory domain, if present, unless a country
754 * IE has been processed or a user wants to help complaince further 761 * IE has been processed or a user wants to help complaince further
755 */ 762 */
756 if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && 763 if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
757 last_request->initiator != NL80211_REGDOM_SET_BY_USER && 764 lr->initiator != NL80211_REGDOM_SET_BY_USER &&
758 wiphy->regd) 765 wiphy->regd)
759 regd = get_wiphy_regdom(wiphy); 766 regd = get_wiphy_regdom(wiphy);
760 else 767 else
@@ -828,8 +835,9 @@ static void handle_channel(struct wiphy *wiphy,
828 const struct ieee80211_power_rule *power_rule = NULL; 835 const struct ieee80211_power_rule *power_rule = NULL;
829 const struct ieee80211_freq_range *freq_range = NULL; 836 const struct ieee80211_freq_range *freq_range = NULL;
830 struct wiphy *request_wiphy = NULL; 837 struct wiphy *request_wiphy = NULL;
838 struct regulatory_request *lr = get_last_request();
831 839
832 request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); 840 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
833 841
834 flags = chan->orig_flags; 842 flags = chan->orig_flags;
835 843
@@ -862,7 +870,7 @@ static void handle_channel(struct wiphy *wiphy,
862 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40)) 870 if (freq_range->max_bandwidth_khz < MHZ_TO_KHZ(40))
863 bw_flags = IEEE80211_CHAN_NO_HT40; 871 bw_flags = IEEE80211_CHAN_NO_HT40;
864 872
865 if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && 873 if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
866 request_wiphy && request_wiphy == wiphy && 874 request_wiphy && request_wiphy == wiphy &&
867 request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) { 875 request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
868 /* 876 /*
@@ -927,7 +935,7 @@ bool reg_last_request_cell_base(void)
927 bool val; 935 bool val;
928 936
929 mutex_lock(&reg_mutex); 937 mutex_lock(&reg_mutex);
930 val = reg_request_cell_base(last_request); 938 val = reg_request_cell_base(get_last_request());
931 mutex_unlock(&reg_mutex); 939 mutex_unlock(&reg_mutex);
932 940
933 return val; 941 return val;
@@ -938,10 +946,12 @@ bool reg_last_request_cell_base(void)
938static enum reg_request_treatment 946static enum reg_request_treatment
939reg_ignore_cell_hint(struct regulatory_request *pending_request) 947reg_ignore_cell_hint(struct regulatory_request *pending_request)
940{ 948{
949 struct regulatory_request *lr = get_last_request();
950
941 if (!reg_num_devs_support_basehint) 951 if (!reg_num_devs_support_basehint)
942 return REG_REQ_IGNORE; 952 return REG_REQ_IGNORE;
943 953
944 if (reg_request_cell_base(last_request) && 954 if (reg_request_cell_base(lr) &&
945 !regdom_changes(pending_request->alpha2)) 955 !regdom_changes(pending_request->alpha2))
946 return REG_REQ_ALREADY_SET; 956 return REG_REQ_ALREADY_SET;
947 957
@@ -969,7 +979,9 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
969static bool ignore_reg_update(struct wiphy *wiphy, 979static bool ignore_reg_update(struct wiphy *wiphy,
970 enum nl80211_reg_initiator initiator) 980 enum nl80211_reg_initiator initiator)
971{ 981{
972 if (!last_request) { 982 struct regulatory_request *lr = get_last_request();
983
984 if (!lr) {
973 REG_DBG_PRINT("Ignoring regulatory request %s since last_request is not set\n", 985 REG_DBG_PRINT("Ignoring regulatory request %s since last_request is not set\n",
974 reg_initiator_name(initiator)); 986 reg_initiator_name(initiator));
975 return true; 987 return true;
@@ -988,13 +1000,13 @@ static bool ignore_reg_update(struct wiphy *wiphy,
988 */ 1000 */
989 if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && 1001 if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd &&
990 initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && 1002 initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
991 !is_world_regdom(last_request->alpha2)) { 1003 !is_world_regdom(lr->alpha2)) {
992 REG_DBG_PRINT("Ignoring regulatory request %s since the driver requires its own regulatory domain to be set first\n", 1004 REG_DBG_PRINT("Ignoring regulatory request %s since the driver requires its own regulatory domain to be set first\n",
993 reg_initiator_name(initiator)); 1005 reg_initiator_name(initiator));
994 return true; 1006 return true;
995 } 1007 }
996 1008
997 if (reg_request_cell_base(last_request)) 1009 if (reg_request_cell_base(lr))
998 return reg_dev_ignore_cell_hint(wiphy); 1010 return reg_dev_ignore_cell_hint(wiphy);
999 1011
1000 return false; 1012 return false;
@@ -1080,12 +1092,12 @@ static bool reg_is_world_roaming(struct wiphy *wiphy)
1080{ 1092{
1081 const struct ieee80211_regdomain *cr = get_cfg80211_regdom(); 1093 const struct ieee80211_regdomain *cr = get_cfg80211_regdom();
1082 const struct ieee80211_regdomain *wr = get_wiphy_regdom(wiphy); 1094 const struct ieee80211_regdomain *wr = get_wiphy_regdom(wiphy);
1095 struct regulatory_request *lr = get_last_request();
1083 1096
1084 if (is_world_regdom(cr->alpha2) || (wr && is_world_regdom(wr->alpha2))) 1097 if (is_world_regdom(cr->alpha2) || (wr && is_world_regdom(wr->alpha2)))
1085 return true; 1098 return true;
1086 1099
1087 if (last_request && 1100 if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
1088 last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
1089 wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) 1101 wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)
1090 return true; 1102 return true;
1091 1103
@@ -1184,13 +1196,12 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
1184 enum nl80211_reg_initiator initiator) 1196 enum nl80211_reg_initiator initiator)
1185{ 1197{
1186 enum ieee80211_band band; 1198 enum ieee80211_band band;
1187 1199 struct regulatory_request *lr = get_last_request();
1188 assert_reg_lock();
1189 1200
1190 if (ignore_reg_update(wiphy, initiator)) 1201 if (ignore_reg_update(wiphy, initiator))
1191 return; 1202 return;
1192 1203
1193 last_request->dfs_region = get_cfg80211_regdom()->dfs_region; 1204 lr->dfs_region = get_cfg80211_regdom()->dfs_region;
1194 1205
1195 for (band = 0; band < IEEE80211_NUM_BANDS; band++) 1206 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
1196 handle_band(wiphy, initiator, wiphy->bands[band]); 1207 handle_band(wiphy, initiator, wiphy->bands[band]);
@@ -1199,7 +1210,7 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
1199 reg_process_ht_flags(wiphy); 1210 reg_process_ht_flags(wiphy);
1200 1211
1201 if (wiphy->reg_notifier) 1212 if (wiphy->reg_notifier)
1202 wiphy->reg_notifier(wiphy, last_request); 1213 wiphy->reg_notifier(wiphy, lr);
1203} 1214}
1204 1215
1205static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) 1216static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
@@ -1220,7 +1231,7 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
1220 if (initiator == NL80211_REGDOM_SET_BY_CORE && 1231 if (initiator == NL80211_REGDOM_SET_BY_CORE &&
1221 wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY && 1232 wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
1222 wiphy->reg_notifier) 1233 wiphy->reg_notifier)
1223 wiphy->reg_notifier(wiphy, last_request); 1234 wiphy->reg_notifier(wiphy, get_last_request());
1224 } 1235 }
1225} 1236}
1226 1237
@@ -1300,28 +1311,28 @@ get_reg_request_treatment(struct wiphy *wiphy,
1300 struct regulatory_request *pending_request) 1311 struct regulatory_request *pending_request)
1301{ 1312{
1302 struct wiphy *last_wiphy = NULL; 1313 struct wiphy *last_wiphy = NULL;
1314 struct regulatory_request *lr = get_last_request();
1303 1315
1304 /* All initial requests are respected */ 1316 /* All initial requests are respected */
1305 if (!last_request) 1317 if (!lr)
1306 return REG_REQ_OK; 1318 return REG_REQ_OK;
1307 1319
1308 switch (pending_request->initiator) { 1320 switch (pending_request->initiator) {
1309 case NL80211_REGDOM_SET_BY_CORE: 1321 case NL80211_REGDOM_SET_BY_CORE:
1310 return REG_REQ_OK; 1322 return REG_REQ_OK;
1311 case NL80211_REGDOM_SET_BY_COUNTRY_IE: 1323 case NL80211_REGDOM_SET_BY_COUNTRY_IE:
1312 if (reg_request_cell_base(last_request)) { 1324 if (reg_request_cell_base(lr)) {
1313 /* Trust a Cell base station over the AP's country IE */ 1325 /* Trust a Cell base station over the AP's country IE */
1314 if (regdom_changes(pending_request->alpha2)) 1326 if (regdom_changes(pending_request->alpha2))
1315 return REG_REQ_IGNORE; 1327 return REG_REQ_IGNORE;
1316 return REG_REQ_ALREADY_SET; 1328 return REG_REQ_ALREADY_SET;
1317 } 1329 }
1318 1330
1319 last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); 1331 last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
1320 1332
1321 if (unlikely(!is_an_alpha2(pending_request->alpha2))) 1333 if (unlikely(!is_an_alpha2(pending_request->alpha2)))
1322 return -EINVAL; 1334 return -EINVAL;
1323 if (last_request->initiator == 1335 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
1324 NL80211_REGDOM_SET_BY_COUNTRY_IE) {
1325 if (last_wiphy != wiphy) { 1336 if (last_wiphy != wiphy) {
1326 /* 1337 /*
1327 * Two cards with two APs claiming different 1338 * Two cards with two APs claiming different
@@ -1343,7 +1354,7 @@ get_reg_request_treatment(struct wiphy *wiphy,
1343 } 1354 }
1344 return 0; 1355 return 0;
1345 case NL80211_REGDOM_SET_BY_DRIVER: 1356 case NL80211_REGDOM_SET_BY_DRIVER:
1346 if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { 1357 if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
1347 if (regdom_changes(pending_request->alpha2)) 1358 if (regdom_changes(pending_request->alpha2))
1348 return REG_REQ_OK; 1359 return REG_REQ_OK;
1349 return REG_REQ_ALREADY_SET; 1360 return REG_REQ_ALREADY_SET;
@@ -1354,7 +1365,7 @@ get_reg_request_treatment(struct wiphy *wiphy,
1354 * back in or if you add a new device for which the previously 1365 * back in or if you add a new device for which the previously
1355 * loaded card also agrees on the regulatory domain. 1366 * loaded card also agrees on the regulatory domain.
1356 */ 1367 */
1357 if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && 1368 if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
1358 !regdom_changes(pending_request->alpha2)) 1369 !regdom_changes(pending_request->alpha2))
1359 return REG_REQ_ALREADY_SET; 1370 return REG_REQ_ALREADY_SET;
1360 1371
@@ -1363,26 +1374,26 @@ get_reg_request_treatment(struct wiphy *wiphy,
1363 if (reg_request_cell_base(pending_request)) 1374 if (reg_request_cell_base(pending_request))
1364 return reg_ignore_cell_hint(pending_request); 1375 return reg_ignore_cell_hint(pending_request);
1365 1376
1366 if (reg_request_cell_base(last_request)) 1377 if (reg_request_cell_base(lr))
1367 return REG_REQ_IGNORE; 1378 return REG_REQ_IGNORE;
1368 1379
1369 if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) 1380 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
1370 return REG_REQ_INTERSECT; 1381 return REG_REQ_INTERSECT;
1371 /* 1382 /*
1372 * If the user knows better the user should set the regdom 1383 * If the user knows better the user should set the regdom
1373 * to their country before the IE is picked up 1384 * to their country before the IE is picked up
1374 */ 1385 */
1375 if (last_request->initiator == NL80211_REGDOM_SET_BY_USER && 1386 if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
1376 last_request->intersect) 1387 lr->intersect)
1377 return REG_REQ_IGNORE; 1388 return REG_REQ_IGNORE;
1378 /* 1389 /*
1379 * Process user requests only after previous user/driver/core 1390 * Process user requests only after previous user/driver/core
1380 * requests have been processed 1391 * requests have been processed
1381 */ 1392 */
1382 if ((last_request->initiator == NL80211_REGDOM_SET_BY_CORE || 1393 if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||
1383 last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || 1394 lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
1384 last_request->initiator == NL80211_REGDOM_SET_BY_USER) && 1395 lr->initiator == NL80211_REGDOM_SET_BY_USER) &&
1385 regdom_changes(last_request->alpha2)) 1396 regdom_changes(lr->alpha2))
1386 return REG_REQ_IGNORE; 1397 return REG_REQ_IGNORE;
1387 1398
1388 if (!regdom_changes(pending_request->alpha2)) 1399 if (!regdom_changes(pending_request->alpha2))
@@ -1397,15 +1408,16 @@ get_reg_request_treatment(struct wiphy *wiphy,
1397static void reg_set_request_processed(void) 1408static void reg_set_request_processed(void)
1398{ 1409{
1399 bool need_more_processing = false; 1410 bool need_more_processing = false;
1411 struct regulatory_request *lr = get_last_request();
1400 1412
1401 last_request->processed = true; 1413 lr->processed = true;
1402 1414
1403 spin_lock(&reg_requests_lock); 1415 spin_lock(&reg_requests_lock);
1404 if (!list_empty(&reg_requests_list)) 1416 if (!list_empty(&reg_requests_list))
1405 need_more_processing = true; 1417 need_more_processing = true;
1406 spin_unlock(&reg_requests_lock); 1418 spin_unlock(&reg_requests_lock);
1407 1419
1408 if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) 1420 if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
1409 cancel_delayed_work(&reg_timeout); 1421 cancel_delayed_work(&reg_timeout);
1410 1422
1411 if (need_more_processing) 1423 if (need_more_processing)
@@ -1432,6 +1444,7 @@ __regulatory_hint(struct wiphy *wiphy,
1432 const struct ieee80211_regdomain *regd; 1444 const struct ieee80211_regdomain *regd;
1433 bool intersect = false; 1445 bool intersect = false;
1434 enum reg_request_treatment treatment; 1446 enum reg_request_treatment treatment;
1447 struct regulatory_request *lr;
1435 1448
1436 treatment = get_reg_request_treatment(wiphy, pending_request); 1449 treatment = get_reg_request_treatment(wiphy, pending_request);
1437 1450
@@ -1472,18 +1485,20 @@ __regulatory_hint(struct wiphy *wiphy,
1472 } 1485 }
1473 1486
1474new_request: 1487new_request:
1475 if (last_request != &core_request_world) 1488 lr = get_last_request();
1476 kfree(last_request); 1489 if (lr != &core_request_world && lr)
1490 kfree_rcu(lr, rcu_head);
1477 1491
1478 last_request = pending_request; 1492 pending_request->intersect = intersect;
1479 last_request->intersect = intersect; 1493 pending_request->processed = false;
1480 last_request->processed = false; 1494 rcu_assign_pointer(last_request, pending_request);
1495 lr = pending_request;
1481 1496
1482 pending_request = NULL; 1497 pending_request = NULL;
1483 1498
1484 if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) { 1499 if (lr->initiator == NL80211_REGDOM_SET_BY_USER) {
1485 user_alpha2[0] = last_request->alpha2[0]; 1500 user_alpha2[0] = lr->alpha2[0];
1486 user_alpha2[1] = last_request->alpha2[1]; 1501 user_alpha2[1] = lr->alpha2[1];
1487 } 1502 }
1488 1503
1489 /* When r == REG_REQ_INTERSECT we do need to call CRDA */ 1504 /* When r == REG_REQ_INTERSECT we do need to call CRDA */
@@ -1494,13 +1509,13 @@ new_request:
1494 * inform userspace we have processed the request 1509 * inform userspace we have processed the request
1495 */ 1510 */
1496 if (treatment == REG_REQ_ALREADY_SET) { 1511 if (treatment == REG_REQ_ALREADY_SET) {
1497 nl80211_send_reg_change_event(last_request); 1512 nl80211_send_reg_change_event(lr);
1498 reg_set_request_processed(); 1513 reg_set_request_processed();
1499 } 1514 }
1500 return treatment; 1515 return treatment;
1501 } 1516 }
1502 1517
1503 if (call_crda(last_request->alpha2)) 1518 if (call_crda(lr->alpha2))
1504 return REG_REQ_IGNORE; 1519 return REG_REQ_IGNORE;
1505 return REG_REQ_OK; 1520 return REG_REQ_OK;
1506} 1521}
@@ -1543,13 +1558,14 @@ static void reg_process_hint(struct regulatory_request *reg_request,
1543 */ 1558 */
1544static void reg_process_pending_hints(void) 1559static void reg_process_pending_hints(void)
1545{ 1560{
1546 struct regulatory_request *reg_request; 1561 struct regulatory_request *reg_request, *lr;
1547 1562
1548 mutex_lock(&cfg80211_mutex); 1563 mutex_lock(&cfg80211_mutex);
1549 mutex_lock(&reg_mutex); 1564 mutex_lock(&reg_mutex);
1565 lr = get_last_request();
1550 1566
1551 /* When last_request->processed becomes true this will be rescheduled */ 1567 /* When last_request->processed becomes true this will be rescheduled */
1552 if (last_request && !last_request->processed) { 1568 if (lr && !lr->processed) {
1553 REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n"); 1569 REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n");
1554 goto out; 1570 goto out;
1555 } 1571 }
@@ -1702,11 +1718,12 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band,
1702{ 1718{
1703 char alpha2[2]; 1719 char alpha2[2];
1704 enum environment_cap env = ENVIRON_ANY; 1720 enum environment_cap env = ENVIRON_ANY;
1705 struct regulatory_request *request; 1721 struct regulatory_request *request, *lr;
1706 1722
1707 mutex_lock(&reg_mutex); 1723 mutex_lock(&reg_mutex);
1724 lr = get_last_request();
1708 1725
1709 if (unlikely(!last_request)) 1726 if (unlikely(!lr))
1710 goto out; 1727 goto out;
1711 1728
1712 /* IE len must be evenly divisible by 2 */ 1729 /* IE len must be evenly divisible by 2 */
@@ -1729,8 +1746,8 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band,
1729 * We leave conflict resolution to the workqueue, where can hold 1746 * We leave conflict resolution to the workqueue, where can hold
1730 * cfg80211_mutex. 1747 * cfg80211_mutex.
1731 */ 1748 */
1732 if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && 1749 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
1733 last_request->wiphy_idx != WIPHY_IDX_INVALID) 1750 lr->wiphy_idx != WIPHY_IDX_INVALID)
1734 goto out; 1751 goto out;
1735 1752
1736 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); 1753 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
@@ -2021,13 +2038,12 @@ static void print_dfs_region(u8 dfs_region)
2021 2038
2022static void print_regdomain(const struct ieee80211_regdomain *rd) 2039static void print_regdomain(const struct ieee80211_regdomain *rd)
2023{ 2040{
2041 struct regulatory_request *lr = get_last_request();
2024 2042
2025 if (is_intersected_alpha2(rd->alpha2)) { 2043 if (is_intersected_alpha2(rd->alpha2)) {
2026 if (last_request->initiator == 2044 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
2027 NL80211_REGDOM_SET_BY_COUNTRY_IE) {
2028 struct cfg80211_registered_device *rdev; 2045 struct cfg80211_registered_device *rdev;
2029 rdev = cfg80211_rdev_by_wiphy_idx( 2046 rdev = cfg80211_rdev_by_wiphy_idx(lr->wiphy_idx);
2030 last_request->wiphy_idx);
2031 if (rdev) { 2047 if (rdev) {
2032 pr_info("Current regulatory domain updated by AP to: %c%c\n", 2048 pr_info("Current regulatory domain updated by AP to: %c%c\n",
2033 rdev->country_ie_alpha2[0], 2049 rdev->country_ie_alpha2[0],
@@ -2042,7 +2058,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
2042 if (is_unknown_alpha2(rd->alpha2)) 2058 if (is_unknown_alpha2(rd->alpha2))
2043 pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); 2059 pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n");
2044 else { 2060 else {
2045 if (reg_request_cell_base(last_request)) 2061 if (reg_request_cell_base(lr))
2046 pr_info("Regulatory domain changed to country: %c%c by Cell Station\n", 2062 pr_info("Regulatory domain changed to country: %c%c by Cell Station\n",
2047 rd->alpha2[0], rd->alpha2[1]); 2063 rd->alpha2[0], rd->alpha2[1]);
2048 else 2064 else
@@ -2067,11 +2083,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2067 const struct ieee80211_regdomain *regd; 2083 const struct ieee80211_regdomain *regd;
2068 const struct ieee80211_regdomain *intersected_rd = NULL; 2084 const struct ieee80211_regdomain *intersected_rd = NULL;
2069 struct wiphy *request_wiphy; 2085 struct wiphy *request_wiphy;
2086 struct regulatory_request *lr = get_last_request();
2070 2087
2071 /* Some basic sanity checks first */ 2088 /* Some basic sanity checks first */
2072 2089
2073 assert_reg_lock();
2074
2075 if (!reg_is_valid_request(rd->alpha2)) 2090 if (!reg_is_valid_request(rd->alpha2))
2076 return -EINVAL; 2091 return -EINVAL;
2077 2092
@@ -2089,7 +2104,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2089 * rd is non static (it means CRDA was present and was used last) 2104 * rd is non static (it means CRDA was present and was used last)
2090 * and the pending request came in from a country IE 2105 * and the pending request came in from a country IE
2091 */ 2106 */
2092 if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { 2107 if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
2093 /* 2108 /*
2094 * If someone else asked us to change the rd lets only bother 2109 * If someone else asked us to change the rd lets only bother
2095 * checking if the alpha2 changes if CRDA was already called 2110 * checking if the alpha2 changes if CRDA was already called
@@ -2111,16 +2126,16 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2111 return -EINVAL; 2126 return -EINVAL;
2112 } 2127 }
2113 2128
2114 request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); 2129 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
2115 if (!request_wiphy && 2130 if (!request_wiphy &&
2116 (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || 2131 (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
2117 last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { 2132 lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
2118 schedule_delayed_work(&reg_timeout, 0); 2133 schedule_delayed_work(&reg_timeout, 0);
2119 return -ENODEV; 2134 return -ENODEV;
2120 } 2135 }
2121 2136
2122 if (!last_request->intersect) { 2137 if (!lr->intersect) {
2123 if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { 2138 if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
2124 reset_regdomains(false, rd); 2139 reset_regdomains(false, rd);
2125 return 0; 2140 return 0;
2126 } 2141 }
@@ -2148,7 +2163,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2148 2163
2149 /* Intersection requires a bit more work */ 2164 /* Intersection requires a bit more work */
2150 2165
2151 if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { 2166 if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
2152 intersected_rd = regdom_intersect(rd, get_cfg80211_regdom()); 2167 intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
2153 if (!intersected_rd) 2168 if (!intersected_rd)
2154 return -EINVAL; 2169 return -EINVAL;
@@ -2158,7 +2173,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2158 * However if a driver requested this specific regulatory 2173 * However if a driver requested this specific regulatory
2159 * domain we keep it for its private use 2174 * domain we keep it for its private use
2160 */ 2175 */
2161 if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) 2176 if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER)
2162 rcu_assign_pointer(request_wiphy->regd, rd); 2177 rcu_assign_pointer(request_wiphy->regd, rd);
2163 else 2178 else
2164 kfree(rd); 2179 kfree(rd);
@@ -2181,9 +2196,11 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
2181 */ 2196 */
2182int set_regdom(const struct ieee80211_regdomain *rd) 2197int set_regdom(const struct ieee80211_regdomain *rd)
2183{ 2198{
2199 struct regulatory_request *lr;
2184 int r; 2200 int r;
2185 2201
2186 mutex_lock(&reg_mutex); 2202 mutex_lock(&reg_mutex);
2203 lr = get_last_request();
2187 2204
2188 /* Note that this doesn't update the wiphys, this is done below */ 2205 /* Note that this doesn't update the wiphys, this is done below */
2189 r = __set_regdom(rd); 2206 r = __set_regdom(rd);
@@ -2196,18 +2213,17 @@ int set_regdom(const struct ieee80211_regdomain *rd)
2196 } 2213 }
2197 2214
2198 /* This would make this whole thing pointless */ 2215 /* This would make this whole thing pointless */
2199 if (WARN_ON(!last_request->intersect && 2216 if (WARN_ON(!lr->intersect && rd != get_cfg80211_regdom())) {
2200 rd != get_cfg80211_regdom())) {
2201 r = -EINVAL; 2217 r = -EINVAL;
2202 goto out; 2218 goto out;
2203 } 2219 }
2204 2220
2205 /* update all wiphys now with the new established regulatory domain */ 2221 /* update all wiphys now with the new established regulatory domain */
2206 update_all_wiphy_regulatory(last_request->initiator); 2222 update_all_wiphy_regulatory(lr->initiator);
2207 2223
2208 print_regdomain(get_cfg80211_regdom()); 2224 print_regdomain(get_cfg80211_regdom());
2209 2225
2210 nl80211_send_reg_change_event(last_request); 2226 nl80211_send_reg_change_event(lr);
2211 2227
2212 reg_set_request_processed(); 2228 reg_set_request_processed();
2213 2229
@@ -2220,10 +2236,11 @@ int set_regdom(const struct ieee80211_regdomain *rd)
2220#ifdef CONFIG_HOTPLUG 2236#ifdef CONFIG_HOTPLUG
2221int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) 2237int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
2222{ 2238{
2223 if (last_request && !last_request->processed) { 2239 struct regulatory_request *lr = get_last_request();
2240
2241 if (lr && !lr->processed) {
2224 if (add_uevent_var(env, "COUNTRY=%c%c", 2242 if (add_uevent_var(env, "COUNTRY=%c%c",
2225 last_request->alpha2[0], 2243 lr->alpha2[0], lr->alpha2[1]))
2226 last_request->alpha2[1]))
2227 return -ENOMEM; 2244 return -ENOMEM;
2228 } 2245 }
2229 2246
@@ -2252,8 +2269,10 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
2252void wiphy_regulatory_deregister(struct wiphy *wiphy) 2269void wiphy_regulatory_deregister(struct wiphy *wiphy)
2253{ 2270{
2254 struct wiphy *request_wiphy = NULL; 2271 struct wiphy *request_wiphy = NULL;
2272 struct regulatory_request *lr;
2255 2273
2256 mutex_lock(&reg_mutex); 2274 mutex_lock(&reg_mutex);
2275 lr = get_last_request();
2257 2276
2258 if (!reg_dev_ignore_cell_hint(wiphy)) 2277 if (!reg_dev_ignore_cell_hint(wiphy))
2259 reg_num_devs_support_basehint--; 2278 reg_num_devs_support_basehint--;
@@ -2261,14 +2280,14 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
2261 rcu_free_regdom(get_wiphy_regdom(wiphy)); 2280 rcu_free_regdom(get_wiphy_regdom(wiphy));
2262 rcu_assign_pointer(wiphy->regd, NULL); 2281 rcu_assign_pointer(wiphy->regd, NULL);
2263 2282
2264 if (last_request) 2283 if (lr)
2265 request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); 2284 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
2266 2285
2267 if (!request_wiphy || request_wiphy != wiphy) 2286 if (!request_wiphy || request_wiphy != wiphy)
2268 goto out; 2287 goto out;
2269 2288
2270 last_request->wiphy_idx = WIPHY_IDX_INVALID; 2289 lr->wiphy_idx = WIPHY_IDX_INVALID;
2271 last_request->country_ie_env = ENVIRON_ANY; 2290 lr->country_ie_env = ENVIRON_ANY;
2272out: 2291out:
2273 mutex_unlock(&reg_mutex); 2292 mutex_unlock(&reg_mutex);
2274} 2293}