diff -u -p --new-file linux/include/linux.w10/netdevice.h linux/include/linux/netdevice.h
--- linux/include/linux.w10/netdevice.h	Mon Apr 14 13:53:05 2003
+++ linux/include/linux/netdevice.h	Mon Apr 14 17:53:35 2003
@@ -226,6 +226,10 @@ struct device
 	struct net_device_stats* (*get_stats)(struct device *dev);
 	struct iw_statistics*	(*get_wireless_stats)(struct device *dev);
 
+	/* List of functions to handle Wireless Extensions (instead of ioctl).
+	 * See <net/iw_handler.h> for details. Jean II */
+	struct iw_handler_def *	wireless_handlers;
+
 	/*
 	 * This marks the end of the "visible" part of the structure. All
 	 * fields hereafter are internal to the system, and may change at
diff -u -p --new-file linux/include/linux.w10/wireless.h linux/include/linux/wireless.h
--- linux/include/linux.w10/wireless.h	Mon Apr 14 13:53:12 2003
+++ linux/include/linux/wireless.h	Mon Apr 14 17:51:58 2003
@@ -1,9 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	9	16.10.99
+ * Version :	15	12.7.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
@@ -11,6 +12,8 @@
 
 /************************** DOCUMENTATION **************************/
 /*
+ * Initial APIs (1996 -> onward) :
+ * -----------------------------
  * Basically, the wireless extensions are for now a set of standard ioctl
  * call + /proc/net/wireless
  *
@@ -27,16 +30,32 @@
  * We have the list of command plus a structure descibing the
  * data exchanged...
  * Note that to add these ioctl, I was obliged to modify :
- *	net/core/dev.c (two place + add include)
- *	net/ipv4/af_inet.c (one place + add include)
+ *	# net/core/dev.c (two place + add include)
+ *	# net/ipv4/af_inet.c (one place + add include)
  *
  * /proc/net/wireless is a copy of /proc/net/dev.
  * We have a structure for data passed from the driver to /proc/net/wireless
  * Too add this, I've modified :
- *	net/core/dev.c (two other places)
- *	include/linux/netdevice.h (one place)
- *	include/linux/proc_fs.h (one place)
+ *	# net/core/dev.c (two other places)
+ *	# include/linux/netdevice.h (one place)
+ *	# include/linux/proc_fs.h (one place)
+ *
+ * New driver API (2002 -> onward) :
+ * -------------------------------
+ * This file is only concerned with the user space API and common definitions.
+ * The new driver API is defined and documented in :
+ *	# include/net/iw_handler.h
+ *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+ *	# include/linux/wireless.c
+ *
+ * Wireless Events (2002 -> onward) :
+ * --------------------------------
+ * Events are defined at the end of this file, and implemented in :
+ *	# include/linux/wireless.c
  *
+ * Other comments :
+ * --------------
  * Do not add here things that are redundant with other mechanisms
  * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
  * wireless specific.
@@ -54,16 +73,14 @@
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
 #include <linux/if.h>			/* for IFNAMSIZ and co... */
 
-/**************************** CONSTANTS ****************************/
-
-/* --------------------------- VERSION --------------------------- */
+/***************************** VERSION *****************************/
 /*
  * This constant is used to know the availability of the wireless
  * extensions and to know which version of wireless extensions it is
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	10
+#define WIRELESS_EXT	15
 
 /*
  * Changes :
@@ -111,15 +128,57 @@
  *	- Add PM modifier : MAX/MIN/RELATIVE
  *	- Add encoding option : IW_ENCODE_NOKEY
  *	- Add TxPower ioctls (work like TxRate)
+ *
+ * V10 to V11
+ * ----------
+ *	- Add WE version in range (help backward/forward compatibility)
+ *	- Add retry ioctls (work like PM)
+ *
+ * V11 to V12
+ * ----------
+ *	- Add SIOCSIWSTATS to get /proc/net/wireless programatically
+ *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
+ *	- Add new statistics (frag, retry, beacon)
+ *	- Add average quality (for user space calibration)
+ *
+ * V12 to V13
+ * ----------
+ *	- Document creation of new driver API.
+ *	- Extract union iwreq_data from struct iwreq (for new driver API).
+ *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
+ *
+ * V13 to V14
+ * ----------
+ *	- Wireless Events support : define struct iw_event
+ *	- Define additional specific event numbers
+ *	- Add "addr" and "param" fields in union iwreq_data
+ *	- AP scanning stuff (SIOCSIWSCAN and friends)
+ *
+ * V14 to V15
+ * ----------
+ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
+ *	- Make struct iw_freq signed (both m & e), add explicit padding
+ *	- Add IWEVCUSTOM for driver specific event/scanning token
+ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
+ *	- Add IW_TXPOW_RANGE for range of Tx Powers
+ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ *	- Add IW_MODE_MONITOR for passive monitor
  */
 
+/**************************** CONSTANTS ****************************/
+
 /* -------------------------- IOCTL LIST -------------------------- */
 
-/* Basic operations */
-#define SIOCSIWNAME	0x8B00		/* Unused */
+/* Wireless Identification */
+#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
 #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
-#define SIOCGIWNWID	0x8B03		/* get network id */
+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
+ * Don't put the name of your driver there, it's useless. */
+
+/* Basic operations */
+#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
+#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
 #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
 #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
 #define SIOCSIWMODE	0x8B06		/* set operation mode */
@@ -132,15 +191,21 @@
 #define SIOCGIWRANGE	0x8B0B		/* Get range of parameters */
 #define SIOCSIWPRIV	0x8B0C		/* Unused */
 #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
+#define SIOCSIWSTATS	0x8B0E		/* Unused */
+#define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
+ * is never passed to the driver (i.e. the driver will never see it). */
 
-/* Mobile IP support */
+/* Mobile IP support (statistics per MAC address) */
 #define SIOCSIWSPY	0x8B10		/* set spy addresses */
 #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
 
 /* Access Point manipulation */
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
 #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
+#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
+#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
+#define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
 #define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
@@ -149,11 +214,9 @@
 #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
 /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
  * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE...
- * The "flags" member indicate if the ESSID is active or not (promiscuous).
- */
+ * point to a string in user space, like it is done for RANGE... */
 
-/* Other parameters usefull in 802.11 and some other devices */
+/* Other parameters useful in 802.11 and some other devices */
 #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
 #define SIOCGIWRATE	0x8B21		/* get default bit rate (bps) */
 #define SIOCSIWRTS	0x8B22		/* set RTS/CTS threshold (bytes) */
@@ -162,6 +225,8 @@
 #define SIOCGIWFRAG	0x8B25		/* get fragmentation thr (bytes) */
 #define SIOCSIWTXPOW	0x8B26		/* set transmit power (dBm) */
 #define SIOCGIWTXPOW	0x8B27		/* get transmit power (dBm) */
+#define SIOCSIWRETRY	0x8B28		/* set retry limits and lifetime */
+#define SIOCGIWRETRY	0x8B29		/* get retry limits and lifetime */
 
 /* Encoding stuff (scrambling, hardware security, WEP...) */
 #define SIOCSIWENCODE	0x8B2A		/* set encoding token & mode */
@@ -170,21 +235,55 @@
 #define SIOCSIWPOWER	0x8B2C		/* set Power Management settings */
 #define SIOCGIWPOWER	0x8B2D		/* get Power Management settings */
 
+/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
+
+/* These 16 ioctl are wireless device private.
+ * Each driver is free to use them for whatever purpose it chooses,
+ * however the driver *must* export the description of those ioctls
+ * with SIOCGIWPRIV and *must* use arguments as defined below.
+ * If you don't follow those rules, DaveM is going to hate you (reason :
+ * it make mixed 32/64bit operation impossible).
+ */
+#define SIOCIWFIRSTPRIV	0x8BE0
+#define SIOCIWLASTPRIV	0x8BFF
+/* Previously, we were using SIOCDEVPRIVATE, but we now have our
+ * separate range because of collisions with other tools such as
+ * 'mii-tool'.
+ * We now have 32 commands, so a bit more space ;-).
+ * Also, all 'odd' commands are only usable by root and don't return the
+ * content of ifr/iwr to user (but you are not obliged to use the set/get
+ * convention, just use every other two command).
+ * And I repeat : you are not obliged to use them with iwspy, but you
+ * must be compliant with it.
+ */
+
 /* ------------------------- IOCTL STUFF ------------------------- */
 
 /* The first and the last (range) */
 #define SIOCIWFIRST	0x8B00
-#define SIOCIWLAST	0x8B30
+#define SIOCIWLAST	SIOCIWLASTPRIV		/* 0x8BFF */
 
 /* Even : get (world access), odd : set (root access) */
 #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
 #define IW_IS_GET(cmd)	((cmd) & 0x1)
 
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/* Those are *NOT* ioctls, do not issue request on them !!! */
+/* Most events use the same identifier as ioctl requests */
+
+#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
+#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
+#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
+#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
+#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
+
+#define IWEVFIRST	0x8C00
+
 /* ------------------------- PRIVATE INFO ------------------------- */
 /*
  * The following is used with SIOCGIWPRIV. It allow a driver to define
  * the interface (name, type of data) for its private ioctl.
- * Privates ioctl are SIOCDEVPRIVATE -> SIOCDEVPRIVATE + 0xF
+ * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
  */
 
 #define IW_PRIV_TYPE_MASK	0x7000	/* Type of arguments */
@@ -192,9 +291,10 @@
 #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
 #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
 #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000
+#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
+#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
 
-#define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
+#define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed number of args */
 
 #define IW_PRIV_SIZE_MASK	0x07FF	/* Max number of those args */
 
@@ -216,9 +316,12 @@
 
 /* Maximum tx powers in the range struct */
 #define IW_MAX_TXPOWER		8
+/* Note : if you more than 8 TXPowers, just set the max and min or
+ * a few of them in the struct iw_range. */
 
 /* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
+#define IW_MAX_SPY		8	/* set */
+#define IW_MAX_GET_SPY		64	/* get */
 
 /* Maximum of address that you may get in the
    list of access points in range */
@@ -234,6 +337,7 @@
 #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
 #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
 #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
+#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
 
 /* Maximum number of size of encoding token available
  * they are listed in the range structure */
@@ -269,8 +373,36 @@
 #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
 
 /* Transmit Power flags available */
+#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
 #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
 #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
+#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
+
+/* Retry limits and lifetime flags available */
+#define IW_RETRY_ON		0x0000	/* No details... */
+#define IW_RETRY_TYPE		0xF000	/* Type of parameter */
+#define IW_RETRY_LIMIT		0x1000	/* Maximum number of retries*/
+#define IW_RETRY_LIFETIME	0x2000	/* Maximum duration of retries in us */
+#define IW_RETRY_MODIFIER	0x000F	/* Modify a parameter */
+#define IW_RETRY_MIN		0x0001	/* Value is a minimum  */
+#define IW_RETRY_MAX		0x0002	/* Value is a maximum */
+#define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+
+/* Scanning request flags */
+#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
+#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
+#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
+#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
+#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
+#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
+#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
+#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
+#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
+/* Maximum size of returned data */
+#define IW_SCAN_MAX_DATA	4096	/* In bytes */
+
+/* Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX		256	/* In bytes */
 
 /****************************** TYPES ******************************/
 
@@ -288,7 +420,7 @@ struct	iw_param
 
 /*
  *	For all data larger than 16 octets, we need to use a
- *	pointer to memory alocated in user space.
+ *	pointer to memory allocated in user space.
  */
 struct	iw_point
 {
@@ -307,9 +439,10 @@ struct	iw_point
  */
 struct	iw_freq
 {
-	__u32		m;		/* Mantissa */
-	__u16		e;		/* Exponent */
+	__s32		m;		/* Mantissa */
+	__s16		e;		/* Exponent */
 	__u8		i;		/* List index (when in range struct) */
+	__u8		pad;		/* Unused - just for alignement */
 };
 
 /*
@@ -317,23 +450,38 @@ struct	iw_freq
  */
 struct	iw_quality
 {
-	__u8		qual;		/* link quality (%retries, SNR or better...) */
-	__u8		level;		/* signal level */
-	__u8		noise;		/* noise level */
+	__u8		qual;		/* link quality (%retries, SNR,
+					   %missed beacons or better...) */
+	__u8		level;		/* signal level (dBm) */
+	__u8		noise;		/* noise level (dBm) */
 	__u8		updated;	/* Flags to know if updated */
 };
 
 /*
  *	Packet discarded in the wireless adapter due to
  *	"wireless" specific problems...
+ *	Note : the list of counter and statistics in net_device_stats
+ *	is already pretty exhaustive, and you should use that first.
+ *	This is only additional stats...
  */
 struct	iw_discarded
 {
-	__u32		nwid;		/* Wrong nwid */
-	__u32		code;		/* Unable to code/decode */
+	__u32		nwid;		/* Rx : Wrong nwid/essid */
+	__u32		code;		/* Rx : Unable to code/decode (WEP) */
+	__u32		fragment;	/* Rx : Can't perform MAC reassembly */
+	__u32		retries;	/* Tx : Max MAC retries num reached */
 	__u32		misc;		/* Others cases */
 };
 
+/*
+ *	Packet/Time period missed in the wireless adapter due to
+ *	"wireless" specific problems...
+ */
+struct	iw_missed
+{
+	__u32		beacon;		/* Missed beacons/superframe */
+};
+
 /* ------------------------ WIRELESS STATS ------------------------ */
 /*
  * Wireless statistics (used for /proc/net/wireless)
@@ -346,17 +494,57 @@ struct	iw_statistics
 	struct iw_quality	qual;		/* Quality of the link
 						 * (instant/mean/max) */
 	struct iw_discarded	discard;	/* Packet discarded counts */
+	struct iw_missed	miss;		/* Packet missed counts */
 };
 
 /* ------------------------ IOCTL REQUEST ------------------------ */
 /*
+ * This structure defines the payload of an ioctl, and is used 
+ * below.
+ *
+ * Note that this structure should fit on the memory footprint
+ * of iwreq (which is the same as ifreq), which mean a max size of
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * You should check this when increasing the structures defined
+ * above in this file...
+ */
+union	iwreq_data
+{
+	/* Config - generic */
+	char		name[IFNAMSIZ];
+	/* Name : used to verify the presence of  wireless extensions.
+	 * Name of the protocol/provider... */
+
+	struct iw_point	essid;		/* Extended network name */
+	struct iw_param	nwid;		/* network id (or domain - the cell) */
+	struct iw_freq	freq;		/* frequency or channel :
+					 * 0-1000 = channel
+					 * > 1000 = frequency in Hz */
+
+	struct iw_param	sens;		/* signal level threshold */
+	struct iw_param	bitrate;	/* default bit rate */
+	struct iw_param	txpower;	/* default transmit power */
+	struct iw_param	rts;		/* RTS threshold threshold */
+	struct iw_param	frag;		/* Fragmentation threshold */
+	__u32		mode;		/* Operation mode */
+	struct iw_param	retry;		/* Retry limits & lifetime */
+
+	struct iw_point	encoding;	/* Encoding stuff : tokens */
+	struct iw_param	power;		/* PM duration/timeout */
+	struct iw_quality qual;		/* Quality part of statistics */
+
+	struct sockaddr	ap_addr;	/* Access point address */
+	struct sockaddr	addr;		/* Destination address (hw) */
+
+	struct iw_param	param;		/* Other small parameters */
+	struct iw_point	data;		/* Other large parameters */
+};
+
+/*
  * The structure to exchange data for ioctl.
  * This structure is the same as 'struct ifreq', but (re)defined for
  * convenience...
- *
- * Note that it should fit on the same memory footprint !
- * You should check this when increasing the above structures (16 octets)
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * Do I need to remind you about structure size (32 octets) ?
  */
 struct	iwreq 
 {
@@ -365,34 +553,8 @@ struct	iwreq 
 		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
 	} ifr_ifrn;
 
-	/* Data part */
-	union
-	{
-		/* Config - generic */
-		char		name[IFNAMSIZ];
-		/* Name : used to verify the presence of  wireless extensions.
-		 * Name of the protocol/provider... */
-
-		struct iw_point	essid;	/* Extended network name */
-		struct iw_param	nwid;	/* network id (or domain - the cell) */
-		struct iw_freq	freq;	/* frequency or channel :
-					 * 0-1000 = channel
-					 * > 1000 = frequency in Hz */
-
-		struct iw_param	sens;		/* signal level threshold */
-		struct iw_param	bitrate;	/* default bit rate */
-		struct iw_param	txpower;	/* default transmit power */
-		struct iw_param	rts;		/* RTS threshold threshold */
-		struct iw_param	frag;		/* Fragmentation threshold */
-		__u32		mode;		/* Operation mode */
-
-		struct iw_point	encoding;	/* Encoding stuff : tokens */
-		struct iw_param	power;		/* PM duration/timeout */
-
-		struct sockaddr	ap_addr;	/* Access point address */
-
-		struct iw_point	data;		/* Other large parameters */
-	}	u;
+	/* Data part (defined just above) */
+	union	iwreq_data	u;
 };
 
 /* -------------------------- IOCTL DATA -------------------------- */
@@ -462,6 +624,32 @@ struct	iw_range
 	__u16		txpower_capa;	/* What options are supported */
 	__u8		num_txpower;	/* Number of entries in the list */
 	__s32		txpower[IW_MAX_TXPOWER];	/* list, in bps */
+
+	/* Wireless Extension version info */
+	__u8		we_version_compiled;	/* Must be WIRELESS_EXT */
+	__u8		we_version_source;	/* Last update of source */
+
+	/* Retry limits and lifetime */
+	__u16		retry_capa;	/* What retry options are supported */
+	__u16		retry_flags;	/* How to decode max/min retry limit */
+	__u16		r_time_flags;	/* How to decode max/min retry life */
+	__s32		min_retry;	/* Minimal number of retries */
+	__s32		max_retry;	/* Maximal number of retries */
+	__s32		min_r_time;	/* Minimal retry lifetime */
+	__s32		max_r_time;	/* Maximal retry lifetime */
+
+	/* Average quality of link & SNR */
+	struct iw_quality	avg_qual;	/* Quality of the link */
+	/* This should contain the average/typical values of the quality
+	 * indicator. This should be the threshold between a "good" and
+	 * a "bad" link (example : monitor going from green to orange).
+	 * Currently, user space apps like quality monitors don't have any
+	 * way to calibrate the measurement. With this, they can split
+	 * the range between 0 and max_qual in different quality level
+	 * (using a geometric subdivision centered on the average).
+	 * I expect that people doing the user space apps will feedback
+	 * us on which value we need to put in each driver...
+	 */
 };
 
 /*
@@ -475,5 +663,36 @@ struct	iw_priv_args
 	__u16		get_args;	/* Type and number of args */
 	char		name[IFNAMSIZ];	/* Name of the extension */
 };
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Wireless events are carried through the rtnetlink socket to user
+ * space. They are encapsulated in the IFLA_WIRELESS field of
+ * a RTM_NEWLINK message.
+ */
+
+/*
+ * A Wireless Event. Contains basically the same data as the ioctl...
+ */
+struct iw_event
+{
+	__u16		len;			/* Real lenght of this stuff */
+	__u16		cmd;			/* Wireless IOCTL */
+	union iwreq_data	u;		/* IOCTL fixed payload */
+};
+
+/* Size of the Event prefix (including padding and alignement junk) */
+#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
+/* Size of the various events */
+#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
+#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
+#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
+#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point))
+#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
+#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
+#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
+
+/* Note : in the case of iw_point, the extra data will come at the
+ * end of the event */
 
 #endif	/* _LINUX_WIRELESS_H */
diff -u -p --new-file linux/include/net.w10/iw_handler.h linux/include/net/iw_handler.h
--- linux/include/net.w10/iw_handler.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/iw_handler.h	Mon Apr 14 17:58:01 2003
@@ -0,0 +1,453 @@
+/*
+ * This file define the new driver API for Wireless Extensions
+ *
+ * Version :	4	21.6.02
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+ */
+
+#ifndef _IW_HANDLER_H
+#define _IW_HANDLER_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Initial driver API (1996 -> onward) :
+ * -----------------------------------
+ * The initial API just sends the IOCTL request received from user space
+ * to the driver (via the driver ioctl handler). The driver has to
+ * handle all the rest...
+ *
+ * The initial API also defines a specific handler in struct device
+ * to handle wireless statistics.
+ *
+ * The initial APIs served us well and has proven a reasonably good design.
+ * However, there is a few shortcommings :
+ *	o No events, everything is a request to the driver.
+ *	o Large ioctl function in driver with gigantic switch statement
+ *	  (i.e. spaghetti code).
+ *	o Driver has to mess up with copy_to/from_user, and in many cases
+ *	  does it unproperly. Common mistakes are :
+ *		* buffer overflows (no checks or off by one checks)
+ *		* call copy_to/from_user with irq disabled
+ *	o The user space interface is tied to ioctl because of the use
+ *	  copy_to/from_user.
+ *
+ * New driver API (2002 -> onward) :
+ * -------------------------------
+ * The new driver API is just a bunch of standard functions (handlers),
+ * each handling a specific Wireless Extension. The driver just export
+ * the list of handler it supports, and those will be called apropriately.
+ *
+ * I tried to keep the main advantage of the previous API (simplicity,
+ * efficiency and light weight), and also I provide a good dose of backward
+ * compatibility (most structures are the same, driver can use both API
+ * simultaneously, ...).
+ * Hopefully, I've also addressed the shortcomming of the initial API.
+ *
+ * The advantage of the new API are :
+ *	o Handling of Extensions in driver broken in small contained functions
+ *	o Tighter checks of ioctl before calling the driver
+ *	o Flexible commit strategy (at least, the start of it)
+ *	o Backward compatibility (can be mixed with old API)
+ *	o Driver doesn't have to worry about memory and user-space issues
+ * The last point is important for the following reasons :
+ *	o You are now able to call the new driver API from any API you
+ *		want (including from within other parts of the kernel).
+ *	o Common mistakes are avoided (buffer overflow, user space copy
+ *		with irq disabled and so on).
+ *
+ * The Drawback of the new API are :
+ *	o bloat (especially kernel)
+ *	o need to migrate existing drivers to new API
+ * My initial testing shows that the new API adds around 3kB to the kernel
+ * and save between 0 and 5kB from a typical driver.
+ * Also, as all structures and data types are unchanged, the migration is
+ * quite straightforward (but tedious).
+ *
+ * ---
+ *
+ * The new driver API is defined below in this file. User space should
+ * not be aware of what's happening down there...
+ *
+ * A new kernel wrapper is in charge of validating the IOCTLs and calling
+ * the appropriate driver handler. This is implemented in :
+ *	# net/core/wireless.c
+ *
+ * The driver export the list of handlers in :
+ *	# include/linux/netdevice.h (one place)
+ *
+ * The new driver API is available for WIRELESS_EXT >= 13.
+ * Good luck with migration to the new API ;-)
+ */
+
+/* ---------------------- THE IMPLEMENTATION ---------------------- */
+/*
+ * Some of the choice I've made are pretty controversials. Defining an
+ * API is very much weighting compromises. This goes into some of the
+ * details and the thinking behind the implementation.
+ *
+ * Implementation goals :
+ * --------------------
+ * The implementation goals were as follow :
+ *	o Obvious : you should not need a PhD to understand what's happening,
+ *		the benefit is easier maintainance.
+ *	o Flexible : it should accomodate a wide variety of driver
+ *		implementations and be as flexible as the old API.
+ *	o Lean : it should be efficient memory wise to minimise the impact
+ *		on kernel footprint.
+ *	o Transparent to user space : the large number of user space
+ *		applications that use Wireless Extensions should not need
+ *		any modifications.
+ *
+ * Array of functions versus Struct of functions
+ * ---------------------------------------------
+ * 1) Having an array of functions allow the kernel code to access the
+ * handler in a single lookup, which is much more efficient (think hash
+ * table here).
+ * 2) The only drawback is that driver writer may put their handler in
+ * the wrong slot. This is trivial to test (I set the frequency, the
+ * bitrate changes). Once the handler is in the proper slot, it will be
+ * there forever, because the array is only extended at the end.
+ * 3) Backward/forward compatibility : adding new handler just require
+ * extending the array, so you can put newer driver in older kernel
+ * without having to patch the kernel code (and vice versa).
+ *
+ * All handler are of the same generic type
+ * ----------------------------------------
+ * That's a feature !!!
+ * 1) Having a generic handler allow to have generic code, which is more
+ * efficient. If each of the handler was individually typed I would need
+ * to add a big switch in the kernel (== more bloat). This solution is
+ * more scalable, adding new Wireless Extensions doesn't add new code.
+ * 2) You can use the same handler in different slots of the array. For
+ * hardware, it may be more efficient or logical to handle multiple
+ * Wireless Extensions with a single function, and the API allow you to
+ * do that. (An example would be a single record on the card to control
+ * both bitrate and frequency, the handler would read the old record,
+ * modify it according to info->cmd and rewrite it).
+ *
+ * Functions prototype uses union iwreq_data
+ * -----------------------------------------
+ * Some would have prefered functions defined this way :
+ *	static int mydriver_ioctl_setrate(struct device *dev, 
+ *					  long rate, int auto)
+ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
+ * can't do it (different hardware may have different notion of what a
+ * valid frequency is), so we don't pretend that we do it.
+ * 2) The above form is not extendable. If I want to add a flag (for
+ * example to distinguish setting max rate and basic rate), I would
+ * break the prototype. Using iwreq_data is more flexible.
+ * 3) Also, the above form is not generic (see above).
+ * 4) I don't expect driver developper using the wrong field of the
+ * union (Doh !), so static typechecking doesn't add much value.
+ * 5) Lastly, you can skip the union by doing :
+ *	static int mydriver_ioctl_setrate(struct device *dev,
+ *					  struct iw_request_info *info,
+ *					  struct iw_param *rrq,
+ *					  char *extra)
+ * And then adding the handler in the array like this :
+ *        (iw_handler) mydriver_ioctl_setrate,             // SIOCSIWRATE
+ *
+ * Using functions and not a registry
+ * ----------------------------------
+ * Another implementation option would have been for every instance to
+ * define a registry (a struct containing all the Wireless Extensions)
+ * and only have a function to commit the registry to the hardware.
+ * 1) This approach can be emulated by the current code, but not
+ * vice versa.
+ * 2) Some drivers don't keep any configuration in the driver, for them
+ * adding such a registry would be a significant bloat.
+ * 3) The code to translate from Wireless Extension to native format is
+ * needed anyway, so it would not reduce significantely the amount of code.
+ * 4) The current approach only selectively translate Wireless Extensions
+ * to native format and only selectively set, whereas the registry approach
+ * would require to translate all WE and set all parameters for any single
+ * change.
+ * 5) For many Wireless Extensions, the GET operation return the current
+ * dynamic value, not the value that was set.
+ *
+ * This header is <net/iw_handler.h>
+ * ---------------------------------
+ * 1) This header is kernel space only and should not be exported to
+ * user space. Headers in "include/linux/" are exported, headers in
+ * "include/net/" are not.
+ *
+ * Mixed 32/64 bit issues
+ * ----------------------
+ * The Wireless Extensions are designed to be 64 bit clean, by using only
+ * datatypes with explicit storage size.
+ * There are some issues related to kernel and user space using different
+ * memory model, and in particular 64bit kernel with 32bit user space.
+ * The problem is related to struct iw_point, that contains a pointer
+ * that *may* need to be translated.
+ * This is quite messy. The new API doesn't solve this problem (it can't),
+ * but is a step in the right direction :
+ * 1) Meta data about each ioctl is easily available, so we know what type
+ * of translation is needed.
+ * 2) The move of data between kernel and user space is only done in a single
+ * place in the kernel, so adding specific hooks in there is possible.
+ * 3) In the long term, it allows to move away from using ioctl as the
+ * user space API.
+ *
+ * So many comments and so few code
+ * --------------------------------
+ * That's a feature. Comments won't bloat the resulting kernel binary.
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <linux/wireless.h>		/* IOCTL user space API */
+
+/***************************** VERSION *****************************/
+/*
+ * This constant is used to know which version of the driver API is
+ * available. Hopefully, this will be pretty stable and no changes
+ * will be needed...
+ * I just plan to increment with each new version.
+ */
+#define IW_HANDLER_VERSION	4
+
+/*
+ * Changes :
+ *
+ * V2 to V3
+ * --------
+ *	- Move event definition in <linux/wireless.h>
+ *	- Add Wireless Event support :
+ *		o wireless_send_event() prototype
+ *		o iwe_stream_add_event/point() inline functions
+ * V3 to V4
+ * --------
+ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ */
+
+/**************************** CONSTANTS ****************************/
+
+/* Special error message for the driver to indicate that we
+ * should do a commit after return from the iw_handler */
+#define EIWCOMMIT	EINPROGRESS
+
+/* Flags available in struct iw_request_info */
+#define IW_REQUEST_FLAG_NONE	0x0000	/* No flag so far */
+
+/* Type of headers we know about (basically union iwreq_data) */
+#define IW_HEADER_TYPE_NULL	0	/* Not available */
+#define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
+#define IW_HEADER_TYPE_UINT	4	/* __u32 */
+#define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
+#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
+#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
+#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
+
+/* Handling flags */
+/* Most are not implemented. I just use them as a reminder of some
+ * cool features we might need one day ;-) */
+#define IW_DESCR_FLAG_NONE	0x0000	/* Obvious */
+/* Wrapper level flags */
+#define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
+#define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
+#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
+				/* SET : Omit payload from generated iwevent */
+/* Driver level flags */
+#define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
+
+/****************************** TYPES ******************************/
+
+/* ----------------------- WIRELESS HANDLER ----------------------- */
+/*
+ * A wireless handler is just a standard function, that looks like the
+ * ioctl handler.
+ * We also define there how a handler list look like... As the Wireless
+ * Extension space is quite dense, we use a simple array, which is faster
+ * (that's the perfect hash table ;-).
+ */
+
+/*
+ * Meta data about the request passed to the iw_handler.
+ * Most handlers can safely ignore what's in there.
+ * The 'cmd' field might come handy if you want to use the same handler
+ * for multiple command...
+ * This struct is also my long term insurance. I can add new fields here
+ * without breaking the prototype of iw_handler...
+ */
+struct iw_request_info
+{
+	__u16		cmd;		/* Wireless Extension command */
+	__u16		flags;		/* More to come ;-) */
+};
+
+/*
+ * This is how a function handling a Wireless Extension should look
+ * like (both get and set, standard and private).
+ */
+typedef int (*iw_handler)(struct device *dev, struct iw_request_info *info,
+			  union iwreq_data *wrqu, char *extra);
+
+/*
+ * This define all the handler that the driver export.
+ * As you need only one per driver type, please use a static const
+ * shared by all driver instances... Same for the members...
+ * This will be linked from device in <linux/netdevice.h>
+ */
+struct iw_handler_def
+{
+	/* Number of handlers defined (more precisely, index of the
+	 * last defined handler + 1) */
+	__u16			num_standard;
+	__u16			num_private;
+	/* Number of private arg description */
+	__u16			num_private_args;
+
+	/* Array of handlers for standard ioctls
+	 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
+	 */
+	iw_handler *		standard;
+
+	/* Array of handlers for private ioctls
+	 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
+	 */
+	iw_handler *		private;
+
+	/* Arguments of private handler. This one is just a list, so you
+	 * can put it in any order you want and should not leave holes...
+	 * We will automatically export that to user space... */
+	struct iw_priv_args *	private_args;
+
+	/* In the long term, get_wireless_stats will move from
+	 * 'struct device' to here, to minimise bloat. */
+};
+
+/* ---------------------- IOCTL DESCRIPTION ---------------------- */
+/*
+ * One of the main goal of the new interface is to deal entirely with
+ * user space/kernel space memory move.
+ * For that, we need to know :
+ *	o if iwreq is a pointer or contain the full data
+ *	o what is the size of the data to copy
+ *
+ * For private IOCTLs, we use the same rules as used by iwpriv and
+ * defined in struct iw_priv_args.
+ *
+ * For standard IOCTLs, things are quite different and we need to
+ * use the stuctures below. Actually, this struct is also more
+ * efficient, but that's another story...
+ */
+
+/*
+ * Describe how a standard IOCTL looks like.
+ */
+struct iw_ioctl_description
+{
+	__u8	header_type;		/* NULL, iw_point or other */
+	__u8	token_type;		/* Future */
+	__u16	token_size;		/* Granularity of payload */
+	__u16	min_tokens;		/* Min acceptable token number */
+	__u16	max_tokens;		/* Max acceptable token number */
+	__u32	flags;			/* Special handling of the request */
+};
+
+/* Need to think of short header translation table. Later. */
+
+/**************************** PROTOTYPES ****************************/
+/*
+ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
+ * Those may be called only within the kernel.
+ */
+
+/* First : function strictly used inside the kernel */
+
+/* Handle /proc/net/wireless, called in net/code/dev.c */
+extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+				 int length, int dummy);
+
+/* Handle IOCTLs, called in net/code/dev.c */
+extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+
+/* Second : functions that may be called by driver modules */
+
+/* Send a single event to user space */
+extern void wireless_send_event(struct device *	dev,
+				unsigned int		cmd,
+				union iwreq_data *	wrqu,
+				char *			extra);
+
+/* We may need a function to send a stream of events to user space.
+ * More on that later... */
+
+/************************* INLINE FUNTIONS *************************/
+/*
+ * Function that are so simple that it's more efficient inlining them
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an Wireless Event to a stream of events.
+ */
+static inline char *
+iwe_stream_add_event(char *	stream,		/* Stream of events */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     int	event_len)	/* Real size of payload */
+{
+	/* Check if it's possible */
+	if((stream + event_len) < ends) {
+		iwe->len = event_len;
+		memcpy(stream, (char *) iwe, event_len);
+		stream += event_len;
+	}
+	return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add an short Wireless Event containing a pointer to a
+ * stream of events.
+ */
+static inline char *
+iwe_stream_add_point(char *	stream,		/* Stream of events */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     char *	extra)
+{
+	int	event_len = IW_EV_POINT_LEN + iwe->u.data.length;
+	/* Check if it's possible */
+	if((stream + event_len) < ends) {
+		iwe->len = event_len;
+		memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
+		memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
+		stream += event_len;
+	}
+	return stream;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper to add a value to a Wireless Event in a stream of events.
+ * Be careful, this one is tricky to use properly :
+ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
+ */
+static inline char *
+iwe_stream_add_value(char *	event,		/* Event in the stream */
+		     char *	value,		/* Value in event */
+		     char *	ends,		/* End of stream */
+		     struct iw_event *iwe,	/* Payload */
+		     int	event_len)	/* Real size of payload */
+{
+	/* Don't duplicate LCP */
+	event_len -= IW_EV_LCP_LEN;
+
+	/* Check if it's possible */
+	if((value + event_len) < ends) {
+		/* Add new value */
+		memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
+		value += event_len;
+		/* Patch LCP */
+		iwe->len = value - event;
+		memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
+	}
+	return value;
+}
+
+#endif	/* _IW_HANDLER_H */
diff -u -p --new-file linux/net/core.w10/Makefile linux/net/core/Makefile
--- linux/net/core.w10/Makefile	Sun Mar 25 08:31:11 2001
+++ linux/net/core/Makefile	Mon Apr 14 14:36:36 2003
@@ -39,6 +39,10 @@ ifdef CONFIG_NET_PROFILE
 OX_OBJS += profile.o
 endif
 
+ifdef CONFIG_NET_RADIO
+OX_OBJS += wireless.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 tar:
diff -u -p --new-file linux/net/core.w10/dev.c linux/net/core/dev.c
--- linux/net/core.w10/dev.c	Mon May 20 16:32:35 2002
+++ linux/net/core/dev.c	Mon Apr 14 14:45:41 2003
@@ -92,7 +92,8 @@
 #include <linux/init.h>
 #include <linux/kmod.h>
 #ifdef CONFIG_NET_RADIO
-#include <linux/wireless.h>
+#include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
+#include <net/iw_handler.h>
 #endif	/* CONFIG_NET_RADIO */
 #ifdef CONFIG_PLIP
 extern int plip_init(void);
@@ -1306,91 +1307,6 @@ static int dev_proc_stats(char *buffer, 
 #endif	/* CONFIG_PROC_FS */
 
 
-#ifdef CONFIG_NET_RADIO
-#ifdef CONFIG_PROC_FS
-
-/*
- * Print one entry of /proc/net/wireless
- * This is a clone of /proc/net/dev (just above)
- */
-static int sprintf_wireless_stats(char *buffer, struct device *dev)
-{
-	/* Get stats from the driver */
-	struct iw_statistics *stats = (dev->get_wireless_stats ?
-				       dev->get_wireless_stats(dev) :
-				       (struct iw_statistics *) NULL);
-	int size;
-
-	if(stats != (struct iw_statistics *) NULL)
-	{
-		size = sprintf(buffer,
-			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d\n",
-			       dev->name,
-			       stats->status,
-			       stats->qual.qual,
-			       stats->qual.updated & 1 ? '.' : ' ',
-			       stats->qual.level,
-			       stats->qual.updated & 2 ? '.' : ' ',
-			       stats->qual.noise,
-			       stats->qual.updated & 4 ? '.' : ' ',
-			       stats->discard.nwid,
-			       stats->discard.code,
-			       stats->discard.misc);
-		stats->qual.updated = 0;
-	}
-	else
-		size = 0;
-
-	return size;
-}
-
-/*
- * Print info for /proc/net/wireless (print all entries)
- * This is a clone of /proc/net/dev (just above)
- */
-int dev_get_wireless_info(char * buffer, char **start, off_t offset,
-			  int length, int dummy)
-{
-	int		len = 0;
-	off_t		begin = 0;
-	off_t		pos = 0;
-	int		size;
-	
-	struct device *	dev;
-
-	size = sprintf(buffer,
-		       "Inter-| sta-|   Quality        |   Discarded packets\n"
-		       " face | tus | link level noise |  nwid  crypt   misc\n"
-			);
-	
-	pos+=size;
-	len+=size;
-
-	for(dev = dev_base; dev != NULL; dev = dev->next) 
-	{
-		size = sprintf_wireless_stats(buffer+len, dev);
-		len+=size;
-		pos=begin+len;
-
-		if(pos < offset)
-		{
-			len=0;
-			begin=pos;
-		}
-		if(pos > offset + length)
-			break;
-	}
-
-	*start = buffer + (offset - begin);	/* Start of wanted data */
-	len -= (offset - begin);		/* Start slop */
-	if(len > length)
-		len = length;		/* Ending slop */
-
-	return len;
-}
-#endif	/* CONFIG_PROC_FS */
-#endif	/* CONFIG_NET_RADIO */
-
 void dev_set_promiscuity(struct device *dev, int inc)
 {
 	unsigned short old_flags = dev->flags;
@@ -1621,14 +1537,6 @@ static int dev_ifsioc(struct ifreq *ifr,
 				return -EOPNOTSUPP;
 			}
 
-#ifdef CONFIG_NET_RADIO
-			if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				if (dev->do_ioctl)
-					return dev->do_ioctl(dev, ifr, cmd);
-				return -EOPNOTSUPP;
-			}
-#endif	/* CONFIG_NET_RADIO */
-
 	}
 	return -EINVAL;
 }
@@ -1749,23 +1657,27 @@ int dev_ioctl(unsigned int cmd, void *ar
 					return -EFAULT;
 				return ret;
 			}
-#ifdef CONFIG_NET_RADIO
+#ifdef WIRELESS_EXT
+			/* Take care of Wireless Extensions */
 			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
-				dev_load(ifr.ifr_name);
-				if (IW_IS_SET(cmd)) {
-					if (!suser())
+				/* 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)) {
+					if(!capable(CAP_NET_ADMIN))
 						return -EPERM;
-					rtnl_lock();
 				}
-				ret = dev_ifsioc(&ifr, cmd);
-				if (IW_IS_SET(cmd))
-					rtnl_unlock();
+				dev_load(ifr.ifr_name);
+				rtnl_lock();
+				/* Follow me in net/core/wireless.c */
+				ret = wireless_process_ioctl(&ifr, cmd);
+				rtnl_unlock();
 				if (!ret && IW_IS_GET(cmd) &&
 				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
 					return -EFAULT;
 				return ret;
 			}
-#endif	/* CONFIG_NET_RADIO */
+#endif	/* WIRELESS_EXT */
 			return -EINVAL;
 	}
 }
@@ -1938,16 +1850,16 @@ static struct proc_dir_entry proc_net_de
 };
 #endif
 
-#ifdef CONFIG_NET_RADIO
+#ifdef WIRELESS_EXT
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_net_wireless = {
 	PROC_NET_WIRELESS, 8, "wireless",
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_net_inode_operations,
-	dev_get_wireless_info
+	dev_get_wireless_info		/* Available in net/core/wireless.c */
 };
 #endif	/* CONFIG_PROC_FS */
-#endif	/* CONFIG_NET_RADIO */
+#endif	/* WIRELESS_EXT */
 
 __initfunc(int net_dev_init(void))
 {
@@ -2072,11 +1984,11 @@ __initfunc(int net_dev_init(void))
 	}
 #endif
 
-#ifdef CONFIG_NET_RADIO
+#ifdef WIRELESS_EXT
 #ifdef CONFIG_PROC_FS
 	proc_net_register(&proc_net_wireless);
 #endif	/* CONFIG_PROC_FS */
-#endif	/* CONFIG_NET_RADIO */
+#endif	/* WIRELESS_EXT */
 
 	init_bh(NET_BH, net_bh);
 
diff -u -p --new-file linux/net/core.w10/wireless.c linux/net/core/wireless.c
--- linux/net/core.w10/wireless.c	Wed Dec 31 16:00:00 1969
+++ linux/net/core/wireless.c	Mon Apr 14 17:35:43 2003
@@ -0,0 +1,1027 @@
+/*
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (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)
+ *
+ * Kernel 2.2.25 backport :
+ *	o Disable RTnetLink support, which mean disable event support
+ *		-> IFLA_WIRELESS can't be safely added
+ *	o Disable WE_STRICT_WRITE for maximum backward compatibility
+ *		-> User space tools may be antiquated
+ *	o struct net_device => struct device
+ */
+
+/***************************** INCLUDES *****************************/
+
+#include <asm/uaccess.h>		/* copy_to_user() */
+#include <linux/config.h>		/* Not needed ??? */
+#include <linux/types.h>		/* off_t */
+#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
+#include <linux/rtnetlink.h>		/* rtnetlink stuff */
+
+#include <linux/wireless.h>		/* Pretty obvious */
+#include <net/iw_handler.h>		/* New driver API */
+
+/**************************** CONSTANTS ****************************/
+
+/* Maximise backward compatibility with user space tools */
+#undef WE_STRICT_WRITE		/* Check write buffer size */
+
+/* Debuging stuff */
+#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
+
+/* Options */
+#undef  WE_EVENT_NETLINK	/* Propagate events using rtnetlink */
+#define WE_SET_EVENT		/* Generate an event on some set commands */
+
+/************************* GLOBAL VARIABLES *************************/
+/*
+ * You should not use global variables, because or 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 */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWNAME */
+	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWNWID */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWNWID */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWFREQ */
+	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWFREQ */
+	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWMODE */
+	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWMODE */
+	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWSENS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWSENS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRANGE */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWRANGE */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWPRIV */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWPRIV (handled directly by us) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWSTATS */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWSTATS (handled directly by us) */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWSPY */
+	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
+	/* SIOCGIWSPY */
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWAP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* SIOCGIWAP */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCGIWAPLIST */
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
+	/* SIOCSIWSCAN */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWSCAN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
+	/* SIOCSIWESSID */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
+	/* SIOCGIWESSID */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
+	/* SIOCSIWNICKN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+	/* SIOCGIWNICKN */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* -- hole -- */
+	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+	/* SIOCSIWRATE */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRATE */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRTS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRTS */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWFRAG */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWFRAG */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWTXPOW */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWTXPOW */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWRETRY */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWRETRY */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCSIWENCODE */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+	/* SIOCGIWENCODE */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
+	/* SIOCSIWPOWER */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+	/* SIOCGIWPOWER */
+	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+};
+static const int 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 */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVQUAL */
+	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
+	/* IWEVCUSTOM */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
+	/* IWEVREGISTERED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVEXPIRED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+};
+static const int standard_event_num = (sizeof(standard_event) /
+				       sizeof(struct iw_ioctl_description));
+
+/* Size (in bytes) of the various private data types */
+static const char priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	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 ************************/
+/*
+ * Stuff that may be used in various place or doesn't fit in one
+ * of the section below.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Return the driver handler associated with a specific Wireless Extension.
+ * Called from various place, so make sure it remains efficient.
+ */
+static inline iw_handler get_handler(struct device *dev,
+				     unsigned int cmd)
+{
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned int	index;		/* *MUST* be unsigned */
+
+	/* Check if we have some wireless handlers defined */
+	if(dev->wireless_handlers == NULL)
+		return NULL;
+
+	/* Try as a standard command */
+	index = cmd - SIOCIWFIRST;
+	if(index < dev->wireless_handlers->num_standard)
+		return dev->wireless_handlers->standard[index];
+
+	/* Try as a private command */
+	index = cmd - SIOCIWFIRSTPRIV;
+	if(index < dev->wireless_handlers->num_private)
+		return dev->wireless_handlers->private[index];
+
+	/* Not found */
+	return NULL;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Get statistics out of the driver
+ */
+static inline struct iw_statistics *get_wireless_stats(struct device *dev)
+{
+	return (dev->get_wireless_stats ?
+		dev->get_wireless_stats(dev) :
+		(struct iw_statistics *) NULL);
+	/* In the future, get_wireless_stats may move from 'struct device'
+	 * to 'struct iw_handler_def', to de-bloat struct device.
+	 * Definitely worse a thought... */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
+ *
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
+ */
+static inline int call_commit_handler(struct device *	dev)
+{
+	if((dev->start) &&
+	   (dev->wireless_handlers->standard[0] != NULL)) {
+		/* Call the commit handler on the driver */
+		return dev->wireless_handlers->standard[0](dev, NULL,
+							   NULL, NULL);
+	} else
+		return 0;		/* Command completed successfully */
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Number of private arguments
+ */
+static inline int get_priv_size(__u16	args)
+{
+	int	num = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	return num * priv_type_size[type];
+}
+
+
+/******************** /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 int sprintf_wireless_stats(char *buffer, struct device *dev)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+	int size;
+
+	stats = get_wireless_stats(dev);
+	if (stats != (struct iw_statistics *) NULL) {
+		size = sprintf(buffer,
+			       "%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 & 1 ? '.' : ' ',
+			       ((__u8) stats->qual.level),
+			       stats->qual.updated & 2 ? '.' : ' ',
+			       ((__u8) stats->qual.noise),
+			       stats->qual.updated & 4 ? '.' : ' ',
+			       stats->discard.nwid,
+			       stats->discard.code,
+			       stats->discard.fragment,
+			       stats->discard.retries,
+			       stats->discard.misc,
+			       stats->miss.beacon);
+		stats->qual.updated = 0;
+	}
+	else
+		size = 0;
+
+	return size;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+			  int length, int dummy)
+{
+	int		len = 0;
+	off_t		begin = 0;
+	off_t		pos = 0;
+	int		size;
+	
+	struct device *	dev;
+
+	size = sprintf(buffer,
+		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
+		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
+			);
+	
+	pos += size;
+	len += size;
+
+	for (dev = dev_base; dev != NULL; dev = dev->next) {
+		size = sprintf_wireless_stats(buffer + len, dev);
+		len += size;
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+		if (pos > offset + length)
+			break;
+	}
+
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);		/* Start slop */
+	if (len > length)
+		len = length;			/* Ending slop */
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif	/* CONFIG_PROC_FS */
+
+/************************** IOCTL SUPPORT **************************/
+/*
+ * The original user space API to configure all those Wireless Extensions
+ * is through IOCTLs.
+ * In there, we check if we need to call the new driver API (iw_handler)
+ * or just call the driver ioctl handler.
+ */
+
+/* ---------------------------------------------------------------- */
+/*
+ *	Allow programatic access to /proc/net/wireless even if /proc
+ *	doesn't exist... Also more efficient...
+ */
+static inline int dev_iwstats(struct device *dev, struct ifreq *ifr)
+{
+	/* Get stats from the driver */
+	struct iw_statistics *stats;
+
+	stats = get_wireless_stats(dev);
+	if (stats != (struct iw_statistics *) NULL) {
+		struct iwreq *	wrq = (struct iwreq *)ifr;
+
+		/* Copy statistics to the user buffer */
+		if(copy_to_user(wrq->u.data.pointer, stats,
+				sizeof(struct iw_statistics)))
+			return -EFAULT;
+
+		/* Check if we need to clear the update flag */
+		if(wrq->u.data.flags != 0)
+			stats->qual.updated = 0;
+		return 0;
+	} else
+		return -EOPNOTSUPP;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Export the driver private handler definition
+ * They will be picked up by tools like iwpriv...
+ */
+static inline int ioctl_export_private(struct device *	dev,
+				       struct ifreq *		ifr)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+
+	/* Check if the driver has something to export */
+	if((dev->wireless_handlers->num_private_args == 0) ||
+	   (dev->wireless_handlers->private_args == NULL))
+		return -EOPNOTSUPP;
+
+	/* Check NULL pointer */
+	if(iwr->u.data.pointer == NULL)
+		return -EFAULT;
+#ifdef WE_STRICT_WRITE
+	/* Check if there is enough buffer up there */
+	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
+		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
+		return -E2BIG;
+	}
+#endif	/* WE_STRICT_WRITE */
+
+	/* Set the number of available ioctls. */
+	iwr->u.data.length = dev->wireless_handlers->num_private_args;
+
+	/* Copy structure to the user buffer. */
+	if (copy_to_user(iwr->u.data.pointer,
+			 dev->wireless_handlers->private_args,
+			 sizeof(struct iw_priv_args) * iwr->u.data.length))
+		return -EFAULT;
+
+	return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * 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 inline int ioctl_standard_call(struct device *	dev,
+				      struct ifreq *		ifr,
+				      unsigned int		cmd,
+				      iw_handler		handler)
+{
+	struct iwreq *				iwr = (struct iwreq *) ifr;
+	const struct iw_ioctl_description *	descr;
+	struct iw_request_info			info;
+	int					ret = -EINVAL;
+	int					user_size = 0;
+
+	/* Get the description of the IOCTL */
+	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+		return -EOPNOTSUPP;
+	descr = &(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;
+
+	/* 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(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	err;
+
+		/* 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_size = iwr->u.data.length;
+		}
+
+#ifdef WE_IOCTL_DEBUG
+		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
+		       dev->name, descr->max_tokens * descr->token_size);
+#endif	/* WE_IOCTL_DEBUG */
+
+		/* Always allocate for max space. Easier, and won't last
+		 * long... */
+		extra = kmalloc(descr->max_tokens * descr->token_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;
+			}
+#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 */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+#ifdef WE_STRICT_WRITE
+			/* Check if there is enough buffer up there */
+			if(user_size < iwr->u.data.length) {
+				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
+				kfree(extra);
+				return -E2BIG;
+			}
+#endif	/* WE_STRICT_WRITE */
+
+			err = copy_to_user(iwr->u.data.pointer, extra,
+					   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 */
+		}
+
+#ifdef WE_SET_EVENT
+		/* 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);
+		}
+#endif	/* WE_SET_EVENT */
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+	/* Call commit handler if needed and defined */
+	if(ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	/* Here, we will generate the appropriate event if needed */
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static inline int ioctl_private_call(struct device *	dev,
+				     struct ifreq *		ifr,
+				     unsigned int		cmd,
+				     iw_handler		handler)
+{
+	struct iwreq *			iwr = (struct iwreq *) ifr;
+	struct iw_priv_args *		descr = NULL;
+	struct iw_request_info		info;
+	int				extra_size = 0;
+	int				i;
+	int				ret = -EINVAL;
+
+	/* Get the description of the IOCTL */
+	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
+		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
+			descr = &(dev->wireless_handlers->private_args[i]);
+			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)) {
+			int	offset = 0;	/* For sub-ioctls */
+			/* Check for sub-ioctl handler */
+			if(descr->name[0] == '\0')
+				/* Reserve one int for sub-ioctl index */
+				offset = sizeof(__u32);
+
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->set_args);
+
+			/* Does it fits in iwr ? */
+			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+			   ((extra_size + offset) <= IFNAMSIZ))
+				extra_size = 0;
+		} else {
+			/* Size of set arguments */
+			extra_size = get_priv_size(descr->get_args);
+
+			/* Does it fits in iwr ? */
+			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+			   (extra_size <= IFNAMSIZ))
+				extra_size = 0;
+		}
+	}
+
+	/* Prepare the call */
+	info.cmd = cmd;
+	info.flags = 0;
+
+	/* Check if we have a pointer to user space data or not. */
+	if(extra_size == 0) {
+		/* No extra arguments. Trivial to handle */
+		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
+	} else {
+		char *	extra;
+		int	err;
+
+		/* 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;
+
+			/* Does it fits within bounds ? */
+			if(iwr->u.data.length > (descr->set_args &
+						 IW_PRIV_SIZE_MASK))
+				return -E2BIG;
+		} else {
+			/* Check NULL pointer */
+			if(iwr->u.data.pointer == NULL)
+				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);
+		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,
+					     extra_size);
+			if (err) {
+				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 */
+		ret = handler(dev, &info, &(iwr->u), extra);
+
+		/* If we have something to return to the user */
+		if (!ret && IW_IS_GET(cmd)) {
+			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 */
+		}
+
+		/* Cleanup - I told you it wasn't that long ;-) */
+		kfree(extra);
+	}
+
+
+	/* Call commit handler if needed and defined */
+	if(ret == -EIWCOMMIT)
+		ret = call_commit_handler(dev);
+
+	return ret;
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main IOCTl dispatcher. Called from the main networking code
+ * (dev_ioctl() in net/core/dev.c).
+ * Check the type of IOCTL and call the appropriate wrapper...
+ */
+int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
+{
+	struct device *dev;
+	iw_handler	handler;
+
+	/* 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(ifr->ifr_name)) == NULL)
+		return -ENODEV;
+
+	/* 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 dev_iwstats(dev, ifr);
+
+		case SIOCGIWPRIV:
+			/* Check if we have some wireless handlers defined */
+			if(dev->wireless_handlers != NULL) {
+				/* We export to user space the definition of
+				 * the private handler ourselves */
+				return ioctl_export_private(dev, ifr);
+			}
+			// ## Fall-through for old API ##
+		default:
+			/* Generic IOCTL */
+			/* New driver API : try to find the handler */
+			handler = get_handler(dev, cmd);
+			if(handler != NULL) {
+				/* Standard and private are not the same */
+				if(cmd < SIOCIWFIRSTPRIV)
+					return ioctl_standard_call(dev,
+								   ifr,
+								   cmd,
+								   handler);
+				else
+					return ioctl_private_call(dev,
+								  ifr,
+								  cmd,
+								  handler);
+			}
+			/* Old driver API : call driver ioctl handler */
+			if (dev->do_ioctl) {
+				return dev->do_ioctl(dev, ifr, cmd);
+			}
+			return -EOPNOTSUPP;
+	}
+	/* Not reached */
+	return -EINVAL;
+}
+
+/************************* EVENT PROCESSING *************************/
+/*
+ * Process events generated by the wireless layer or the driver.
+ * Most often, the event will be propagated through rtnetlink
+ */
+
+#ifdef WE_EVENT_NETLINK
+/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
+ * It is declared in <linux/rtnetlink.h> */
+
+/* ---------------------------------------------------------------- */
+/*
+ * 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 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_type = dev->type;
+	r->ifi_index = dev->ifindex;
+	r->ifi_flags = dev->flags;
+	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 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_groups = RTMGRP_LINK;
+	netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
+}
+#endif	/* WE_EVENT_NETLINK */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the apropriate channels.
+ * May be called from interrupt context.
+ */
+void wireless_send_event(struct 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 */
+	/* Don't "optimise" the following variable, it will crash */
+	unsigned	cmd_index;		/* *MUST* be unsigned */
+
+	/* Get the description of the IOCTL */
+	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;
+#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, event_len %d\n", dev->name, cmd, hdr_len, 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, wrqu, hdr_len - IW_EV_LCP_LEN);
+	if(extra != NULL)
+		memcpy(((char *) event) + hdr_len, extra, extra_len);
+
+#ifdef WE_EVENT_NETLINK
+	/* rtnetlink event channel */
+	rtmsg_iwinfo(dev, (char *) event, event_len);
+#endif	/* WE_EVENT_NETLINK */
+
+	/* Cleanup */
+	kfree(event);
+
+	return;		/* Always success, I guess ;-) */
+}
diff -u -p linux/net/netsyms.w10.c linux/net/netsyms.c
--- linux/net/netsyms.w10.c	Mon Apr 14 14:17:28 2003
+++ linux/net/netsyms.c	Mon Apr 14 15:16:43 2003
@@ -569,4 +569,9 @@ EXPORT_SYMBOL(unregister_tcf_proto_ops);
 
 EXPORT_SYMBOL(register_gifconf);
 
+#ifdef CONFIG_NET_RADIO
+#include <net/iw_handler.h>
+EXPORT_SYMBOL(wireless_send_event);
+#endif	/* CONFIG_NET_RADIO */
+
 #endif  /* CONFIG_NET */
diff -u -p linux/drivers/net/wavelan.w10.c linux/drivers/net/wavelan.c
--- linux/drivers/net/wavelan.w10.c	Mon Apr 14 14:23:36 2003
+++ linux/drivers/net/wavelan.c	Mon Apr 14 14:27:13 2003
@@ -2104,8 +2104,15 @@ wavelan_ioctl(struct device *	dev,	/* de
 	{
 	  struct iw_range	range;
 
-	  /* Set the length (useless:  it's constant). */
+	  /* Set the length (very important for backward compatibility) */
 	  wrq->u.data.length = sizeof(struct iw_range);
+
+	  /* Set all the info we don't care or don't know about to zero */
+	  memset(&range, 0, sizeof(range));
+
+	  /* Set the Wireless Extension versions */
+	  range.we_version_compiled = WIRELESS_EXT;
+	  range.we_version_source = 9;
 
 	  /* Set information in the range struct.  */
 	  range.throughput = 1.6 * 1000 * 1000;	/* don't argue on this ! */
