Skip to content

Commit

Permalink
[NL80211]: add netlink interface to cfg80211
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and David S. Miller committed Oct 10, 2007
1 parent 0800f17 commit 5568296
Show file tree
Hide file tree
Showing 10 changed files with 762 additions and 9 deletions.
97 changes: 94 additions & 3 deletions include/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,109 @@
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*/

/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
*
* @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy name, needs %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
* @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
* %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
*
* @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
* either a dump request on a %NL80211_ATTR_WIPHY or a specific get
* on an %NL80211_ATTR_IFINDEX is supported.
* @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
* @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
* to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
* %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
* be sent from userspace to request creation of a new virtual interface,
* then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
* %NL80211_ATTR_IFNAME.
* @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
* userspace to request deletion of a virtual interface, then requires
* attribute %NL80211_ATTR_IFINDEX.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
enum nl80211_commands {
/* don't change the order or add anything inbetween, this is ABI! */
NL80211_CMD_UNSPEC,

NL80211_CMD_GET_WIPHY, /* can dump */
NL80211_CMD_SET_WIPHY,
NL80211_CMD_NEW_WIPHY,
NL80211_CMD_DEL_WIPHY,

NL80211_CMD_GET_INTERFACE, /* can dump */
NL80211_CMD_SET_INTERFACE,
NL80211_CMD_NEW_INTERFACE,
NL80211_CMD_DEL_INTERFACE,

/* add commands here */

/* used to define NL80211_CMD_MAX below */
__NL80211_CMD_AFTER_LAST,
NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
};


/**
* enum nl80211_attrs - nl80211 netlink attributes
*
* @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
*
* @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
* /sys/class/ieee80211/<phyname>/index
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
*
* @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
* @NL80211_ATTR_IFNAME: network interface name
* @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
enum nl80211_attrs {
/* don't change the order or add anything inbetween, this is ABI! */
NL80211_ATTR_UNSPEC,

NL80211_ATTR_WIPHY,
NL80211_ATTR_WIPHY_NAME,

NL80211_ATTR_IFINDEX,
NL80211_ATTR_IFNAME,
NL80211_ATTR_IFTYPE,

/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};

/**
* enum nl80211_iftype - (virtual) interface types
*
* @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
* @NL80211_IFTYPE_ADHOC: independent BSS member
* @NL80211_IFTYPE_STATION: managed BSS member
* @NL80211_IFTYPE_AP: access point
* @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
* @NL80211_IFTYPE_WDS: wireless distribution interface
* @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @__NL80211_IFTYPE_AFTER_LAST: internal use
*
* These values are used with the NL80211_ATTR_IFTYPE
* These values are used with the %NL80211_ATTR_IFTYPE
* to set the type of an interface.
*
*/
Expand All @@ -31,8 +122,8 @@ enum nl80211_iftype {
NL80211_IFTYPE_MONITOR,

/* keep last */
__NL80211_IFTYPE_AFTER_LAST
__NL80211_IFTYPE_AFTER_LAST,
NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
};
#define NL80211_IFTYPE_MAX (__NL80211_IFTYPE_AFTER_LAST - 1)

#endif /* __LINUX_NL80211_H */
11 changes: 8 additions & 3 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/nl80211.h>
#include <net/genetlink.h>

/*
* 802.11 configuration in-kernel interface
*
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*/


/* Radiotap header iteration
* implemented in net/wireless/radiotap.c
* docs in Documentation/networking/radiotap-headers.txt
Expand Down Expand Up @@ -68,11 +68,16 @@ struct wiphy;
* @add_virtual_intf: create a new virtual interface with the given name
*
* @del_virtual_intf: remove the virtual interface determined by ifindex.
*
* @change_virtual_intf: change type of virtual interface
*
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
unsigned int type);
enum nl80211_iftype type);
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
enum nl80211_iftype type);
};

#endif /* __NET_CFG80211_H */
8 changes: 7 additions & 1 deletion include/net/iw_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,13 @@ struct iw_public_data {
* Those may be called only within the kernel.
*/

/* functions that may be called by driver modules */
/* First : function strictly used inside the kernel */

/* Handle /proc/net/wireless, called in net/code/dev.c */
extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
int length);

/* Second : functions that may be called by driver modules */

/* Send a single event to user space */
extern void wireless_send_event(struct net_device * dev,
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/ieee80211_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "ieee80211_cfg.h"

static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
unsigned int type)
enum nl80211_iftype type)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
int itype;
Expand Down
17 changes: 16 additions & 1 deletion net/wireless/Kconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
config CFG80211
tristate "Improved wireless configuration API"

config NL80211
bool "nl80211 new netlink interface support"
depends CFG80211
default y
---help---
This option turns on the new netlink interface
(nl80211) support in cfg80211.

If =n, drivers using mac80211 will be configured via
wireless extension support provided by that subsystem.

If unsure, say Y.

config WIRELESS_EXT
bool "Wireless extensions"
default n
Expand All @@ -10,7 +23,9 @@ config WIRELESS_EXT

Wireless extensions will be replaced by cfg80211 and
will be required only by legacy drivers that implement
wireless extension handlers.
wireless extension handlers. This option does not
affect the wireless-extension backward compatibility
code in cfg80211.

Say N (if you can) unless you know you need wireless
extensions for external modules.
1 change: 1 addition & 0 deletions net/wireless/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o

cfg80211-y += core.o sysfs.o radiotap.o
cfg80211-$(CONFIG_NL80211) += nl80211.o
148 changes: 148 additions & 0 deletions net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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)
Expand Down Expand Up @@ -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:
Expand All @@ -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();
}
Expand Down
Loading

0 comments on commit 5568296

Please sign in to comment.