diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h
--- linux/include/linux-w13/rtnetlink.h	Thu Jun  6 14:44:08 2002
+++ linux/include/linux/rtnetlink.h	Thu Jun  6 15:47:44 2002
@@ -440,12 +440,14 @@ enum
 #define IFLA_COST IFLA_COST
 	IFLA_PRIORITY,
 #define IFLA_PRIORITY IFLA_PRIORITY
-	IFLA_MASTER
+	IFLA_MASTER,
 #define IFLA_MASTER IFLA_MASTER
+	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
 };
 
 
-#define IFLA_MAX IFLA_MASTER
+#define IFLA_MAX IFLA_WIRELESS
 
 #define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
 #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h
--- linux/include/linux-w13/wireless.h	Thu Jun  6 15:00:28 2002
+++ linux/include/linux/wireless.h	Thu Jun  6 15:47:44 2002
@@ -1,10 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	13	6.12.01
+ * Version :	14	25.1.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
@@ -40,7 +40,7 @@
  *	# include/linux/netdevice.h (one place)
  *	# include/linux/proc_fs.h (one place)
  *
- * New driver API (2001 -> onward) :
+ * 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 :
@@ -49,6 +49,11 @@
  * 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
@@ -75,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	13
+#define WIRELESS_EXT	14
 
 /*
  * Changes :
@@ -141,6 +146,13 @@
  *	- 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)
  */
 
 /**************************** CONSTANTS ****************************/
@@ -175,6 +187,8 @@
 #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 SIOCSIWSCAN	0x8B18		/* trigger scanning */
+#define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
 #define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
@@ -238,6 +252,15 @@
 #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 */
+
+#define IWEVFIRST	0x8C00
+
 /* ------------------------- PRIVATE INFO ------------------------- */
 /*
  * The following is used with SIOCGIWPRIV. It allow a driver to define
@@ -340,6 +363,19 @@
 #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 */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -466,9 +502,12 @@ union	iwreq_data
 
 	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 */
 };
 
@@ -595,5 +634,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 -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h
--- linux/include/net-w13/iw_handler.h	Thu Jun  6 15:06:16 2002
+++ linux/include/net/iw_handler.h	Thu Jun  6 15:48:06 2002
@@ -1,10 +1,10 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	2	6.12.01
+ * Version :	3	17.1.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _IW_HANDLER_H
@@ -33,7 +33,7 @@
  *	o The user space interface is tied to ioctl because of the use
  *	  copy_to/from_user.
  *
- * New driver API (2001 -> onward) :
+ * 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
@@ -206,7 +206,18 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	2
+#define IW_HANDLER_VERSION	3
+
+/*
+ * 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
+ */
 
 /**************************** CONSTANTS ****************************/
 
@@ -225,6 +236,7 @@
 #define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
 #define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
 #define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
+#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
 
 /* Handling flags */
 /* Most are not implemented. I just use them as a reminder of some
@@ -233,7 +245,8 @@
 /* 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 */
+#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 */
 
@@ -303,25 +316,6 @@ struct iw_handler_def
 	 * 'struct net_device' to here, to minimise bloat. */
 };
 
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/*
- * Currently we don't support events, so let's just plan for the
- * future...
- */
-
-/*
- * A Wireless Event.
- */
-// How do we define short header ? We don't want a flag on length.
-// Probably a flag on event ? Highest bit to zero...
-struct iw_event
-{
-	__u16		length;			/* Lenght of this stuff */
-	__u16		event;			/* Wireless IOCTL */
-	union	iwreq_data	header;		/* IOCTL fixed payload */
-	char		extra[0];		/* Optional IOCTL data */
-};
-
 /* ---------------------- IOCTL DESCRIPTION ---------------------- */
 /*
  * One of the main goal of the new interface is to deal entirely with
@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * 
 extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
 
 /* Second : functions that may be called by driver modules */
-/* None yet */
 
-#endif	/* _LINUX_WIRELESS_H */
+/* Send a single event to user space */
+extern void wireless_send_event(struct net_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 -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c
--- linux/net/netsyms-w13.c	Thu Jun  6 15:46:34 2002
+++ linux/net/netsyms.c	Thu Jun  6 15:47:44 2002
@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf);
 EXPORT_SYMBOL(net_call_rx_atomic);
 EXPORT_SYMBOL(softnet_data);
 
+#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+/* Don't include the whole header mess for a single function */
+extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra);
+EXPORT_SYMBOL(wireless_send_event);
+#endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+
 #endif  /* CONFIG_NET */
diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c
--- linux/net/core/wireless-w13.c	Thu Jun  6 15:46:45 2002
+++ linux/net/core/wireless.c	Thu Jun  6 15:48:06 2002
@@ -2,7 +2,7 @@
  * This file implement the Wireless Extensions APIs.
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
  *
  * (As all part of the Linux kernel, this file is GPL)
  */
@@ -25,6 +25,16 @@
  *	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.01 - Jean II
+ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
  */
 
 /***************************** INCLUDES *****************************/
@@ -33,6 +43,7 @@
 #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 */
@@ -44,14 +55,23 @@
 
 /* Debuging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
+
+/* Options */
+#define 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 (internal) */
+	/* SIOCSIWCOMMIT */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* SIOCGIWNAME */
 	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
@@ -99,18 +119,18 @@ static const struct iw_ioctl_description
 	{ 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},
-	/* -- hole -- */
-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
-	/* -- hole -- */
-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 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, IW_DESCR_FLAG_EVENT},
+	{ 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, IW_DESCR_FLAG_DUMP},
+	{ 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, 0},
+	{ 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, 0},
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
 	/* -- hole -- */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* -- hole -- */
@@ -136,7 +156,7 @@ static const struct iw_ioctl_description
 	/* SIOCGIWRETRY */
 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
 	/* SIOCSIWENCODE */
-	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+	{ 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 */
@@ -144,9 +164,38 @@ static const struct iw_ioctl_description
 	/* 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},
+};
+static const int standard_event_num = (sizeof(standard_event) /
+				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+
+/* Size (in bytes) of various events */
+static const int event_type_size[] = {
+	IW_EV_LCP_LEN,
+	0,
+	IW_EV_CHAR_LEN,
+	0,
+	IW_EV_UINT_LEN,
+	IW_EV_FREQ_LEN,
+	IW_EV_POINT_LEN,		/* Without variable payload */
+	IW_EV_PARAM_LEN,
+	IW_EV_ADDR_LEN,
+	IW_EV_QUAL_LEN,
+};
 
 /************************ COMMON SUBROUTINES ************************/
 /*
@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4,
 static inline iw_handler get_handler(struct net_device *dev,
 				     unsigned int cmd)
 {
-	unsigned int	index;		/* MUST be unsigned */
+	/* 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)
@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats
 			       stats->status,
 			       stats->qual.qual,
 			       stats->qual.updated & 1 ? '.' : ' ',
-			       stats->qual.level,
+			       ((__u8) stats->qual.level),
 			       stats->qual.updated & 2 ? '.' : ' ',
-			       stats->qual.noise,
+			       ((__u8) stats->qual.noise),
 			       stats->qual.updated & 4 ? '.' : ' ',
 			       stats->discard.nwid,
 			       stats->discard.code,
@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st
 	int					ret = -EINVAL;
 
 	/* 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 : Found standard handler for 0x%04X\n",
+	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
 	       ifr->ifr_name, cmd);
-	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+	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 */
@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st
 
 	/* 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;
@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st
 		}
 
 #ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "Malloc %d bytes\n",
-		       descr->max_tokens * descr->token_size);
+		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
@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st
 				return -EFAULT;
 			}
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Got %d bytes\n",
+			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
+			       dev->name,
 			       iwr->u.data.length * descr->token_size);
 #endif	/* WE_IOCTL_DEBUG */
 		}
@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st
 			if (err)
 				ret =  -EFAULT;				   
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Wrote %d bytes\n",
+			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);
 	}
@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str
 		}
 
 #ifdef WE_IOCTL_DEBUG
-	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
+	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
 	       ifr->ifr_name, cmd);
 	if(descr) {
-		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
-		       descr->name, descr->set_args, descr->get_args);
+		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 */
 
@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str
 		}
 
 #ifdef WE_IOCTL_DEBUG
-		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
+		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
@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str
 				return -EFAULT;
 			}
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
+			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
+			       dev->name, iwr->u.data.length);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str
 			if (err)
 				ret =  -EFAULT;				   
 #ifdef WE_IOCTL_DEBUG
-			printk(KERN_DEBUG "Wrote %d elem\n",
-			       iwr->u.data.length);
+			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
+			       dev->name, iwr->u.data.length);
 #endif	/* WE_IOCTL_DEBUG */
 		}
 
@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq 
 	}
 	/* 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 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_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 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_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 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 */
+	/* 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 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 ;-) */
 }