aboutsummaryrefslogtreecommitdiffstats
path: root/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff
diff options
context:
space:
mode:
Diffstat (limited to 'linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff')
-rw-r--r--linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff838
1 files changed, 838 insertions, 0 deletions
diff --git a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff
index e69de29bb2..539b160068 100644
--- a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff
+++ b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff
@@ -0,0 +1,838 @@
+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 ;-) */
+ }