diff options
Diffstat (limited to 'linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff')
-rw-r--r-- | linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff | 1513 |
1 files changed, 0 insertions, 1513 deletions
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff deleted file mode 100644 index a27a7654a9..0000000000 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff +++ /dev/null @@ -1,1513 +0,0 @@ -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; -+} |