Skip to content

Commit fe33eb3

Browse files
Luis R. Rodriguezlinvjw
Luis R. Rodriguez
authored andcommitted
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 <[email protected]> Signed-off-by: John W. Linville <[email protected]>
1 parent 0441d6f commit fe33eb3

File tree

7 files changed

+194
-41
lines changed

7 files changed

+194
-41
lines changed

drivers/net/wireless/ath9k/main.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -1656,8 +1656,12 @@ int ath_attach(u16 devid, struct ath_softc *sc)
16561656

16571657
error = ieee80211_register_hw(hw);
16581658

1659-
if (!ath9k_is_world_regd(sc->sc_ah))
1660-
regulatory_hint(hw->wiphy, sc->sc_ah->regulatory.alpha2);
1659+
if (!ath9k_is_world_regd(sc->sc_ah)) {
1660+
error = regulatory_hint(hw->wiphy,
1661+
sc->sc_ah->regulatory.alpha2);
1662+
if (error)
1663+
goto error_attach;
1664+
}
16611665

16621666
/* Initialize LED control */
16631667
ath_init_leds(sc);

drivers/net/wireless/zd1211rw/zd_mac.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ int zd_mac_init_hw(struct ieee80211_hw *hw)
170170
goto disable_int;
171171

172172
r = zd_reg2alpha2(mac->regdomain, alpha2);
173-
if (!r)
174-
regulatory_hint(hw->wiphy, alpha2);
173+
if (r)
174+
goto disable_int;
175175

176-
r = 0;
176+
r = regulatory_hint(hw->wiphy, alpha2);
177177
disable_int:
178178
zd_chip_disable_int(chip);
179179
out:

include/net/cfg80211.h

+2
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ enum environment_cap {
404404
* country IE
405405
* @country_ie_env: lets us know if the AP is telling us we are outdoor,
406406
* indoor, or if it doesn't matter
407+
* @list: used to insert into the reg_requests_list linked list
407408
*/
408409
struct regulatory_request {
409410
int wiphy_idx;
@@ -412,6 +413,7 @@ struct regulatory_request {
412413
bool intersect;
413414
u32 country_ie_checksum;
414415
enum environment_cap country_ie_env;
416+
struct list_head list;
415417
};
416418

417419
struct ieee80211_freq_range {

include/net/wireless.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,15 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
401401
* domain should be in or by providing a completely build regulatory domain.
402402
* If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
403403
* for a regulatory domain structure for the respective country.
404+
*
405+
* The wiphy must have been registered to cfg80211 prior to this call.
406+
* For cfg80211 drivers this means you must first use wiphy_register(),
407+
* for mac80211 drivers you must first use ieee80211_register_hw().
408+
*
409+
* Drivers should check the return value, its possible you can get
410+
* an -ENOMEM.
404411
*/
405-
extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
412+
extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
406413

407414
/**
408415
* regulatory_hint_11d - hints a country IE as a regulatory domain

net/wireless/nl80211.c

+10-20
Original file line numberDiff line numberDiff line change
@@ -1915,34 +1915,24 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
19151915
*/
19161916
mutex_lock(&cfg80211_mutex);
19171917
if (unlikely(!cfg80211_regdomain)) {
1918-
r = -EINPROGRESS;
1919-
goto out;
1918+
mutex_unlock(&cfg80211_mutex);
1919+
return -EINPROGRESS;
19201920
}
1921+
mutex_unlock(&cfg80211_mutex);
19211922

1922-
if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) {
1923-
r = -EINVAL;
1924-
goto out;
1925-
}
1923+
if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
1924+
return -EINVAL;
19261925

19271926
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
19281927

19291928
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
19301929
/* We ignore world regdom requests with the old regdom setup */
1931-
if (is_world_regdom(data)) {
1932-
r = -EINVAL;
1933-
goto out;
1934-
}
1930+
if (is_world_regdom(data))
1931+
return -EINVAL;
19351932
#endif
1936-
r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
1937-
/*
1938-
* This means the regulatory domain was already set, however
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;
1944-
out:
1945-
mutex_unlock(&cfg80211_mutex);
1933+
1934+
r = regulatory_hint_user(data);
1935+
19461936
return r;
19471937
}
19481938

net/wireless/reg.c

+163-15
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
6464
* what it thinks should apply for the same country */
6565
static const struct ieee80211_regdomain *country_ie_regdomain;
6666

67+
static LIST_HEAD(reg_requests_list);
68+
static spinlock_t reg_requests_lock;
69+
6770
/* We keep a static world regulatory domain in case of the absence of CRDA */
6871
static const struct ieee80211_regdomain world_regdom = {
6972
.n_reg_rules = 1,
@@ -831,7 +834,7 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
831834
const struct ieee80211_power_rule *power_rule = NULL;
832835
struct ieee80211_supported_band *sband;
833836
struct ieee80211_channel *chan;
834-
struct wiphy *request_wiphy;
837+
struct wiphy *request_wiphy = NULL;
835838

836839
assert_cfg80211_lock();
837840

@@ -1195,6 +1198,89 @@ int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
11951198
return call_crda(alpha2);
11961199
}
11971200

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() */
11981284
static int regulatory_hint_core(const char *alpha2)
11991285
{
12001286
struct regulatory_request *request;
@@ -1210,23 +1296,56 @@ static int regulatory_hint_core(const char *alpha2)
12101296
request->alpha2[1] = alpha2[1];
12111297
request->initiator = REGDOM_SET_BY_CORE;
12121298

1213-
last_request = request;
1299+
queue_regulatory_request(request);
12141300

1215-
return call_crda(alpha2);
1301+
return 0;
12161302
}
12171303

1218-
void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
1304+
/* User hints */
1305+
int regulatory_hint_user(const char *alpha2)
12191306
{
1220-
int r;
1307+
struct regulatory_request *request;
1308+
12211309
BUG_ON(!alpha2);
12221310

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;
12301349
}
12311350
EXPORT_SYMBOL(regulatory_hint);
12321351

@@ -1260,6 +1379,7 @@ void regulatory_hint_11d(struct wiphy *wiphy,
12601379
char alpha2[2];
12611380
u32 checksum = 0;
12621381
enum environment_cap env = ENVIRON_ANY;
1382+
struct regulatory_request *request;
12631383

12641384
mutex_lock(&cfg80211_mutex);
12651385

@@ -1343,14 +1463,26 @@ void regulatory_hint_11d(struct wiphy *wiphy,
13431463
if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
13441464
goto free_rd_out;
13451465

1466+
request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
1467+
if (!request)
1468+
goto free_rd_out;
1469+
13461470
/* We keep this around for when CRDA comes back with a response so
13471471
* we can intersect with that */
13481472
country_ie_regdomain = rd;
13491473

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);
13521482

1353-
goto out;
1483+
queue_regulatory_request(request);
1484+
1485+
return;
13541486

13551487
free_rd_out:
13561488
kfree(rd);
@@ -1661,6 +1793,8 @@ int regulatory_init(void)
16611793
if (IS_ERR(reg_pdev))
16621794
return PTR_ERR(reg_pdev);
16631795

1796+
spin_lock_init(&reg_requests_lock);
1797+
16641798
#ifdef CONFIG_WIRELESS_OLD_REGULATORY
16651799
cfg80211_regdomain = static_regdom(ieee80211_regdom);
16661800

@@ -1700,6 +1834,10 @@ int regulatory_init(void)
17001834

17011835
void regulatory_exit(void)
17021836
{
1837+
struct regulatory_request *reg_request, *tmp;
1838+
1839+
cancel_work_sync(&reg_work);
1840+
17031841
mutex_lock(&cfg80211_mutex);
17041842

17051843
reset_regdomains();
@@ -1711,5 +1849,15 @@ void regulatory_exit(void)
17111849

17121850
platform_device_unregister(reg_pdev);
17131851

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+
17141862
mutex_unlock(&cfg80211_mutex);
17151863
}

net/wireless/reg.h

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain;
66
bool is_world_regdom(const char *alpha2);
77
bool reg_is_valid_request(const char *alpha2);
88

9+
int regulatory_hint_user(const char *alpha2);
10+
911
void reg_device_remove(struct wiphy *wiphy);
1012

1113
int regulatory_init(void);

0 commit comments

Comments
 (0)