cfg80211: make regulatory_request use wiphy_idx instead of wiphy

We do this so later on we can move the pending requests onto a
workqueue. By using the wiphy_idx instead of the wiphy we can
later easily check if the wiphy has disappeared or not.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Luis R. Rodriguez 2009-02-21 00:04:26 -05:00 committed by John W. Linville
parent 761cf7ecff
commit 806a9e3967
4 changed files with 82 additions and 30 deletions

View File

@ -383,9 +383,9 @@ enum environment_cap {
}; };
/** /**
* struct regulatory_request - receipt of last regulatory request * struct regulatory_request - used to keep track of regulatory requests
* *
* @wiphy: this is set if this request's initiator is * @wiphy_idx: this is set if this request's initiator is
* %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
* can be used by the wireless core to deal with conflicts * can be used by the wireless core to deal with conflicts
* and potentially inform users of which devices specifically * and potentially inform users of which devices specifically
@ -406,7 +406,7 @@ enum environment_cap {
* indoor, or if it doesn't matter * indoor, or if it doesn't matter
*/ */
struct regulatory_request { struct regulatory_request {
struct wiphy *wiphy; int wiphy_idx;
enum reg_set_by initiator; enum reg_set_by initiator;
char alpha2[2]; char alpha2[2];
bool intersect; bool intersect;

View File

@ -40,9 +40,8 @@ DEFINE_MUTEX(cfg80211_mutex);
/* for debugfs */ /* for debugfs */
static struct dentry *ieee80211_debugfs_dir; static struct dentry *ieee80211_debugfs_dir;
/* requires cfg80211_drv_mutex to be held! */ /* requires cfg80211_mutex to be held! */
static struct cfg80211_registered_device * struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
cfg80211_drv_by_wiphy_idx(int wiphy_idx)
{ {
struct cfg80211_registered_device *result = NULL, *drv; struct cfg80211_registered_device *result = NULL, *drv;
@ -61,6 +60,31 @@ cfg80211_drv_by_wiphy_idx(int wiphy_idx)
return result; return result;
} }
int get_wiphy_idx(struct wiphy *wiphy)
{
struct cfg80211_registered_device *drv;
if (!wiphy)
return WIPHY_IDX_STALE;
drv = wiphy_to_dev(wiphy);
return drv->wiphy_idx;
}
/* requires cfg80211_drv_mutex to be held! */
struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
{
struct cfg80211_registered_device *drv;
if (!wiphy_idx_valid(wiphy_idx))
return NULL;
assert_cfg80211_lock();
drv = cfg80211_drv_by_wiphy_idx(wiphy_idx);
if (!drv)
return NULL;
return &drv->wiphy;
}
/* requires cfg80211_mutex to be held! */ /* requires cfg80211_mutex to be held! */
static struct cfg80211_registered_device * static struct cfg80211_registered_device *
__cfg80211_drv_from_info(struct genl_info *info) __cfg80211_drv_from_info(struct genl_info *info)

View File

@ -79,6 +79,12 @@ static inline void assert_cfg80211_lock(void)
BUG_ON(!mutex_is_locked(&cfg80211_mutex)); BUG_ON(!mutex_is_locked(&cfg80211_mutex));
} }
/*
* You can use this to mark a wiphy_idx as not having an associated wiphy.
* It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL
*/
#define WIPHY_IDX_STALE -1
struct cfg80211_internal_bss { struct cfg80211_internal_bss {
struct list_head list; struct list_head list;
struct rb_node rbn; struct rb_node rbn;
@ -88,6 +94,9 @@ struct cfg80211_internal_bss {
struct cfg80211_bss pub; struct cfg80211_bss pub;
}; };
struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);
int get_wiphy_idx(struct wiphy *wiphy);
/* /*
* This function returns a pointer to the driver * This function returns a pointer to the driver
* that the genl_info item that is passed refers to. * that the genl_info item that is passed refers to.
@ -111,6 +120,9 @@ struct cfg80211_internal_bss {
extern struct cfg80211_registered_device * extern struct cfg80211_registered_device *
cfg80211_get_dev_from_info(struct genl_info *info); cfg80211_get_dev_from_info(struct genl_info *info);
/* requires cfg80211_drv_mutex to be held! */
struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);
/* identical to cfg80211_get_dev_from_info but only operate on ifindex */ /* identical to cfg80211_get_dev_from_info but only operate on ifindex */
extern struct cfg80211_registered_device * extern struct cfg80211_registered_device *
cfg80211_get_dev_from_ifindex(int ifindex); cfg80211_get_dev_from_ifindex(int ifindex);

View File

@ -831,9 +831,12 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
const struct ieee80211_power_rule *power_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL;
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
struct wiphy *request_wiphy;
assert_cfg80211_lock(); assert_cfg80211_lock();
request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
sband = wiphy->bands[band]; sband = wiphy->bands[band];
BUG_ON(chan_idx >= sband->n_channels); BUG_ON(chan_idx >= sband->n_channels);
chan = &sband->channels[chan_idx]; chan = &sband->channels[chan_idx];
@ -881,8 +884,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
power_rule = &reg_rule->power_rule; power_rule = &reg_rule->power_rule;
if (last_request->initiator == REGDOM_SET_BY_DRIVER && if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
last_request->wiphy && last_request->wiphy == wiphy && request_wiphy && request_wiphy == wiphy &&
last_request->wiphy->strict_regulatory) { request_wiphy->strict_regulatory) {
/* This gaurantees the driver's requested regulatory domain /* This gaurantees the driver's requested regulatory domain
* will always be used as a base for further regulatory * will always be used as a base for further regulatory
* settings */ * settings */
@ -1046,6 +1049,7 @@ static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
const char *alpha2) const char *alpha2)
{ {
struct wiphy *last_wiphy = NULL;
assert_cfg80211_lock(); assert_cfg80211_lock();
@ -1059,10 +1063,13 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
case REGDOM_SET_BY_CORE: case REGDOM_SET_BY_CORE:
return -EINVAL; return -EINVAL;
case REGDOM_SET_BY_COUNTRY_IE: case REGDOM_SET_BY_COUNTRY_IE:
last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
if (unlikely(!is_an_alpha2(alpha2))) if (unlikely(!is_an_alpha2(alpha2)))
return -EINVAL; return -EINVAL;
if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
if (last_request->wiphy != wiphy) { if (last_wiphy != wiphy) {
/* /*
* Two cards with two APs claiming different * Two cards with two APs claiming different
* different Country IE alpha2s. We could * different Country IE alpha2s. We could
@ -1163,7 +1170,7 @@ new_request:
request->alpha2[0] = alpha2[0]; request->alpha2[0] = alpha2[0];
request->alpha2[1] = alpha2[1]; request->alpha2[1] = alpha2[1];
request->initiator = set_by; request->initiator = set_by;
request->wiphy = wiphy; request->wiphy_idx = get_wiphy_idx(wiphy);
request->intersect = intersect; request->intersect = intersect;
request->country_ie_checksum = country_ie_checksum; request->country_ie_checksum = country_ie_checksum;
request->country_ie_env = env; request->country_ie_env = env;
@ -1226,11 +1233,16 @@ EXPORT_SYMBOL(regulatory_hint);
static bool reg_same_country_ie_hint(struct wiphy *wiphy, static bool reg_same_country_ie_hint(struct wiphy *wiphy,
u32 country_ie_checksum) u32 country_ie_checksum)
{ {
struct wiphy *request_wiphy;
assert_cfg80211_lock(); assert_cfg80211_lock();
if (!last_request->wiphy) request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
if (!request_wiphy)
return false; return false;
if (likely(last_request->wiphy != wiphy))
if (likely(request_wiphy != wiphy))
return !country_ie_integrity_changes(country_ie_checksum); return !country_ie_integrity_changes(country_ie_checksum);
/* We should not have let these through at this point, they /* We should not have let these through at this point, they
* should have been picked up earlier by the first alpha2 check * should have been picked up earlier by the first alpha2 check
@ -1278,14 +1290,15 @@ void regulatory_hint_11d(struct wiphy *wiphy,
/* We will run this for *every* beacon processed for the BSSID, so /* We will run this for *every* beacon processed for the BSSID, so
* we optimize an early check to exit out early if we don't have to * we optimize an early check to exit out early if we don't have to
* do anything */ * do anything */
if (likely(last_request->wiphy)) { if (likely(wiphy_idx_valid(last_request->wiphy_idx))) {
struct cfg80211_registered_device *drv_last_ie; struct cfg80211_registered_device *drv_last_ie;
drv_last_ie = wiphy_to_dev(last_request->wiphy); drv_last_ie =
cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx);
/* Lets keep this simple -- we trust the first AP /* Lets keep this simple -- we trust the first AP
* after we intersect with CRDA */ * after we intersect with CRDA */
if (likely(last_request->wiphy == wiphy)) { if (likely(&drv_last_ie->wiphy == wiphy)) {
/* Ignore IEs coming in on this wiphy with /* Ignore IEs coming in on this wiphy with
* the same alpha2 and environment cap */ * the same alpha2 and environment cap */
if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
@ -1377,13 +1390,12 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
{ {
if (is_intersected_alpha2(rd->alpha2)) { if (is_intersected_alpha2(rd->alpha2)) {
struct wiphy *wiphy = NULL;
struct cfg80211_registered_device *drv;
if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
if (last_request->wiphy) { struct cfg80211_registered_device *drv;
wiphy = last_request->wiphy; drv = cfg80211_drv_by_wiphy_idx(
drv = wiphy_to_dev(wiphy); last_request->wiphy_idx);
if (drv) {
printk(KERN_INFO "cfg80211: Current regulatory " printk(KERN_INFO "cfg80211: Current regulatory "
"domain updated by AP to: %c%c\n", "domain updated by AP to: %c%c\n",
drv->country_ie_alpha2[0], drv->country_ie_alpha2[0],
@ -1449,7 +1461,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
{ {
const struct ieee80211_regdomain *intersected_rd = NULL; const struct ieee80211_regdomain *intersected_rd = NULL;
struct cfg80211_registered_device *drv = NULL; struct cfg80211_registered_device *drv = NULL;
struct wiphy *wiphy = NULL; struct wiphy *request_wiphy;
/* Some basic sanity checks first */ /* Some basic sanity checks first */
if (is_world_regdom(rd->alpha2)) { if (is_world_regdom(rd->alpha2)) {
@ -1477,8 +1489,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
return -EINVAL; return -EINVAL;
} }
wiphy = last_request->wiphy;
/* Now lets set the regulatory domain, update all driver channels /* Now lets set the regulatory domain, update all driver channels
* and finally inform them of what we have done, in case they want * and finally inform them of what we have done, in case they want
* to review or adjust their own settings based on their own * to review or adjust their own settings based on their own
@ -1494,6 +1504,8 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
return -EINVAL; return -EINVAL;
} }
request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
if (!last_request->intersect) { if (!last_request->intersect) {
int r; int r;
@ -1506,9 +1518,9 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
/* For a driver hint, lets copy the regulatory domain the /* For a driver hint, lets copy the regulatory domain the
* driver wanted to the wiphy to deal with conflicts */ * driver wanted to the wiphy to deal with conflicts */
BUG_ON(last_request->wiphy->regd); BUG_ON(request_wiphy->regd);
r = reg_copy_regd(&last_request->wiphy->regd, rd); r = reg_copy_regd(&request_wiphy->regd, rd);
if (r) if (r)
return r; return r;
@ -1529,7 +1541,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
* However if a driver requested this specific regulatory * However if a driver requested this specific regulatory
* domain we keep it for its private use */ * domain we keep it for its private use */
if (last_request->initiator == REGDOM_SET_BY_DRIVER) if (last_request->initiator == REGDOM_SET_BY_DRIVER)
last_request->wiphy->regd = rd; request_wiphy->regd = rd;
else else
kfree(rd); kfree(rd);
@ -1569,7 +1581,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
if (!intersected_rd) if (!intersected_rd)
return -EINVAL; return -EINVAL;
drv = wiphy_to_dev(wiphy); drv = wiphy_to_dev(request_wiphy);
drv->country_ie_alpha2[0] = rd->alpha2[0]; drv->country_ie_alpha2[0] = rd->alpha2[0];
drv->country_ie_alpha2[1] = rd->alpha2[1]; drv->country_ie_alpha2[1] = rd->alpha2[1];
@ -1618,14 +1630,18 @@ int set_regdom(const struct ieee80211_regdomain *rd)
/* Caller must hold cfg80211_mutex */ /* Caller must hold cfg80211_mutex */
void reg_device_remove(struct wiphy *wiphy) void reg_device_remove(struct wiphy *wiphy)
{ {
struct wiphy *request_wiphy;
assert_cfg80211_lock(); assert_cfg80211_lock();
request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
kfree(wiphy->regd); kfree(wiphy->regd);
if (!last_request || !last_request->wiphy) if (!last_request || !request_wiphy)
return; return;
if (last_request->wiphy != wiphy) if (request_wiphy != wiphy)
return; return;
last_request->wiphy = NULL; last_request->wiphy_idx = WIPHY_IDX_STALE;
last_request->country_ie_env = ENVIRON_ANY; last_request->country_ie_env = ENVIRON_ANY;
} }