#include <linux/if.h>
#include <linux/module.h>
#include <linux/err.h>
-#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/nl80211.h>
#include <linux/debugfs.h>
* only read the list, and that can happen quite
* often because we need to do it for each command */
LIST_HEAD(cfg80211_drv_list);
-DEFINE_MUTEX(cfg80211_drv_mutex);
+
+/*
+ * This is used to protect the cfg80211_drv_list, cfg80211_regdomain,
+ * country_ie_regdomain, the reg_beacon_list and the the last regulatory
+ * request receipt (last_request).
+ */
+DEFINE_MUTEX(cfg80211_mutex);
/* for debugfs */
static struct dentry *ieee80211_debugfs_dir;
-/* requires cfg80211_drv_mutex to be held! */
-static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy)
+/* requires cfg80211_mutex to be held! */
+struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
{
struct cfg80211_registered_device *result = NULL, *drv;
+ if (!wiphy_idx_valid(wiphy_idx))
+ return NULL;
+
+ assert_cfg80211_lock();
+
list_for_each_entry(drv, &cfg80211_drv_list, list) {
- if (drv->idx == wiphy) {
+ if (drv->wiphy_idx == wiphy_idx) {
result = drv;
break;
}
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! */
-static struct cfg80211_registered_device *
+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! */
+struct cfg80211_registered_device *
__cfg80211_drv_from_info(struct genl_info *info)
{
int ifindex;
- struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL;
+ struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
struct net_device *dev;
int err = -EINVAL;
+ assert_cfg80211_lock();
+
if (info->attrs[NL80211_ATTR_WIPHY]) {
- bywiphy = cfg80211_drv_by_wiphy(
+ bywiphyidx = cfg80211_drv_by_wiphy_idx(
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
err = -ENODEV;
}
err = -ENODEV;
}
- if (bywiphy && byifidx) {
- if (bywiphy != byifidx)
+ if (bywiphyidx && byifidx) {
+ if (bywiphyidx != byifidx)
return ERR_PTR(-EINVAL);
else
- return bywiphy; /* == byifidx */
+ return bywiphyidx; /* == byifidx */
}
- if (bywiphy)
- return bywiphy;
+ if (bywiphyidx)
+ return bywiphyidx;
if (byifidx)
return byifidx;
{
struct cfg80211_registered_device *drv;
- mutex_lock(&cfg80211_drv_mutex);
+ mutex_lock(&cfg80211_mutex);
drv = __cfg80211_drv_from_info(info);
/* if it is not an error we grab the lock on
if (!IS_ERR(drv))
mutex_lock(&drv->mtx);
- mutex_unlock(&cfg80211_drv_mutex);
+ mutex_unlock(&cfg80211_mutex);
return drv;
}
struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);
struct net_device *dev;
- mutex_lock(&cfg80211_drv_mutex);
+ mutex_lock(&cfg80211_mutex);
dev = dev_get_by_index(&init_net, ifindex);
if (!dev)
goto out;
drv = ERR_PTR(-ENODEV);
dev_put(dev);
out:
- mutex_unlock(&cfg80211_drv_mutex);
+ mutex_unlock(&cfg80211_mutex);
return drv;
}
mutex_unlock(&drv->mtx);
}
+/* requires cfg80211_mutex to be held */
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname)
{
struct cfg80211_registered_device *drv;
- int idx, taken = -1, result, digits;
+ int wiphy_idx, taken = -1, result, digits;
- mutex_lock(&cfg80211_drv_mutex);
+ assert_cfg80211_lock();
/* prohibit calling the thing phy%d when %d is not its number */
- sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
- if (taken == strlen(newname) && idx != rdev->idx) {
- /* count number of places needed to print idx */
+ sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
+ if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) {
+ /* count number of places needed to print wiphy_idx */
digits = 1;
- while (idx /= 10)
+ while (wiphy_idx /= 10)
digits++;
/*
* deny the name if it is phy<idx> where <idx> is printed
* without leading zeroes. taken == strlen(newname) here
*/
- result = -EINVAL;
if (taken == strlen(PHY_NAME) + digits)
- goto out_unlock;
+ return -EINVAL;
}
/* Ignore nop renames */
- result = 0;
if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
- goto out_unlock;
+ return 0;
/* Ensure another device does not already have this name. */
- list_for_each_entry(drv, &cfg80211_drv_list, list) {
- result = -EINVAL;
+ list_for_each_entry(drv, &cfg80211_drv_list, list)
if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
- goto out_unlock;
- }
+ return -EINVAL;
- /* this will only check for collisions in sysfs
- * which is not even always compiled in.
- */
result = device_rename(&rdev->wiphy.dev, newname);
if (result)
- goto out_unlock;
+ return result;
if (rdev->wiphy.debugfsdir &&
!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
newname);
- result = 0;
-out_unlock:
- mutex_unlock(&cfg80211_drv_mutex);
- if (result == 0)
- nl80211_notify_dev_rename(rdev);
+ nl80211_notify_dev_rename(rdev);
- return result;
+ return 0;
}
/* exported functions */
drv->ops = ops;
- mutex_lock(&cfg80211_drv_mutex);
+ mutex_lock(&cfg80211_mutex);
- drv->idx = wiphy_counter++;
+ drv->wiphy_idx = wiphy_counter++;
- if (unlikely(drv->idx < 0)) {
+ if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) {
wiphy_counter--;
- mutex_unlock(&cfg80211_drv_mutex);
+ mutex_unlock(&cfg80211_mutex);
/* ugh, wrapped! */
kfree(drv);
return NULL;
}
- mutex_unlock(&cfg80211_drv_mutex);
+ mutex_unlock(&cfg80211_mutex);
/* give it a proper name */
- dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx);
+ dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx);
mutex_init(&drv->mtx);
mutex_init(&drv->devlist_mtx);
/* check and set up bitrates */
ieee80211_set_bitrate_flags(wiphy);
- mutex_lock(&cfg80211_drv_mutex);
+ mutex_lock(&cfg80211_mutex);
/* set up regulatory info */
- wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
+ wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
res = device_add(&drv->wiphy.dev);
if (res)
if (IS_ERR(drv->wiphy.debugfsdir))
drv->wiphy.debugfsdir = NULL;
+ if (wiphy->custom_regulatory) {
+ struct regulatory_request request;
+
+ request.wiphy_idx = get_wiphy_idx(wiphy);
+ request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+ request.alpha2[0] = '9';
+ request.alpha2[1] = '9';
+
+ nl80211_send_reg_change_event(&request);
+ }
+
res = 0;
out_unlock:
- mutex_unlock(&cfg80211_drv_mutex);
+ mutex_unlock(&cfg80211_mutex);
return res;
}
EXPORT_SYMBOL(wiphy_register);
struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
/* protect the device list */
- mutex_lock(&cfg80211_drv_mutex);
+ mutex_lock(&cfg80211_mutex);
BUG_ON(!list_empty(&drv->netdev_list));
device_del(&drv->wiphy.dev);
debugfs_remove(drv->wiphy.debugfsdir);
- mutex_unlock(&cfg80211_drv_mutex);
+ mutex_unlock(&cfg80211_mutex);
}
EXPORT_SYMBOL(wiphy_unregister);