diff options
Diffstat (limited to 'linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff')
-rw-r--r-- | linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff | 838 |
1 files changed, 838 insertions, 0 deletions
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff index e69de29bb2..539b160068 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/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 ;-) */ + } |