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.c138
1 files changed, 45 insertions, 93 deletions
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index cc35fbaa4578..5a24c986f34b 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -81,7 +81,10 @@ static struct regulatory_request core_request_world = {
81 .country_ie_env = ENVIRON_ANY, 81 .country_ie_env = ENVIRON_ANY,
82}; 82};
83 83
84/* Receipt of information from last regulatory request */ 84/*
85 * Receipt of information from last regulatory request,
86 * protected by RTNL (and can be accessed with RCU protection)
87 */
85static struct regulatory_request __rcu *last_request = 88static struct regulatory_request __rcu *last_request =
86 (void __rcu *)&core_request_world; 89 (void __rcu *)&core_request_world;
87 90
@@ -96,39 +99,25 @@ static struct device_type reg_device_type = {
96 * Central wireless core regulatory domains, we only need two, 99 * Central wireless core regulatory domains, we only need two,
97 * the current one and a world regulatory domain in case we have no 100 * the current one and a world regulatory domain in case we have no
98 * information to give us an alpha2. 101 * information to give us an alpha2.
102 * (protected by RTNL, can be read under RCU)
99 */ 103 */
100const struct ieee80211_regdomain __rcu *cfg80211_regdomain; 104const struct ieee80211_regdomain __rcu *cfg80211_regdomain;
101 105
102/* 106/*
103 * Protects static reg.c components:
104 * - cfg80211_regdomain (if not used with RCU)
105 * - cfg80211_world_regdom
106 * - last_request (if not used with RCU)
107 * - reg_num_devs_support_basehint
108 */
109static DEFINE_MUTEX(reg_mutex);
110
111/*
112 * Number of devices that registered to the core 107 * Number of devices that registered to the core
113 * that support cellular base station regulatory hints 108 * that support cellular base station regulatory hints
109 * (protected by RTNL)
114 */ 110 */
115static int reg_num_devs_support_basehint; 111static int reg_num_devs_support_basehint;
116 112
117static inline void assert_reg_lock(void)
118{
119 lockdep_assert_held(&reg_mutex);
120}
121
122static const struct ieee80211_regdomain *get_cfg80211_regdom(void) 113static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
123{ 114{
124 return rcu_dereference_protected(cfg80211_regdomain, 115 return rtnl_dereference(cfg80211_regdomain);
125 lockdep_is_held(&reg_mutex));
126} 116}
127 117
128static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy) 118static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
129{ 119{
130 return rcu_dereference_protected(wiphy->regd, 120 return rtnl_dereference(wiphy->regd);
131 lockdep_is_held(&reg_mutex));
132} 121}
133 122
134static void rcu_free_regdom(const struct ieee80211_regdomain *r) 123static void rcu_free_regdom(const struct ieee80211_regdomain *r)
@@ -140,8 +129,7 @@ static void rcu_free_regdom(const struct ieee80211_regdomain *r)
140 129
141static struct regulatory_request *get_last_request(void) 130static struct regulatory_request *get_last_request(void)
142{ 131{
143 return rcu_dereference_check(last_request, 132 return rcu_dereference_rtnl(last_request);
144 lockdep_is_held(&reg_mutex));
145} 133}
146 134
147/* Used to queue up regulatory hints */ 135/* Used to queue up regulatory hints */
@@ -200,6 +188,7 @@ static const struct ieee80211_regdomain world_regdom = {
200 } 188 }
201}; 189};
202 190
191/* protected by RTNL */
203static const struct ieee80211_regdomain *cfg80211_world_regdom = 192static const struct ieee80211_regdomain *cfg80211_world_regdom =
204 &world_regdom; 193 &world_regdom;
205 194
@@ -215,7 +204,7 @@ static void reset_regdomains(bool full_reset,
215 const struct ieee80211_regdomain *r; 204 const struct ieee80211_regdomain *r;
216 struct regulatory_request *lr; 205 struct regulatory_request *lr;
217 206
218 assert_reg_lock(); 207 ASSERT_RTNL();
219 208
220 r = get_cfg80211_regdom(); 209 r = get_cfg80211_regdom();
221 210
@@ -377,7 +366,7 @@ static void reg_regdb_search(struct work_struct *work)
377 const struct ieee80211_regdomain *curdom, *regdom = NULL; 366 const struct ieee80211_regdomain *curdom, *regdom = NULL;
378 int i; 367 int i;
379 368
380 mutex_lock(&cfg80211_mutex); 369 rtnl_lock();
381 370
382 mutex_lock(&reg_regdb_search_mutex); 371 mutex_lock(&reg_regdb_search_mutex);
383 while (!list_empty(&reg_regdb_search_list)) { 372 while (!list_empty(&reg_regdb_search_list)) {
@@ -402,7 +391,7 @@ static void reg_regdb_search(struct work_struct *work)
402 if (!IS_ERR_OR_NULL(regdom)) 391 if (!IS_ERR_OR_NULL(regdom))
403 set_regdom(regdom); 392 set_regdom(regdom);
404 393
405 mutex_unlock(&cfg80211_mutex); 394 rtnl_unlock();
406} 395}
407 396
408static DECLARE_WORK(reg_regdb_work, reg_regdb_search); 397static DECLARE_WORK(reg_regdb_work, reg_regdb_search);
@@ -936,13 +925,7 @@ static bool reg_request_cell_base(struct regulatory_request *request)
936 925
937bool reg_last_request_cell_base(void) 926bool reg_last_request_cell_base(void)
938{ 927{
939 bool val; 928 return reg_request_cell_base(get_last_request());
940
941 mutex_lock(&reg_mutex);
942 val = reg_request_cell_base(get_last_request());
943 mutex_unlock(&reg_mutex);
944
945 return val;
946} 929}
947 930
948#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS 931#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
@@ -1225,7 +1208,7 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
1225 struct cfg80211_registered_device *rdev; 1208 struct cfg80211_registered_device *rdev;
1226 struct wiphy *wiphy; 1209 struct wiphy *wiphy;
1227 1210
1228 assert_cfg80211_lock(); 1211 ASSERT_RTNL();
1229 1212
1230 list_for_each_entry(rdev, &cfg80211_rdev_list, list) { 1213 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
1231 wiphy = &rdev->wiphy; 1214 wiphy = &rdev->wiphy;
@@ -1362,7 +1345,7 @@ get_reg_request_treatment(struct wiphy *wiphy,
1362 return REG_REQ_OK; 1345 return REG_REQ_OK;
1363 return REG_REQ_ALREADY_SET; 1346 return REG_REQ_ALREADY_SET;
1364 } 1347 }
1365 return 0; 1348 return REG_REQ_OK;
1366 case NL80211_REGDOM_SET_BY_DRIVER: 1349 case NL80211_REGDOM_SET_BY_DRIVER:
1367 if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) { 1350 if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {
1368 if (regdom_changes(pending_request->alpha2)) 1351 if (regdom_changes(pending_request->alpha2))
@@ -1444,8 +1427,6 @@ static void reg_set_request_processed(void)
1444 * what it believes should be the current regulatory domain. 1427 * what it believes should be the current regulatory domain.
1445 * 1428 *
1446 * Returns one of the different reg request treatment values. 1429 * Returns one of the different reg request treatment values.
1447 *
1448 * Caller must hold &reg_mutex
1449 */ 1430 */
1450static enum reg_request_treatment 1431static enum reg_request_treatment
1451__regulatory_hint(struct wiphy *wiphy, 1432__regulatory_hint(struct wiphy *wiphy,
@@ -1570,21 +1551,19 @@ static void reg_process_pending_hints(void)
1570{ 1551{
1571 struct regulatory_request *reg_request, *lr; 1552 struct regulatory_request *reg_request, *lr;
1572 1553
1573 mutex_lock(&cfg80211_mutex);
1574 mutex_lock(&reg_mutex);
1575 lr = get_last_request(); 1554 lr = get_last_request();
1576 1555
1577 /* When last_request->processed becomes true this will be rescheduled */ 1556 /* When last_request->processed becomes true this will be rescheduled */
1578 if (lr && !lr->processed) { 1557 if (lr && !lr->processed) {
1579 REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n"); 1558 REG_DBG_PRINT("Pending regulatory request, waiting for it to be processed...\n");
1580 goto out; 1559 return;
1581 } 1560 }
1582 1561
1583 spin_lock(&reg_requests_lock); 1562 spin_lock(&reg_requests_lock);
1584 1563
1585 if (list_empty(&reg_requests_list)) { 1564 if (list_empty(&reg_requests_list)) {
1586 spin_unlock(&reg_requests_lock); 1565 spin_unlock(&reg_requests_lock);
1587 goto out; 1566 return;
1588 } 1567 }
1589 1568
1590 reg_request = list_first_entry(&reg_requests_list, 1569 reg_request = list_first_entry(&reg_requests_list,
@@ -1595,10 +1574,6 @@ static void reg_process_pending_hints(void)
1595 spin_unlock(&reg_requests_lock); 1574 spin_unlock(&reg_requests_lock);
1596 1575
1597 reg_process_hint(reg_request, reg_request->initiator); 1576 reg_process_hint(reg_request, reg_request->initiator);
1598
1599out:
1600 mutex_unlock(&reg_mutex);
1601 mutex_unlock(&cfg80211_mutex);
1602} 1577}
1603 1578
1604/* Processes beacon hints -- this has nothing to do with country IEs */ 1579/* Processes beacon hints -- this has nothing to do with country IEs */
@@ -1607,9 +1582,6 @@ static void reg_process_pending_beacon_hints(void)
1607 struct cfg80211_registered_device *rdev; 1582 struct cfg80211_registered_device *rdev;
1608 struct reg_beacon *pending_beacon, *tmp; 1583 struct reg_beacon *pending_beacon, *tmp;
1609 1584
1610 mutex_lock(&cfg80211_mutex);
1611 mutex_lock(&reg_mutex);
1612
1613 /* This goes through the _pending_ beacon list */ 1585 /* This goes through the _pending_ beacon list */
1614 spin_lock_bh(&reg_pending_beacons_lock); 1586 spin_lock_bh(&reg_pending_beacons_lock);
1615 1587
@@ -1626,14 +1598,14 @@ static void reg_process_pending_beacon_hints(void)
1626 } 1598 }
1627 1599
1628 spin_unlock_bh(&reg_pending_beacons_lock); 1600 spin_unlock_bh(&reg_pending_beacons_lock);
1629 mutex_unlock(&reg_mutex);
1630 mutex_unlock(&cfg80211_mutex);
1631} 1601}
1632 1602
1633static void reg_todo(struct work_struct *work) 1603static void reg_todo(struct work_struct *work)
1634{ 1604{
1605 rtnl_lock();
1635 reg_process_pending_hints(); 1606 reg_process_pending_hints();
1636 reg_process_pending_beacon_hints(); 1607 reg_process_pending_beacon_hints();
1608 rtnl_unlock();
1637} 1609}
1638 1610
1639static void queue_regulatory_request(struct regulatory_request *request) 1611static void queue_regulatory_request(struct regulatory_request *request)
@@ -1717,29 +1689,23 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
1717} 1689}
1718EXPORT_SYMBOL(regulatory_hint); 1690EXPORT_SYMBOL(regulatory_hint);
1719 1691
1720/*
1721 * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and
1722 * therefore cannot iterate over the rdev list here.
1723 */
1724void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, 1692void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band,
1725 const u8 *country_ie, u8 country_ie_len) 1693 const u8 *country_ie, u8 country_ie_len)
1726{ 1694{
1727 char alpha2[2]; 1695 char alpha2[2];
1728 enum environment_cap env = ENVIRON_ANY; 1696 enum environment_cap env = ENVIRON_ANY;
1729 struct regulatory_request *request, *lr; 1697 struct regulatory_request *request = NULL, *lr;
1730
1731 mutex_lock(&reg_mutex);
1732 lr = get_last_request();
1733
1734 if (unlikely(!lr))
1735 goto out;
1736 1698
1737 /* IE len must be evenly divisible by 2 */ 1699 /* IE len must be evenly divisible by 2 */
1738 if (country_ie_len & 0x01) 1700 if (country_ie_len & 0x01)
1739 goto out; 1701 return;
1740 1702
1741 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) 1703 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
1742 goto out; 1704 return;
1705
1706 request = kzalloc(sizeof(*request), GFP_KERNEL);
1707 if (!request)
1708 return;
1743 1709
1744 alpha2[0] = country_ie[0]; 1710 alpha2[0] = country_ie[0];
1745 alpha2[1] = country_ie[1]; 1711 alpha2[1] = country_ie[1];
@@ -1749,19 +1715,21 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band,
1749 else if (country_ie[2] == 'O') 1715 else if (country_ie[2] == 'O')
1750 env = ENVIRON_OUTDOOR; 1716 env = ENVIRON_OUTDOOR;
1751 1717
1718 rcu_read_lock();
1719 lr = get_last_request();
1720
1721 if (unlikely(!lr))
1722 goto out;
1723
1752 /* 1724 /*
1753 * We will run this only upon a successful connection on cfg80211. 1725 * We will run this only upon a successful connection on cfg80211.
1754 * We leave conflict resolution to the workqueue, where can hold 1726 * We leave conflict resolution to the workqueue, where can hold
1755 * cfg80211_mutex. 1727 * the RTNL.
1756 */ 1728 */
1757 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && 1729 if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
1758 lr->wiphy_idx != WIPHY_IDX_INVALID) 1730 lr->wiphy_idx != WIPHY_IDX_INVALID)
1759 goto out; 1731 goto out;
1760 1732
1761 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
1762 if (!request)
1763 goto out;
1764
1765 request->wiphy_idx = get_wiphy_idx(wiphy); 1733 request->wiphy_idx = get_wiphy_idx(wiphy);
1766 request->alpha2[0] = alpha2[0]; 1734 request->alpha2[0] = alpha2[0];
1767 request->alpha2[1] = alpha2[1]; 1735 request->alpha2[1] = alpha2[1];
@@ -1769,8 +1737,10 @@ void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band,
1769 request->country_ie_env = env; 1737 request->country_ie_env = env;
1770 1738
1771 queue_regulatory_request(request); 1739 queue_regulatory_request(request);
1740 request = NULL;
1772out: 1741out:
1773 mutex_unlock(&reg_mutex); 1742 kfree(request);
1743 rcu_read_unlock();
1774} 1744}
1775 1745
1776static void restore_alpha2(char *alpha2, bool reset_user) 1746static void restore_alpha2(char *alpha2, bool reset_user)
@@ -1858,8 +1828,7 @@ static void restore_regulatory_settings(bool reset_user)
1858 LIST_HEAD(tmp_reg_req_list); 1828 LIST_HEAD(tmp_reg_req_list);
1859 struct cfg80211_registered_device *rdev; 1829 struct cfg80211_registered_device *rdev;
1860 1830
1861 mutex_lock(&cfg80211_mutex); 1831 ASSERT_RTNL();
1862 mutex_lock(&reg_mutex);
1863 1832
1864 reset_regdomains(true, &world_regdom); 1833 reset_regdomains(true, &world_regdom);
1865 restore_alpha2(alpha2, reset_user); 1834 restore_alpha2(alpha2, reset_user);
@@ -1914,9 +1883,6 @@ static void restore_regulatory_settings(bool reset_user)
1914 list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list); 1883 list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list);
1915 spin_unlock(&reg_requests_lock); 1884 spin_unlock(&reg_requests_lock);
1916 1885
1917 mutex_unlock(&reg_mutex);
1918 mutex_unlock(&cfg80211_mutex);
1919
1920 REG_DBG_PRINT("Kicking the queue\n"); 1886 REG_DBG_PRINT("Kicking the queue\n");
1921 1887
1922 schedule_work(&reg_work); 1888 schedule_work(&reg_work);
@@ -2231,7 +2197,6 @@ int set_regdom(const struct ieee80211_regdomain *rd)
2231 struct regulatory_request *lr; 2197 struct regulatory_request *lr;
2232 int r; 2198 int r;
2233 2199
2234 mutex_lock(&reg_mutex);
2235 lr = get_last_request(); 2200 lr = get_last_request();
2236 2201
2237 /* Note that this doesn't update the wiphys, this is done below */ 2202 /* Note that this doesn't update the wiphys, this is done below */
@@ -2241,14 +2206,12 @@ int set_regdom(const struct ieee80211_regdomain *rd)
2241 reg_set_request_processed(); 2206 reg_set_request_processed();
2242 2207
2243 kfree(rd); 2208 kfree(rd);
2244 goto out; 2209 return r;
2245 } 2210 }
2246 2211
2247 /* This would make this whole thing pointless */ 2212 /* This would make this whole thing pointless */
2248 if (WARN_ON(!lr->intersect && rd != get_cfg80211_regdom())) { 2213 if (WARN_ON(!lr->intersect && rd != get_cfg80211_regdom()))
2249 r = -EINVAL; 2214 return -EINVAL;
2250 goto out;
2251 }
2252 2215
2253 /* update all wiphys now with the new established regulatory domain */ 2216 /* update all wiphys now with the new established regulatory domain */
2254 update_all_wiphy_regulatory(lr->initiator); 2217 update_all_wiphy_regulatory(lr->initiator);
@@ -2259,10 +2222,7 @@ int set_regdom(const struct ieee80211_regdomain *rd)
2259 2222
2260 reg_set_request_processed(); 2223 reg_set_request_processed();
2261 2224
2262 out: 2225 return 0;
2263 mutex_unlock(&reg_mutex);
2264
2265 return r;
2266} 2226}
2267 2227
2268int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) 2228int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
@@ -2287,23 +2247,17 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
2287 2247
2288void wiphy_regulatory_register(struct wiphy *wiphy) 2248void wiphy_regulatory_register(struct wiphy *wiphy)
2289{ 2249{
2290 mutex_lock(&reg_mutex);
2291
2292 if (!reg_dev_ignore_cell_hint(wiphy)) 2250 if (!reg_dev_ignore_cell_hint(wiphy))
2293 reg_num_devs_support_basehint++; 2251 reg_num_devs_support_basehint++;
2294 2252
2295 wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); 2253 wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
2296
2297 mutex_unlock(&reg_mutex);
2298} 2254}
2299 2255
2300/* Caller must hold cfg80211_mutex */
2301void wiphy_regulatory_deregister(struct wiphy *wiphy) 2256void wiphy_regulatory_deregister(struct wiphy *wiphy)
2302{ 2257{
2303 struct wiphy *request_wiphy = NULL; 2258 struct wiphy *request_wiphy = NULL;
2304 struct regulatory_request *lr; 2259 struct regulatory_request *lr;
2305 2260
2306 mutex_lock(&reg_mutex);
2307 lr = get_last_request(); 2261 lr = get_last_request();
2308 2262
2309 if (!reg_dev_ignore_cell_hint(wiphy)) 2263 if (!reg_dev_ignore_cell_hint(wiphy))
@@ -2316,12 +2270,10 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
2316 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx); 2270 request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);
2317 2271
2318 if (!request_wiphy || request_wiphy != wiphy) 2272 if (!request_wiphy || request_wiphy != wiphy)
2319 goto out; 2273 return;
2320 2274
2321 lr->wiphy_idx = WIPHY_IDX_INVALID; 2275 lr->wiphy_idx = WIPHY_IDX_INVALID;
2322 lr->country_ie_env = ENVIRON_ANY; 2276 lr->country_ie_env = ENVIRON_ANY;
2323out:
2324 mutex_unlock(&reg_mutex);
2325} 2277}
2326 2278
2327static void reg_timeout_work(struct work_struct *work) 2279static void reg_timeout_work(struct work_struct *work)
@@ -2385,9 +2337,9 @@ void regulatory_exit(void)
2385 cancel_delayed_work_sync(&reg_timeout); 2337 cancel_delayed_work_sync(&reg_timeout);
2386 2338
2387 /* Lock to suppress warnings */ 2339 /* Lock to suppress warnings */
2388 mutex_lock(&reg_mutex); 2340 rtnl_lock();
2389 reset_regdomains(true, NULL); 2341 reset_regdomains(true, NULL);
2390 mutex_unlock(&reg_mutex); 2342 rtnl_unlock();
2391 2343
2392 dev_set_uevent_suppress(&reg_pdev->dev, true); 2344 dev_set_uevent_suppress(&reg_pdev->dev, true);
2393 2345