@@ -64,6 +64,9 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
64
64
* what it thinks should apply for the same country */
65
65
static const struct ieee80211_regdomain * country_ie_regdomain ;
66
66
67
+ static LIST_HEAD (reg_requests_list );
68
+ static spinlock_t reg_requests_lock ;
69
+
67
70
/* We keep a static world regulatory domain in case of the absence of CRDA */
68
71
static const struct ieee80211_regdomain world_regdom = {
69
72
.n_reg_rules = 1 ,
@@ -831,7 +834,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
831
834
const struct ieee80211_power_rule * power_rule = NULL ;
832
835
struct ieee80211_supported_band * sband ;
833
836
struct ieee80211_channel * chan ;
834
- struct wiphy * request_wiphy ;
837
+ struct wiphy * request_wiphy = NULL ;
835
838
836
839
assert_cfg80211_lock ();
837
840
@@ -1195,6 +1198,89 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
1195
1198
return call_crda (alpha2 );
1196
1199
}
1197
1200
1201
+ /* This currently only processes user and driver regulatory hints */
1202
+ static 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 );
1228
+ out :
1229
+ mutex_unlock (& cfg80211_mutex );
1230
+
1231
+ if (r == - EALREADY )
1232
+ r = 0 ;
1233
+
1234
+ return r ;
1235
+ }
1236
+
1237
+ static 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
+
1267
+ static void reg_todo (struct work_struct * work )
1268
+ {
1269
+ reg_process_pending_hints ();
1270
+ }
1271
+
1272
+ static DECLARE_WORK (reg_work , reg_todo ) ;
1273
+
1274
+ static 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() */
1198
1284
static int regulatory_hint_core (const char * alpha2 )
1199
1285
{
1200
1286
struct regulatory_request * request ;
@@ -1210,23 +1296,56 @@ static int regulatory_hint_core(const char *alpha2)
1210
1296
request -> alpha2 [1 ] = alpha2 [1 ];
1211
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
1218
- void regulatory_hint (struct wiphy * wiphy , const char * alpha2 )
1304
+ /* User hints */
1305
+ int regulatory_hint_user (const char * alpha2 )
1219
1306
{
1220
- int r ;
1307
+ struct regulatory_request * request ;
1308
+
1221
1309
BUG_ON (!alpha2 );
1222
1310
1223
- mutex_lock (& cfg80211_mutex );
1224
- r = __regulatory_hint (wiphy , REGDOM_SET_BY_DRIVER ,
1225
- alpha2 , 0 , ENVIRON_ANY );
1226
- /* This is required so that the orig_* parameters are saved */
1227
- if (r == - EALREADY && wiphy -> strict_regulatory )
1228
- wiphy_update_regulatory (wiphy , REGDOM_SET_BY_DRIVER );
1229
- mutex_unlock (& cfg80211_mutex );
1311
+ request = kzalloc (sizeof (struct regulatory_request ), GFP_KERNEL );
1312
+ if (!request )
1313
+ return - ENOMEM ;
1314
+
1315
+ request -> wiphy_idx = WIPHY_IDX_STALE ;
1316
+ request -> alpha2 [0 ] = alpha2 [0 ];
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 */
1326
+ int 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
}
1231
1350
EXPORT_SYMBOL (regulatory_hint );
1232
1351
@@ -1260,6 +1379,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
1260
1379
char alpha2 [2 ];
1261
1380
u32 checksum = 0 ;
1262
1381
enum environment_cap env = ENVIRON_ANY ;
1382
+ struct regulatory_request * request ;
1263
1383
1264
1384
mutex_lock (& cfg80211_mutex );
1265
1385
@@ -1343,14 +1463,26 @@ void regulatory_hint_11d(struct wiphy *wiphy,
1343
1463
if (WARN_ON (reg_same_country_ie_hint (wiphy , checksum )))
1344
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
1470
/* We keep this around for when CRDA comes back with a response so
1347
1471
* we can intersect with that */
1348
1472
country_ie_regdomain = rd ;
1349
1473
1350
- __regulatory_hint (wiphy , REGDOM_SET_BY_COUNTRY_IE ,
1351
- country_ie_regdomain -> alpha2 , checksum , env );
1474
+ request -> wiphy_idx = get_wiphy_idx (wiphy );
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
1355
1487
free_rd_out :
1356
1488
kfree (rd );
@@ -1661,6 +1793,8 @@ int regulatory_init(void)
1661
1793
if (IS_ERR (reg_pdev ))
1662
1794
return PTR_ERR (reg_pdev );
1663
1795
1796
+ spin_lock_init (& reg_requests_lock );
1797
+
1664
1798
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
1665
1799
cfg80211_regdomain = static_regdom (ieee80211_regdom );
1666
1800
@@ -1700,6 +1834,10 @@ int regulatory_init(void)
1700
1834
1701
1835
void regulatory_exit (void )
1702
1836
{
1837
+ struct regulatory_request * reg_request , * tmp ;
1838
+
1839
+ cancel_work_sync (& reg_work );
1840
+
1703
1841
mutex_lock (& cfg80211_mutex );
1704
1842
1705
1843
reset_regdomains ();
@@ -1711,5 +1849,15 @@ void regulatory_exit(void)
1711
1849
1712
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
1862
mutex_unlock (& cfg80211_mutex );
1715
1863
}
0 commit comments