[NL80211]: add netlink interface to cfg80211
Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
0800f17026
commit
5568296573
@@ -16,6 +16,7 @@
|
||||
#include <net/genetlink.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <net/wireless.h>
|
||||
#include "nl80211.h"
|
||||
#include "core.h"
|
||||
#include "sysfs.h"
|
||||
|
||||
@@ -36,6 +37,146 @@ static int wiphy_counter;
|
||||
/* 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)
|
||||
{
|
||||
struct cfg80211_registered_device *result = NULL, *drv;
|
||||
|
||||
list_for_each_entry(drv, &cfg80211_drv_list, list) {
|
||||
if (drv->idx == wiphy) {
|
||||
result = drv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* requires cfg80211_drv_mutex to be held! */
|
||||
static struct cfg80211_registered_device *
|
||||
__cfg80211_drv_from_info(struct genl_info *info)
|
||||
{
|
||||
int ifindex;
|
||||
struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL;
|
||||
struct net_device *dev;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY]) {
|
||||
bywiphy = cfg80211_drv_by_wiphy(
|
||||
nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
|
||||
err = -ENODEV;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_IFINDEX]) {
|
||||
ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
|
||||
dev = dev_get_by_index(&init_net, ifindex);
|
||||
if (dev) {
|
||||
if (dev->ieee80211_ptr)
|
||||
byifidx =
|
||||
wiphy_to_dev(dev->ieee80211_ptr->wiphy);
|
||||
dev_put(dev);
|
||||
}
|
||||
err = -ENODEV;
|
||||
}
|
||||
|
||||
if (bywiphy && byifidx) {
|
||||
if (bywiphy != byifidx)
|
||||
return ERR_PTR(-EINVAL);
|
||||
else
|
||||
return bywiphy; /* == byifidx */
|
||||
}
|
||||
if (bywiphy)
|
||||
return bywiphy;
|
||||
|
||||
if (byifidx)
|
||||
return byifidx;
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
struct cfg80211_registered_device *
|
||||
cfg80211_get_dev_from_info(struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *drv;
|
||||
|
||||
mutex_lock(&cfg80211_drv_mutex);
|
||||
drv = __cfg80211_drv_from_info(info);
|
||||
|
||||
/* if it is not an error we grab the lock on
|
||||
* it to assure it won't be going away while
|
||||
* we operate on it */
|
||||
if (!IS_ERR(drv))
|
||||
mutex_lock(&drv->mtx);
|
||||
|
||||
mutex_unlock(&cfg80211_drv_mutex);
|
||||
|
||||
return drv;
|
||||
}
|
||||
|
||||
struct cfg80211_registered_device *
|
||||
cfg80211_get_dev_from_ifindex(int ifindex)
|
||||
{
|
||||
struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);
|
||||
struct net_device *dev;
|
||||
|
||||
mutex_lock(&cfg80211_drv_mutex);
|
||||
dev = dev_get_by_index(&init_net, ifindex);
|
||||
if (!dev)
|
||||
goto out;
|
||||
if (dev->ieee80211_ptr) {
|
||||
drv = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
|
||||
mutex_lock(&drv->mtx);
|
||||
} else
|
||||
drv = ERR_PTR(-ENODEV);
|
||||
dev_put(dev);
|
||||
out:
|
||||
mutex_unlock(&cfg80211_drv_mutex);
|
||||
return drv;
|
||||
}
|
||||
|
||||
void cfg80211_put_dev(struct cfg80211_registered_device *drv)
|
||||
{
|
||||
BUG_ON(IS_ERR(drv));
|
||||
mutex_unlock(&drv->mtx);
|
||||
}
|
||||
|
||||
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
|
||||
char *newname)
|
||||
{
|
||||
int idx, taken = -1, result, digits;
|
||||
|
||||
/* 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 */
|
||||
digits = 1;
|
||||
while (idx /= 10)
|
||||
digits++;
|
||||
/*
|
||||
* deny the name if it is phy<idx> where <idx> is printed
|
||||
* without leading zeroes. taken == strlen(newname) here
|
||||
*/
|
||||
if (taken == strlen(PHY_NAME) + digits)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* this will check for collisions */
|
||||
result = device_rename(&rdev->wiphy.dev, newname);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
|
||||
rdev->wiphy.debugfsdir,
|
||||
rdev->wiphy.debugfsdir->d_parent,
|
||||
newname))
|
||||
printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
|
||||
newname);
|
||||
|
||||
nl80211_notify_dev_rename(rdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* exported functions */
|
||||
|
||||
struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
|
||||
@@ -204,10 +345,16 @@ static int cfg80211_init(void)
|
||||
if (err)
|
||||
goto out_fail_notifier;
|
||||
|
||||
err = nl80211_init();
|
||||
if (err)
|
||||
goto out_fail_nl80211;
|
||||
|
||||
ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
out_fail_nl80211:
|
||||
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
|
||||
out_fail_notifier:
|
||||
wiphy_sysfs_exit();
|
||||
out_fail_sysfs:
|
||||
@@ -218,6 +365,7 @@ subsys_initcall(cfg80211_init);
|
||||
static void cfg80211_exit(void)
|
||||
{
|
||||
debugfs_remove(ieee80211_debugfs_dir);
|
||||
nl80211_exit();
|
||||
unregister_netdevice_notifier(&cfg80211_netdev_notifier);
|
||||
wiphy_sysfs_exit();
|
||||
}
|
||||
|
Reference in New Issue
Block a user