diff options
Diffstat (limited to 'linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff')
-rw-r--r-- | linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff | 1513 |
1 files changed, 1513 insertions, 0 deletions
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff index e69de29bb2..a27a7654a9 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff @@ -0,0 +1,1513 @@ +diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h +--- linux/include/linux-w12/netdevice.h Thu Nov 22 11:47:09 2001 ++++ linux/include/linux/netdevice.h Thu Jan 17 12:00:39 2002 +@@ -278,6 +278,10 @@ struct net_device + struct net_device_stats* (*get_stats)(struct net_device *dev); + struct iw_statistics* (*get_wireless_stats)(struct net_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 -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w12/wireless.h Thu Nov 22 11:47:12 2001 ++++ linux/include/linux/wireless.h Thu Jan 17 12:04:08 2002 +@@ -1,9 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 12 5.10.01 ++ * Version : 13 6.12.01 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 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,27 @@ + * 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 (2001 -> 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 ++ * ++ * 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 +68,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 12 ++#define WIRELESS_EXT 13 + + /* + * Changes : +@@ -123,12 +135,20 @@ + * - 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 + */ + ++/**************************** CONSTANTS ****************************/ ++ + /* -------------------------- IOCTL LIST -------------------------- */ + + /* Basic operations */ +-#define SIOCSIWNAME 0x8B00 /* Unused */ ++#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 */ +@@ -414,13 +434,49 @@ struct iw_statistics + + /* ------------------------ 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 sockaddr ap_addr; /* Access point address */ ++ ++ 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 + { +@@ -429,35 +485,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_param retry; /* Retry limits & lifetime */ +- +- 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 -------------------------- */ +diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w12/iw_handler.h Wed Dec 31 16:00:00 1969 ++++ linux/include/net/iw_handler.h Thu Jan 17 12:16:46 2002 +@@ -0,0 +1,374 @@ ++/* ++ * This file define the new driver API for Wireless Extensions ++ * ++ * Version : 2 6.12.01 ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 2001 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 net_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 (2001 -> 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 net_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 net_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 2 ++ ++/**************************** 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_POINT 6 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ ++#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++ ++/* 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 */ ++/* 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 net_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 net_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 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 ++ * 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); ++ ++/* 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 */ ++/* None yet */ ++ ++#endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile +--- linux/net/core-w12/Makefile Tue Oct 30 15:08:12 2001 ++++ linux/net/core/Makefile Thu Jan 17 11:06:07 2002 +@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d + obj-$(CONFIG_NETFILTER) += netfilter.o + obj-$(CONFIG_NET_DIVERT) += dv.o + obj-$(CONFIG_NET_PROFILE) += profile.o ++obj-$(CONFIG_NET_RADIO) += wireless.o ++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless ++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o + + include $(TOPDIR)/Rules.make +diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c +--- linux/net/core-w12/dev.c Wed Nov 7 14:39:36 2001 ++++ linux/net/core/dev.c Thu Jan 17 11:06:07 2002 +@@ -102,6 +102,7 @@ + #include <linux/module.h> + #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) + #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ ++#include <net/iw_handler.h> + #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + #ifdef CONFIG_PLIP + extern int plip_init(void); +@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, + #endif /* CONFIG_PROC_FS */ + + +-#ifdef WIRELESS_EXT +-#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 net_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 %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.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) +- * This is a clone of /proc/net/dev (just above) +- */ +-static int dev_get_wireless_info(char * buffer, char **start, off_t offset, +- int length) +-{ +- int len = 0; +- off_t begin = 0; +- off_t pos = 0; +- int size; +- +- struct net_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; +- +- read_lock(&dev_base_lock); +- 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; +- } +- read_unlock(&dev_base_lock); +- +- *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 */ +- +-/* +- * Allow programatic access to /proc/net/wireless even if /proc +- * doesn't exist... Also more efficient... +- */ +-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- +- 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; +-} +-#endif /* WIRELESS_EXT */ +- + /** + * netdev_set_master - set up master/slave pair + * @slave: slave device +@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr, + notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + return 0; + +-#ifdef WIRELESS_EXT +- case SIOCGIWSTATS: +- return dev_iwstats(dev, ifr); +-#endif /* WIRELESS_EXT */ +- + /* + * Unknown or private ioctl + */ +@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr, + return -EOPNOTSUPP; + } + +-#ifdef WIRELESS_EXT +- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { +- if (dev->do_ioctl) { +- if (!netif_device_present(dev)) +- return -ENODEV; +- return dev->do_ioctl(dev, ifr, cmd); +- } +- return -EOPNOTSUPP; +- } +-#endif /* WIRELESS_EXT */ +- + } + return -EINVAL; + } +@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar + } + dev_load(ifr.ifr_name); + rtnl_lock(); +- ret = dev_ifsioc(&ifr, cmd); ++ /* 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))) +@@ -2856,6 +2726,7 @@ int __init net_dev_init(void) + proc_net_create("dev", 0, dev_get_info); + create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL); + #ifdef WIRELESS_EXT ++ /* Available in net/core/wireless.c */ + proc_net_create("wireless", 0, dev_get_wireless_info); + #endif /* WIRELESS_EXT */ + #endif /* CONFIG_PROC_FS */ +diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c +--- linux/net/core-w12/wireless.c Wed Dec 31 16:00:00 1969 ++++ linux/net/core/wireless.c Mon Jan 21 11:13:23 2002 +@@ -0,0 +1,733 @@ ++/* ++ * This file implement the Wireless Extensions APIs. ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 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 ++ */ ++ ++/***************************** 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/wireless.h> /* Pretty obvious */ ++#include <net/iw_handler.h> /* New driver API */ ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* This will be turned on later on... */ ++#undef WE_STRICT_WRITE /* Check write buffer size */ ++ ++/* Debuging stuff */ ++#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++ ++/************************* GLOBAL VARIABLES *************************/ ++/* ++ * You should not use global variables, because or re-entrancy. ++ * On our case, it's only const, so it's OK... ++ */ ++static const struct iw_ioctl_description standard_ioctl[] = { ++ /* SIOCSIWCOMMIT (internal) */ ++ { 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_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}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* SIOCGIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 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, 4, 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}, ++}; ++ ++/* Size (in bytes) of the various private data types */ ++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/************************ 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 net_device *dev, ++ unsigned int cmd) ++{ ++ 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 net_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 net_device' ++ * to 'struct iw_handler_def', to de-bloat struct net_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 net_device * dev) ++{ ++ if((netif_running(dev)) && ++ (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 net_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 ? '.' : ' ', ++ stats->qual.level, ++ stats->qual.updated & 2 ? '.' : ' ', ++ 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 len = 0; ++ off_t begin = 0; ++ off_t pos = 0; ++ int size; ++ ++ struct net_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; ++ ++ read_lock(&dev_base_lock); ++ 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; ++ } ++ read_unlock(&dev_base_lock); ++ ++ *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 net_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 net_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 < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ 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 net_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; ++ ++ /* Get the description of the IOCTL */ ++ descr = &(standard_ioctl[cmd - SIOCIWFIRST]); ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : 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); ++#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); ++ } 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; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < descr->max_tokens) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", ++ 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 "Got %d bytes\n", ++ 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)) { ++ 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 "Wrote %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#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); ++ ++ /* 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 net_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 : 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); ++ } ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Compute the size of the set/get arguments */ ++ if(descr != NULL) { ++ if(IW_IS_SET(cmd)) { ++ /* 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 < 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 "Malloc %d bytes\n", 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 "Got %d elem\n", 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 "Wrote %d elem\n", ++ 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 net_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_by_name(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 */ ++ /* Basic check */ ++ if (!netif_device_present(dev)) ++ return -ENODEV; ++ /* 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; ++} |