aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2009-02-21 00:04:30 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-02-27 14:52:57 -0500
commitfe33eb390854886e1fd5d4835d833b80d145aafb (patch)
tree5349c48092c9528b5640d5981425e161e0731ed3 /net/wireless
parent0441d6ffc705de17d85923264a1b03b71ebfccb8 (diff)
cfg80211: move all regulatory hints to workqueue
All regulatory hints (core, driver, userspace and 11d) are now processed in a workqueue. Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/nl80211.c30
-rw-r--r--net/wireless/reg.c178
-rw-r--r--net/wireless/reg.h2
3 files changed, 175 insertions, 35 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e0d3879b8852..97f69bed3fe2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1915,34 +1915,24 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
1915 */ 1915 */
1916 mutex_lock(&cfg80211_mutex); 1916 mutex_lock(&cfg80211_mutex);
1917 if (unlikely(!cfg80211_regdomain)) { 1917 if (unlikely(!cfg80211_regdomain)) {
1918 r = -EINPROGRESS; 1918 mutex_unlock(&cfg80211_mutex);
1919 goto out; 1919 return -EINPROGRESS;
1920 } 1920 }
1921 mutex_unlock(&cfg80211_mutex);
1921 1922
1922 if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) { 1923 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
1923 r = -EINVAL; 1924 return -EINVAL;
1924 goto out;
1925 }
1926 1925
1927 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); 1926 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
1928 1927
1929#ifdef CONFIG_WIRELESS_OLD_REGULATORY 1928#ifdef CONFIG_WIRELESS_OLD_REGULATORY
1930 /* We ignore world regdom requests with the old regdom setup */ 1929 /* We ignore world regdom requests with the old regdom setup */
1931 if (is_world_regdom(data)) { 1930 if (is_world_regdom(data))
1932 r = -EINVAL; 1931 return -EINVAL;
1933 goto out;
1934 }
1935#endif 1932#endif
1936 r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); 1933
1937 /* 1934 r = regulatory_hint_user(data);
1938 * This means the regulatory domain was already set, however 1935
1939 * we don't want to confuse userspace with a "successful error"
1940 * message so lets just treat it as a success
1941 */
1942 if (r == -EALREADY)
1943 r = 0;
1944out:
1945 mutex_unlock(&cfg80211_mutex);
1946 return r; 1936 return r;
1947} 1937}
1948 1938
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index af762be3f0a1..0b8c4b86789a 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -64,6 +64,9 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
64 * what it thinks should apply for the same country */ 64 * what it thinks should apply for the same country */
65static const struct ieee80211_regdomain *country_ie_regdomain; 65static const struct ieee80211_regdomain *country_ie_regdomain;
66 66
67static LIST_HEAD(reg_requests_list);
68static spinlock_t reg_requests_lock;
69
67/* We keep a static world regulatory domain in case of the absence of CRDA */ 70/* We keep a static world regulatory domain in case of the absence of CRDA */
68static const struct ieee80211_regdomain world_regdom = { 71static const struct ieee80211_regdomain world_regdom = {
69 .n_reg_rules = 1, 72 .n_reg_rules = 1,
@@ -831,7 +834,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
831 const struct ieee80211_power_rule *power_rule = NULL; 834 const struct ieee80211_power_rule *power_rule = NULL;
832 struct ieee80211_supported_band *sband; 835 struct ieee80211_supported_band *sband;
833 struct ieee80211_channel *chan; 836 struct ieee80211_channel *chan;
834 struct wiphy *request_wiphy; 837 struct wiphy *request_wiphy = NULL;
835 838
836 assert_cfg80211_lock(); 839 assert_cfg80211_lock();
837 840
@@ -1195,6 +1198,89 @@ new_request:
1195 return call_crda(alpha2); 1198 return call_crda(alpha2);
1196} 1199}
1197 1200
1201/* This currently only processes user and driver regulatory hints */
1202static int reg_process_hint(struct regulatory_request *reg_request)
1203{
1204 int r = 0;
1205 struct wiphy *wiphy = NULL;
1206
1207 BUG_ON(!reg_request->alpha2);
1208
1209 mutex_lock(&cfg80211_mutex);
1210
1211 if (wiphy_idx_valid(reg_request->wiphy_idx))
1212 wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
1213
1214 if (reg_request->initiator == REGDOM_SET_BY_DRIVER &&
1215 !wiphy) {
1216 r = -ENODEV;
1217 goto out;
1218 }
1219
1220 r = __regulatory_hint(wiphy,
1221 reg_request->initiator,
1222 reg_request->alpha2,
1223 reg_request->country_ie_checksum,
1224 reg_request->country_ie_env);
1225 /* This is required so that the orig_* parameters are saved */
1226 if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
1227 wiphy_update_regulatory(wiphy, reg_request->initiator);
1228out:
1229 mutex_unlock(&cfg80211_mutex);
1230
1231 if (r == -EALREADY)
1232 r = 0;
1233
1234 return r;
1235}
1236
1237static void reg_process_pending_hints(void)
1238 {
1239 struct regulatory_request *reg_request;
1240 int r;
1241
1242 spin_lock(&reg_requests_lock);
1243 while (!list_empty(&reg_requests_list)) {
1244 reg_request = list_first_entry(&reg_requests_list,
1245 struct regulatory_request,
1246 list);
1247 list_del_init(&reg_request->list);
1248 spin_unlock(&reg_requests_lock);
1249
1250 r = reg_process_hint(reg_request);
1251#ifdef CONFIG_CFG80211_REG_DEBUG
1252 if (r && (reg_request->initiator == REGDOM_SET_BY_DRIVER ||
1253 reg_request->initiator == REGDOM_SET_BY_COUNTRY_IE))
1254 printk(KERN_ERR "cfg80211: wiphy_idx %d sent a "
1255 "regulatory hint for %c%c but now has "
1256 "gone fishing, ignoring request\n",
1257 reg_request->wiphy_idx,
1258 reg_request->alpha2[0],
1259 reg_request->alpha2[1]);
1260#endif
1261 kfree(reg_request);
1262 spin_lock(&reg_requests_lock);
1263 }
1264 spin_unlock(&reg_requests_lock);
1265}
1266
1267static void reg_todo(struct work_struct *work)
1268{
1269 reg_process_pending_hints();
1270}
1271
1272static DECLARE_WORK(reg_work, reg_todo);
1273
1274static void queue_regulatory_request(struct regulatory_request *request)
1275{
1276 spin_lock(&reg_requests_lock);
1277 list_add_tail(&request->list, &reg_requests_list);
1278 spin_unlock(&reg_requests_lock);
1279
1280 schedule_work(&reg_work);
1281}
1282
1283/* Core regulatory hint -- happens once during cfg80211_init() */
1198static int regulatory_hint_core(const char *alpha2) 1284static int regulatory_hint_core(const char *alpha2)
1199{ 1285{
1200 struct regulatory_request *request; 1286 struct regulatory_request *request;
@@ -1210,23 +1296,56 @@ static int regulatory_hint_core(const char *alpha2)
1210 request->alpha2[1] = alpha2[1]; 1296 request->alpha2[1] = alpha2[1];
1211 request->initiator = REGDOM_SET_BY_CORE; 1297 request->initiator = REGDOM_SET_BY_CORE;
1212 1298
1213 last_request = request; 1299 queue_regulatory_request(request);
1214 1300
1215 return call_crda(alpha2); 1301 return 0;
1216} 1302}
1217 1303
1218void regulatory_hint(struct wiphy *wiphy, const char *alpha2) 1304/* User hints */
1305int regulatory_hint_user(const char *alpha2)
1219{ 1306{
1220 int r; 1307 struct regulatory_request *request;
1308
1221 BUG_ON(!alpha2); 1309 BUG_ON(!alpha2);
1222 1310
1223 mutex_lock(&cfg80211_mutex); 1311 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
1224 r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, 1312 if (!request)
1225 alpha2, 0, ENVIRON_ANY); 1313 return -ENOMEM;
1226 /* This is required so that the orig_* parameters are saved */ 1314
1227 if (r == -EALREADY && wiphy->strict_regulatory) 1315 request->wiphy_idx = WIPHY_IDX_STALE;
1228 wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER); 1316 request->alpha2[0] = alpha2[0];
1229 mutex_unlock(&cfg80211_mutex); 1317 request->alpha2[1] = alpha2[1];
1318 request->initiator = REGDOM_SET_BY_USER,
1319
1320 queue_regulatory_request(request);
1321
1322 return 0;
1323}
1324
1325/* Driver hints */
1326int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
1327{
1328 struct regulatory_request *request;
1329
1330 BUG_ON(!alpha2);
1331 BUG_ON(!wiphy);
1332
1333 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
1334 if (!request)
1335 return -ENOMEM;
1336
1337 request->wiphy_idx = get_wiphy_idx(wiphy);
1338
1339 /* Must have registered wiphy first */
1340 BUG_ON(!wiphy_idx_valid(request->wiphy_idx));
1341
1342 request->alpha2[0] = alpha2[0];
1343 request->alpha2[1] = alpha2[1];
1344 request->initiator = REGDOM_SET_BY_DRIVER;
1345
1346 queue_regulatory_request(request);
1347
1348 return 0;
1230} 1349}
1231EXPORT_SYMBOL(regulatory_hint); 1350EXPORT_SYMBOL(regulatory_hint);
1232 1351
@@ -1260,6 +1379,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
1260 char alpha2[2]; 1379 char alpha2[2];
1261 u32 checksum = 0; 1380 u32 checksum = 0;
1262 enum environment_cap env = ENVIRON_ANY; 1381 enum environment_cap env = ENVIRON_ANY;
1382 struct regulatory_request *request;
1263 1383
1264 mutex_lock(&cfg80211_mutex); 1384 mutex_lock(&cfg80211_mutex);
1265 1385
@@ -1343,14 +1463,26 @@ void regulatory_hint_11d(struct wiphy *wiphy,
1343 if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum))) 1463 if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
1344 goto free_rd_out; 1464 goto free_rd_out;
1345 1465
1466 request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
1467 if (!request)
1468 goto free_rd_out;
1469
1346 /* We keep this around for when CRDA comes back with a response so 1470 /* We keep this around for when CRDA comes back with a response so
1347 * we can intersect with that */ 1471 * we can intersect with that */
1348 country_ie_regdomain = rd; 1472 country_ie_regdomain = rd;
1349 1473
1350 __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE, 1474 request->wiphy_idx = get_wiphy_idx(wiphy);
1351 country_ie_regdomain->alpha2, checksum, env); 1475 request->alpha2[0] = rd->alpha2[0];
1476 request->alpha2[1] = rd->alpha2[1];
1477 request->initiator = REGDOM_SET_BY_COUNTRY_IE;
1478 request->country_ie_checksum = checksum;
1479 request->country_ie_env = env;
1480
1481 mutex_unlock(&cfg80211_mutex);
1352 1482
1353 goto out; 1483 queue_regulatory_request(request);
1484
1485 return;
1354 1486
1355free_rd_out: 1487free_rd_out:
1356 kfree(rd); 1488 kfree(rd);
@@ -1661,6 +1793,8 @@ int regulatory_init(void)
1661 if (IS_ERR(reg_pdev)) 1793 if (IS_ERR(reg_pdev))
1662 return PTR_ERR(reg_pdev); 1794 return PTR_ERR(reg_pdev);
1663 1795
1796 spin_lock_init(&reg_requests_lock);
1797
1664#ifdef CONFIG_WIRELESS_OLD_REGULATORY 1798#ifdef CONFIG_WIRELESS_OLD_REGULATORY
1665 cfg80211_regdomain = static_regdom(ieee80211_regdom); 1799 cfg80211_regdomain = static_regdom(ieee80211_regdom);
1666 1800
@@ -1700,6 +1834,10 @@ int regulatory_init(void)
1700 1834
1701void regulatory_exit(void) 1835void regulatory_exit(void)
1702{ 1836{
1837 struct regulatory_request *reg_request, *tmp;
1838
1839 cancel_work_sync(&reg_work);
1840
1703 mutex_lock(&cfg80211_mutex); 1841 mutex_lock(&cfg80211_mutex);
1704 1842
1705 reset_regdomains(); 1843 reset_regdomains();
@@ -1711,5 +1849,15 @@ void regulatory_exit(void)
1711 1849
1712 platform_device_unregister(reg_pdev); 1850 platform_device_unregister(reg_pdev);
1713 1851
1852 spin_lock(&reg_requests_lock);
1853 if (!list_empty(&reg_requests_list)) {
1854 list_for_each_entry_safe(reg_request, tmp,
1855 &reg_requests_list, list) {
1856 list_del(&reg_request->list);
1857 kfree(reg_request);
1858 }
1859 }
1860 spin_unlock(&reg_requests_lock);
1861
1714 mutex_unlock(&cfg80211_mutex); 1862 mutex_unlock(&cfg80211_mutex);
1715} 1863}
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index fe8c83f34fb7..4730def5a69d 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -6,6 +6,8 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain;
6bool is_world_regdom(const char *alpha2); 6bool is_world_regdom(const char *alpha2);
7bool reg_is_valid_request(const char *alpha2); 7bool reg_is_valid_request(const char *alpha2);
8 8
9int regulatory_hint_user(const char *alpha2);
10
9void reg_device_remove(struct wiphy *wiphy); 11void reg_device_remove(struct wiphy *wiphy);
10 12
11int regulatory_init(void); 13int regulatory_init(void);