1 diff -u -p linux/include/linux/netdevice.we16.h linux/include/linux/netdevice.h
2 --- linux/include/linux/netdevice.we16.h 2005-02-03 14:54:56.000000000 -0800
3 +++ linux/include/linux/netdevice.h 2005-02-03 15:43:30.000000000 -0800
4 @@ -295,7 +295,9 @@ struct net_device
6 /* List of functions to handle Wireless Extensions (instead of ioctl).
7 * See <net/iw_handler.h> for details. Jean II */
8 - struct iw_handler_def * wireless_handlers;
9 + const struct iw_handler_def * wireless_handlers;
10 + /* Instance data managed by the core of Wireless Extensions. */
11 + struct iw_public_data * wireless_data;
13 struct ethtool_ops *ethtool_ops;
15 diff -u -p linux/include/linux/wireless.we16.h linux/include/linux/wireless.h
16 --- linux/include/linux/wireless.we16.h 2005-02-03 14:55:04.000000000 -0800
17 +++ linux/include/linux/wireless.h 2005-02-03 15:44:48.000000000 -0800
20 * This file define a set of standard wireless extensions
22 - * Version : 16 2.4.03
23 + * Version : 17 21.6.04
25 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
26 - * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
27 + * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
30 #ifndef _LINUX_WIRELESS_H
32 * # include/net/iw_handler.h
34 * Note as well that /proc/net/wireless implementation has now moved in :
35 - * # include/linux/wireless.c
36 + * # net/core/wireless.c
38 * Wireless Events (2002 -> onward) :
39 * --------------------------------
40 * Events are defined at the end of this file, and implemented in :
41 - * # include/linux/wireless.c
42 + * # net/core/wireless.c
47 * (there is some stuff that will be added in the future...)
48 * I just plan to increment with each new version.
50 -#define WIRELESS_EXT 16
51 +#define WIRELESS_EXT 17
56 * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
57 * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
58 * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
62 + * - Add flags to frequency -> auto/fixed
63 + * - Document (struct iw_quality *)->updated, add new flags (INVALID)
64 + * - Wireless Event capability in struct iw_range
65 + * - Add support for relative TxPower (yick !)
68 /**************************** CONSTANTS ****************************/
71 /* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
73 -/* These 16 ioctl are wireless device private.
74 +/* These 32 ioctl are wireless device private, for 16 commands.
75 * Each driver is free to use them for whatever purpose it chooses,
76 * however the driver *must* export the description of those ioctls
77 * with SIOCGIWPRIV and *must* use arguments as defined below.
79 * We now have 32 commands, so a bit more space ;-).
80 * Also, all 'odd' commands are only usable by root and don't return the
81 * content of ifr/iwr to user (but you are not obliged to use the set/get
82 - * convention, just use every other two command).
83 - * And I repeat : you are not obliged to use them with iwspy, but you
84 + * convention, just use every other two command). More details in iwpriv.c.
85 + * And I repeat : you are not forced to use them with iwpriv, but you
86 * must be compliant with it.
90 #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
91 #define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
93 +/* Statistics flags (bitmask in updated) */
94 +#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */
95 +#define IW_QUAL_LEVEL_UPDATED 0x2
96 +#define IW_QUAL_NOISE_UPDATED 0x4
97 +#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
98 +#define IW_QUAL_LEVEL_INVALID 0x20
99 +#define IW_QUAL_NOISE_INVALID 0x40
101 +/* Frequency flags */
102 +#define IW_FREQ_AUTO 0x00 /* Let the driver decides */
103 +#define IW_FREQ_FIXED 0x01 /* Force a specific value */
105 /* Maximum number of size of encoding token available
106 * they are listed in the range structure */
107 #define IW_MAX_ENCODING_SIZES 8
109 #define IW_TXPOW_TYPE 0x00FF /* Type of value */
110 #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
111 #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */
112 +#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */
113 #define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */
115 /* Retry limits and lifetime flags available */
117 /* Max number of char in custom event - use multiple of them if needed */
118 #define IW_CUSTOM_MAX 256 /* In bytes */
120 +/* Event capability macros - in (struct iw_range *)->event_capa
121 + * Because we have more than 32 possible events, we use an array of
122 + * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
123 +#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \
124 + (cmd - SIOCIWFIRSTPRIV + 0x60) : \
125 + (cmd - SIOCSIWCOMMIT))
126 +#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5)
127 +#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
128 +/* Event capability constants - event autogenerated by the kernel
129 + * This list is valid for most 802.11 devices, customise as needed... */
130 +#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \
131 + IW_EVENT_CAPA_MASK(0x8B06) | \
132 + IW_EVENT_CAPA_MASK(0x8B1A))
133 +#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A))
134 +/* "Easy" macro to set events in iw_range (less efficient) */
135 +#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
136 +#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
139 /****************************** TYPES ******************************/
141 /* --------------------------- SUBTYPES --------------------------- */
142 @@ -456,7 +495,7 @@ struct iw_freq
143 __s32 m; /* Mantissa */
144 __s16 e; /* Exponent */
145 __u8 i; /* List index (when in range struct) */
146 - __u8 pad; /* Unused - just for alignement */
147 + __u8 flags; /* Flags (fixed/auto) */
151 @@ -610,11 +649,12 @@ struct iw_range
152 /* Old Frequency (backward compat - moved lower ) */
153 __u16 old_num_channels;
154 __u8 old_num_frequency;
155 - /* Filler to keep "version" at the same offset */
158 + /* Wireless event capability bitmasks */
159 + __u32 event_capa[6];
161 /* signal level threshold range */
165 /* Quality of link & SNR stuff */
166 /* Quality range (link, level, noise)
167 diff -u -p linux/include/net/iw_handler.we16.h linux/include/net/iw_handler.h
168 --- linux/include/net/iw_handler.we16.h 2005-02-03 14:55:26.000000000 -0800
169 +++ linux/include/net/iw_handler.h 2005-02-03 15:47:04.000000000 -0800
172 * This file define the new driver API for Wireless Extensions
174 - * Version : 5 4.12.02
175 + * Version : 6 21.6.04
177 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
178 - * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
179 + * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
182 #ifndef _IW_HANDLER_H
185 * I just plan to increment with each new version.
187 -#define IW_HANDLER_VERSION 5
188 +#define IW_HANDLER_VERSION 6
192 @@ -224,11 +224,18 @@
195 * - Add new spy support : struct iw_spy_data & prototypes
199 + * - Change the way we get to spy_data method for added safety
200 + * - Remove spy #ifdef, they are always on -> cleaner code
201 + * - Add IW_DESCR_FLAG_NOMAX flag for very large requests
202 + * - Start migrating get_wireless_stats to struct iw_handler_def
205 /**************************** CONSTANTS ****************************/
207 -/* Enable enhanced spy support. Disable to reduce footprint */
208 +/* Enhanced spy support available */
209 #define IW_WIRELESS_SPY
210 #define IW_WIRELESS_THRSPY
213 #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
214 #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
215 /* SET : Omit payload from generated iwevent */
216 +#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
217 /* Driver level flags */
218 #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
220 @@ -311,23 +319,25 @@ struct iw_handler_def
221 /* Array of handlers for standard ioctls
222 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
224 - iw_handler * standard;
225 + const iw_handler * standard;
227 /* Array of handlers for private ioctls
228 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
230 - iw_handler * private;
231 + const iw_handler * private;
233 /* Arguments of private handler. This one is just a list, so you
234 * can put it in any order you want and should not leave holes...
235 * We will automatically export that to user space... */
236 - struct iw_priv_args * private_args;
237 + const struct iw_priv_args * private_args;
239 - /* Driver enhanced spy support */
240 - long spy_offset; /* Spy data offset */
241 + /* This field will be *removed* in the next version of WE */
242 + long spy_offset; /* DO NOT USE */
244 - /* In the long term, get_wireless_stats will move from
245 - * 'struct net_device' to here, to minimise bloat. */
246 + /* New location of get_wireless_stats, to de-bloat struct net_device.
247 + * The old pointer in struct net_device will be gradually phased
248 + * out, and drivers are encouraged to use this one... */
249 + struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
252 /* ---------------------- IOCTL DESCRIPTION ---------------------- */
253 @@ -374,18 +384,29 @@ struct iw_ioctl_description
257 -#ifdef IW_WIRELESS_SPY
258 /* --- Standard spy support --- */
260 u_char spy_address[IW_MAX_SPY][ETH_ALEN];
261 struct iw_quality spy_stat[IW_MAX_SPY];
262 -#ifdef IW_WIRELESS_THRSPY
263 /* --- Enhanced spy support (event) */
264 struct iw_quality spy_thr_low; /* Low threshold */
265 struct iw_quality spy_thr_high; /* High threshold */
266 u_char spy_thr_under[IW_MAX_SPY];
267 -#endif /* IW_WIRELESS_THRSPY */
268 -#endif /* IW_WIRELESS_SPY */
271 +/* --------------------- DEVICE WIRELESS DATA --------------------- */
273 + * This is all the wireless data specific to a device instance that
274 + * is managed by the core of Wireless Extensions.
275 + * We only keep pointer to those structures, so that a driver is free
276 + * to share them between instances.
277 + * This structure should be initialised before registering the device.
278 + * Access to this data follow the same rules as any other struct net_device
279 + * data (i.e. valid as long as struct net_device exist, same locking rules).
281 +struct iw_public_data {
282 + /* Driver enhanced spy support */
283 + struct iw_spy_data * spy_data;
286 /**************************** PROTOTYPES ****************************/
287 diff -u -p linux/net/core/dev.we16.c linux/net/core/dev.c
288 --- linux/net/core/dev.we16.c 2005-02-03 14:55:56.000000000 -0800
289 +++ linux/net/core/dev.c 2005-02-03 15:28:48.000000000 -0800
290 @@ -2426,7 +2426,7 @@ int dev_ioctl(unsigned int cmd, void *ar
291 /* Follow me in net/core/wireless.c */
292 ret = wireless_process_ioctl(&ifr, cmd);
294 - if (!ret && IW_IS_GET(cmd) &&
295 + if (IW_IS_GET(cmd) &&
296 copy_to_user(arg, &ifr, sizeof(struct ifreq)))
299 diff -u -p linux/net/core/wireless.we16.c linux/net/core/wireless.c
300 --- linux/net/core/wireless.we16.c 2005-02-03 14:56:09.000000000 -0800
301 +++ linux/net/core/wireless.c 2005-02-03 16:33:22.000000000 -0800
303 * This file implement the Wireless Extensions APIs.
305 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
306 - * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
307 + * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
309 * (As all part of the Linux kernel, this file is GPL)
312 * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
313 * o Add enhanced spy support : iw_handler_set_thrspy() and event.
314 * o Add WIRELESS_EXT version display in /proc/net/wireless
316 + * v6 - 18.06.04 - Jean II
317 + * o Change get_spydata() method for added safety
318 + * o Remove spy #ifdef, they are always on -> cleaner code
319 + * o Allow any size GET request if user specifies length > max
320 + * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
321 + * o Start migrating get_wireless_stats to struct iw_handler_def
322 + * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
323 + * Based on patch from Pavel Roskin <proski@gnu.org> :
324 + * o Fix kernel data leak to user space in private handler handling
327 /***************************** INCLUDES *****************************/
330 /**************************** CONSTANTS ****************************/
332 -/* Enough lenience, let's make sure things are proper... */
333 -#define WE_STRICT_WRITE /* Check write buffer size */
334 -/* I'll probably drop both the define and kernel message in the next version */
336 -/* Debuging stuff */
337 +/* Debugging stuff */
338 #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
339 #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
340 #undef WE_SPY_DEBUG /* Debug enhanced spy support */
341 @@ -134,11 +140,11 @@ static const struct iw_ioctl_description
343 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
345 - { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
346 + { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, IW_DESCR_FLAG_NOMAX},
348 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
350 - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
351 + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, IW_DESCR_FLAG_NOMAX},
353 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
355 @@ -203,7 +209,7 @@ static const int standard_event_num = (s
356 sizeof(struct iw_ioctl_description));
358 /* Size (in bytes) of the various private data types */
359 -static const char priv_type_size[] = {
360 +static const char iw_priv_type_size[] = {
361 0, /* IW_PRIV_TYPE_NONE */
362 1, /* IW_PRIV_TYPE_BYTE */
363 1, /* IW_PRIV_TYPE_CHAR */
364 @@ -270,12 +276,15 @@ static inline iw_handler get_handler(str
366 static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
369 + if((dev->wireless_handlers != NULL) &&
370 + (dev->wireless_handlers->get_wireless_stats != NULL))
371 + return dev->wireless_handlers->get_wireless_stats(dev);
373 + /* Old location, will be phased out in next WE */
374 return (dev->get_wireless_stats ?
375 dev->get_wireless_stats(dev) :
376 (struct iw_statistics *) NULL);
377 - /* In the future, get_wireless_stats may move from 'struct net_device'
378 - * to 'struct iw_handler_def', to de-bloat struct net_device.
379 - * Definitely worse a thought... */
382 /* ---------------------------------------------------------------- */
383 @@ -310,14 +319,32 @@ static inline int call_commit_handler(st
385 /* ---------------------------------------------------------------- */
387 - * Number of private arguments
388 + * Calculate size of private arguments
390 static inline int get_priv_size(__u16 args)
392 int num = args & IW_PRIV_SIZE_MASK;
393 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
395 - return num * priv_type_size[type];
396 + return num * iw_priv_type_size[type];
399 +/* ---------------------------------------------------------------- */
401 + * Re-calculate the size of private arguments
403 +static inline int adjust_priv_size(__u16 args,
404 + union iwreq_data * wrqu)
406 + int num = wrqu->data.length;
407 + int max = args & IW_PRIV_SIZE_MASK;
408 + int type = (args & IW_PRIV_TYPE_MASK) >> 12;
410 + /* Make sure the driver doesn't goof up */
414 + return num * iw_priv_type_size[type];
418 @@ -350,11 +377,14 @@ static inline int sprintf_wireless_stats
422 - stats->qual.updated & 1 ? '.' : ' ',
423 + stats->qual.updated & IW_QUAL_QUAL_UPDATED
425 ((__u8) stats->qual.level),
426 - stats->qual.updated & 2 ? '.' : ' ',
427 + stats->qual.updated & IW_QUAL_LEVEL_UPDATED
429 ((__u8) stats->qual.noise),
430 - stats->qual.updated & 4 ? '.' : ' ',
431 + stats->qual.updated & IW_QUAL_NOISE_UPDATED
435 stats->discard.fragment,
436 @@ -470,13 +500,15 @@ static inline int ioctl_export_private(s
437 /* Check NULL pointer */
438 if(iwr->u.data.pointer == NULL)
440 -#ifdef WE_STRICT_WRITE
442 /* Check if there is enough buffer up there */
443 if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
444 - 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);
445 + /* User space can't know in advance how large the buffer
446 + * needs to be. Give it a hint, so that we can support
447 + * any size buffer we want somewhat efficiently... */
448 + iwr->u.data.length = dev->wireless_handlers->num_private_args;
451 -#endif /* WE_STRICT_WRITE */
453 /* Set the number of available ioctls. */
454 iwr->u.data.length = dev->wireless_handlers->num_private_args;
455 @@ -505,7 +537,6 @@ static inline int ioctl_standard_call(st
456 const struct iw_ioctl_description * descr;
457 struct iw_request_info info;
461 /* Get the description of the IOCTL */
462 if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
463 @@ -536,8 +567,14 @@ static inline int ioctl_standard_call(st
464 #endif /* WE_SET_EVENT */
468 + int user_length = 0;
471 + /* Calculate space needed by arguments. Always allocate
472 + * for max space. Easier, and won't last long... */
473 + extra_size = descr->max_tokens * descr->token_size;
475 /* Check what user space is giving us */
477 /* Check NULL pointer */
478 @@ -554,18 +591,33 @@ static inline int ioctl_standard_call(st
479 if(iwr->u.data.pointer == NULL)
481 /* Save user space buffer size for checking */
482 - user_size = iwr->u.data.length;
483 + user_length = iwr->u.data.length;
485 + /* Don't check if user_length > max to allow forward
486 + * compatibility. The test user_length < min is
487 + * implied by the test at the end. */
489 + /* Support for very large requests */
490 + if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
491 + (user_length > descr->max_tokens)) {
492 + /* Allow userspace to GET more than max so
493 + * we can support any size GET requests.
494 + * There is still a limit : -ENOMEM. */
495 + extra_size = user_length * descr->token_size;
496 + /* Note : user_length is originally a __u16,
497 + * and token_size is controlled by us,
498 + * so extra_size won't get negative and
499 + * won't overflow... */
503 #ifdef WE_IOCTL_DEBUG
504 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
505 - dev->name, descr->max_tokens * descr->token_size);
506 + dev->name, extra_size);
507 #endif /* WE_IOCTL_DEBUG */
509 - /* Always allocate for max space. Easier, and won't last
511 - extra = kmalloc(descr->max_tokens * descr->token_size,
513 + /* Create the kernel buffer */
514 + extra = kmalloc(extra_size, GFP_KERNEL);
518 @@ -591,14 +643,11 @@ static inline int ioctl_standard_call(st
520 /* If we have something to return to the user */
521 if (!ret && IW_IS_GET(cmd)) {
522 -#ifdef WE_STRICT_WRITE
523 /* Check if there is enough buffer up there */
524 - if(user_size < iwr->u.data.length) {
525 - printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
526 + if(user_length < iwr->u.data.length) {
530 -#endif /* WE_STRICT_WRITE */
532 err = copy_to_user(iwr->u.data.pointer, extra,
534 @@ -661,7 +710,7 @@ static inline int ioctl_private_call(str
537 struct iwreq * iwr = (struct iwreq *) ifr;
538 - struct iw_priv_args * descr = NULL;
539 + const struct iw_priv_args * descr = NULL;
540 struct iw_request_info info;
543 @@ -701,7 +750,7 @@ static inline int ioctl_private_call(str
544 ((extra_size + offset) <= IFNAMSIZ))
547 - /* Size of set arguments */
548 + /* Size of get arguments */
549 extra_size = get_priv_size(descr->get_args);
551 /* Does it fits in iwr ? */
552 @@ -771,6 +820,14 @@ static inline int ioctl_private_call(str
554 /* If we have something to return to the user */
555 if (!ret && IW_IS_GET(cmd)) {
557 + /* Adjust for the actual length if it's variable,
558 + * avoid leaking kernel bits outside. */
559 + if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
560 + extra_size = adjust_priv_size(descr->get_args,
564 err = copy_to_user(iwr->u.data.pointer, extra,
567 @@ -1042,9 +1099,25 @@ void wireless_send_event(struct net_devi
568 * One of the main advantage of centralising spy support here is that
569 * it becomes much easier to improve and extend it without having to touch
570 * the drivers. One example is the addition of the Spy-Threshold events.
571 - * Note : IW_WIRELESS_SPY is defined in iw_handler.h
574 +/* ---------------------------------------------------------------- */
576 + * Return the pointer to the spy data in the driver.
577 + * Because this is called on the Rx path via wireless_spy_update(),
578 + * we want it to be efficient...
580 +static inline struct iw_spy_data * get_spydata(struct net_device *dev)
582 + /* This is the new way */
583 + if(dev->wireless_data)
584 + return(dev->wireless_data->spy_data);
586 + /* This is the old way. Doesn't work for multi-headed drivers.
587 + * It will be removed in the next version of WE. */
588 + return (dev->priv + dev->wireless_handlers->spy_offset);
591 /*------------------------------------------------------------------*/
593 * Standard Wireless Handler : set Spy List
594 @@ -1054,16 +1127,26 @@ int iw_handler_set_spy(struct net_device
595 union iwreq_data * wrqu,
598 -#ifdef IW_WIRELESS_SPY
599 - struct iw_spy_data * spydata = (dev->priv +
600 - dev->wireless_handlers->spy_offset);
601 + struct iw_spy_data * spydata = get_spydata(dev);
602 struct sockaddr * address = (struct sockaddr *) extra;
604 + /* Make sure driver is not buggy or using the old API */
606 + return -EOPNOTSUPP;
608 /* Disable spy collection while we copy the addresses.
609 - * As we don't disable interrupts, we need to do this to avoid races.
610 - * As we are the only writer, this is good enough. */
611 + * While we copy addresses, any call to wireless_spy_update()
612 + * will NOP. This is OK, as anyway the addresses are changing. */
613 spydata->spy_number = 0;
615 + /* We want to operate without locking, because wireless_spy_update()
616 + * most likely will happen in the interrupt handler, and therefore
617 + * have its own locking constraints and needs performance.
618 + * The rtnl_lock() make sure we don't race with the other iw_handlers.
619 + * This make sure wireless_spy_update() "see" that the spy list
620 + * is temporarily disabled. */
623 /* Are there are addresses to copy? */
624 if(wrqu->data.length > 0) {
626 @@ -1089,13 +1172,14 @@ int iw_handler_set_spy(struct net_device
627 spydata->spy_address[i][5]);
628 #endif /* WE_SPY_DEBUG */
631 + /* Make sure above is updated before re-enabling */
634 /* Enable addresses */
635 spydata->spy_number = wrqu->data.length;
638 -#else /* IW_WIRELESS_SPY */
639 - return -EOPNOTSUPP;
640 -#endif /* IW_WIRELESS_SPY */
643 /*------------------------------------------------------------------*/
644 @@ -1107,12 +1191,14 @@ int iw_handler_get_spy(struct net_device
645 union iwreq_data * wrqu,
648 -#ifdef IW_WIRELESS_SPY
649 - struct iw_spy_data * spydata = (dev->priv +
650 - dev->wireless_handlers->spy_offset);
651 + struct iw_spy_data * spydata = get_spydata(dev);
652 struct sockaddr * address = (struct sockaddr *) extra;
655 + /* Make sure driver is not buggy or using the old API */
657 + return -EOPNOTSUPP;
659 wrqu->data.length = spydata->spy_number;
661 /* Copy addresses. */
662 @@ -1129,9 +1215,6 @@ int iw_handler_get_spy(struct net_device
663 for(i = 0; i < spydata->spy_number; i++)
664 spydata->spy_stat[i].updated = 0;
666 -#else /* IW_WIRELESS_SPY */
667 - return -EOPNOTSUPP;
668 -#endif /* IW_WIRELESS_SPY */
671 /*------------------------------------------------------------------*/
672 @@ -1143,11 +1226,13 @@ int iw_handler_set_thrspy(struct net_dev
673 union iwreq_data * wrqu,
676 -#ifdef IW_WIRELESS_THRSPY
677 - struct iw_spy_data * spydata = (dev->priv +
678 - dev->wireless_handlers->spy_offset);
679 + struct iw_spy_data * spydata = get_spydata(dev);
680 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
682 + /* Make sure driver is not buggy or using the old API */
684 + return -EOPNOTSUPP;
687 memcpy(&(spydata->spy_thr_low), &(threshold->low),
688 2 * sizeof(struct iw_quality));
689 @@ -1160,9 +1245,6 @@ int iw_handler_set_thrspy(struct net_dev
690 #endif /* WE_SPY_DEBUG */
693 -#else /* IW_WIRELESS_THRSPY */
694 - return -EOPNOTSUPP;
695 -#endif /* IW_WIRELESS_THRSPY */
698 /*------------------------------------------------------------------*/
699 @@ -1174,22 +1256,20 @@ int iw_handler_get_thrspy(struct net_dev
700 union iwreq_data * wrqu,
703 -#ifdef IW_WIRELESS_THRSPY
704 - struct iw_spy_data * spydata = (dev->priv +
705 - dev->wireless_handlers->spy_offset);
706 + struct iw_spy_data * spydata = get_spydata(dev);
707 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
709 + /* Make sure driver is not buggy or using the old API */
711 + return -EOPNOTSUPP;
714 memcpy(&(threshold->low), &(spydata->spy_thr_low),
715 2 * sizeof(struct iw_quality));
718 -#else /* IW_WIRELESS_THRSPY */
719 - return -EOPNOTSUPP;
720 -#endif /* IW_WIRELESS_THRSPY */
723 -#ifdef IW_WIRELESS_THRSPY
724 /*------------------------------------------------------------------*/
726 * Prepare and send a Spy Threshold event
727 @@ -1227,7 +1307,6 @@ static void iw_send_thrspy_event(struct
728 /* Send event to user space */
729 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
731 -#endif /* IW_WIRELESS_THRSPY */
733 /* ---------------------------------------------------------------- */
735 @@ -1240,12 +1319,14 @@ void wireless_spy_update(struct net_devi
736 unsigned char * address,
737 struct iw_quality * wstats)
739 -#ifdef IW_WIRELESS_SPY
740 - struct iw_spy_data * spydata = (dev->priv +
741 - dev->wireless_handlers->spy_offset);
742 + struct iw_spy_data * spydata = get_spydata(dev);
746 + /* Make sure driver is not buggy or using the old API */
751 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]);
752 #endif /* WE_SPY_DEBUG */
753 @@ -1257,7 +1338,7 @@ void wireless_spy_update(struct net_devi
754 sizeof(struct iw_quality));
757 -#ifdef IW_WIRELESS_THRSPY
759 /* Generate an event if we cross the spy threshold.
760 * To avoid event storms, we have a simple hysteresis : we generate
761 * event only when we go under the low threshold or above the
762 @@ -1277,6 +1358,4 @@ void wireless_spy_update(struct net_devi
766 -#endif /* IW_WIRELESS_THRSPY */
767 -#endif /* IW_WIRELESS_SPY */