All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] cfg80211
@ 2007-02-09 16:27 johannes
  2007-02-09 16:27 ` [PATCH 1/4] create cfg80211 johannes
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: johannes @ 2007-02-09 16:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: John Linville

This patch series introduces cfg80211 along with the wext compatibility
code. cfg80211 including the wext compat code can be built as a module
so that we can replace it safely without requiring a kernel recompile.

johannes


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/4] create cfg80211
  2007-02-09 16:27 [PATCH 0/4] cfg80211 johannes
@ 2007-02-09 16:27 ` johannes
  2007-02-11 19:39   ` Johannes Berg
  2007-02-09 16:27 ` [PATCH 3/4] cfg80211: wext compat code johannes
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: johannes @ 2007-02-09 16:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: John Linville

This patch adds cfg80211, a new configuration system for wireless
hardware.

It currently features a bunch of configuration requests, support for
adding and removing virtual interfaces and lots more. It also takes
ownership of a new ieee80211_ptr in struct net_device with a newly
created struct wiphy.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 include/linux/netdevice.h |    3 
 include/net/cfg80211.h    |  235 ++++++++++++++++++++++++++++++++++++++++++++++
 net/Kconfig               |    3 
 net/Makefile              |    1 
 net/wireless/Makefile     |    3 
 net/wireless/core.c       |  160 +++++++++++++++++++++++++++++++
 net/wireless/core.h       |   68 +++++++++++++
 net/wireless/sysfs.c      |   65 ++++++++++++
 net/wireless/sysfs.h      |   10 +
 9 files changed, 548 insertions(+)

--- linux-2.6.orig/include/linux/netdevice.h	2007-02-09 16:58:57.853840519 +0100
+++ linux-2.6/include/linux/netdevice.h	2007-02-09 17:05:52.723840519 +0100
@@ -42,6 +42,8 @@
 struct vlan_group;
 struct ethtool_ops;
 struct netpoll_info;
+/* 802.11 specific */
+struct wiphy;
 					/* source back-compat hooks */
 #define SET_ETHTOOL_OPS(netdev,ops) \
 	( (netdev)->ethtool_ops = (ops) )
@@ -398,6 +400,7 @@ struct net_device
 	void                    *ip6_ptr;       /* IPv6 specific data */
 	void			*ec_ptr;	/* Econet specific data	*/
 	void			*ax25_ptr;	/* AX.25 specific data */
+	struct wiphy		*ieee80211_ptr;	/* IEEE 802.11 specific data */
 
 /*
  * Cache line mostly used on receive path (including eth_type_trans())
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/net/cfg80211.h	2007-02-09 16:59:00.363840519 +0100
@@ -0,0 +1,235 @@
+#ifndef __NET_CFG80211_H
+#define __NET_CFG80211_H
+
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+#include <linux/wireless.h>
+#include <linux/device.h>
+
+/*
+ * 802.11 configuration and wiphy management in-kernel interface
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+
+/**
+ * struct wiphy
+ *
+ * @wiphy_index: the wiphy index assigned to this item
+ * @class_dev: the class device representing /sys/class/ieee80211/<wiphy-name>
+ * @name: name of this wiphy
+ */
+struct wiphy {
+	/* assign these fields before you register the wiphy */
+
+	/* permanent MAC address */
+	u8 perm_addr[ETH_ALEN];
+
+	/* the actual hardware */
+	struct device *dev;
+
+	/* fields below are read-only, assigned by cfg80211 */
+
+	/* index assigned to this wiphy */
+	int wiphy_index;
+	/* dir in /sys/class/ieee80211/ */
+	struct class_device class_dev;
+};
+
+#define WIPHY_PRIV_ALIGN	32
+#define WIPHY_PRIV_ALIGN_CONST	(WIPHY_PRIV_ALIGN-1)
+
+/**
+ * struct cfg80211_config - description of a configuration (request)
+ */
+struct cfg80211_config {
+	/* see below */
+	u32 valid;
+
+	s8 ssid_len;
+	u8 *ssid;
+
+	u16 network_id;
+	s32 rx_sensitivity;
+	u32 transmit_power;
+	u32 fragmentation_threshold;
+	u32 channel;
+};
+
+#define CFG80211_CFG_VALID_SSID			(1<<0)
+#define CFG80211_CFG_VALID_NWID			(1<<1)
+#define CFG80211_CFG_VALID_RX_SENSITIVITY	(1<<2)
+#define CFG80211_CFG_VALID_TRANSMIT_POWER	(1<<3)
+#define CFG80211_CFG_VALID_FRAG_THRESHOLD	(1<<4)
+#define CFG80211_CFG_VALID_CHANNEL		(1<<5)
+
+struct scan_channel {
+	u32 channel;
+	int active;
+};
+
+struct scan_params {
+	/* number of items in 'channels' array
+	 * or -1 to indicate scanning all channels
+	 * (in that case 'channels' is NULL) */
+	int n_channels;
+
+	/* use only when n_channels is -1 to determine
+	 * whether scanning should be active or not */
+	int active;
+
+	/* the channel list if any */
+	struct scan_channel *channels;
+};
+
+/**
+ * struct cfg80211_ops - backend description for wireless configuration
+ *
+ * This struct is registered by fullmac card drivers and/or wireless stacks
+ * in order to handle configuration requests on their interfaces.
+ *
+ * All callbacks except where otherwise noted should return 0
+ * on success or a negative error code.
+ *
+ * @list_interfaces: Call the one() function with the given data and the
+ *                   ifindex for each interface belonging to the wiphy.
+ *		     This callback is required.
+ *
+ * @add_virtual_intf: create a new virtual interface with the given name
+ *
+ * @del_virtual_intf: remove the virtual interface determined by ifindex.
+ *
+ * @configure: configure the given interface as requested in the config struct.
+ *	       must not ignore any configuration item, if something is
+ *	       is requested that cannot be fulfilled return an error.
+ *             This call does not actually initiate any association or such.
+ *
+ * @get_config: fill the given config structure with the current configuration
+ *
+ * @get_config_valid: return a bitmask of CFG80211_CFG_VALID_* indicating
+ *		      which parameters can be set.
+ *
+ * @associate: associate with previously given settings (SSID, BSSID
+ *             if userspace roaming is enabled)
+ *
+ * @reassociate: reassociate with current settings (SSID, BSSID if
+ *		 userspace roaming is enabled)
+ *
+ * @disassociate: disassociate from current AP
+ *
+ * @deauth: deauth from current AP
+ *
+ * @initiate_scan: ...
+ *
+ * @set_roaming: set who gets to control roaming, the roaming_control
+ *		 parameter is passed NL80211_ROAMING_CONTROL_* values.
+ *
+ * @get_roaming: return where roaming control currently is done or
+ *		 a negative error.
+ *
+ * @set_fixed_bssid: set BSSID to use with userspace roaming, forces
+ *		     reassociation if changing.
+ * @get_fixed_bssid: get BSSID that is used with userspace roaming,
+ *		     the bssid parameter has space for 6 bytes
+ *
+ * @get_association: get BSSID of the BSS that the device is currently
+ *		     associated to and return 1, or return 0 if not
+ *		     associated (or a negative error code)
+ * @get_auth_list: get list of BSSIDs of all BSSs the device has
+ *		   authenticated with, must call next_bssid for each,
+ *		   next_bssid returns non-zero on error, the given data
+ *		   is to be passed to that callback
+ */
+struct cfg80211_ops {
+	int	(*list_interfaces)(struct wiphy *wiphy, void *data,
+				   int (*one)(void *data, int ifindex));
+
+
+	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
+				    unsigned int type);
+	int	(*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
+
+
+	int	(*configure)(struct wiphy *wiphy, struct net_device *dev,
+			     struct cfg80211_config *cfg);
+	void	(*get_config)(struct wiphy *wiphy, struct net_device *dev,
+			      struct cfg80211_config *cfg);
+	u32	(*get_config_valid)(struct wiphy *wiphy,
+				    struct net_device *dev);
+
+
+	int	(*associate)(struct wiphy *wiphy, struct net_device *dev);
+	int	(*reassociate)(struct wiphy *wiphy, struct net_device *dev);
+	int	(*disassociate)(struct wiphy *wiphy, struct net_device *dev);
+	int	(*deauth)(struct wiphy *wiphy, struct net_device *dev);
+
+
+	int	(*initiate_scan)(struct wiphy *wiphy, struct net_device *dev,
+				 struct scan_params *params);
+
+
+	int	(*set_roaming)(struct wiphy *wiphy, struct net_device *dev,
+			       int roaming_control);
+	int	(*get_roaming)(struct wiphy *wiphy, struct net_device *dev);
+	int	(*set_fixed_bssid)(struct wiphy *wiphy, struct net_device *dev,
+				   u8 *bssid);
+	int	(*get_fixed_bssid)(struct wiphy *wiphy, struct net_device *dev,
+				   u8 *bssid);
+
+
+	int	(*get_association)(struct wiphy *wiphy, struct net_device *dev,
+				   u8 *bssid);
+
+	int	(*get_auth_list)(struct wiphy *wiphy, struct net_device *dev,
+				 void *data,
+				 int (*next_bssid)(void *data, u8 *bssid));
+};
+
+/**
+ * wiphy_priv - return priv from wiphy
+ */
+static inline void *wiphy_priv(struct wiphy *wiphy)
+{
+	return (char *)wiphy +
+		((sizeof(struct wiphy)+WIPHY_PRIV_ALIGN_CONST)
+			& ~WIPHY_PRIV_ALIGN_CONST);
+}
+
+/**
+ * wiphy_new - create a new wiphy for use with cfg80211
+ *
+ * create a new wiphy and associate the given operations with it.
+ * @sizeof_priv bytes are allocated for private use.
+ *
+ * the returned pointer must be assigned to each netdev's
+ * ieee80211_ptr for proper operation.
+ */
+struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv);
+
+/**
+ * wiphy_register - register a wiphy with cfg80211
+ *
+ * register the given wiphy
+ *
+ * Returns a non-negative wiphy index or a negative error code.
+ */
+extern int wiphy_register(struct wiphy *wiphy);
+
+/**
+ * wiphy_unregister - deregister a wiphy from cfg80211
+ *
+ * unregister a device with the given priv pointer.
+ * After this call, no more requests can be made with this priv
+ * pointer, but the call may sleep to wait for an outstanding
+ * request that is being handled.
+ */
+extern void wiphy_unregister(struct wiphy *wiphy);
+
+/**
+ * cfg80211_free - free wiphy
+ */
+extern void wiphy_free(struct wiphy *wiphy);
+
+#endif /* __NET_CFG80211_H */
--- linux-2.6.orig/net/Kconfig	2007-02-09 16:58:57.963840519 +0100
+++ linux-2.6/net/Kconfig	2007-02-09 17:05:52.853840519 +0100
@@ -226,6 +226,9 @@ config WIRELESS_EXT
 config FIB_RULES
 	bool
 
+config CFG80211
+	tristate "Improved wireless configuration API"
+
 endif   # if NET
 endmenu # Networking
 
--- linux-2.6.orig/net/Makefile	2007-02-09 16:58:57.983840519 +0100
+++ linux-2.6/net/Makefile	2007-02-09 17:05:55.643840519 +0100
@@ -44,6 +44,7 @@ obj-$(CONFIG_ECONET)		+= econet/
 obj-$(CONFIG_VLAN_8021Q)	+= 8021q/
 obj-$(CONFIG_IP_DCCP)		+= dccp/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
+obj-$(CONFIG_CFG80211)		+= wireless/
 obj-$(CONFIG_IEEE80211)		+= ieee80211/
 obj-$(CONFIG_TIPC)		+= tipc/
 obj-$(CONFIG_NETLABEL)		+= netlabel/
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/Makefile	2007-02-09 17:05:55.863840519 +0100
@@ -0,0 +1,3 @@
+obj-$(CONFIG_CFG80211) += cfg80211.o
+
+cfg80211-y += core.o sysfs.o
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/core.c	2007-02-09 17:06:41.513840519 +0100
@@ -0,0 +1,160 @@
+/*
+ * This is the linux wireless configuration interface.
+ *
+ * Copyright 2006, 2007		Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/if.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <net/genetlink.h>
+#include <net/cfg80211.h>
+#include "core.h"
+#include "sysfs.h"
+
+MODULE_AUTHOR("Johannes Berg");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("wireless configuration support");
+
+/* RCU might be appropriate here since we usually
+ * 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);
+static int wiphy_counter;
+
+struct cfg80211_registered_driver *
+cfg80211_get_drv_from_ifindex(int ifindex)
+{
+	struct cfg80211_registered_driver *drv = ERR_PTR(-ENODEV);
+	struct net_device *dev;
+
+	mutex_lock(&cfg80211_drv_mutex);
+	dev = dev_get_by_index(ifindex);
+	if (!dev)
+		goto out;
+	drv = wiphy_to_drv(dev->ieee80211_ptr);
+	if (drv)
+		mutex_lock(&drv->mtx);
+	else
+		drv = ERR_PTR(-ENODEV);
+	dev_put(dev);
+ out:
+	mutex_unlock(&cfg80211_drv_mutex);
+	return drv;
+}
+
+void cfg80211_put_drv(struct cfg80211_registered_driver *drv)
+{
+	BUG_ON(IS_ERR(drv));
+	mutex_unlock(&drv->mtx);
+}
+
+/* exported functions */
+
+struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
+{
+	struct cfg80211_registered_driver *result;
+	int alloc_size;
+
+	if (!ops->list_interfaces)
+		return NULL;
+
+	alloc_size = sizeof(*result) + sizeof_priv;
+
+	result = kzalloc(alloc_size, GFP_KERNEL);
+	if (!result)
+		return NULL;
+
+	result->ops = ops;
+	mutex_init(&result->mtx);
+	/* special index -1: newly created */
+	result->wiphy.wiphy_index = -1;
+
+	return &result->wiphy;
+}
+EXPORT_SYMBOL(wiphy_new);
+
+int wiphy_register(struct wiphy *wiphy)
+{
+	struct cfg80211_registered_driver *drv = wiphy_to_drv(wiphy);
+	int res;
+
+	if (wiphy->wiphy_index != -1)
+		return -EINVAL;
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	if (unlikely(wiphy_counter<0)) {
+		/* ugh, wrapped! */
+		res = -ENOSPC;
+		goto out_unlock;
+	}
+	drv->wiphy.wiphy_index = wiphy_counter;
+	list_add(&drv->list, &cfg80211_drv_list);
+
+	/* give it a proper name */
+	snprintf(drv->wiphy.class_dev.class_id, BUS_ID_SIZE,
+		 "wiphy%d", drv->wiphy.wiphy_index);
+
+	res = wiphy_sysfs_add(&drv->wiphy);
+	if (res)
+		goto out_unlock;
+
+	/* now increase counter for the next time */
+	wiphy_counter++;
+
+	/* return wiphy number */
+	res = drv->wiphy.wiphy_index;
+
+ out_unlock:
+	mutex_unlock(&cfg80211_drv_mutex);
+	return res;
+}
+EXPORT_SYMBOL(wiphy_register);
+
+void wiphy_unregister(struct wiphy *wiphy)
+{
+	struct cfg80211_registered_driver *drv = wiphy_to_drv(wiphy);
+
+	mutex_lock(&cfg80211_drv_mutex);
+
+	/* hold registered driver mutex during list removal as well
+	 * to make sure no commands are in progress at the moment */
+	mutex_lock(&drv->mtx);
+	list_del(&drv->list);
+	mutex_unlock(&drv->mtx);
+
+	mutex_unlock(&cfg80211_drv_mutex);
+}
+EXPORT_SYMBOL(wiphy_unregister);
+
+void cfg80211_drv_free(struct cfg80211_registered_driver *drv)
+{
+	mutex_destroy(&drv->mtx);
+	kfree(drv);
+}
+
+void wiphy_free(struct wiphy *wiphy)
+{
+	if (wiphy->wiphy_index != -1)
+		wiphy_sysfs_del(wiphy);
+	else
+		cfg80211_drv_free(wiphy_to_drv(wiphy));
+}
+EXPORT_SYMBOL(wiphy_free);
+
+
+static int cfg80211_init(void)
+{
+	return wiphy_sysfs_init();
+}
+module_init(cfg80211_init);
+
+static void cfg80211_exit(void)
+{
+	wiphy_sysfs_exit();
+}
+module_exit(cfg80211_exit);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/core.h	2007-02-09 17:05:53.073840519 +0100
@@ -0,0 +1,68 @@
+/*
+ * Wireless configuration interface internals.
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ */
+#ifndef __NET_WIRELESS_CORE_H
+#define __NET_WIRELESS_CORE_H
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <net/genetlink.h>
+#include <net/cfg80211.h>
+
+struct cfg80211_registered_driver {
+	struct cfg80211_ops *ops;
+	struct list_head list;
+	/* we hold this mutex during any call so that
+	 * we cannot do multiple calls at once, and also
+	 * to avoid the deregister call to proceed while
+	 * any call is in progress */
+	struct mutex mtx;
+
+	/* must be last because of the way we do wiphy_priv(),
+	 * and it should at least be aligned to NETDEV_ALIGN */
+	struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
+};
+
+static inline struct cfg80211_registered_driver *wiphy_to_drv(struct wiphy *wiphy)
+{
+	return container_of(wiphy, struct cfg80211_registered_driver, wiphy);
+}
+
+extern struct mutex cfg80211_drv_mutex;
+extern struct list_head cfg80211_drv_list;
+
+/*
+ * This function returns a pointer to the driver
+ * that the genl_info item that is passed refers to.
+ * If successful, it returns non-NULL and also locks
+ * the driver's mutex!
+ *
+ * This means that you need to call cfg80211_put_drv()
+ * before being allowed to acquire &cfg80211_drv_mutex!
+ *
+ * This is necessary because we need to lock the global
+ * mutex to get an item off the list safely, and then
+ * we lock the drv mutex so it doesn't go away under us.
+ *
+ * We don't want to keep cfg80211_drv_mutex locked
+ * for all the time in order to allow requests on
+ * other interfaces to go through at the same time.
+ *
+ * The result of this can be a PTR_ERR and hence must
+ * be checked with IS_ERR() for errors.
+ */
+extern struct cfg80211_registered_driver *
+cfg80211_get_drv_from_info(struct genl_info *info);
+
+/* identical to cfg80211_get_drv_from_info but only operate on ifindex */
+extern struct cfg80211_registered_driver *
+cfg80211_get_drv_from_ifindex(int ifindex);
+
+extern void cfg80211_put_drv(struct cfg80211_registered_driver *drv);
+
+/* free object */
+extern void cfg80211_drv_free(struct cfg80211_registered_driver *drv);
+
+#endif /* __NET_WIRELESS_CORE_H */
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/sysfs.c	2007-02-09 16:59:00.373840519 +0100
@@ -0,0 +1,65 @@
+/*
+ * This file provides /sys/class/ieee80211/<wiphy name>/
+ * and some default attributes.
+ *
+ * Copyright 2005-2006	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2006	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is GPLv2 as found in COPYING.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <net/cfg80211.h>
+#include "core.h"
+
+static inline struct cfg80211_registered_driver *cdev_to_drv(
+	struct class_device *cdev)
+{
+	return container_of(cdev, struct cfg80211_registered_driver, wiphy.class_dev);
+}
+
+static void wiphy_class_dev_release(struct class_device *cdev)
+{
+	struct cfg80211_registered_driver *drv = cdev_to_drv(cdev);
+
+	cfg80211_drv_free(drv);
+}
+
+static int wiphy_uevent(struct class_device *cdev, char **envp,
+			int num_envp, char *buf, int size)
+{
+	return 0;
+}
+
+static struct class ieee80211_class = {
+	.name = "ieee80211",
+	.owner = THIS_MODULE,
+	.release = wiphy_class_dev_release,
+#ifdef CONFIG_HOTPLUG
+	.uevent = wiphy_uevent,
+#endif
+};
+
+int wiphy_sysfs_init(void)
+{
+	return class_register(&ieee80211_class);
+}
+
+void wiphy_sysfs_exit(void)
+{
+	class_unregister(&ieee80211_class);
+}
+
+int wiphy_sysfs_add(struct wiphy *wiphy)
+{
+	wiphy->class_dev.class = &ieee80211_class;
+	wiphy->class_dev.class_data = wiphy;
+	class_device_initialize(&wiphy->class_dev);
+	return class_device_add(&wiphy->class_dev);
+}
+
+void wiphy_sysfs_del(struct wiphy *wiphy)
+{
+	class_device_del(&wiphy->class_dev);
+}
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/sysfs.h	2007-02-09 16:59:00.383840519 +0100
@@ -0,0 +1,10 @@
+#ifndef __WIRELESS_SYSFS_H
+#define __WIRELESS_SYSFS_H
+
+extern int wiphy_sysfs_init(void);
+extern void wiphy_sysfs_exit(void);
+
+extern int wiphy_sysfs_add(struct wiphy *wiphy);
+extern void wiphy_sysfs_del(struct wiphy *wiphy);
+
+#endif /* __WIRELESS_SYSFS_H */

--


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/4] cfg80211: wext compat code
  2007-02-09 16:27 [PATCH 0/4] cfg80211 johannes
  2007-02-09 16:27 ` [PATCH 1/4] create cfg80211 johannes
@ 2007-02-09 16:27 ` johannes
  2007-02-13 15:42   ` Johannes Berg
  2007-02-09 16:27 ` [PATCH 4/4] wext: clean up johannes
  2007-02-09 16:33 ` [PATCH 0/4] cfg80211 Johannes Berg
  3 siblings, 1 reply; 9+ messages in thread
From: johannes @ 2007-02-09 16:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: John Linville

This adds wext compat code into cfg80211 and arranges it so that the compat
code can be in the cfg80211 module while the called stuff is built in. This
enable us to upgrade the compatibility code without upgrading the kernel, no
cfg80211 bits need to be built into the kernel.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 include/linux/netdevice.h  |    3 
 include/net/iw_handler.h   |    3 
 include/net/wireless.h     |   23 +
 net/Kconfig                |   14 
 net/core/dev.c             |   33 -
 net/core/net-sysfs.c       |    4 
 net/wireless/Makefile      |   13 
 net/wireless/core.c        |   19 -
 net/wireless/core.h        |    5 
 net/wireless/wext-common.c |  663 +++++++++++++++++++++++++++++++++++
 net/wireless/wext-compat.c |  844 +++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/wext-export.c |   29 +
 net/wireless/wext-mod.c    |   20 +
 net/wireless/wext-old.c    |  641 ----------------------------------
 net/wireless/wext.h        |   47 ++
 15 files changed, 1692 insertions(+), 669 deletions(-)

--- linux-2.6.orig/include/linux/netdevice.h	2007-02-09 17:07:23.523840519 +0100
+++ linux-2.6/include/linux/netdevice.h	2007-02-09 17:07:25.513840519 +0100
@@ -350,12 +350,13 @@ struct net_device
 
 	struct net_device_stats* (*get_stats)(struct net_device *dev);
 
+#ifdef CONFIG_WIRELESS_EXT
 	/* List of functions to handle Wireless Extensions (instead of ioctl).
 	 * See <net/iw_handler.h> for details. Jean II */
 	const struct iw_handler_def *	wireless_handlers;
 	/* Instance data managed by the core of Wireless Extensions. */
 	struct iw_public_data *	wireless_data;
-
+#endif
 	const struct ethtool_ops *ethtool_ops;
 
 	/*
--- linux-2.6.orig/net/Kconfig	2007-02-09 17:07:23.623840519 +0100
+++ linux-2.6/net/Kconfig	2007-02-09 17:07:25.523840519 +0100
@@ -229,6 +229,20 @@ config FIB_RULES
 config CFG80211
 	tristate "Improved wireless configuration API"
 
+config CFG80211_WEXT_COMPAT
+	bool "cfg80211 Wireless Extensions compatibility"
+	depends CFG80211
+	default y
+	---help---
+	This option allows using devices whose drivers have been
+	converted to use the new cfg80211 with wireless extensions,
+	providing WE-20 compatibility. Note that cfg80211's "native"
+	interface is nl80211 using generic netlink. The wireless
+	extensions are being deprecated, but userspace tools may still
+	be using them.
+
+	If unsure, say Y.
+
 endif   # if NET
 endmenu # Networking
 
--- linux-2.6.orig/net/core/dev.c	2007-02-09 17:07:23.663840519 +0100
+++ linux-2.6/net/core/dev.c	2007-02-09 17:07:25.523840519 +0100
@@ -116,6 +116,7 @@
 #include <linux/dmaengine.h>
 #include <linux/err.h>
 #include <linux/ctype.h>
+#include <net/wireless.h>
 
 /*
  *	The list of packet types we will receive (as opposed to discard)
@@ -2228,12 +2229,6 @@ static struct file_operations softnet_se
 	.release = seq_release,
 };
 
-#ifdef CONFIG_WIRELESS_EXT
-extern int wireless_proc_init(void);
-#else
-#define wireless_proc_init() 0
-#endif
-
 static int __init dev_proc_init(void)
 {
 	int rc = -ENOMEM;
@@ -2798,29 +2793,9 @@ int dev_ioctl(unsigned int cmd, void __u
 					ret = -EFAULT;
 				return ret;
 			}
-#ifdef CONFIG_WIRELESS_EXT
-			/* Take care of Wireless Extensions */
-			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				/* If command is `set a parameter', or
-				 * `get the encoding parameters', check if
-				 * the user has the right to do it */
-				if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE
-				    || cmd == SIOCGIWENCODEEXT) {
-					if (!capable(CAP_NET_ADMIN))
-						return -EPERM;
-				}
-				dev_load(ifr.ifr_name);
-				rtnl_lock();
-				/* Follow me in net/wireless/wext-old.c */
-				ret = wireless_process_ioctl(&ifr, cmd);
-				rtnl_unlock();
-				if (IW_IS_GET(cmd) &&
-				    copy_to_user(arg, &ifr,
-					    	 sizeof(struct ifreq)))
-					ret = -EFAULT;
-				return ret;
-			}
-#endif	/* CONFIG_WIRELESS_EXT */
+			/* Take care of wireless extensions */
+			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
+				return wext_ioctl(cmd, &ifr, arg);
 			return -EINVAL;
 	}
 }
--- linux-2.6.orig/net/core/net-sysfs.c	2007-02-09 17:07:23.893840519 +0100
+++ linux-2.6/net/core/net-sysfs.c	2007-02-09 17:07:25.523840519 +0100
@@ -329,7 +329,7 @@ static struct attribute_group netstat_gr
 	.attrs  = netstat_attrs,
 };
 
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 /* helper function that does all the locking etc for wireless stats */
 static ssize_t wireless_show(struct class_device *cd, char *buf,
 			     ssize_t (*format)(const struct iw_statistics *,
@@ -462,7 +462,7 @@ int netdev_register_sysfs(struct net_dev
 	if (net->get_stats)
 		*groups++ = &netstat_group;
 
-#ifdef WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT
 	if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
 		*groups++ = &wireless_group;
 #endif
--- linux-2.6.orig/net/wireless/Makefile	2007-02-09 17:07:23.913840519 +0100
+++ linux-2.6/net/wireless/Makefile	2007-02-09 17:07:25.523840519 +0100
@@ -1,5 +1,16 @@
 obj-$(CONFIG_CFG80211) += cfg80211.o
 
 cfg80211-y += core.o sysfs.o
+cfg80211-$(CONFIG_CFG80211_WEXT_COMPAT) += wext-compat.o
 
-obj-$(CONFIG_WIRELESS_EXT) += wext-old.o
+ifeq ($(CONFIG_CFG80211),m)
+obj-$(CONFIG_CFG80211_WEXT_COMPAT) += wext-export.o
+cfg80211-$(CONFIG_CFG80211_WEXT_COMPAT) += wext-mod.o
+# we need something to tell us what's up...
+# but we can't use #ifdef MODULE because we also need to
+# know in the part that is built in (namely wext-common.c)
+CFLAGS += -DCFG80211_MODULE
+endif
+
+obj-$(CONFIG_WIRELESS_EXT) += wext-common.o wext-old.o
+obj-$(CONFIG_CFG80211_WEXT_COMPAT) += wext-common.o
--- linux-2.6.orig/net/wireless/core.h	2007-02-09 17:07:23.943840519 +0100
+++ linux-2.6/net/wireless/core.h	2007-02-09 17:07:25.523840519 +0100
@@ -20,6 +20,11 @@ struct cfg80211_registered_driver {
 	 * any call is in progress */
 	struct mutex mtx;
 
+#ifdef CONFIG_CFG80211_WEXT_COMPAT
+	/* wext compat */
+	struct cfg80211_config *wext_pending_config;
+#endif
+
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
 	struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/wext-common.c	2007-02-09 17:07:25.533840519 +0100
@@ -0,0 +1,663 @@
+/*
+ * common wext support routines, proc interface and events
+ *
+ *
+ * Most code is from the original wireless.c:
+ * Copyright 1997-2006  Jean Tourrilhes <jt@hpl.hp.com>
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/wireless.h>
+#include <linux/types.h>
+#include <net/iw_handler.h>
+#include <linux/seq_file.h>
+#include <net/netlink.h>
+#include <linux/rtnetlink.h>
+#include "wext.h"
+
+/* common data */
+/*
+ * Meta-data about all the standard Wireless Extension request we
+ * know about.
+ */
+const struct iw_ioctl_description wext_standard_ioctl[] = {
+	[SIOCSIWCOMMIT	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWNAME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_CHAR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWNWID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWFREQ	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_FREQ,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWMODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_UINT,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWSENS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWRANGE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_range),
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWPRIV	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWPRIV	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_priv_args),
+		.max_tokens	= 16,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWSTATS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_NULL,
+	},
+	[SIOCGIWSTATS	- SIOCIWFIRST] = { /* (handled directly by us) */
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_statistics),
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCGIWSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCSIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[SIOCGIWAP	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWMLME	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_mlme),
+		.max_tokens	= sizeof(struct iw_mlme),
+	},
+	[SIOCGIWAPLIST	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct sockaddr) +
+				  sizeof(struct iw_quality),
+		.max_tokens	= IW_MAX_AP,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= 0,
+		.max_tokens	= sizeof(struct iw_scan_req),
+	},
+	[SIOCGIWSCAN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_SCAN_MAX_DATA,
+		.flags		= IW_DESCR_FLAG_NOMAX,
+	},
+	[SIOCSIWESSID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+		.flags		= IW_DESCR_FLAG_EVENT,
+	},
+	[SIOCGIWESSID	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+		.flags		= IW_DESCR_FLAG_DUMP,
+	},
+	[SIOCSIWNICKN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+	},
+	[SIOCGIWNICKN	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ESSID_MAX_SIZE,
+	},
+	[SIOCSIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRATE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRTS	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWFRAG	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWTXPOW	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWRETRY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCGIWENCODE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_ENCODING_TOKEN_MAX,
+		.flags		= IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
+	},
+	[SIOCSIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWPOWER	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCGIWGENIE	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[SIOCSIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCGIWAUTH	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_PARAM,
+	},
+	[SIOCSIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCGIWENCODEEXT - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_encode_ext),
+		.max_tokens	= sizeof(struct iw_encode_ext) +
+				  IW_ENCODING_TOKEN_MAX,
+	},
+	[SIOCSIWPMKSA - SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.min_tokens	= sizeof(struct iw_pmksa),
+		.max_tokens	= sizeof(struct iw_pmksa),
+	},
+};
+const unsigned wext_standard_ioctl_num = ARRAY_SIZE(wext_standard_ioctl);
+
+/*
+ * Meta-data about all the additional standard Wireless Extension events
+ * we know about.
+ */
+const struct iw_ioctl_description standard_event[] = {
+	[IWEVTXDROP	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVQUAL	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_QUAL,
+	},
+	[IWEVCUSTOM	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_CUSTOM_MAX,
+	},
+	[IWEVREGISTERED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVEXPIRED	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_ADDR,
+	},
+	[IWEVGENIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVMICHAELMICFAILURE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_michaelmicfailure),
+	},
+	[IWEVASSOCREQIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVASSOCRESPIE	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= IW_GENERIC_IE_MAX,
+	},
+	[IWEVPMKIDCAND	- IWEVFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= 1,
+		.max_tokens	= sizeof(struct iw_pmkid_cand),
+	},
+};
+unsigned standard_event_num = (sizeof(standard_event) /
+					sizeof(struct iw_ioctl_description));
+
+
+/* Size (in bytes) of various events */
+const int event_type_size[] = {
+	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
+	0,
+	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
+	0,
+	IW_EV_POINT_LEN,		/* Without variable payload */
+	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
+};
+
+
+struct iw_statistics *get_wireless_stats(struct net_device *dev,
+					 struct iw_statistics *out)
+{
+#ifdef CONFIG_CFG80211
+	if (dev->ieee80211_ptr && out) {
+		/* bah, just fake some stuff for now */
+		memset(out, 0, sizeof(*out));
+		return out;
+	}
+#endif
+#ifdef CONFIG_WIRELESS_EXT
+	if ((dev->wireless_handlers != NULL) &&
+	    (dev->wireless_handlers->get_wireless_stats != NULL))
+		return dev->wireless_handlers->get_wireless_stats(dev);
+#endif
+	return NULL;
+}
+
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Print one entry (line) of /proc/net/wireless
+ */
+static void wireless_seq_printf_stats(struct seq_file *seq,
+				      struct net_device *dev)
+{
+	/* Get stats from the driver */
+	struct iw_statistics stats_buf;
+	struct iw_statistics *stats = get_wireless_stats(dev, &stats_buf);
+
+	if (stats) {
+		seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
+				"%6d %6d   %6d\n",
+			   dev->name, stats->status, stats->qual.qual,
+			   stats->qual.updated & IW_QUAL_QUAL_UPDATED
+			   ? '.' : ' ',
+			   ((__s32) stats->qual.level) -
+			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+			   stats->qual.updated & IW_QUAL_LEVEL_UPDATED
+			   ? '.' : ' ',
+			   ((__s32) stats->qual.noise) -
+			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+			   stats->qual.updated & IW_QUAL_NOISE_UPDATED
+			   ? '.' : ' ',
+			   stats->discard.nwid, stats->discard.code,
+			   stats->discard.fragment, stats->discard.retries,
+			   stats->discard.misc, stats->miss.beacon);
+		stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+	}
+}
+
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+static int wireless_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == SEQ_START_TOKEN)
+		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
+				"packets               | Missed | WE\n"
+				" face | tus | link level noise |  nwid  "
+				"crypt   frag  retry   misc | beacon | %d\n",
+			   WIRELESS_EXT);
+	else
+		wireless_seq_printf_stats(seq, v);
+	return 0;
+}
+
+static struct seq_operations wireless_seq_ops = {
+	.start = dev_seq_start,
+	.next  = dev_seq_next,
+	.stop  = dev_seq_stop,
+	.show  = wireless_seq_show,
+};
+
+static int wireless_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &wireless_seq_ops);
+}
+
+static struct file_operations wireless_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open    = wireless_seq_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+};
+
+int __init wireless_proc_init(void)
+{
+	/* Create /proc/net/wireless entry */
+	if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
+		return -ENOMEM;
+
+	return 0;
+}
+#endif	/* CONFIG_PROC_FS */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Locking...
+ * ----------
+ *
+ * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
+ * the locking issue in here and implementing this code !
+ *
+ * The issue : wireless_send_event() is often called in interrupt context,
+ * while the Netlink layer can never be called in interrupt context.
+ * The fully formed RtNetlink events are queued, and then a tasklet is run
+ * to feed those to Netlink.
+ * The skb_queue is interrupt safe, and its lock is not held while calling
+ * Netlink, so there is no possibility of dealock.
+ * Jean II
+ */
+
+static struct sk_buff_head wireless_nlevent_queue;
+
+static int __init wireless_nlevent_init(void)
+{
+	skb_queue_head_init(&wireless_nlevent_queue);
+	return 0;
+}
+
+subsys_initcall(wireless_nlevent_init);
+
+static void wireless_nlevent_process(unsigned long data)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&wireless_nlevent_queue)))
+		rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+}
+
+static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
+
+/* ---------------------------------------------------------------- */
+/*
+ * Fill a rtnetlink message with our event data.
+ * Note that we propage only the specified event and don't dump the
+ * current wireless config. Dumping the wireless config is far too
+ * expensive (for each parameter, the driver need to query the hardware).
+ */
+static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
+					struct net_device *	dev,
+					int			type,
+					char *			event,
+					int			event_len)
+{
+	struct ifinfomsg *r;
+	struct nlmsghdr  *nlh;
+	unsigned char	 *b = skb->tail;
+
+	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
+	r = NLMSG_DATA(nlh);
+	r->ifi_family = AF_UNSPEC;
+	r->__ifi_pad = 0;
+	r->ifi_type = dev->type;
+	r->ifi_index = dev->ifindex;
+	r->ifi_flags = dev_get_flags(dev);
+	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
+
+	/* Add the wireless events in the netlink packet */
+	RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
+
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Create and broadcast and send it on the standard rtnetlink socket
+ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
+ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
+ * within a RTM_NEWLINK event.
+ */
+static inline void rtmsg_iwinfo(struct net_device *	dev,
+				char *			event,
+				int			event_len)
+{
+	struct sk_buff *skb;
+	int size = NLMSG_GOODSIZE;
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		return;
+
+	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
+				  event, event_len) < 0) {
+		kfree_skb(skb);
+		return;
+	}
+	NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
+	skb_queue_tail(&wireless_nlevent_queue, skb);
+	tasklet_schedule(&wireless_nlevent_tasklet);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the appropriate channels.
+ * May be called from interrupt context.
+ */
+void wireless_send_event(struct net_device *	dev,
+			 unsigned int		cmd,
+			 union iwreq_data *	wrqu,
+			 char *			extra)
+{
+	const struct iw_ioctl_description *	descr = NULL;
+	int extra_len = 0;
+	struct iw_event  *event;		/* Mallocated whole event */
+	int event_len;				/* Its size */
+	int hdr_len;				/* Size of the event header */
+	int wrqu_off = 0;			/* Offset in wrqu */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned	cmd_index;		/* *MUST* be unsigned */
+
+	/* Get the description of the Event */
+	if(cmd <= SIOCIWLAST) {
+		cmd_index = cmd - SIOCIWFIRST;
+		if(cmd_index < wext_standard_ioctl_num)
+			descr = &(wext_standard_ioctl[cmd_index]);
+	} else {
+		cmd_index = cmd - IWEVFIRST;
+		if(cmd_index < standard_event_num)
+			descr = &(standard_event[cmd_index]);
+	}
+	/* Don't accept unknown events */
+	if(descr == NULL) {
+		/* Note : we don't return an error to the driver, because
+		 * the driver would not know what to do about it. It can't
+		 * return an error to the user, because the event is not
+		 * initiated by a user request.
+		 * The best the driver could do is to log an error message.
+		 * We will do it ourselves instead...
+		 */
+	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+		       dev->name, cmd);
+		return;
+	}
+
+	/* Check extra parameters and set extra_len */
+	if(descr->header_type == IW_HEADER_TYPE_POINT) {
+		/* Check if number of token fits within bounds */
+		if(wrqu->data.length > descr->max_tokens) {
+		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		if(wrqu->data.length < descr->min_tokens) {
+		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
+			return;
+		}
+		/* Calculate extra_len - extra is NULL for restricted events */
+		if(extra != NULL)
+			extra_len = wrqu->data.length * descr->token_size;
+		/* Always at an offset in wrqu */
+		wrqu_off = IW_EV_POINT_OFF;
+	}
+
+	/* Total length of the event */
+	hdr_len = event_type_size[descr->header_type];
+	event_len = hdr_len + extra_len;
+
+	/* Create temporary buffer to hold the event */
+	event = kmalloc(event_len, GFP_ATOMIC);
+	if(event == NULL)
+		return;
+
+	/* Fill event */
+	event->len = event_len;
+	event->cmd = cmd;
+	memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
+	if(extra != NULL)
+		memcpy(((char *) event) + hdr_len, extra, extra_len);
+
+	/* Send via the RtNetlink event channel */
+	rtmsg_iwinfo(dev, (char *) event, event_len);
+
+	/* Cleanup */
+	kfree(event);
+
+	return;		/* Always success, I guess ;-) */
+}
+EXPORT_SYMBOL(wireless_send_event);
+
+/* common code to handle wireless extension ioctls */
+int wext_ioctl(unsigned int cmd, struct ifreq *ifr, void __user *arg)
+{
+	int ret = -EINVAL;
+
+	/* If command is `set a parameter', or `get the encoding parameters',
+	 * check if the user is allowed to do it */
+	if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT)
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+	dev_load(ifr->ifr_name);
+
+#ifdef CONFIG_WIRELESS_EXT
+	rtnl_lock();
+	/* Follow me in wext-old.c */
+	ret = wireless_process_ioctl(ifr, cmd);
+	rtnl_unlock();
+
+	if (ret == 0 && IW_IS_GET(cmd) &&
+	    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+		ret = -EFAULT;
+	/* haha, I cheat here by allowing a driver or stack to have both WE and
+	 * CFG80211-WE for a little while during conversion... wext returns
+	 * -EOPNOTSUPP if a handler is not assigned, so we can in that case try
+	 * calling cfg80211's compat code instead.
+	 */
+	if (ret != -EOPNOTSUPP)
+		return ret;
+#endif
+
+#ifdef CONFIG_CFG80211_WEXT_COMPAT
+	rtnl_lock();
+	ret = call_cfg80211_wext_ioctl(ifr, cmd);
+	rtnl_unlock();
+
+	if (ret == 0 && IW_IS_GET(cmd) &&
+	    copy_to_user(arg, ifr, sizeof(struct ifreq)))
+		ret = -EFAULT;
+#endif
+
+	return ret;
+}
--- linux-2.6.orig/net/wireless/wext-old.c	2007-02-09 17:07:24.003840519 +0100
+++ linux-2.6/net/wireless/wext-old.c	2007-02-09 17:07:25.533840519 +0100
@@ -83,9 +83,7 @@
 #include <linux/module.h>
 #include <linux/types.h>		/* off_t */
 #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
-#include <linux/proc_fs.h>
 #include <linux/rtnetlink.h>		/* rtnetlink stuff */
-#include <linux/seq_file.h>
 #include <linux/init.h>			/* for __init */
 #include <linux/if_arp.h>		/* ARPHRD_ETHER */
 #include <linux/etherdevice.h>		/* compare_ether_addr */
@@ -97,6 +95,8 @@
 
 #include <asm/uaccess.h>		/* copy_to_user() */
 
+#include "wext.h"
+
 /**************************** CONSTANTS ****************************/
 
 /* Debugging stuff */
@@ -111,294 +111,6 @@
 #define WE_SET_EVENT		/* Generate an event on some set commands */
 
 /************************* GLOBAL VARIABLES *************************/
-/*
- * You should not use global variables, because of re-entrancy.
- * On our case, it's only const, so it's OK...
- */
-/*
- * Meta-data about all the standard Wireless Extension request we
- * know about.
- */
-static const struct iw_ioctl_description standard_ioctl[] = {
-	[SIOCSIWCOMMIT	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWNAME	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_CHAR,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWNWID	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-		.flags		= IW_DESCR_FLAG_EVENT,
-	},
-	[SIOCGIWNWID	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWFREQ	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_FREQ,
-		.flags		= IW_DESCR_FLAG_EVENT,
-	},
-	[SIOCGIWFREQ	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_FREQ,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWMODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_UINT,
-		.flags		= IW_DESCR_FLAG_EVENT,
-	},
-	[SIOCGIWMODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_UINT,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWSENS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWSENS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWRANGE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWRANGE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_range),
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWPRIV	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWPRIV	- SIOCIWFIRST] = { /* (handled directly by us) */
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct iw_priv_args),
-		.max_tokens	= 16,
-		.flags		= IW_DESCR_FLAG_NOMAX,
-	},
-	[SIOCSIWSTATS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_NULL,
-	},
-	[SIOCGIWSTATS	- SIOCIWFIRST] = { /* (handled directly by us) */
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_statistics),
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct sockaddr),
-		.max_tokens	= IW_MAX_SPY,
-	},
-	[SIOCGIWSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct sockaddr) +
-				  sizeof(struct iw_quality),
-		.max_tokens	= IW_MAX_SPY,
-	},
-	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct iw_thrspy),
-		.min_tokens	= 1,
-		.max_tokens	= 1,
-	},
-	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct iw_thrspy),
-		.min_tokens	= 1,
-		.max_tokens	= 1,
-	},
-	[SIOCSIWAP	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-	},
-	[SIOCGIWAP	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWMLME	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_mlme),
-		.max_tokens	= sizeof(struct iw_mlme),
-	},
-	[SIOCGIWAPLIST	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= sizeof(struct sockaddr) +
-				  sizeof(struct iw_quality),
-		.max_tokens	= IW_MAX_AP,
-		.flags		= IW_DESCR_FLAG_NOMAX,
-	},
-	[SIOCSIWSCAN	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= 0,
-		.max_tokens	= sizeof(struct iw_scan_req),
-	},
-	[SIOCGIWSCAN	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_SCAN_MAX_DATA,
-		.flags		= IW_DESCR_FLAG_NOMAX,
-	},
-	[SIOCSIWESSID	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ESSID_MAX_SIZE,
-		.flags		= IW_DESCR_FLAG_EVENT,
-	},
-	[SIOCGIWESSID	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ESSID_MAX_SIZE,
-		.flags		= IW_DESCR_FLAG_DUMP,
-	},
-	[SIOCSIWNICKN	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ESSID_MAX_SIZE,
-	},
-	[SIOCGIWNICKN	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ESSID_MAX_SIZE,
-	},
-	[SIOCSIWRATE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWRATE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWRTS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWRTS	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWFRAG	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWFRAG	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWTXPOW	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWTXPOW	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWRETRY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWRETRY	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWENCODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ENCODING_TOKEN_MAX,
-		.flags		= IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
-	},
-	[SIOCGIWENCODE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_ENCODING_TOKEN_MAX,
-		.flags		= IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
-	},
-	[SIOCSIWPOWER	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWPOWER	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWGENIE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[SIOCGIWGENIE	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[SIOCSIWAUTH	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCGIWAUTH	- SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_PARAM,
-	},
-	[SIOCSIWENCODEEXT - SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_encode_ext),
-		.max_tokens	= sizeof(struct iw_encode_ext) +
-				  IW_ENCODING_TOKEN_MAX,
-	},
-	[SIOCGIWENCODEEXT - SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_encode_ext),
-		.max_tokens	= sizeof(struct iw_encode_ext) +
-				  IW_ENCODING_TOKEN_MAX,
-	},
-	[SIOCSIWPMKSA - SIOCIWFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.min_tokens	= sizeof(struct iw_pmksa),
-		.max_tokens	= sizeof(struct iw_pmksa),
-	},
-};
-static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) /
-					    sizeof(struct iw_ioctl_description));
-
-/*
- * Meta-data about all the additional standard Wireless Extension events
- * we know about.
- */
-static const struct iw_ioctl_description standard_event[] = {
-	[IWEVTXDROP	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-	},
-	[IWEVQUAL	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_QUAL,
-	},
-	[IWEVCUSTOM	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_CUSTOM_MAX,
-	},
-	[IWEVREGISTERED	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR,
-	},
-	[IWEVEXPIRED	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_ADDR, 
-	},
-	[IWEVGENIE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[IWEVMICHAELMICFAILURE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT, 
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_michaelmicfailure),
-	},
-	[IWEVASSOCREQIE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[IWEVASSOCRESPIE	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= IW_GENERIC_IE_MAX,
-	},
-	[IWEVPMKIDCAND	- IWEVFIRST] = {
-		.header_type	= IW_HEADER_TYPE_POINT,
-		.token_size	= 1,
-		.max_tokens	= sizeof(struct iw_pmkid_cand),
-	},
-};
-static const unsigned standard_event_num = (sizeof(standard_event) /
-					    sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
 static const char iw_priv_type_size[] = {
@@ -412,20 +124,6 @@ static const char iw_priv_type_size[] = 
 	0,				/* Not defined */
 };
 
-/* Size (in bytes) of various events */
-static const int event_type_size[] = {
-	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
-	0,
-	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
-	0,
-	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
-	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
-	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
-	0,
-	IW_EV_POINT_LEN,		/* Without variable payload */
-	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
-	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
-};
 
 /************************ COMMON SUBROUTINES ************************/
 /*
@@ -464,21 +162,6 @@ static inline iw_handler get_handler(str
 
 /* ---------------------------------------------------------------- */
 /*
- * Get statistics out of the driver
- */
-static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
-{
-	/* New location */
-	if((dev->wireless_handlers != NULL) &&
-	   (dev->wireless_handlers->get_wireless_stats != NULL))
-		return dev->wireless_handlers->get_wireless_stats(dev);
-
-	/* Not found */
-	return (struct iw_statistics *) NULL;
-}
-
-/* ---------------------------------------------------------------- */
-/*
  * Call the commit handler in the driver
  * (if exist and if conditions are right)
  *
@@ -551,7 +234,7 @@ static int iw_handler_get_iwstats(struct
 	/* Get stats from the driver */
 	struct iw_statistics *stats;
 
-	stats = get_wireless_stats(dev);
+	stats = get_wireless_stats(dev, NULL);
 	if (stats != (struct iw_statistics *) NULL) {
 
 		/* Copy statistics to extra */
@@ -601,97 +284,6 @@ static int iw_handler_get_private(struct
 	return 0;
 }
 
-
-/******************** /proc/net/wireless SUPPORT ********************/
-/*
- * The /proc/net/wireless file is a human readable user-space interface
- * exporting various wireless specific statistics from the wireless devices.
- * This is the most popular part of the Wireless Extensions ;-)
- *
- * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
- * The content of the file is basically the content of "struct iw_statistics".
- */
-
-#ifdef CONFIG_PROC_FS
-
-/* ---------------------------------------------------------------- */
-/*
- * Print one entry (line) of /proc/net/wireless
- */
-static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
-						 struct net_device *dev)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats = get_wireless_stats(dev);
-
-	if (stats) {
-		seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
-				"%6d %6d   %6d\n",
-			   dev->name, stats->status, stats->qual.qual,
-			   stats->qual.updated & IW_QUAL_QUAL_UPDATED
-			   ? '.' : ' ',
-			   ((__s32) stats->qual.level) - 
-			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
-			   stats->qual.updated & IW_QUAL_LEVEL_UPDATED
-			   ? '.' : ' ',
-			   ((__s32) stats->qual.noise) - 
-			   ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
-			   stats->qual.updated & IW_QUAL_NOISE_UPDATED
-			   ? '.' : ' ',
-			   stats->discard.nwid, stats->discard.code,
-			   stats->discard.fragment, stats->discard.retries,
-			   stats->discard.misc, stats->miss.beacon);
-		stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
-	}
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Print info for /proc/net/wireless (print all entries)
- */
-static int wireless_seq_show(struct seq_file *seq, void *v)
-{
-	if (v == SEQ_START_TOKEN)
-		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
-				"packets               | Missed | WE\n"
-				" face | tus | link level noise |  nwid  "
-				"crypt   frag  retry   misc | beacon | %d\n",
-			   WIRELESS_EXT);
-	else
-		wireless_seq_printf_stats(seq, v);
-	return 0;
-}
-
-static struct seq_operations wireless_seq_ops = {
-	.start = dev_seq_start,
-	.next  = dev_seq_next,
-	.stop  = dev_seq_stop,
-	.show  = wireless_seq_show,
-};
-
-static int wireless_seq_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &wireless_seq_ops);
-}
-
-static struct file_operations wireless_seq_fops = {
-	.owner	 = THIS_MODULE,
-	.open    = wireless_seq_open,
-	.read    = seq_read,
-	.llseek  = seq_lseek,
-	.release = seq_release,
-};
-
-int __init wireless_proc_init(void)
-{
-	/* Create /proc/net/wireless entry */
-	if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
-		return -ENOMEM;
-
-	return 0;
-}
-#endif	/* CONFIG_PROC_FS */
-
 /************************** IOCTL SUPPORT **************************/
 /*
  * The original user space API to configure all those Wireless Extensions
@@ -717,9 +309,9 @@ static int ioctl_standard_call(struct ne
 	int					ret = -EINVAL;
 
 	/* Get the description of the IOCTL */
-	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+	if((cmd - SIOCIWFIRST) >= wext_standard_ioctl_num)
 		return -EOPNOTSUPP;
-	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+	descr = &(wext_standard_ioctl[cmd - SIOCIWFIRST]);
 
 #ifdef WE_IOCTL_DEBUG
 	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
@@ -1178,9 +770,9 @@ static int rtnetlink_standard_get(struct
 
 	/* Get the description of the Request */
 	cmd = request->cmd;
-	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+	if((cmd - SIOCIWFIRST) >= wext_standard_ioctl_num)
 		return -EOPNOTSUPP;
-	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+	descr = &(wext_standard_ioctl[cmd - SIOCIWFIRST]);
 
 #ifdef WE_RTNETLINK_DEBUG
 	printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n",
@@ -1320,9 +912,9 @@ static inline int rtnetlink_standard_set
 
 	/* Get the description of the Request */
 	cmd = request->cmd;
-	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+	if((cmd - SIOCIWFIRST) >= wext_standard_ioctl_num)
 		return -EOPNOTSUPP;
-	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+	descr = &(wext_standard_ioctl[cmd - SIOCIWFIRST]);
 
 #ifdef WE_RTNETLINK_DEBUG
 	printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n",
@@ -1863,220 +1455,6 @@ int wireless_rtnetlink_set(struct net_de
 }
 #endif	/* CONFIG_NET_WIRELESS_RTNETLINK */
 
-
-/************************* EVENT PROCESSING *************************/
-/*
- * Process events generated by the wireless layer or the driver.
- * Most often, the event will be propagated through rtnetlink
- */
-
-#ifdef WE_EVENT_RTNETLINK
-/* ---------------------------------------------------------------- */
-/*
- * Locking...
- * ----------
- *
- * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
- * the locking issue in here and implementing this code !
- *
- * The issue : wireless_send_event() is often called in interrupt context,
- * while the Netlink layer can never be called in interrupt context.
- * The fully formed RtNetlink events are queued, and then a tasklet is run
- * to feed those to Netlink.
- * The skb_queue is interrupt safe, and its lock is not held while calling
- * Netlink, so there is no possibility of dealock.
- * Jean II
- */
-
-static struct sk_buff_head wireless_nlevent_queue;
-
-static int __init wireless_nlevent_init(void)
-{
-	skb_queue_head_init(&wireless_nlevent_queue);
-	return 0;
-}
-
-subsys_initcall(wireless_nlevent_init);
-
-static void wireless_nlevent_process(unsigned long data)
-{
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&wireless_nlevent_queue)))
-		rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
-}
-
-static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
-
-/* ---------------------------------------------------------------- */
-/*
- * Fill a rtnetlink message with our event data.
- * Note that we propage only the specified event and don't dump the
- * current wireless config. Dumping the wireless config is far too
- * expensive (for each parameter, the driver need to query the hardware).
- */
-static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
-					struct net_device *	dev,
-					int			type,
-					char *			event,
-					int			event_len)
-{
-	struct ifinfomsg *r;
-	struct nlmsghdr  *nlh;
-	unsigned char	 *b = skb->tail;
-
-	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
-	r = NLMSG_DATA(nlh);
-	r->ifi_family = AF_UNSPEC;
-	r->__ifi_pad = 0;
-	r->ifi_type = dev->type;
-	r->ifi_index = dev->ifindex;
-	r->ifi_flags = dev_get_flags(dev);
-	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
-
-	/* Add the wireless events in the netlink packet */
-	RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
-
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-rtattr_failure:
-	skb_trim(skb, b - skb->data);
-	return -1;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Create and broadcast and send it on the standard rtnetlink socket
- * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
- * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
- * within a RTM_NEWLINK event.
- */
-static inline void rtmsg_iwinfo(struct net_device *	dev,
-				char *			event,
-				int			event_len)
-{
-	struct sk_buff *skb;
-	int size = NLMSG_GOODSIZE;
-
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-		return;
-
-	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
-				  event, event_len) < 0) {
-		kfree_skb(skb);
-		return;
-	}
-	NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
-	skb_queue_tail(&wireless_nlevent_queue, skb);
-	tasklet_schedule(&wireless_nlevent_tasklet);
-}
-
-#endif	/* WE_EVENT_RTNETLINK */
-
-/* ---------------------------------------------------------------- */
-/*
- * Main event dispatcher. Called from other parts and drivers.
- * Send the event on the appropriate channels.
- * May be called from interrupt context.
- */
-void wireless_send_event(struct net_device *	dev,
-			 unsigned int		cmd,
-			 union iwreq_data *	wrqu,
-			 char *			extra)
-{
-	const struct iw_ioctl_description *	descr = NULL;
-	int extra_len = 0;
-	struct iw_event  *event;		/* Mallocated whole event */
-	int event_len;				/* Its size */
-	int hdr_len;				/* Size of the event header */
-	int wrqu_off = 0;			/* Offset in wrqu */
-	/* Don't "optimise" the following variable, it will crash */
-	unsigned	cmd_index;		/* *MUST* be unsigned */
-
-	/* Get the description of the Event */
-	if(cmd <= SIOCIWLAST) {
-		cmd_index = cmd - SIOCIWFIRST;
-		if(cmd_index < standard_ioctl_num)
-			descr = &(standard_ioctl[cmd_index]);
-	} else {
-		cmd_index = cmd - IWEVFIRST;
-		if(cmd_index < standard_event_num)
-			descr = &(standard_event[cmd_index]);
-	}
-	/* Don't accept unknown events */
-	if(descr == NULL) {
-		/* Note : we don't return an error to the driver, because
-		 * the driver would not know what to do about it. It can't
-		 * return an error to the user, because the event is not
-		 * initiated by a user request.
-		 * The best the driver could do is to log an error message.
-		 * We will do it ourselves instead...
-		 */
-	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
-		       dev->name, cmd);
-		return;
-	}
-#ifdef WE_EVENT_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_EVENT_DEBUG */
-
-	/* Check extra parameters and set extra_len */
-	if(descr->header_type == IW_HEADER_TYPE_POINT) {
-		/* Check if number of token fits within bounds */
-		if(wrqu->data.length > descr->max_tokens) {
-		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
-			return;
-		}
-		if(wrqu->data.length < descr->min_tokens) {
-		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
-			return;
-		}
-		/* Calculate extra_len - extra is NULL for restricted events */
-		if(extra != NULL)
-			extra_len = wrqu->data.length * descr->token_size;
-		/* Always at an offset in wrqu */
-		wrqu_off = IW_EV_POINT_OFF;
-#ifdef WE_EVENT_DEBUG
-		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
-#endif	/* WE_EVENT_DEBUG */
-	}
-
-	/* Total length of the event */
-	hdr_len = event_type_size[descr->header_type];
-	event_len = hdr_len + extra_len;
-
-#ifdef WE_EVENT_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len);
-#endif	/* WE_EVENT_DEBUG */
-
-	/* Create temporary buffer to hold the event */
-	event = kmalloc(event_len, GFP_ATOMIC);
-	if(event == NULL)
-		return;
-
-	/* Fill event */
-	event->len = event_len;
-	event->cmd = cmd;
-	memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
-	if(extra != NULL)
-		memcpy(((char *) event) + hdr_len, extra, extra_len);
-
-#ifdef WE_EVENT_RTNETLINK
-	/* Send via the RtNetlink event channel */
-	rtmsg_iwinfo(dev, (char *) event, event_len);
-#endif	/* WE_EVENT_RTNETLINK */
-
-	/* Cleanup */
-	kfree(event);
-
-	return;		/* Always success, I guess ;-) */
-}
-
 /********************** ENHANCED IWSPY SUPPORT **********************/
 /*
  * In the old days, the driver was handling spy support all by itself.
@@ -2349,5 +1727,4 @@ EXPORT_SYMBOL(iw_handler_get_spy);
 EXPORT_SYMBOL(iw_handler_get_thrspy);
 EXPORT_SYMBOL(iw_handler_set_spy);
 EXPORT_SYMBOL(iw_handler_set_thrspy);
-EXPORT_SYMBOL(wireless_send_event);
 EXPORT_SYMBOL(wireless_spy_update);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/wext.h	2007-02-09 17:07:25.533840519 +0100
@@ -0,0 +1,47 @@
+/*
+ * some foo for wext compat/wext interoperability
+ */
+#ifndef _WEXT_H
+#define _WEXT_H
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+
+/* wext compatibility must be compiled in...
+ * this extern is in wext-compat.c */
+struct cfg80211_ioctl_ops {
+	/* used to make sure the module isn't going away
+	 * can't really happen, except if no driver has cfg80211
+	 * in use, but in that case  */
+	struct module *module;
+
+	/* and finally this is used to do work */
+	int (*do_wext_ioctl)(struct ifreq *ifr, unsigned int cmd);
+};
+extern struct cfg80211_ioctl_ops cfg80211_ioctl_ops;
+
+
+struct iw_statistics *get_wireless_stats(struct net_device *dev,
+					 struct iw_statistics *out);
+int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+
+int cfg80211_wext_ioctl(struct ifreq *ifr, unsigned int cmd);
+#ifdef CFG80211_MODULE
+int call_cfg80211_wext_ioctl(struct ifreq *ifr, unsigned int cmd);
+int cfg80211_wext_init(void);
+void cfg80211_wext_exit(void);
+#else
+#define call_cfg80211_wext_ioctl cfg80211_wext_ioctl
+static inline int cfg80211_wext_init(void)
+{
+	return 0;
+}
+static inline void cfg80211_wext_exit(void) {}
+#endif
+
+extern const struct iw_ioctl_description wext_standard_ioctl[];
+extern const unsigned wext_standard_ioctl_num;
+extern const struct iw_ioctl_description standard_event[];
+extern const int event_type_size[];
+#endif /* _WEXT_H */
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/wext-compat.c	2007-02-09 17:07:25.543840519 +0100
@@ -0,0 +1,844 @@
+/*
+ * wireless extensions compatibility for cfg80211.
+ *
+ * Lots of code from the original wireless.c:
+ * Copyright 1997-2006	Jean Tourrilhes <jt@hpl.hp.com>
+ *
+ * Copyright 2006,2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2.
+ *
+ * Theory of operation, so to speak:
+ *
+ * To implement compatibility, I added a new field to struct net_device
+ * that contains the pending configuration structure. This is dynamically
+ * allocated when needed and freed when committed.
+ *
+ * Commit is done some time after the last parameter was changed
+ * (with each parameter change simply (re-)schedule a timer) or
+ * if explicitly asked for. This is probably not what most people
+ * would expect, but perfectly fine in the WE API.
+ *
+ * NB: we leak memory if the user
+ *      - changes some settings
+ *      - quickly rmmod's the module so that the net device is destroyed
+ * Since only root can do it and I don't see a way to hook into
+ * the net device's destruction... tough.
+ *
+ * NB2: Note that each of the wrappers should check if the cfg80211
+ * user provides the command, and for configure() it must also check
+ * if that parameter can be set or not via get_config_valid()
+ *
+ * NB3: It's really bad that we can't report an error from the timer-
+ * based commit... Hopefully get_config_valid() can catch everything?
+ *
+ * see set_essid for an example
+ *
+ * another question I just thought about.. does wext expect to see
+ * the new config even if it wasn't committed... if so, we need to
+ * look at the pending config in various _get_ calls...
+ */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/netlink.h>
+#include <asm/uaccess.h>
+#include <net/cfg80211.h>
+
+#include "core.h"
+#include "wext.h"
+
+/* internal API: use this function when changing
+ * some parameter that needs to be committed */
+static void cfg80211_wx_start_commit_timer(int ifindex)
+{
+	/* TODO:
+	 * start a timer associate with this interface
+	 * and then when it expires commit the pending
+	 * data...
+	 * This function must be callable when the timer
+	 * is already running, and the timer must
+	 * be able to deal with an unassigned
+	 * dev->cfg80211_wext_pending_config pointer
+	 * as well as taking the rtnl lock (due to wext)! */
+}
+
+static struct cfg80211_config *cfg80211_ensure_pending_cfg(
+	struct cfg80211_registered_driver *drv)
+{
+	struct cfg80211_config *cfg = drv->wext_pending_config;
+	if (!cfg)
+		cfg = kmalloc(sizeof(*cfg)+32, GFP_KERNEL);
+	if (cfg) {
+		cfg->ssid = (char*)cfg + sizeof(*cfg);
+		drv->wext_pending_config = cfg;
+	}
+	return cfg;
+}
+
+static int cfg80211_wx_set_commit(struct cfg80211_registered_driver *drv,
+				  struct net_device *net_dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *data,
+				  char *extra)
+{
+	int err;
+
+	if (!drv->wext_pending_config) {
+		err = 0;
+		goto out;
+	}
+
+	err = drv->ops->configure(&drv->wiphy, net_dev,
+				  drv->wext_pending_config);
+
+	kfree(drv->wext_pending_config);
+	drv->wext_pending_config = NULL;
+
+ out:
+	return err;
+}
+
+static int cfg80211_wx_get_name(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_nwid(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_nwid(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_freq(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_freq(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_mode(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_mode(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_sens(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_sens(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_range(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_range(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_ap(struct cfg80211_registered_driver *drv,
+			      struct net_device *net_dev,
+			      struct iw_request_info *info,
+			      union iwreq_data *data,
+			      char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	/* TODO: DO SOMETHING */
+	/* SIOCSIWAP
+	 *   -> if bssid is all-ones: set roaming to kernel, reassociate
+	 *   -> if bssid is all-zeroes: set roaming to kernel
+	 *   -> otherwise: set roaming to userspace, set bssid
+	 */
+
+	return err;
+}
+
+static int cfg80211_wx_get_ap(struct cfg80211_registered_driver *drv,
+			      struct net_device *net_dev,
+			      struct iw_request_info *info,
+			      union iwreq_data *data,
+			      char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	/* TODO: DO SOMETHING */
+	/* SIOCGIWAP
+	 *   -> get association parameters and fill return bssid appropriately
+	 */
+
+	return err;
+}
+
+static int cfg80211_wx_set_mlme(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_waplist(struct cfg80211_registered_driver *drv,
+				   struct net_device *net_dev,
+				   struct iw_request_info *info,
+				   union iwreq_data *data,
+				   char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_scan(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_scan(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_essid(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+	struct cfg80211_config *cfg;
+
+	if (!drv->ops->configure || !drv->ops->get_config_valid)
+		goto out;
+	if (!(drv->ops->get_config_valid(&drv->wiphy, net_dev)
+			& CFG80211_CFG_VALID_SSID))
+		goto out;
+
+	cfg = cfg80211_ensure_pending_cfg(drv);
+	if (!cfg) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	memcpy(cfg->ssid, extra, data->essid.length);
+	cfg->ssid_len = data->essid.length;
+	cfg->valid |= CFG80211_CFG_VALID_SSID;
+
+	cfg80211_wx_start_commit_timer(net_dev->ifindex);
+	err = 0;
+ out:
+	return err;
+}
+
+static int cfg80211_wx_get_essid(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_rate(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_rate(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_rts(struct cfg80211_registered_driver *drv,
+			       struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_rts(struct cfg80211_registered_driver *drv,
+			       struct net_device *net_dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *data,
+			       char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_frag(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_frag(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_txpow(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_txpow(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_retry(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_retry(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_encode(struct cfg80211_registered_driver *drv,
+				  struct net_device *net_dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *data,
+				  char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_encode(struct cfg80211_registered_driver *drv,
+				  struct net_device *net_dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *data,
+				  char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_power(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_power(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_genie(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_genie(struct cfg80211_registered_driver *drv,
+				 struct net_device *net_dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *data,
+				 char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_auth(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_auth(struct cfg80211_registered_driver *drv,
+				struct net_device *net_dev,
+				struct iw_request_info *info,
+				union iwreq_data *data,
+				char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_encodeext(struct cfg80211_registered_driver *drv,
+				     struct net_device *net_dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *data,
+				     char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_get_encodeext(struct cfg80211_registered_driver *drv,
+				     struct net_device *net_dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *data,
+				     char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+static int cfg80211_wx_set_wpmksa(struct cfg80211_registered_driver *drv,
+				  struct net_device *net_dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *data,
+				  char *extra)
+{
+	int err = -EOPNOTSUPP;
+
+	return err;
+}
+
+
+typedef int (*iw_compat_handler)(struct cfg80211_registered_driver *drv,
+				 struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra);
+
+/* operations array */
+#ifdef WX
+# undef WX
+#endif
+#define WX(ioctl)  [(ioctl) - SIOCIWFIRST]
+static const iw_compat_handler cfg80211_wx_handlers[] = {
+	WX(SIOCSIWCOMMIT)	= cfg80211_wx_set_commit,
+	WX(SIOCGIWNAME)		= cfg80211_wx_get_name,
+	WX(SIOCSIWNWID)		= cfg80211_wx_set_nwid,
+	WX(SIOCGIWNWID)		= cfg80211_wx_get_nwid,
+	WX(SIOCSIWFREQ)		= cfg80211_wx_set_freq,
+	WX(SIOCGIWFREQ)		= cfg80211_wx_get_freq,
+	WX(SIOCSIWMODE)		= cfg80211_wx_set_mode,
+	WX(SIOCGIWMODE)		= cfg80211_wx_get_mode,
+	WX(SIOCSIWSENS)		= cfg80211_wx_set_sens,
+	WX(SIOCGIWSENS)		= cfg80211_wx_get_sens,
+	WX(SIOCSIWRANGE)	= cfg80211_wx_set_range,
+	WX(SIOCGIWRANGE)	= cfg80211_wx_get_range,
+	WX(SIOCSIWAP)		= cfg80211_wx_set_ap,
+	WX(SIOCGIWAP)		= cfg80211_wx_get_ap,
+	WX(SIOCSIWMLME)		= cfg80211_wx_set_mlme,
+	WX(SIOCGIWAPLIST)	= cfg80211_wx_get_waplist,
+	WX(SIOCSIWSCAN)		= cfg80211_wx_set_scan,
+	WX(SIOCGIWSCAN)		= cfg80211_wx_get_scan,
+	WX(SIOCSIWESSID)	= cfg80211_wx_set_essid,
+	WX(SIOCGIWESSID)	= cfg80211_wx_get_essid,
+	WX(SIOCSIWRATE)		= cfg80211_wx_set_rate,
+	WX(SIOCGIWRATE)		= cfg80211_wx_get_rate,
+	WX(SIOCSIWRTS)		= cfg80211_wx_set_rts,
+	WX(SIOCGIWRTS)		= cfg80211_wx_get_rts,
+	WX(SIOCSIWFRAG)		= cfg80211_wx_set_frag,
+	WX(SIOCGIWFRAG)		= cfg80211_wx_get_frag,
+	WX(SIOCSIWTXPOW)	= cfg80211_wx_set_txpow,
+	WX(SIOCGIWTXPOW)	= cfg80211_wx_get_txpow,
+	WX(SIOCSIWRETRY)	= cfg80211_wx_set_retry,
+	WX(SIOCGIWRETRY)	= cfg80211_wx_get_retry,
+	WX(SIOCSIWENCODE)	= cfg80211_wx_set_encode,
+	WX(SIOCGIWENCODE)	= cfg80211_wx_get_encode,
+	WX(SIOCSIWPOWER)	= cfg80211_wx_set_power,
+	WX(SIOCGIWPOWER)	= cfg80211_wx_get_power,
+	WX(SIOCSIWGENIE)	= cfg80211_wx_set_genie,
+	WX(SIOCGIWGENIE)	= cfg80211_wx_get_genie,
+	WX(SIOCSIWAUTH)		= cfg80211_wx_set_auth,
+	WX(SIOCGIWAUTH)		= cfg80211_wx_get_auth,
+	WX(SIOCSIWENCODEEXT)	= cfg80211_wx_set_encodeext,
+	WX(SIOCGIWENCODEEXT)	= cfg80211_wx_get_encodeext,
+	WX(SIOCSIWPMKSA)	= cfg80211_wx_set_wpmksa,
+};
+
+/* dummy so I didn't have to change that much code... */
+static iw_compat_handler get_handler(unsigned int cmd)
+{
+	int idx = cmd - SIOCIWFIRST;
+	if (idx < ARRAY_SIZE(cfg80211_wx_handlers))
+		return cfg80211_wx_handlers[idx];
+	return NULL;
+}
+
+/*
+ * this is sort of backwards and wouldn't need to call
+ * get_wireless_stats, but it was easier to just copy the code...
+ */
+static int iw_handler_get_iwstats(struct cfg80211_registered_driver *drv,
+				  struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *extra)
+{
+	/* Get stats from the driver */
+	struct iw_statistics stats_buf;
+	struct iw_statistics *stats;
+
+	stats = get_wireless_stats(dev, &stats_buf);
+	if (stats != (struct iw_statistics *) NULL) {
+
+		/* Copy statistics to extra */
+		memcpy(extra, stats, sizeof(struct iw_statistics));
+		wrqu->data.length = sizeof(struct iw_statistics);
+
+		/* Check if we need to clear the updated flag */
+		if(wrqu->data.flags != 0)
+			stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+		return 0;
+	} else
+		return -EOPNOTSUPP;
+}
+
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static int ioctl_standard_call(struct cfg80211_registered_driver *drv,
+			       struct net_device *dev,
+			       struct ifreq *ifr,
+			       unsigned int cmd,
+			       iw_compat_handler handler)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+	const struct iw_ioctl_description *	descr;
+	struct iw_request_info			info;
+	int					ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	if((cmd - SIOCIWFIRST) >= wext_standard_ioctl_num)
+		return -EOPNOTSUPP;
+	descr = &(wext_standard_ioctl[cmd - SIOCIWFIRST]);
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not */
+	if(descr->header_type != IW_HEADER_TYPE_POINT) {
+
+		/* No extra arguments. Trivial to handle */
+		ret = handler(drv, dev, &info, &(iwr->u), NULL);
+
+		/* Generate an event to notify listeners of the change */
+		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT)))
+			wireless_send_event(dev, cmd, &(iwr->u), NULL);
+	} else {
+		char *	extra;
+		int	extra_size;
+		int	user_length = 0;
+		int	err;
+
+		/* Calculate space needed by arguments. Always allocate
+		 * for max space. Easier, and won't last long... */
+		extra_size = descr->max_tokens * descr->token_size;
+
+		/* Check what user space is giving us */
+		if(IW_IS_SET(cmd)) {
+			/* Check NULL pointer */
+			if((iwr->u.data.pointer == NULL) &&
+			   (iwr->u.data.length != 0))
+				return -EFAULT;
+			/* Check if number of token fits within bounds */
+			if(iwr->u.data.length > descr->max_tokens)
+				return -E2BIG;
+			if(iwr->u.data.length < descr->min_tokens)
+				return -EINVAL;
+		} else {
+			/* Check NULL pointer */
+			if(iwr->u.data.pointer == NULL)
+				return -EFAULT;
+			/* Save user space buffer size for checking */
+			user_length = iwr->u.data.length;
+
+			/* Don't check if user_length > max to allow forward
+			 * compatibility. The test user_length < min is
+			 * implied by the test at the end. */
+
+			/* Support for very large requests */
+			if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
+			   (user_length > descr->max_tokens)) {
+				/* Allow userspace to GET more than max so
+				 * we can support any size GET requests.
+				 * There is still a limit : -ENOMEM. */
+				extra_size = user_length * descr->token_size;
+				/* Note : user_length is originally a __u16,
+				 * and token_size is controlled by us,
+				 * so extra_size won't get negative and
+				 * won't overflow... */
+			}
+		}
+
+		/* Create the kernel buffer */
+		extra = kmalloc(extra_size, GFP_KERNEL);
+		if (extra == NULL) {
+			return -ENOMEM;
+		}
+
+		/* If it is a SET, get all the extra data in here */
+		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
+			err = copy_from_user(extra, iwr->u.data.pointer,
+					     iwr->u.data.length *
+					     descr->token_size);
+			if (err) {
+				kfree(extra);
+				return -EFAULT;
+			}
+		}
+
+		/* Call the handler */
+		ret = handler(drv, dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+			/* Check if there is enough buffer up there */
+			if(user_length < iwr->u.data.length) {
+				kfree(extra);
+				return -E2BIG;
+			}
+
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   iwr->u.data.length *
+					   descr->token_size);
+			if (err)
+				ret =  -EFAULT;
+		}
+
+		/* Generate an event to notify listeners of the change */
+		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
+		   ((ret == 0) || (ret == -EIWCOMMIT))) {
+			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
+				/* If the event is restricted, don't
+				 * export the payload */
+				wireless_send_event(dev, cmd, &(iwr->u), NULL);
+			else
+				wireless_send_event(dev, cmd, &(iwr->u),
+						    extra);
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+	return ret;
+}
+
+/* and finally the ioctl wrapper */
+int cfg80211_wext_ioctl(struct ifreq *ifr, unsigned int cmd)
+{
+	struct net_device *dev;
+	iw_compat_handler handler;
+	struct cfg80211_registered_driver *drv;
+
+	/* Permissions are already checked in dev_ioctl() before calling us.
+	 * The copy_to/from_user() of ifr is also dealt with in there */
+
+	/* Make sure the device exist */
+	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
+		return -ENODEV;
+
+	drv = cfg80211_get_drv_from_ifindex(dev->ifindex);
+	if (!IS_ERR(drv))
+		return PTR_ERR(drv);
+
+	/* A bunch of special cases, then the generic case...
+	 * Note that 'cmd' is already filtered in dev_ioctl() with
+	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
+	switch(cmd) {
+		case SIOCGIWSTATS:
+			/* Get Wireless Stats */
+			return ioctl_standard_call(drv, dev, ifr, cmd,
+						   &iw_handler_get_iwstats);
+
+		case SIOCGIWPRIV:
+			return -EOPNOTSUPP;
+		default:
+			handler = get_handler(cmd);
+			if(cmd < SIOCIWFIRSTPRIV && handler != NULL)
+				return ioctl_standard_call(drv, dev, ifr, cmd,
+							   handler);
+			return -EOPNOTSUPP;
+	}
+	return -EINVAL;
+}
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/include/net/wireless.h	2007-02-09 17:07:25.543840519 +0100
@@ -0,0 +1,23 @@
+#ifndef __NET_WIRELESS_H
+#define __NET_WIRELESS_H
+
+/*
+ * internal definitions for wireless
+ */
+
+#if defined(CONFIG_CFG80211_WEXT_COMPAT) || defined(CONFIG_WIRELESS_EXT)
+int wext_ioctl(unsigned int cmd, struct ifreq *ifreq, void __user *arg);
+int wireless_proc_init(void);
+#else
+static inline
+int wext_ioctl(unsigned int cmd, struct ifreq *ifreq, void __user *arg)
+{
+	return -EINVAL;
+}
+static inline int wireless_proc_init(void)
+{
+	return 0;
+}
+#endif
+
+#endif /* __NET_WIRELESS_H */
--- linux-2.6.orig/include/net/iw_handler.h	2007-02-09 17:07:23.603840519 +0100
+++ linux-2.6/include/net/iw_handler.h	2007-02-09 17:07:25.543840519 +0100
@@ -433,9 +433,6 @@ struct iw_public_data {
 extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
 				 int length);
 
-/* Handle IOCTLs, called in net/core/dev.c */
-extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
-
 /* Handle RtNetlink requests, called in net/core/rtnetlink.c */
 extern int wireless_rtnetlink_set(struct net_device *	dev,
 				  char *		data,
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/wext-export.c	2007-02-09 17:07:25.543840519 +0100
@@ -0,0 +1,29 @@
+/*
+ * things we only need in the kernel when cfg80211 is modular.
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include "wext.h"
+
+EXPORT_SYMBOL_GPL(wext_standard_ioctl);
+EXPORT_SYMBOL_GPL(wext_standard_ioctl_num);
+EXPORT_SYMBOL_GPL(get_wireless_stats);
+
+struct cfg80211_ioctl_ops cfg80211_ioctl_ops;
+EXPORT_SYMBOL_GPL(cfg80211_ioctl_ops);
+
+int call_cfg80211_wext_ioctl(struct ifreq *ifr, unsigned int cmd)
+{
+	int err = -ENOSYS;
+
+	if (!try_module_get(cfg80211_ioctl_ops.module))
+		return -ENOSYS;
+
+	if (cfg80211_ioctl_ops.do_wext_ioctl)
+		err = cfg80211_ioctl_ops.do_wext_ioctl(ifr, cmd);
+
+	module_put(cfg80211_ioctl_ops.module);
+
+	return err;
+}
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/net/wireless/wext-mod.c	2007-02-09 17:07:25.543840519 +0100
@@ -0,0 +1,20 @@
+/*
+ * things we only need in cfg80211 when it is modular.
+ *
+ * Copyright 2007       Johannes Berg <johannes@sipsolutions.net>
+ */
+
+#include "wext.h"
+
+int cfg80211_wext_init(void)
+{
+	cfg80211_ioctl_ops.do_wext_ioctl = cfg80211_wext_ioctl;
+	cfg80211_ioctl_ops.module = THIS_MODULE;
+	return 0;
+}
+
+void cfg80211_wext_exit(void)
+{
+	cfg80211_ioctl_ops.module = NULL;
+	cfg80211_ioctl_ops.do_wext_ioctl = NULL;
+}
--- linux-2.6.orig/net/wireless/core.c	2007-02-09 17:07:24.553840519 +0100
+++ linux-2.6/net/wireless/core.c	2007-02-09 17:07:25.543840519 +0100
@@ -13,6 +13,7 @@
 #include <net/cfg80211.h>
 #include "core.h"
 #include "sysfs.h"
+#include "wext.h"
 
 MODULE_AUTHOR("Johannes Berg");
 MODULE_LICENSE("GPL");
@@ -149,12 +150,28 @@ EXPORT_SYMBOL(wiphy_free);
 
 static int cfg80211_init(void)
 {
-	return wiphy_sysfs_init();
+	int err = wiphy_sysfs_init();
+
+	if (err)
+		return err;
+
+	err = cfg80211_wext_init();
+
+	if (err)
+		goto out_exit_sysfs;
+
+	return 0;
+
+ out_exit_sysfs:
+ 	wiphy_sysfs_exit();
+
+	return err;
 }
 module_init(cfg80211_init);
 
 static void cfg80211_exit(void)
 {
+	cfg80211_wext_exit();
 	wiphy_sysfs_exit();
 }
 module_exit(cfg80211_exit);

--


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 4/4] wext: clean up
  2007-02-09 16:27 [PATCH 0/4] cfg80211 johannes
  2007-02-09 16:27 ` [PATCH 1/4] create cfg80211 johannes
  2007-02-09 16:27 ` [PATCH 3/4] cfg80211: wext compat code johannes
@ 2007-02-09 16:27 ` johannes
  2007-02-09 16:33 ` [PATCH 0/4] cfg80211 Johannes Berg
  3 siblings, 0 replies; 9+ messages in thread
From: johannes @ 2007-02-09 16:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: John Linville

This cleans up wext.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

---
 net/wireless/wext-old.c |  302 ++----------------------------------------------
 1 file changed, 17 insertions(+), 285 deletions(-)

--- linux-2.6.orig/net/wireless/wext-old.c	2007-02-09 16:59:02.573840519 +0100
+++ linux-2.6/net/wireless/wext-old.c	2007-02-09 16:59:03.573840519 +0100
@@ -7,79 +7,6 @@
  * (As all part of the Linux kernel, this file is GPL)
  */
 
-/************************** DOCUMENTATION **************************/
-/*
- * API definition :
- * --------------
- * See <linux/wireless.h> for details of the APIs and the rest.
- *
- * History :
- * -------
- *
- * v1 - 5.12.01 - Jean II
- *	o Created this file.
- *
- * v2 - 13.12.01 - Jean II
- *	o Move /proc/net/wireless stuff from net/core/dev.c to here
- *	o Make Wireless Extension IOCTLs go through here
- *	o Added iw_handler handling ;-)
- *	o Added standard ioctl description
- *	o Initial dumb commit strategy based on orinoco.c
- *
- * v3 - 19.12.01 - Jean II
- *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
- *	o Add event dispatcher function
- *	o Add event description
- *	o Propagate events as rtnetlink IFLA_WIRELESS option
- *	o Generate event on selected SET requests
- *
- * v4 - 18.04.02 - Jean II
- *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
- *
- * v5 - 21.06.02 - Jean II
- *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
- *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
- *	o Add IWEVCUSTOM for driver specific event/scanning token
- *	o Turn on WE_STRICT_WRITE by default + kernel warning
- *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
- *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
- *
- * v6 - 9.01.03 - Jean II
- *	o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
- *	o Add enhanced spy support : iw_handler_set_thrspy() and event.
- *	o Add WIRELESS_EXT version display in /proc/net/wireless
- *
- * v6 - 18.06.04 - Jean II
- *	o Change get_spydata() method for added safety
- *	o Remove spy #ifdef, they are always on -> cleaner code
- *	o Allow any size GET request if user specifies length > max
- *		and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
- *	o Start migrating get_wireless_stats to struct iw_handler_def
- *	o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
- * Based on patch from Pavel Roskin <proski@gnu.org> :
- *	o Fix kernel data leak to user space in private handler handling
- *
- * v7 - 18.3.05 - Jean II
- *	o Remove (struct iw_point *)->pointer from events and streams
- *	o Remove spy_offset from struct iw_handler_def
- *	o Start deprecating dev->get_wireless_stats, output a warning
- *	o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
- *	o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
- *
- * v8 - 17.02.06 - Jean II
- *	o RtNetlink requests support (SET/GET)
- *
- * v8b - 03.08.06 - Herbert Xu
- *	o Fix Wireless Event locking issues.
- *
- * v9 - 14.3.06 - Jean II
- *	o Change length in ESSID and NICK to strlen() instead of strlen()+1
- *	o Make standard_ioctl_num and standard_event_num unsigned
- *	o Remove (struct net_device *)->get_wireless_stats()
- */
-
-/***************************** INCLUDES *****************************/
-
 #include <linux/module.h>
 #include <linux/types.h>		/* off_t */
 #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
@@ -97,19 +24,6 @@
 
 #include "wext.h"
 
-/**************************** CONSTANTS ****************************/
-
-/* Debugging stuff */
-#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
-#undef WE_RTNETLINK_DEBUG	/* Debug RtNetlink API */
-#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
-#undef WE_SPY_DEBUG		/* Debug enhanced spy support */
-
-/* Options */
-//CONFIG_NET_WIRELESS_RTNETLINK	/* Wireless requests over RtNetlink */
-#define WE_EVENT_RTNETLINK	/* Propagate events using RtNetlink */
-#define WE_SET_EVENT		/* Generate an event on some set commands */
-
 /************************* GLOBAL VARIABLES *************************/
 
 /* Size (in bytes) of the various private data types */
@@ -313,12 +227,6 @@ static int ioctl_standard_call(struct ne
 		return -EOPNOTSUPP;
 	descr = &(wext_standard_ioctl[cmd - SIOCIWFIRST]);
 
-#ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
-	       ifr->ifr_name, cmd);
-	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_IOCTL_DEBUG */
-
 	/* Prepare the call */
 	info.cmd = cmd;
 	info.flags = 0;
@@ -329,12 +237,10 @@ static int ioctl_standard_call(struct ne
 		/* No extra arguments. Trivial to handle */
 		ret = handler(dev, &info, &(iwr->u), NULL);
 
-#ifdef WE_SET_EVENT
 		/* Generate an event to notify listeners of the change */
 		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
 		   ((ret == 0) || (ret == -EIWCOMMIT)))
 			wireless_send_event(dev, cmd, &(iwr->u), NULL);
-#endif	/* WE_SET_EVENT */
 	} else {
 		char *	extra;
 		int	extra_size;
@@ -409,11 +315,6 @@ static int ioctl_standard_call(struct ne
 			}
 		}
 
-#ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_IOCTL_DEBUG */
-
 		/* Create the kernel buffer */
 		/*    kzalloc ensures NULL-termination for essid_compat */
 		extra = kzalloc(extra_size, GFP_KERNEL);
@@ -430,11 +331,6 @@ static int ioctl_standard_call(struct ne
 				kfree(extra);
 				return -EFAULT;
 			}
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
-			       dev->name,
-			       iwr->u.data.length * descr->token_size);
-#endif	/* WE_IOCTL_DEBUG */
 		}
 
 		/* Call the handler */
@@ -454,15 +350,9 @@ static int ioctl_standard_call(struct ne
 					   iwr->u.data.length *
 					   descr->token_size);
 			if (err)
-				ret =  -EFAULT;				   
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
-			       dev->name,
-			       iwr->u.data.length * descr->token_size);
-#endif	/* WE_IOCTL_DEBUG */
+				ret =  -EFAULT;
 		}
 
-#ifdef WE_SET_EVENT
 		/* Generate an event to notify listeners of the change */
 		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
 		   ((ret == 0) || (ret == -EIWCOMMIT))) {
@@ -474,7 +364,6 @@ static int ioctl_standard_call(struct ne
 				wireless_send_event(dev, cmd, &(iwr->u),
 						    extra);
 		}
-#endif	/* WE_SET_EVENT */
 
 		/* Cleanup - I told you it wasn't that long ;-) */
 		kfree(extra);
@@ -524,16 +413,6 @@ static inline int ioctl_private_call(str
 			break;
 		}
 
-#ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
-	       ifr->ifr_name, cmd);
-	if(descr) {
-		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
-		       dev->name, descr->name,
-		       descr->set_args, descr->get_args);
-	}
-#endif	/* WE_IOCTL_DEBUG */
-
 	/* Compute the size of the set/get arguments */
 	if(descr != NULL) {
 		if(IW_IS_SET(cmd)) {
@@ -590,11 +469,6 @@ static inline int ioctl_private_call(str
 				return -EFAULT;
 		}
 
-#ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_IOCTL_DEBUG */
-
 		/* Always allocate for max space. Easier, and won't last
 		 * long... */
 		extra = kmalloc(extra_size, GFP_KERNEL);
@@ -610,10 +484,6 @@ static inline int ioctl_private_call(str
 				kfree(extra);
 				return -EFAULT;
 			}
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
-			       dev->name, iwr->u.data.length);
-#endif	/* WE_IOCTL_DEBUG */
 		}
 
 		/* Call the handler */
@@ -632,11 +502,7 @@ static inline int ioctl_private_call(str
 			err = copy_to_user(iwr->u.data.pointer, extra,
 					   extra_size);
 			if (err)
-				ret =  -EFAULT;				   
-#ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
-			       dev->name, iwr->u.data.length);
-#endif	/* WE_IOCTL_DEBUG */
+				ret =  -EFAULT;
 		}
 
 		/* Cleanup - I told you it wasn't that long ;-) */
@@ -672,8 +538,7 @@ int wireless_process_ioctl(struct ifreq 
 	/* A bunch of special cases, then the generic case...
 	 * Note that 'cmd' is already filtered in dev_ioctl() with
 	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
-	switch(cmd) 
-	{
+	switch(cmd) {
 		case SIOCGIWSTATS:
 			/* Get Wireless Stats */
 			return ioctl_standard_call(dev,
@@ -774,22 +639,10 @@ static int rtnetlink_standard_get(struct
 		return -EOPNOTSUPP;
 	descr = &(wext_standard_ioctl[cmd - SIOCIWFIRST]);
 
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_RTNETLINK_DEBUG */
-
 	/* Check if wrqu is complete */
 	hdr_len = event_type_size[descr->header_type];
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
+	if(request_len < hdr_len)
 		return -EINVAL;
-	}
 
 	/* Prepare the call */
 	info.cmd = cmd;
@@ -833,10 +686,6 @@ static int rtnetlink_standard_get(struct
 			extra_size = (wrqu_point.data.length
 				      * descr->token_size);
 		buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
-		       dev->name, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
 
 		/* Create the kernel buffer that we will return */
 		buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -868,10 +717,6 @@ static int rtnetlink_standard_get(struct
 		 * dummy pointer. */
 		memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
 
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-
 		/* Check if there is enough buffer up there */
 		if(wrqu_point.data.length < wrqu->data.length)
 			ret = -E2BIG;
@@ -916,25 +761,13 @@ static inline int rtnetlink_standard_set
 		return -EOPNOTSUPP;
 	descr = &(wext_standard_ioctl[cmd - SIOCIWFIRST]);
 
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
-#endif	/* WE_RTNETLINK_DEBUG */
-
 	/* Extract fixed header from request. This is properly aligned. */
 	wrqu = &request->u;
 
 	/* Check if wrqu is complete */
 	hdr_len = event_type_size[descr->header_type];
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
+	if(request_len < hdr_len)
 		return -EINVAL;
-	}
 
 	/* Prepare the call */
 	info.cmd = cmd;
@@ -965,18 +798,8 @@ static inline int rtnetlink_standard_set
 		extra_len = wrqu_point.data.length * descr->token_size;
 
 		/* Check if request is self consistent */
-		if((request_len - hdr_len) < extra_len) {
-#ifdef WE_RTNETLINK_DEBUG
-			printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
-			       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
+		if((request_len - hdr_len) < extra_len)
 			return -EINVAL;
-		}
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
 
 		/* Always allocate for max space. Easier, and won't last
 		 * long... */
@@ -992,7 +815,6 @@ static inline int rtnetlink_standard_set
 		ret = handler(dev, &info, &wrqu_point, extra);
 	}
 
-#ifdef WE_SET_EVENT
 	/* Generate an event to notify listeners of the change */
 	if((descr->flags & IW_DESCR_FLAG_EVENT) &&
 	   ((ret == 0) || (ret == -EIWCOMMIT))) {
@@ -1003,7 +825,6 @@ static inline int rtnetlink_standard_set
 		else
 			wireless_send_event(dev, cmd, wrqu, extra);
 	}
-#endif	/* WE_SET_EVENT */
 
 	/* Cleanup - I told you it wasn't that long ;-) */
 	if(extra)
@@ -1059,13 +880,6 @@ static inline int rtnetlink_private_get(
 	if(descr == NULL)
 		return -EOPNOTSUPP;
 
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
-	       dev->name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
-	       dev->name, descr->name, descr->set_args, descr->get_args);
-#endif	/* WE_RTNETLINK_DEBUG */
-
 	/* Compute the max size of the get arguments */
 	extra_size = get_priv_size(descr->get_args);
 
@@ -1079,14 +893,8 @@ static inline int rtnetlink_private_get(
 	}
 
 	/* Check if wrqu is complete */
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
+	if(request_len < hdr_len)
 		return -EINVAL;
-	}
 
 	/* Prepare the call */
 	info.cmd = cmd;
@@ -1117,11 +925,6 @@ static inline int rtnetlink_private_get(
 		/* Buffer for full reply */
 		buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
 
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
-		       dev->name, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
-
 		/* Create the kernel buffer that we will return */
 		buffer = kmalloc(buffer_size, GFP_KERNEL);
 		if (buffer == NULL) {
@@ -1153,10 +956,6 @@ static inline int rtnetlink_private_get(
 		/* Put the iwe header where it should, i.e. scrap the
 		 * dummy pointer. */
 		memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
-#endif	/* WE_RTNETLINK_DEBUG */
 	}
 
 	/* Return the buffer to the caller */
@@ -1214,13 +1013,6 @@ static inline int rtnetlink_private_set(
 	if(descr == NULL)
 		return -EOPNOTSUPP;
 
-#ifdef WE_RTNETLINK_DEBUG
-	printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
-	       ifr->ifr_name, cmd);
-	printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
-	       dev->name, descr->name, descr->set_args, descr->get_args);
-#endif	/* WE_RTNETLINK_DEBUG */
-
 	/* Compute the size of the set arguments */
 	/* Check for sub-ioctl handler */
 	if(descr->name[0] == '\0')
@@ -1243,14 +1035,8 @@ static inline int rtnetlink_private_set(
 	wrqu = &request->u;
 
 	/* Check if wrqu is complete */
-	if(request_len < hdr_len) {
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG
-		       "%s (WE.r) : Wireless request too short (%d)\n",
-		       dev->name, request_len);
-#endif	/* WE_RTNETLINK_DEBUG */
+	if(request_len < hdr_len)
 		return -EINVAL;
-	}
 
 	/* Prepare the call */
 	info.cmd = cmd;
@@ -1278,18 +1064,8 @@ static inline int rtnetlink_private_set(
 		extra_len = adjust_priv_size(descr->set_args, &wrqu_point);
 
 		/* Check if request is self consistent */
-		if((request_len - hdr_len) < extra_len) {
-#ifdef WE_RTNETLINK_DEBUG
-			printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
-			       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
+		if((request_len - hdr_len) < extra_len)
 			return -EINVAL;
-		}
-
-#ifdef WE_RTNETLINK_DEBUG
-		printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
-		       dev->name, extra_size);
-#endif	/* WE_RTNETLINK_DEBUG */
 
 		/* Always allocate for max space. Easier, and won't last
 		 * long... */
@@ -1330,18 +1106,12 @@ int wireless_rtnetlink_get(struct net_de
 	iw_handler		handler;
 
 	/* Check length */
-	if(len < IW_EV_LCP_LEN) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
-		       dev->name, len);
+	if(len < IW_EV_LCP_LEN)
 		return -EINVAL;
-	}
 
 	/* ReCheck length (len may have padding) */
-	if(request->len > len) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
-		       dev->name, request->len, len);
+	if(request->len > len)
 		return -EINVAL;
-	}
 
 	/* Only accept GET requests in here */
 	if(!IW_IS_GET(request->cmd))
@@ -1414,18 +1184,12 @@ int wireless_rtnetlink_set(struct net_de
 	iw_handler		handler;
 
 	/* Check length */
-	if(len < IW_EV_LCP_LEN) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
-		       dev->name, len);
+	if(len < IW_EV_LCP_LEN)
 		return -EINVAL;
-	}
 
 	/* ReCheck length (len may have padding) */
-	if(request->len > len) {
-		printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
-		       dev->name, request->len, len);
+	if(request->len > len)
 		return -EINVAL;
-	}
 
 	/* Only accept SET requests in here */
 	if(!IW_IS_SET(request->cmd))
@@ -1521,19 +1285,6 @@ int iw_handler_set_spy(struct net_device
 		/* Reset stats */
 		memset(spydata->spy_stat, 0,
 		       sizeof(struct iw_quality) * IW_MAX_SPY);
-
-#ifdef WE_SPY_DEBUG
-		printk(KERN_DEBUG "iw_handler_set_spy() :  wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length);
-		for (i = 0; i < wrqu->data.length; i++)
-			printk(KERN_DEBUG
-			       "%02X:%02X:%02X:%02X:%02X:%02X \n",
-			       spydata->spy_address[i][0],
-			       spydata->spy_address[i][1],
-			       spydata->spy_address[i][2],
-			       spydata->spy_address[i][3],
-			       spydata->spy_address[i][4],
-			       spydata->spy_address[i][5]);
-#endif	/* WE_SPY_DEBUG */
 	}
 
 	/* Make sure above is updated before re-enabling */
@@ -1544,6 +1295,7 @@ int iw_handler_set_spy(struct net_device
 
 	return 0;
 }
+EXPORT_SYMBOL(iw_handler_set_spy);
 
 /*------------------------------------------------------------------*/
 /*
@@ -1579,6 +1331,7 @@ int iw_handler_get_spy(struct net_device
 		spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
 	return 0;
 }
+EXPORT_SYMBOL(iw_handler_get_spy);
 
 /*------------------------------------------------------------------*/
 /*
@@ -1603,12 +1356,9 @@ int iw_handler_set_thrspy(struct net_dev
 	/* Clear flag */
 	memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
 
-#ifdef WE_SPY_DEBUG
-	printk(KERN_DEBUG "iw_handler_set_thrspy() :  low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
-#endif	/* WE_SPY_DEBUG */
-
 	return 0;
 }
+EXPORT_SYMBOL(iw_handler_set_thrspy);
 
 /*------------------------------------------------------------------*/
 /*
@@ -1632,6 +1382,7 @@ int iw_handler_get_thrspy(struct net_dev
 
 	return 0;
 }
+EXPORT_SYMBOL(iw_handler_get_thrspy);
 
 /*------------------------------------------------------------------*/
 /*
@@ -1657,16 +1408,6 @@ static void iw_send_thrspy_event(struct 
 	memcpy(&(threshold.low), &(spydata->spy_thr_low),
 	       2 * sizeof(struct iw_quality));
 
-#ifdef WE_SPY_DEBUG
-	printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
-	       threshold.addr.sa_data[0],
-	       threshold.addr.sa_data[1],
-	       threshold.addr.sa_data[2],
-	       threshold.addr.sa_data[3],
-	       threshold.addr.sa_data[4],
-	       threshold.addr.sa_data[5], threshold.qual.level);
-#endif	/* WE_SPY_DEBUG */
-
 	/* Send event to user space */
 	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
 }
@@ -1690,10 +1431,6 @@ void wireless_spy_update(struct net_devi
 	if(!spydata)
 		return;
 
-#ifdef WE_SPY_DEBUG
-	printk(KERN_DEBUG "wireless_spy_update() :  wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
-#endif	/* WE_SPY_DEBUG */
-
 	/* Update all records that match */
 	for(i = 0; i < spydata->spy_number; i++)
 		if(!compare_ether_addr(address, spydata->spy_address[i])) {
@@ -1722,9 +1459,4 @@ void wireless_spy_update(struct net_devi
 		}
 	}
 }
-
-EXPORT_SYMBOL(iw_handler_get_spy);
-EXPORT_SYMBOL(iw_handler_get_thrspy);
-EXPORT_SYMBOL(iw_handler_set_spy);
-EXPORT_SYMBOL(iw_handler_set_thrspy);
 EXPORT_SYMBOL(wireless_spy_update);

--


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/4] cfg80211
  2007-02-09 16:27 [PATCH 0/4] cfg80211 johannes
                   ` (2 preceding siblings ...)
  2007-02-09 16:27 ` [PATCH 4/4] wext: clean up johannes
@ 2007-02-09 16:33 ` Johannes Berg
  3 siblings, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2007-02-09 16:33 UTC (permalink / raw)
  To: linux-wireless; +Cc: John Linville

[-- Attachment #1: Type: text/plain, Size: 109 bytes --]

2/4 was dropped, the whole thing is here:

http://johannes.sipsolutions.net/patches/cfg80211/

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/4] create cfg80211
  2007-02-09 16:27 ` [PATCH 1/4] create cfg80211 johannes
@ 2007-02-11 19:39   ` Johannes Berg
  2007-02-12  8:12     ` Johannes Berg
  0 siblings, 1 reply; 9+ messages in thread
From: Johannes Berg @ 2007-02-11 19:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: John Linville

[-- Attachment #1: Type: text/plain, Size: 964 bytes --]

On Fri, 2007-02-09 at 17:27 +0100, johannes@sipsolutions.net wrote:

This

> +void wiphy_free(struct wiphy *wiphy)
> +{
> +	if (wiphy->wiphy_index != -1)
> +		wiphy_sysfs_del(wiphy);
> +	else
> +		cfg80211_drv_free(wiphy_to_drv(wiphy));
> +}

and this

> +static void wiphy_class_dev_release(struct class_device *cdev)
> +{
> +	struct cfg80211_registered_driver *drv = cdev_to_drv(cdev);
> +
> +	cfg80211_drv_free(drv);
> +}

needs to be changed. wiphy_free() should wait for
wiphy_class_dev_release (to make sure sysfs is gone) before freeing the
structure (if it has ever been added to sysfs).

I'll respin both patchsets tomorrow. Until then, should you want to test
it and not just review the code, please just comment out the
cfg80211_drv_free(drv) in wiphy_class_dev_release, that'll give you a
memory leak though, but I have to leave and can't write the code
handling it with a completion etc. in under a minute ;)

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/4] create cfg80211
  2007-02-11 19:39   ` Johannes Berg
@ 2007-02-12  8:12     ` Johannes Berg
  2007-02-13  0:15       ` Michael Buesch
  0 siblings, 1 reply; 9+ messages in thread
From: Johannes Berg @ 2007-02-12  8:12 UTC (permalink / raw)
  To: linux-wireless; +Cc: Michael Buesch, Broadcom Linux

[-- Attachment #1: Type: text/plain, Size: 3888 bytes --]

On Sun, 2007-02-11 at 20:39 +0100, Johannes Berg wrote:
> On Fri, 2007-02-09 at 17:27 +0100, johannes@sipsolutions.net wrote:

> [...]
> needs to be changed. wiphy_free() should wait for
> wiphy_class_dev_release (to make sure sysfs is gone) before freeing the
> structure (if it has ever been added to sysfs).

On second thought, no, that's perfectly correct. There's a slight bug
however in the registration, it must not set wiphy_index when sysfs
registration fails.

The real bug I'm chasing (use-after-free leading to oops when rmmod'ing
bcm43xx-d80211 while device is up) is in bcm43xx-d80211 and I found it
too. Consider the following changes I made to debug:

diff --git a/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
index 9f4d51d..5205859 100644
--- a/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
@@ -1479,6 +1479,8 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id)
 	if (!dev)
 		return IRQ_NONE;
 
+	printk(KERN_INFO "bcm43xx_interrupt_handler\n");
+
 	spin_lock(&dev->wl->irq_lock);
 
 	assert(bcm43xx_status(dev) == BCM43xx_STAT_INITIALIZED);
@@ -3453,7 +3455,8 @@ static void bcm43xx_one_core_detach(struct ssb_device *dev)
 	list_del(&wldev->list);
 	wl->nr_devs--;
 	ssb_set_drvdata(dev, NULL);
-	kfree(wldev);
+	printk(KERN_INFO "kfree(wldev)\n");
+//	kfree(wldev);
 }
 
 static int bcm43xx_one_core_attach(struct ssb_device *dev,
@@ -3535,8 +3538,10 @@ static void bcm43xx_wireless_exit(struct ssb_device *dev,
 {
 	struct ieee80211_hw *hw = wl->hw;
 
+	printk(KERN_INFO "bcm43xx_wireless_exit(): unregister_hw()\n");
 	ieee80211_unregister_hw(hw);
 	ssb_set_devtypedata(dev, NULL);
+	printk(KERN_INFO "bcm43xx_wireless_exit(): free_hw()\n");
 	ieee80211_free_hw(hw);
 }
 

Now remember the oops I got which was a use-after-free in the interrupt handler.

Now also consider this message log I got when inserting bcm43xx,
scanning (I removed some interrupt messages), and then removing the
module again:

[ 1443.269289] wlan0: starting scan
[ 1443.316409] bcm43xx_interrupt_handler
...
[ 1444.016378] bcm43xx_interrupt_handler
[ 1444.053623] wlan0: scan completed
[ 1445.317311] kfree(wldev)
[ 1445.317931] bcm43xx_wireless_exit(): unregister_hw()
[ 1445.385872] bcm43xx_d80211: Wireless interface stopped
[ 1445.386554] bcm43xx_d80211: Removing Interface type 2
[ 1445.387219] bcm43xx_d80211: DMA-32 0x0200 (RX) max used slots: 0/64
[ 1445.389551] bcm43xx_d80211: DMA-32 0x02A0 (TX) max used slots: 0/128
[ 1445.390609] bcm43xx_d80211: DMA-32 0x0280 (TX) max used slots: 0/128
[ 1445.391678] bcm43xx_d80211: DMA-32 0x0260 (TX) max used slots: 0/128
[ 1445.392756] bcm43xx_d80211: DMA-32 0x0240 (TX) max used slots: 0/128
[ 1445.393821] bcm43xx_d80211: DMA-32 0x0220 (TX) max used slots: 2/128
[ 1445.394869] bcm43xx_d80211: DMA-32 0x0200 (TX) max used slots: 0/128
[ 1445.395924] bcm43xx_d80211: Radio turned off
[ 1445.516479] bcm43xx_wireless_exit(): free_hw()
[ 1445.517144] wiphy_free()
[ 1445.518029] PM: Removing info for ssb:ssb04:04
[ 1445.518164] PM: Removing info for ssb:ssb04:03
[ 1445.518284] PM: Removing info for ssb:ssb04:02
[ 1445.518405] PM: Removing info for ssb:ssb04:01
[ 1445.518597] PM: Removing info for ssb:ssb04:00


Now let's also take a look at the code that prints "Wireless interface
stopped". That function is bcm43xx_wireless_core_stop(), which is passed
a struct bcm43xx_wldev, precisely the one that two lines before was
passed to that kfree()...

So what happens is that sometimes a whole bunch of things in
bcm43xx_wireless_core_stop will not work properly due to the
use-after-free we have here. Unless you have slab debugging disabled
(like me) where of course it fails every time...

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/4] create cfg80211
  2007-02-12  8:12     ` Johannes Berg
@ 2007-02-13  0:15       ` Michael Buesch
  0 siblings, 0 replies; 9+ messages in thread
From: Michael Buesch @ 2007-02-13  0:15 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Broadcom Linux

On Monday 12 February 2007 09:12, Johannes Berg wrote:
> The real bug I'm chasing (use-after-free leading to oops when rmmod'ing
> bcm43xx-d80211 while device is up) is in bcm43xx-d80211 and I found it
> too. Consider the following changes I made to debug:

Should be fixed in my tree now.
Thanks for the good bugreport.

-- 
Greetings Michael.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/4] cfg80211: wext compat code
  2007-02-09 16:27 ` [PATCH 3/4] cfg80211: wext compat code johannes
@ 2007-02-13 15:42   ` Johannes Berg
  0 siblings, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2007-02-13 15:42 UTC (permalink / raw)
  To: linux-wireless; +Cc: John Linville

[-- Attachment #1: Type: text/plain, Size: 904 bytes --]

On Fri, 2007-02-09 at 17:27 +0100, johannes@sipsolutions.net wrote:

> +#ifdef CONFIG_CFG80211_WEXT_COMPAT
> +	rtnl_lock();
> +	ret = call_cfg80211_wext_ioctl(ifr, cmd);
> +	rtnl_unlock();

No need to take the rtnl here if we change the compat code slightly.

> +static struct cfg80211_config *cfg80211_ensure_pending_cfg(
> +	struct cfg80211_registered_driver *drv)
> +{
> +	struct cfg80211_config *cfg = drv->wext_pending_config;
> +	if (!cfg)
> +		cfg = kmalloc(sizeof(*cfg)+32, GFP_KERNEL);
> +	if (cfg) {
> +		cfg->ssid = (char*)cfg + sizeof(*cfg);
> +		drv->wext_pending_config = cfg;

This is a problem. It means that every driver can only have a single
interface that is configurable via wext, or if you try multiple ones
we'll run into a lot of trouble. The solution is to implement a list of
pending configs that each have a netdev pointer in them. Bit icky.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 190 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2007-02-13 16:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-09 16:27 [PATCH 0/4] cfg80211 johannes
2007-02-09 16:27 ` [PATCH 1/4] create cfg80211 johannes
2007-02-11 19:39   ` Johannes Berg
2007-02-12  8:12     ` Johannes Berg
2007-02-13  0:15       ` Michael Buesch
2007-02-09 16:27 ` [PATCH 3/4] cfg80211: wext compat code johannes
2007-02-13 15:42   ` Johannes Berg
2007-02-09 16:27 ` [PATCH 4/4] wext: clean up johannes
2007-02-09 16:33 ` [PATCH 0/4] cfg80211 Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.