summaryrefslogtreecommitdiff
path: root/packages/linux/files/iw249_we17-13.diff
diff options
context:
space:
mode:
authorKoen Kooi <koen@openembedded.org>2005-06-30 08:19:37 +0000
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>2005-06-30 08:19:37 +0000
commitc8e5702127e507e82e6f68a4b8c546803accea9d (patch)
tree00583491f40ecc640f2b28452af995e3a63a09d7 /packages/linux/files/iw249_we17-13.diff
parent87ec8ca4d2e2eb4d1c1e1e1a6b46a395d56805b9 (diff)
import clean BK tree at cset 1.3670
Diffstat (limited to 'packages/linux/files/iw249_we17-13.diff')
-rw-r--r--packages/linux/files/iw249_we17-13.diff768
1 files changed, 768 insertions, 0 deletions
diff --git a/packages/linux/files/iw249_we17-13.diff b/packages/linux/files/iw249_we17-13.diff
index e69de29bb2..674f4ffbc0 100644
--- a/packages/linux/files/iw249_we17-13.diff
+++ b/packages/linux/files/iw249_we17-13.diff
@@ -0,0 +1,768 @@
+diff -u -p linux/include/linux/netdevice.we16.h linux/include/linux/netdevice.h
+--- linux/include/linux/netdevice.we16.h 2005-02-03 14:54:56.000000000 -0800
++++ linux/include/linux/netdevice.h 2005-02-03 15:43:30.000000000 -0800
+@@ -295,7 +295,9 @@ struct net_device
+
+ /* 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;
++ const struct iw_handler_def * wireless_handlers;
++ /* Instance data managed by the core of Wireless Extensions. */
++ struct iw_public_data * wireless_data;
+
+ struct ethtool_ops *ethtool_ops;
+
+diff -u -p linux/include/linux/wireless.we16.h linux/include/linux/wireless.h
+--- linux/include/linux/wireless.we16.h 2005-02-03 14:55:04.000000000 -0800
++++ linux/include/linux/wireless.h 2005-02-03 15:44:48.000000000 -0800
+@@ -1,10 +1,10 @@
+ /*
+ * This file define a set of standard wireless extensions
+ *
+- * Version : 16 2.4.03
++ * Version : 17 21.6.04
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
+ */
+
+ #ifndef _LINUX_WIRELESS_H
+@@ -47,12 +47,12 @@
+ * # include/net/iw_handler.h
+ *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+- * # include/linux/wireless.c
++ * # net/core/wireless.c
+ *
+ * Wireless Events (2002 -> onward) :
+ * --------------------------------
+ * Events are defined at the end of this file, and implemented in :
+- * # include/linux/wireless.c
++ * # net/core/wireless.c
+ *
+ * Other comments :
+ * --------------
+@@ -82,7 +82,7 @@
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+-#define WIRELESS_EXT 16
++#define WIRELESS_EXT 17
+
+ /*
+ * Changes :
+@@ -175,6 +175,13 @@
+ * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
+ * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
+ * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
++ *
++ * V16 to V17
++ * ----------
++ * - Add flags to frequency -> auto/fixed
++ * - Document (struct iw_quality *)->updated, add new flags (INVALID)
++ * - Wireless Event capability in struct iw_range
++ * - Add support for relative TxPower (yick !)
+ */
+
+ /**************************** CONSTANTS ****************************/
+@@ -251,7 +258,7 @@
+
+ /* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
+
+-/* These 16 ioctl are wireless device private.
++/* These 32 ioctl are wireless device private, for 16 commands.
+ * Each driver is free to use them for whatever purpose it chooses,
+ * however the driver *must* export the description of those ioctls
+ * with SIOCGIWPRIV and *must* use arguments as defined below.
+@@ -266,8 +273,8 @@
+ * We now have 32 commands, so a bit more space ;-).
+ * Also, all 'odd' commands are only usable by root and don't return the
+ * content of ifr/iwr to user (but you are not obliged to use the set/get
+- * convention, just use every other two command).
+- * And I repeat : you are not obliged to use them with iwspy, but you
++ * convention, just use every other two command). More details in iwpriv.c.
++ * And I repeat : you are not forced to use them with iwpriv, but you
+ * must be compliant with it.
+ */
+
+@@ -352,6 +359,18 @@
+ #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
+ #define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
+
++/* Statistics flags (bitmask in updated) */
++#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */
++#define IW_QUAL_LEVEL_UPDATED 0x2
++#define IW_QUAL_NOISE_UPDATED 0x4
++#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
++#define IW_QUAL_LEVEL_INVALID 0x20
++#define IW_QUAL_NOISE_INVALID 0x40
++
++/* Frequency flags */
++#define IW_FREQ_AUTO 0x00 /* Let the driver decides */
++#define IW_FREQ_FIXED 0x01 /* Force a specific value */
++
+ /* Maximum number of size of encoding token available
+ * they are listed in the range structure */
+ #define IW_MAX_ENCODING_SIZES 8
+@@ -390,6 +409,7 @@
+ #define IW_TXPOW_TYPE 0x00FF /* Type of value */
+ #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
+ #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */
++#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */
+ #define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */
+
+ /* Retry limits and lifetime flags available */
+@@ -418,6 +438,25 @@
+ /* Max number of char in custom event - use multiple of them if needed */
+ #define IW_CUSTOM_MAX 256 /* In bytes */
+
++/* Event capability macros - in (struct iw_range *)->event_capa
++ * Because we have more than 32 possible events, we use an array of
++ * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
++#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \
++ (cmd - SIOCIWFIRSTPRIV + 0x60) : \
++ (cmd - SIOCSIWCOMMIT))
++#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5)
++#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
++/* Event capability constants - event autogenerated by the kernel
++ * This list is valid for most 802.11 devices, customise as needed... */
++#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \
++ IW_EVENT_CAPA_MASK(0x8B06) | \
++ IW_EVENT_CAPA_MASK(0x8B1A))
++#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A))
++/* "Easy" macro to set events in iw_range (less efficient) */
++#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
++#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
++
++
+ /****************************** TYPES ******************************/
+
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -456,7 +495,7 @@ struct iw_freq
+ __s32 m; /* Mantissa */
+ __s16 e; /* Exponent */
+ __u8 i; /* List index (when in range struct) */
+- __u8 pad; /* Unused - just for alignement */
++ __u8 flags; /* Flags (fixed/auto) */
+ };
+
+ /*
+@@ -610,11 +649,12 @@ struct iw_range
+ /* Old Frequency (backward compat - moved lower ) */
+ __u16 old_num_channels;
+ __u8 old_num_frequency;
+- /* Filler to keep "version" at the same offset */
+- __s32 old_freq[6];
++
++ /* Wireless event capability bitmasks */
++ __u32 event_capa[6];
+
+ /* signal level threshold range */
+- __s32 sensitivity;
++ __s32 sensitivity;
+
+ /* Quality of link & SNR stuff */
+ /* Quality range (link, level, noise)
+diff -u -p linux/include/net/iw_handler.we16.h linux/include/net/iw_handler.h
+--- linux/include/net/iw_handler.we16.h 2005-02-03 14:55:26.000000000 -0800
++++ linux/include/net/iw_handler.h 2005-02-03 15:47:04.000000000 -0800
+@@ -1,10 +1,10 @@
+ /*
+ * This file define the new driver API for Wireless Extensions
+ *
+- * Version : 5 4.12.02
++ * Version : 6 21.6.04
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
+ */
+
+ #ifndef _IW_HANDLER_H
+@@ -206,7 +206,7 @@
+ * will be needed...
+ * I just plan to increment with each new version.
+ */
+-#define IW_HANDLER_VERSION 5
++#define IW_HANDLER_VERSION 6
+
+ /*
+ * Changes :
+@@ -224,11 +224,18 @@
+ * V4 to V5
+ * --------
+ * - Add new spy support : struct iw_spy_data & prototypes
++ *
++ * V5 to V6
++ * --------
++ * - Change the way we get to spy_data method for added safety
++ * - Remove spy #ifdef, they are always on -> cleaner code
++ * - Add IW_DESCR_FLAG_NOMAX flag for very large requests
++ * - Start migrating get_wireless_stats to struct iw_handler_def
+ */
+
+ /**************************** CONSTANTS ****************************/
+
+-/* Enable enhanced spy support. Disable to reduce footprint */
++/* Enhanced spy support available */
+ #define IW_WIRELESS_SPY
+ #define IW_WIRELESS_THRSPY
+
+@@ -258,6 +265,7 @@
+ #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
+ #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
+ /* SET : Omit payload from generated iwevent */
++#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
+ /* Driver level flags */
+ #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
+
+@@ -311,23 +319,25 @@ struct iw_handler_def
+ /* Array of handlers for standard ioctls
+ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
+ */
+- iw_handler * standard;
++ const iw_handler * standard;
+
+ /* Array of handlers for private ioctls
+ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
+ */
+- iw_handler * private;
++ const 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;
++ const struct iw_priv_args * private_args;
+
+- /* Driver enhanced spy support */
+- long spy_offset; /* Spy data offset */
++ /* This field will be *removed* in the next version of WE */
++ long spy_offset; /* DO NOT USE */
+
+- /* In the long term, get_wireless_stats will move from
+- * 'struct net_device' to here, to minimise bloat. */
++ /* New location of get_wireless_stats, to de-bloat struct net_device.
++ * The old pointer in struct net_device will be gradually phased
++ * out, and drivers are encouraged to use this one... */
++ struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
+ };
+
+ /* ---------------------- IOCTL DESCRIPTION ---------------------- */
+@@ -374,18 +384,29 @@ struct iw_ioctl_description
+ */
+ struct iw_spy_data
+ {
+-#ifdef IW_WIRELESS_SPY
+ /* --- Standard spy support --- */
+ int spy_number;
+ u_char spy_address[IW_MAX_SPY][ETH_ALEN];
+ struct iw_quality spy_stat[IW_MAX_SPY];
+-#ifdef IW_WIRELESS_THRSPY
+ /* --- Enhanced spy support (event) */
+ struct iw_quality spy_thr_low; /* Low threshold */
+ struct iw_quality spy_thr_high; /* High threshold */
+ u_char spy_thr_under[IW_MAX_SPY];
+-#endif /* IW_WIRELESS_THRSPY */
+-#endif /* IW_WIRELESS_SPY */
++};
++
++/* --------------------- DEVICE WIRELESS DATA --------------------- */
++/*
++ * This is all the wireless data specific to a device instance that
++ * is managed by the core of Wireless Extensions.
++ * We only keep pointer to those structures, so that a driver is free
++ * to share them between instances.
++ * This structure should be initialised before registering the device.
++ * Access to this data follow the same rules as any other struct net_device
++ * data (i.e. valid as long as struct net_device exist, same locking rules).
++ */
++struct iw_public_data {
++ /* Driver enhanced spy support */
++ struct iw_spy_data * spy_data;
+ };
+
+ /**************************** PROTOTYPES ****************************/
+diff -u -p linux/net/core/dev.we16.c linux/net/core/dev.c
+--- linux/net/core/dev.we16.c 2005-02-03 14:55:56.000000000 -0800
++++ linux/net/core/dev.c 2005-02-03 15:28:48.000000000 -0800
+@@ -2426,7 +2426,7 @@ int dev_ioctl(unsigned int cmd, void *ar
+ /* Follow me in net/core/wireless.c */
+ ret = wireless_process_ioctl(&ifr, cmd);
+ rtnl_unlock();
+- if (!ret && IW_IS_GET(cmd) &&
++ if (IW_IS_GET(cmd) &&
+ copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+ return -EFAULT;
+ return ret;
+diff -u -p linux/net/core/wireless.we16.c linux/net/core/wireless.c
+--- linux/net/core/wireless.we16.c 2005-02-03 14:56:09.000000000 -0800
++++ linux/net/core/wireless.c 2005-02-03 16:33:22.000000000 -0800
+@@ -2,7 +2,7 @@
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+@@ -48,6 +48,16 @@
+ * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
+ * o Add enhanced spy support : iw_handler_set_thrspy() and event.
+ * o Add WIRELESS_EXT version display in /proc/net/wireless
++ *
++ * v6 - 18.06.04 - Jean II
++ * o Change get_spydata() method for added safety
++ * o Remove spy #ifdef, they are always on -> cleaner code
++ * o Allow any size GET request if user specifies length > max
++ * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
++ * o Start migrating get_wireless_stats to struct iw_handler_def
++ * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
++ * Based on patch from Pavel Roskin <proski@gnu.org> :
++ * o Fix kernel data leak to user space in private handler handling
+ */
+
+ /***************************** INCLUDES *****************************/
+@@ -64,11 +74,7 @@
+
+ /**************************** CONSTANTS ****************************/
+
+-/* Enough lenience, let's make sure things are proper... */
+-#define WE_STRICT_WRITE /* Check write buffer size */
+-/* I'll probably drop both the define and kernel message in the next version */
+-
+-/* Debuging stuff */
++/* Debugging stuff */
+ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
+ #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
+ #undef WE_SPY_DEBUG /* Debug enhanced spy support */
+@@ -134,11 +140,11 @@ static const struct iw_ioctl_description
+ /* -- 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},
++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, IW_DESCR_FLAG_NOMAX},
+ /* SIOCSIWSCAN */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWSCAN */
+- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, IW_DESCR_FLAG_NOMAX},
+ /* SIOCSIWESSID */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
+ /* SIOCGIWESSID */
+@@ -203,7 +209,7 @@ static const int standard_event_num = (s
+ sizeof(struct iw_ioctl_description));
+
+ /* Size (in bytes) of the various private data types */
+-static const char priv_type_size[] = {
++static const char iw_priv_type_size[] = {
+ 0, /* IW_PRIV_TYPE_NONE */
+ 1, /* IW_PRIV_TYPE_BYTE */
+ 1, /* IW_PRIV_TYPE_CHAR */
+@@ -270,12 +276,15 @@ static inline iw_handler get_handler(str
+ */
+ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
+ {
++ /* New location */
++ if((dev->wireless_handlers != NULL) &&
++ (dev->wireless_handlers->get_wireless_stats != NULL))
++ return dev->wireless_handlers->get_wireless_stats(dev);
++
++ /* Old location, will be phased out in next WE */
+ 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... */
+ }
+
+ /* ---------------------------------------------------------------- */
+@@ -310,14 +319,32 @@ static inline int call_commit_handler(st
+
+ /* ---------------------------------------------------------------- */
+ /*
+- * Number of private arguments
++ * Calculate size 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];
++ return num * iw_priv_type_size[type];
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Re-calculate the size of private arguments
++ */
++static inline int adjust_priv_size(__u16 args,
++ union iwreq_data * wrqu)
++{
++ int num = wrqu->data.length;
++ int max = args & IW_PRIV_SIZE_MASK;
++ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
++
++ /* Make sure the driver doesn't goof up */
++ if (max < num)
++ num = max;
++
++ return num * iw_priv_type_size[type];
+ }
+
+
+@@ -350,11 +377,14 @@ static inline int sprintf_wireless_stats
+ dev->name,
+ stats->status,
+ stats->qual.qual,
+- stats->qual.updated & 1 ? '.' : ' ',
++ stats->qual.updated & IW_QUAL_QUAL_UPDATED
++ ? '.' : ' ',
+ ((__u8) stats->qual.level),
+- stats->qual.updated & 2 ? '.' : ' ',
++ stats->qual.updated & IW_QUAL_LEVEL_UPDATED
++ ? '.' : ' ',
+ ((__u8) stats->qual.noise),
+- stats->qual.updated & 4 ? '.' : ' ',
++ stats->qual.updated & IW_QUAL_NOISE_UPDATED
++ ? '.' : ' ',
+ stats->discard.nwid,
+ stats->discard.code,
+ stats->discard.fragment,
+@@ -470,13 +500,15 @@ static inline int ioctl_export_private(s
+ /* 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 < dev->wireless_handlers->num_private_args) {
+- printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
++ /* User space can't know in advance how large the buffer
++ * needs to be. Give it a hint, so that we can support
++ * any size buffer we want somewhat efficiently... */
++ iwr->u.data.length = dev->wireless_handlers->num_private_args;
+ return -E2BIG;
+ }
+-#endif /* WE_STRICT_WRITE */
+
+ /* Set the number of available ioctls. */
+ iwr->u.data.length = dev->wireless_handlers->num_private_args;
+@@ -505,7 +537,6 @@ static inline int ioctl_standard_call(st
+ const struct iw_ioctl_description * descr;
+ struct iw_request_info info;
+ int ret = -EINVAL;
+- int user_size = 0;
+
+ /* Get the description of the IOCTL */
+ if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+@@ -536,8 +567,14 @@ static inline int ioctl_standard_call(st
+ #endif /* WE_SET_EVENT */
+ } else {
+ char * extra;
++ int extra_size;
++ int user_length = 0;
+ int err;
+
++ /* Calculate space needed by arguments. Always allocate
++ * for max space. Easier, and won't last long... */
++ extra_size = descr->max_tokens * descr->token_size;
++
+ /* Check what user space is giving us */
+ if(IW_IS_SET(cmd)) {
+ /* Check NULL pointer */
+@@ -554,18 +591,33 @@ static inline int ioctl_standard_call(st
+ if(iwr->u.data.pointer == NULL)
+ return -EFAULT;
+ /* Save user space buffer size for checking */
+- user_size = iwr->u.data.length;
++ user_length = iwr->u.data.length;
++
++ /* Don't check if user_length > max to allow forward
++ * compatibility. The test user_length < min is
++ * implied by the test at the end. */
++
++ /* Support for very large requests */
++ if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
++ (user_length > descr->max_tokens)) {
++ /* Allow userspace to GET more than max so
++ * we can support any size GET requests.
++ * There is still a limit : -ENOMEM. */
++ extra_size = user_length * descr->token_size;
++ /* Note : user_length is originally a __u16,
++ * and token_size is controlled by us,
++ * so extra_size won't get negative and
++ * won't overflow... */
++ }
+ }
+
+ #ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
+- dev->name, descr->max_tokens * descr->token_size);
++ dev->name, extra_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);
++ /* Create the kernel buffer */
++ extra = kmalloc(extra_size, GFP_KERNEL);
+ if (extra == NULL) {
+ return -ENOMEM;
+ }
+@@ -591,14 +643,11 @@ static inline int ioctl_standard_call(st
+
+ /* If we have something to return to the user */
+ if (!ret && IW_IS_GET(cmd)) {
+-#ifdef WE_STRICT_WRITE
+ /* Check if there is enough buffer up there */
+- if(user_size < iwr->u.data.length) {
+- printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
++ if(user_length < iwr->u.data.length) {
+ kfree(extra);
+ return -E2BIG;
+ }
+-#endif /* WE_STRICT_WRITE */
+
+ err = copy_to_user(iwr->u.data.pointer, extra,
+ iwr->u.data.length *
+@@ -661,7 +710,7 @@ static inline int ioctl_private_call(str
+ iw_handler handler)
+ {
+ struct iwreq * iwr = (struct iwreq *) ifr;
+- struct iw_priv_args * descr = NULL;
++ const struct iw_priv_args * descr = NULL;
+ struct iw_request_info info;
+ int extra_size = 0;
+ int i;
+@@ -701,7 +750,7 @@ static inline int ioctl_private_call(str
+ ((extra_size + offset) <= IFNAMSIZ))
+ extra_size = 0;
+ } else {
+- /* Size of set arguments */
++ /* Size of get arguments */
+ extra_size = get_priv_size(descr->get_args);
+
+ /* Does it fits in iwr ? */
+@@ -771,6 +820,14 @@ static inline int ioctl_private_call(str
+
+ /* If we have something to return to the user */
+ if (!ret && IW_IS_GET(cmd)) {
++
++ /* Adjust for the actual length if it's variable,
++ * avoid leaking kernel bits outside. */
++ if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
++ extra_size = adjust_priv_size(descr->get_args,
++ &(iwr->u));
++ }
++
+ err = copy_to_user(iwr->u.data.pointer, extra,
+ extra_size);
+ if (err)
+@@ -1042,9 +1099,25 @@ void wireless_send_event(struct net_devi
+ * One of the main advantage of centralising spy support here is that
+ * it becomes much easier to improve and extend it without having to touch
+ * the drivers. One example is the addition of the Spy-Threshold events.
+- * Note : IW_WIRELESS_SPY is defined in iw_handler.h
+ */
+
++/* ---------------------------------------------------------------- */
++/*
++ * Return the pointer to the spy data in the driver.
++ * Because this is called on the Rx path via wireless_spy_update(),
++ * we want it to be efficient...
++ */
++static inline struct iw_spy_data * get_spydata(struct net_device *dev)
++{
++ /* This is the new way */
++ if(dev->wireless_data)
++ return(dev->wireless_data->spy_data);
++
++ /* This is the old way. Doesn't work for multi-headed drivers.
++ * It will be removed in the next version of WE. */
++ return (dev->priv + dev->wireless_handlers->spy_offset);
++}
++
+ /*------------------------------------------------------------------*/
+ /*
+ * Standard Wireless Handler : set Spy List
+@@ -1054,16 +1127,26 @@ int iw_handler_set_spy(struct net_device
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_SPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ /* Disable spy collection while we copy the addresses.
+- * As we don't disable interrupts, we need to do this to avoid races.
+- * As we are the only writer, this is good enough. */
++ * While we copy addresses, any call to wireless_spy_update()
++ * will NOP. This is OK, as anyway the addresses are changing. */
+ spydata->spy_number = 0;
+
++ /* We want to operate without locking, because wireless_spy_update()
++ * most likely will happen in the interrupt handler, and therefore
++ * have its own locking constraints and needs performance.
++ * The rtnl_lock() make sure we don't race with the other iw_handlers.
++ * This make sure wireless_spy_update() "see" that the spy list
++ * is temporarily disabled. */
++ wmb();
++
+ /* Are there are addresses to copy? */
+ if(wrqu->data.length > 0) {
+ int i;
+@@ -1089,13 +1172,14 @@ int iw_handler_set_spy(struct net_device
+ spydata->spy_address[i][5]);
+ #endif /* WE_SPY_DEBUG */
+ }
++
++ /* Make sure above is updated before re-enabling */
++ wmb();
++
+ /* Enable addresses */
+ spydata->spy_number = wrqu->data.length;
+
+ return 0;
+-#else /* IW_WIRELESS_SPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_SPY */
+ }
+
+ /*------------------------------------------------------------------*/
+@@ -1107,12 +1191,14 @@ int iw_handler_get_spy(struct net_device
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_SPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+ int i;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ wrqu->data.length = spydata->spy_number;
+
+ /* Copy addresses. */
+@@ -1129,9 +1215,6 @@ int iw_handler_get_spy(struct net_device
+ for(i = 0; i < spydata->spy_number; i++)
+ spydata->spy_stat[i].updated = 0;
+ return 0;
+-#else /* IW_WIRELESS_SPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_SPY */
+ }
+
+ /*------------------------------------------------------------------*/
+@@ -1143,11 +1226,13 @@ int iw_handler_set_thrspy(struct net_dev
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_THRSPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ /* Just do it */
+ memcpy(&(spydata->spy_thr_low), &(threshold->low),
+ 2 * sizeof(struct iw_quality));
+@@ -1160,9 +1245,6 @@ int iw_handler_set_thrspy(struct net_dev
+ #endif /* WE_SPY_DEBUG */
+
+ return 0;
+-#else /* IW_WIRELESS_THRSPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_THRSPY */
+ }
+
+ /*------------------------------------------------------------------*/
+@@ -1174,22 +1256,20 @@ int iw_handler_get_thrspy(struct net_dev
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_THRSPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ /* Just do it */
+ memcpy(&(threshold->low), &(spydata->spy_thr_low),
+ 2 * sizeof(struct iw_quality));
+
+ return 0;
+-#else /* IW_WIRELESS_THRSPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_THRSPY */
+ }
+
+-#ifdef IW_WIRELESS_THRSPY
+ /*------------------------------------------------------------------*/
+ /*
+ * Prepare and send a Spy Threshold event
+@@ -1227,7 +1307,6 @@ static void iw_send_thrspy_event(struct
+ /* Send event to user space */
+ wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+ }
+-#endif /* IW_WIRELESS_THRSPY */
+
+ /* ---------------------------------------------------------------- */
+ /*
+@@ -1240,12 +1319,14 @@ void wireless_spy_update(struct net_devi
+ unsigned char * address,
+ struct iw_quality * wstats)
+ {
+-#ifdef IW_WIRELESS_SPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ int i;
+ int match = -1;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return;
++
+ #ifdef WE_SPY_DEBUG
+ printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
+ #endif /* WE_SPY_DEBUG */
+@@ -1257,7 +1338,7 @@ void wireless_spy_update(struct net_devi
+ sizeof(struct iw_quality));
+ match = i;
+ }
+-#ifdef IW_WIRELESS_THRSPY
++
+ /* Generate an event if we cross the spy threshold.
+ * To avoid event storms, we have a simple hysteresis : we generate
+ * event only when we go under the low threshold or above the
+@@ -1277,6 +1358,4 @@ void wireless_spy_update(struct net_devi
+ }
+ }
+ }
+-#endif /* IW_WIRELESS_THRSPY */
+-#endif /* IW_WIRELESS_SPY */
+ }