diff options
author | Koen Kooi <koen@openembedded.org> | 2005-06-30 08:19:37 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2005-06-30 08:19:37 +0000 |
commit | c8e5702127e507e82e6f68a4b8c546803accea9d (patch) | |
tree | 00583491f40ecc640f2b28452af995e3a63a09d7 /packages/linux/files/iw249_we17-13.diff | |
parent | 87ec8ca4d2e2eb4d1c1e1e1a6b46a395d56805b9 (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.diff | 768 |
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 */ + } |