Commit 704232c2718c9d4b3375ec15a14fc0397970c449

Authored by Johannes Berg
Committed by David S. Miller
1 parent 2a5e1c0eb9

[WIRELESS] cfg80211: New wireless config infrastructure.

This patch creates the core cfg80211 code along with some sysfs bits.
This is a stripped down version to allow mac80211 to function, but
doesn't include any configuration yet except for creating and removing
virtual interfaces.

This patch includes the nl80211 header file but it only contains the
interface types which the cfg80211 interface for creating virtual
interfaces relies on.

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>

Showing 13 changed files with 583 additions and 1 deletions Side-by-side Diff

... ... @@ -317,6 +317,12 @@
317 317 S: Seattle, Washington 98126-2010
318 318 S: USA
319 319  
  320 +N: Johannes Berg
  321 +E: johannes@sipsolutions.net
  322 +W: http://johannes.sipsolutions.net/
  323 +P: 1024D/9AB78CA5 AD02 0176 4E29 C137 1DF6 08D2 FC44 CF86 9AB7 8CA5
  324 +D: powerpc & 802.11 hacker
  325 +
320 326 N: Stephen R. van den Berg (AKA BuGless)
321 327 E: berg@pool.informatik.rwth-aachen.de
322 328 D: General kernel, gcc, and libc hacker
... ... @@ -894,6 +894,12 @@
894 894 L: linux-kernel@vger.kernel.org
895 895 S: Maintained
896 896  
  897 +CFG80211 and NL80211
  898 +P: Johannes Berg
  899 +M: johannes@sipsolutions.net
  900 +L: linux-wireless@vger.kernel.org
  901 +S: Maintained
  902 +
897 903 COMMON INTERNET FILE SYSTEM (CIFS)
898 904 P: Steve French
899 905 M: sfrench@samba.org
include/linux/Kbuild
... ... @@ -113,6 +113,7 @@
113 113 header-y += nfs2.h
114 114 header-y += nfs4_mount.h
115 115 header-y += nfs_mount.h
  116 +header-y += nl80211.h
116 117 header-y += oom.h
117 118 header-y += param.h
118 119 header-y += pci_regs.h
include/linux/netdevice.h
... ... @@ -42,6 +42,8 @@
42 42 struct vlan_group;
43 43 struct ethtool_ops;
44 44 struct netpoll_info;
  45 +/* 802.11 specific */
  46 +struct wireless_dev;
45 47 /* source back-compat hooks */
46 48 #define SET_ETHTOOL_OPS(netdev,ops) \
47 49 ( (netdev)->ethtool_ops = (ops) )
... ... @@ -400,6 +402,8 @@
400 402 void *ip6_ptr; /* IPv6 specific data */
401 403 void *ec_ptr; /* Econet specific data */
402 404 void *ax25_ptr; /* AX.25 specific data */
  405 + struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
  406 + assign before registering */
403 407  
404 408 /*
405 409 * Cache line mostly used on receive path (including eth_type_trans())
include/linux/nl80211.h
  1 +#ifndef __LINUX_NL80211_H
  2 +#define __LINUX_NL80211_H
  3 +/*
  4 + * 802.11 netlink interface public header
  5 + *
  6 + * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
  7 + */
  8 +
  9 +/**
  10 + * enum nl80211_iftype - (virtual) interface types
  11 + * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
  12 + * @NL80211_IFTYPE_ADHOC: independent BSS member
  13 + * @NL80211_IFTYPE_STATION: managed BSS member
  14 + * @NL80211_IFTYPE_AP: access point
  15 + * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
  16 + * @NL80211_IFTYPE_WDS: wireless distribution interface
  17 + * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
  18 + * @__NL80211_IFTYPE_AFTER_LAST: internal use
  19 + *
  20 + * These values are used with the NL80211_ATTR_IFTYPE
  21 + * to set the type of an interface.
  22 + *
  23 + */
  24 +enum nl80211_iftype {
  25 + NL80211_IFTYPE_UNSPECIFIED,
  26 + NL80211_IFTYPE_ADHOC,
  27 + NL80211_IFTYPE_STATION,
  28 + NL80211_IFTYPE_AP,
  29 + NL80211_IFTYPE_AP_VLAN,
  30 + NL80211_IFTYPE_WDS,
  31 + NL80211_IFTYPE_MONITOR,
  32 +
  33 + /* keep last */
  34 + __NL80211_IFTYPE_AFTER_LAST
  35 +};
  36 +#define NL80211_IFTYPE_MAX (__NL80211_IFTYPE_AFTER_LAST - 1)
  37 +
  38 +#endif /* __LINUX_NL80211_H */
include/net/cfg80211.h
  1 +#ifndef __NET_CFG80211_H
  2 +#define __NET_CFG80211_H
  3 +
  4 +#include <linux/netlink.h>
  5 +#include <linux/skbuff.h>
  6 +#include <net/genetlink.h>
  7 +
  8 +/*
  9 + * 802.11 configuration in-kernel interface
  10 + *
  11 + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  12 + */
  13 +
  14 +/* from net/wireless.h */
  15 +struct wiphy;
  16 +
  17 +/**
  18 + * struct cfg80211_ops - backend description for wireless configuration
  19 + *
  20 + * This struct is registered by fullmac card drivers and/or wireless stacks
  21 + * in order to handle configuration requests on their interfaces.
  22 + *
  23 + * All callbacks except where otherwise noted should return 0
  24 + * on success or a negative error code.
  25 + *
  26 + * @add_virtual_intf: create a new virtual interface with the given name
  27 + *
  28 + * @del_virtual_intf: remove the virtual interface determined by ifindex.
  29 + */
  30 +struct cfg80211_ops {
  31 + int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
  32 + unsigned int type);
  33 + int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
  34 +};
  35 +
  36 +#endif /* __NET_CFG80211_H */
include/net/wireless.h
  1 +#ifndef __NET_WIRELESS_H
  2 +#define __NET_WIRELESS_H
  3 +
  4 +/*
  5 + * 802.11 device management
  6 + *
  7 + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
  8 + */
  9 +
  10 +#include <linux/netdevice.h>
  11 +#include <linux/debugfs.h>
  12 +#include <linux/list.h>
  13 +#include <net/cfg80211.h>
  14 +
  15 +/**
  16 + * struct wiphy - wireless hardware description
  17 + * @idx: the wiphy index assigned to this item
  18 + * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
  19 + */
  20 +struct wiphy {
  21 + /* assign these fields before you register the wiphy */
  22 +
  23 + /* permanent MAC address */
  24 + u8 perm_addr[ETH_ALEN];
  25 +
  26 + /* If multiple wiphys are registered and you're handed e.g.
  27 + * a regular netdev with assigned ieee80211_ptr, you won't
  28 + * know whether it points to a wiphy your driver has registered
  29 + * or not. Assign this to something global to your driver to
  30 + * help determine whether you own this wiphy or not. */
  31 + void *privid;
  32 +
  33 + /* fields below are read-only, assigned by cfg80211 */
  34 +
  35 + /* the item in /sys/class/ieee80211/ points to this,
  36 + * you need use set_wiphy_dev() (see below) */
  37 + struct device dev;
  38 +
  39 + /* dir in debugfs: ieee80211/<wiphyname> */
  40 + struct dentry *debugfsdir;
  41 +
  42 + char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
  43 +};
  44 +
  45 +/** struct wireless_dev - wireless per-netdev state
  46 + *
  47 + * This structure must be allocated by the driver/stack
  48 + * that uses the ieee80211_ptr field in struct net_device
  49 + * (this is intentional so it can be allocated along with
  50 + * the netdev.)
  51 + *
  52 + * @wiphy: pointer to hardware description
  53 + */
  54 +struct wireless_dev {
  55 + struct wiphy *wiphy;
  56 +
  57 + /* private to the generic wireless code */
  58 + struct list_head list;
  59 + struct net_device *netdev;
  60 +};
  61 +
  62 +/**
  63 + * wiphy_priv - return priv from wiphy
  64 + */
  65 +static inline void *wiphy_priv(struct wiphy *wiphy)
  66 +{
  67 + BUG_ON(!wiphy);
  68 + return &wiphy->priv;
  69 +}
  70 +
  71 +/**
  72 + * set_wiphy_dev - set device pointer for wiphy
  73 + */
  74 +static inline void set_wiphy_dev(struct wiphy *wiphy, struct device *dev)
  75 +{
  76 + wiphy->dev.parent = dev;
  77 +}
  78 +
  79 +/**
  80 + * wiphy_dev - get wiphy dev pointer
  81 + */
  82 +static inline struct device *wiphy_dev(struct wiphy *wiphy)
  83 +{
  84 + return wiphy->dev.parent;
  85 +}
  86 +
  87 +/**
  88 + * wiphy_name - get wiphy name
  89 + */
  90 +static inline char *wiphy_name(struct wiphy *wiphy)
  91 +{
  92 + return wiphy->dev.bus_id;
  93 +}
  94 +
  95 +/**
  96 + * wdev_priv - return wiphy priv from wireless_dev
  97 + */
  98 +static inline void *wdev_priv(struct wireless_dev *wdev)
  99 +{
  100 + BUG_ON(!wdev);
  101 + return wiphy_priv(wdev->wiphy);
  102 +}
  103 +
  104 +/**
  105 + * wiphy_new - create a new wiphy for use with cfg80211
  106 + *
  107 + * create a new wiphy and associate the given operations with it.
  108 + * @sizeof_priv bytes are allocated for private use.
  109 + *
  110 + * the returned pointer must be assigned to each netdev's
  111 + * ieee80211_ptr for proper operation.
  112 + */
  113 +struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv);
  114 +
  115 +/**
  116 + * wiphy_register - register a wiphy with cfg80211
  117 + *
  118 + * register the given wiphy
  119 + *
  120 + * Returns a non-negative wiphy index or a negative error code.
  121 + */
  122 +extern int wiphy_register(struct wiphy *wiphy);
  123 +
  124 +/**
  125 + * wiphy_unregister - deregister a wiphy from cfg80211
  126 + *
  127 + * unregister a device with the given priv pointer.
  128 + * After this call, no more requests can be made with this priv
  129 + * pointer, but the call may sleep to wait for an outstanding
  130 + * request that is being handled.
  131 + */
  132 +extern void wiphy_unregister(struct wiphy *wiphy);
  133 +
  134 +/**
  135 + * wiphy_free - free wiphy
  136 + */
  137 +extern void wiphy_free(struct wiphy *wiphy);
  138 +
  139 +#endif /* __NET_WIRELESS_H */
net/wireless/Kconfig
  1 +config CFG80211
  2 + tristate "Improved wireless configuration API"
  3 +
1 4 config WIRELESS_EXT
2 5 bool "Wireless extensions"
3 6 default n
net/wireless/Makefile
1   -# dummy file for now
  1 +obj-$(CONFIG_CFG80211) += cfg80211.o
  2 +
  3 +cfg80211-y += core.o sysfs.o
  1 +/*
  2 + * This is the linux wireless configuration interface.
  3 + *
  4 + * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
  5 + */
  6 +
  7 +#include <linux/if.h>
  8 +#include <linux/module.h>
  9 +#include <linux/err.h>
  10 +#include <linux/mutex.h>
  11 +#include <linux/list.h>
  12 +#include <linux/nl80211.h>
  13 +#include <linux/debugfs.h>
  14 +#include <linux/notifier.h>
  15 +#include <linux/device.h>
  16 +#include <net/genetlink.h>
  17 +#include <net/cfg80211.h>
  18 +#include <net/wireless.h>
  19 +#include "core.h"
  20 +#include "sysfs.h"
  21 +
  22 +/* name for sysfs, %d is appended */
  23 +#define PHY_NAME "phy"
  24 +
  25 +MODULE_AUTHOR("Johannes Berg");
  26 +MODULE_LICENSE("GPL");
  27 +MODULE_DESCRIPTION("wireless configuration support");
  28 +
  29 +/* RCU might be appropriate here since we usually
  30 + * only read the list, and that can happen quite
  31 + * often because we need to do it for each command */
  32 +LIST_HEAD(cfg80211_drv_list);
  33 +DEFINE_MUTEX(cfg80211_drv_mutex);
  34 +static int wiphy_counter;
  35 +
  36 +/* for debugfs */
  37 +static struct dentry *ieee80211_debugfs_dir;
  38 +
  39 +/* exported functions */
  40 +
  41 +struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
  42 +{
  43 + struct cfg80211_registered_device *drv;
  44 + int alloc_size;
  45 +
  46 + alloc_size = sizeof(*drv) + sizeof_priv;
  47 +
  48 + drv = kzalloc(alloc_size, GFP_KERNEL);
  49 + if (!drv)
  50 + return NULL;
  51 +
  52 + drv->ops = ops;
  53 +
  54 + mutex_lock(&cfg80211_drv_mutex);
  55 +
  56 + if (unlikely(wiphy_counter<0)) {
  57 + /* ugh, wrapped! */
  58 + kfree(drv);
  59 + return NULL;
  60 + }
  61 + drv->idx = wiphy_counter;
  62 +
  63 + /* give it a proper name */
  64 + snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE,
  65 + PHY_NAME "%d", drv->idx);
  66 +
  67 + /* now increase counter for the next time */
  68 + wiphy_counter++;
  69 + mutex_unlock(&cfg80211_drv_mutex);
  70 +
  71 + mutex_init(&drv->mtx);
  72 + mutex_init(&drv->devlist_mtx);
  73 + INIT_LIST_HEAD(&drv->netdev_list);
  74 +
  75 + device_initialize(&drv->wiphy.dev);
  76 + drv->wiphy.dev.class = &ieee80211_class;
  77 + drv->wiphy.dev.platform_data = drv;
  78 +
  79 + return &drv->wiphy;
  80 +}
  81 +EXPORT_SYMBOL(wiphy_new);
  82 +
  83 +int wiphy_register(struct wiphy *wiphy)
  84 +{
  85 + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
  86 + int res;
  87 +
  88 + mutex_lock(&cfg80211_drv_mutex);
  89 +
  90 +
  91 + res = device_add(&drv->wiphy.dev);
  92 + if (res)
  93 + goto out_unlock;
  94 +
  95 + list_add(&drv->list, &cfg80211_drv_list);
  96 +
  97 + /* add to debugfs */
  98 + drv->wiphy.debugfsdir =
  99 + debugfs_create_dir(wiphy_name(&drv->wiphy),
  100 + ieee80211_debugfs_dir);
  101 +
  102 + res = 0;
  103 +out_unlock:
  104 + mutex_unlock(&cfg80211_drv_mutex);
  105 + return res;
  106 +}
  107 +EXPORT_SYMBOL(wiphy_register);
  108 +
  109 +void wiphy_unregister(struct wiphy *wiphy)
  110 +{
  111 + struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
  112 +
  113 + mutex_lock(&cfg80211_drv_mutex);
  114 +
  115 + /* hold registered driver mutex during list removal as well
  116 + * to make sure no commands are in progress at the moment */
  117 + mutex_lock(&drv->mtx);
  118 + list_del(&drv->list);
  119 + mutex_unlock(&drv->mtx);
  120 +
  121 + device_del(&drv->wiphy.dev);
  122 + debugfs_remove(drv->wiphy.debugfsdir);
  123 +
  124 + mutex_unlock(&cfg80211_drv_mutex);
  125 +}
  126 +EXPORT_SYMBOL(wiphy_unregister);
  127 +
  128 +void cfg80211_dev_free(struct cfg80211_registered_device *drv)
  129 +{
  130 + mutex_destroy(&drv->mtx);
  131 + mutex_destroy(&drv->devlist_mtx);
  132 + kfree(drv);
  133 +}
  134 +
  135 +void wiphy_free(struct wiphy *wiphy)
  136 +{
  137 + put_device(&wiphy->dev);
  138 +}
  139 +EXPORT_SYMBOL(wiphy_free);
  140 +
  141 +static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
  142 + unsigned long state,
  143 + void *ndev)
  144 +{
  145 + struct net_device *dev = ndev;
  146 + struct cfg80211_registered_device *rdev;
  147 +
  148 + if (!dev->ieee80211_ptr)
  149 + return 0;
  150 +
  151 + rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
  152 +
  153 + switch (state) {
  154 + case NETDEV_REGISTER:
  155 + mutex_lock(&rdev->devlist_mtx);
  156 + list_add(&dev->ieee80211_ptr->list, &rdev->netdev_list);
  157 + if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj,
  158 + "phy80211")) {
  159 + printk(KERN_ERR "wireless: failed to add phy80211 "
  160 + "symlink to netdev!\n");
  161 + }
  162 + dev->ieee80211_ptr->netdev = dev;
  163 + mutex_unlock(&rdev->devlist_mtx);
  164 + break;
  165 + case NETDEV_UNREGISTER:
  166 + mutex_lock(&rdev->devlist_mtx);
  167 + if (!list_empty(&dev->ieee80211_ptr->list)) {
  168 + sysfs_remove_link(&dev->dev.kobj, "phy80211");
  169 + list_del_init(&dev->ieee80211_ptr->list);
  170 + }
  171 + mutex_unlock(&rdev->devlist_mtx);
  172 + break;
  173 + }
  174 +
  175 + return 0;
  176 +}
  177 +
  178 +static struct notifier_block cfg80211_netdev_notifier = {
  179 + .notifier_call = cfg80211_netdev_notifier_call,
  180 +};
  181 +
  182 +static int cfg80211_init(void)
  183 +{
  184 + int err = wiphy_sysfs_init();
  185 + if (err)
  186 + goto out_fail_sysfs;
  187 +
  188 + err = register_netdevice_notifier(&cfg80211_netdev_notifier);
  189 + if (err)
  190 + goto out_fail_notifier;
  191 +
  192 + ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);
  193 +
  194 + return 0;
  195 +
  196 +out_fail_notifier:
  197 + wiphy_sysfs_exit();
  198 +out_fail_sysfs:
  199 + return err;
  200 +}
  201 +module_init(cfg80211_init);
  202 +
  203 +static void cfg80211_exit(void)
  204 +{
  205 + debugfs_remove(ieee80211_debugfs_dir);
  206 + unregister_netdevice_notifier(&cfg80211_netdev_notifier);
  207 + wiphy_sysfs_exit();
  208 +}
  209 +module_exit(cfg80211_exit);
  1 +/*
  2 + * Wireless configuration interface internals.
  3 + *
  4 + * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
  5 + */
  6 +#ifndef __NET_WIRELESS_CORE_H
  7 +#define __NET_WIRELESS_CORE_H
  8 +#include <linux/mutex.h>
  9 +#include <linux/list.h>
  10 +#include <linux/netdevice.h>
  11 +#include <net/genetlink.h>
  12 +#include <net/wireless.h>
  13 +#include <net/cfg80211.h>
  14 +
  15 +struct cfg80211_registered_device {
  16 + struct cfg80211_ops *ops;
  17 + struct list_head list;
  18 + /* we hold this mutex during any call so that
  19 + * we cannot do multiple calls at once, and also
  20 + * to avoid the deregister call to proceed while
  21 + * any call is in progress */
  22 + struct mutex mtx;
  23 +
  24 + /* wiphy index, internal only */
  25 + int idx;
  26 +
  27 + /* associate netdev list */
  28 + struct mutex devlist_mtx;
  29 + struct list_head netdev_list;
  30 +
  31 + /* must be last because of the way we do wiphy_priv(),
  32 + * and it should at least be aligned to NETDEV_ALIGN */
  33 + struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
  34 +};
  35 +
  36 +static inline
  37 +struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
  38 +{
  39 + BUG_ON(!wiphy);
  40 + return container_of(wiphy, struct cfg80211_registered_device, wiphy);
  41 +}
  42 +
  43 +extern struct mutex cfg80211_drv_mutex;
  44 +extern struct list_head cfg80211_drv_list;
  45 +
  46 +/* free object */
  47 +extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
  48 +
  49 +#endif /* __NET_WIRELESS_CORE_H */
net/wireless/sysfs.c
  1 +/*
  2 + * This file provides /sys/class/ieee80211/<wiphy name>/
  3 + * and some default attributes.
  4 + *
  5 + * Copyright 2005-2006 Jiri Benc <jbenc@suse.cz>
  6 + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  7 + *
  8 + * This file is GPLv2 as found in COPYING.
  9 + */
  10 +
  11 +#include <linux/device.h>
  12 +#include <linux/module.h>
  13 +#include <linux/netdevice.h>
  14 +#include <linux/nl80211.h>
  15 +#include <linux/rtnetlink.h>
  16 +#include <net/cfg80211.h>
  17 +#include "sysfs.h"
  18 +#include "core.h"
  19 +
  20 +static inline struct cfg80211_registered_device *dev_to_rdev(
  21 + struct device *dev)
  22 +{
  23 + return container_of(dev, struct cfg80211_registered_device, wiphy.dev);
  24 +}
  25 +
  26 +static ssize_t _show_index(struct device *dev, struct device_attribute *attr,
  27 + char *buf)
  28 +{
  29 + return sprintf(buf, "%d\n", dev_to_rdev(dev)->idx);
  30 +}
  31 +
  32 +static ssize_t _show_permaddr(struct device *dev,
  33 + struct device_attribute *attr,
  34 + char *buf)
  35 +{
  36 + char *addr = dev_to_rdev(dev)->wiphy.perm_addr;
  37 +
  38 + return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
  39 + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
  40 +}
  41 +
  42 +static struct device_attribute ieee80211_dev_attrs[] = {
  43 + __ATTR(index, S_IRUGO, _show_index, NULL),
  44 + __ATTR(macaddress, S_IRUGO, _show_permaddr, NULL),
  45 + {}
  46 +};
  47 +
  48 +static void wiphy_dev_release(struct device *dev)
  49 +{
  50 + struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
  51 +
  52 + cfg80211_dev_free(rdev);
  53 +}
  54 +
  55 +static int wiphy_uevent(struct device *dev, char **envp,
  56 + int num_envp, char *buf, int size)
  57 +{
  58 + /* TODO, we probably need stuff here */
  59 + return 0;
  60 +}
  61 +
  62 +struct class ieee80211_class = {
  63 + .name = "ieee80211",
  64 + .owner = THIS_MODULE,
  65 + .dev_release = wiphy_dev_release,
  66 + .dev_attrs = ieee80211_dev_attrs,
  67 +#ifdef CONFIG_HOTPLUG
  68 + .dev_uevent = wiphy_uevent,
  69 +#endif
  70 +};
  71 +
  72 +int wiphy_sysfs_init(void)
  73 +{
  74 + return class_register(&ieee80211_class);
  75 +}
  76 +
  77 +void wiphy_sysfs_exit(void)
  78 +{
  79 + class_unregister(&ieee80211_class);
  80 +}
net/wireless/sysfs.h
  1 +#ifndef __WIRELESS_SYSFS_H
  2 +#define __WIRELESS_SYSFS_H
  3 +
  4 +extern int wiphy_sysfs_init(void);
  5 +extern void wiphy_sysfs_exit(void);
  6 +
  7 +extern struct class ieee80211_class;
  8 +
  9 +#endif /* __WIRELESS_SYSFS_H */