From 2315b47b10b345d339b0c296bbe7f373074bc3d6 Mon Sep 17 00:00:00 2001
From: wbx <wbx@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Tue, 14 Mar 2006 21:11:36 +0000
Subject: wireless extension 18 for 2.4 kernels, needed for xsupplicant

git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@3367 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 .../patches/100-wireless-extension.patch           | 1121 ++++++++++++++++++++
 1 file changed, 1121 insertions(+)
 create mode 100644 target/linux/generic-2.4/patches/100-wireless-extension.patch

diff --git a/target/linux/generic-2.4/patches/100-wireless-extension.patch b/target/linux/generic-2.4/patches/100-wireless-extension.patch
new file mode 100644
index 000000000..88e91831f
--- /dev/null
+++ b/target/linux/generic-2.4/patches/100-wireless-extension.patch
@@ -0,0 +1,1121 @@
+diff -Nur linux-2.4.32/include/linux/netdevice.h linux-2.4.32-we/include/linux/netdevice.h
+--- linux-2.4.32/include/linux/netdevice.h	2004-11-17 12:54:22.000000000 +0100
++++ linux-2.4.32-we/include/linux/netdevice.h	2006-03-13 12:10:57.000000000 +0100
+@@ -295,7 +295,9 @@
+ 
+ 	/* 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 -Nur linux-2.4.32/include/linux/wireless.h linux-2.4.32-we/include/linux/wireless.h
+--- linux-2.4.32/include/linux/wireless.h	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.32-we/include/linux/wireless.h	2006-03-13 12:11:02.000000000 +0100
+@@ -1,10 +1,10 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	16	2.4.03
++ * Version :	18	12.3.05
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2005 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	18
+ 
+ /*
+  * Changes :
+@@ -175,6 +175,28 @@
+  *	- 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 !)
++ *
++ * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>)
++ * ----------
++ *	- Add support for WPA/WPA2
++ *	- Add extended encoding configuration (SIOCSIWENCODEEXT and
++ *	  SIOCGIWENCODEEXT)
++ *	- Add SIOCSIWGENIE/SIOCGIWGENIE
++ *	- Add SIOCSIWMLME
++ *	- Add SIOCSIWPMKSA
++ *	- Add struct iw_range bit field for supported encoding capabilities
++ *	- Add optional scan request parameters for SIOCSIWSCAN
++ *	- Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
++ *	  related parameters (extensible up to 4096 parameter values)
++ *	- Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
++ *	  IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+@@ -249,9 +271,33 @@
+ #define SIOCSIWPOWER	0x8B2C		/* set Power Management settings */
+ #define SIOCGIWPOWER	0x8B2D		/* get Power Management settings */
+ 
++/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
++ * This ioctl uses struct iw_point and data buffer that includes IE id and len
++ * fields. More than one IE may be included in the request. Setting the generic
++ * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
++ * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
++ * are required to report the used IE as a wireless event, e.g., when
++ * associating with an AP. */
++#define SIOCSIWGENIE	0x8B30		/* set generic IE */
++#define SIOCGIWGENIE	0x8B31		/* get generic IE */
++
++/* WPA : IEEE 802.11 MLME requests */
++#define SIOCSIWMLME	0x8B16		/* request MLME operation; uses
++					 * struct iw_mlme */
++/* WPA : Authentication mode parameters */
++#define SIOCSIWAUTH	0x8B32		/* set authentication mode params */
++#define SIOCGIWAUTH	0x8B33		/* get authentication mode params */
++
++/* WPA : Extended version of encoding configuration */
++#define SIOCSIWENCODEEXT 0x8B34		/* set encoding token & mode */
++#define SIOCGIWENCODEEXT 0x8B35		/* get encoding token & mode */
++
++/* WPA2 : PMKSA cache management */
++#define SIOCSIWPMKSA	0x8B36		/* PMKSA cache operation */
++
+ /* -------------------- 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 +312,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.
+  */
+ 
+@@ -290,6 +336,34 @@
+ #define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
+ #define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
+ #define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
++#define IWEVGENIE	0x8C05		/* Generic IE (WPA, RSN, WMM, ..)
++					 * (scan results); This includes id and
++					 * length fields. One IWEVGENIE may
++					 * contain more than one IE. Scan
++					 * results may contain one or more
++					 * IWEVGENIE events. */
++#define IWEVMICHAELMICFAILURE 0x8C06	/* Michael MIC failure
++					 * (struct iw_michaelmicfailure)
++					 */
++#define IWEVASSOCREQIE	0x8C07		/* IEs used in (Re)Association Request.
++					 * The data includes id and length
++					 * fields and may contain more than one
++					 * IE. This event is required in
++					 * Managed mode if the driver
++					 * generates its own WPA/RSN IE. This
++					 * should be sent just before
++					 * IWEVREGISTERED event for the
++					 * association. */
++#define IWEVASSOCRESPIE	0x8C08		/* IEs used in (Re)Association
++					 * Response. The data includes id and
++					 * length fields and may contain more
++					 * than one IE. This may be sent
++					 * between IWEVASSOCREQIE and
++					 * IWEVREGISTERED events for the
++					 * association. */
++#define IWEVPMKIDCAND	0x8C09		/* PMKID candidate for RSN
++					 * pre-authentication
++					 * (struct iw_pmkid_cand) */
+ 
+ #define IWEVFIRST	0x8C00
+ 
+@@ -352,6 +426,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 +476,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 */
+@@ -412,12 +499,113 @@
+ #define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
+ #define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
+ #define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
++/* struct iw_scan_req scan_type */
++#define IW_SCAN_TYPE_ACTIVE 0
++#define IW_SCAN_TYPE_PASSIVE 1
+ /* Maximum size of returned data */
+ #define IW_SCAN_MAX_DATA	4096	/* In bytes */
+ 
+ /* Max number of char in custom event - use multiple of them if needed */
+ #define IW_CUSTOM_MAX		256	/* In bytes */
+ 
++/* Generic information element */
++#define IW_GENERIC_IE_MAX	1024
++
++/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
++#define IW_MLME_DEAUTH		0
++#define IW_MLME_DISASSOC	1
++
++/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
++#define IW_AUTH_INDEX		0x0FFF
++#define IW_AUTH_FLAGS		0xF000
++/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
++ * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
++ * parameter that is being set/get to; value will be read/written to
++ * struct iw_param value field) */
++#define IW_AUTH_WPA_VERSION		0
++#define IW_AUTH_CIPHER_PAIRWISE		1
++#define IW_AUTH_CIPHER_GROUP		2
++#define IW_AUTH_KEY_MGMT		3
++#define IW_AUTH_TKIP_COUNTERMEASURES	4
++#define IW_AUTH_DROP_UNENCRYPTED	5
++#define IW_AUTH_80211_AUTH_ALG		6
++#define IW_AUTH_WPA_ENABLED		7
++#define IW_AUTH_RX_UNENCRYPTED_EAPOL	8
++#define IW_AUTH_ROAMING_CONTROL		9
++#define IW_AUTH_PRIVACY_INVOKED		10
++
++/* IW_AUTH_WPA_VERSION values (bit field) */
++#define IW_AUTH_WPA_VERSION_DISABLED	0x00000001
++#define IW_AUTH_WPA_VERSION_WPA		0x00000002
++#define IW_AUTH_WPA_VERSION_WPA2	0x00000004
++
++/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */
++#define IW_AUTH_CIPHER_NONE	0x00000001
++#define IW_AUTH_CIPHER_WEP40	0x00000002
++#define IW_AUTH_CIPHER_TKIP	0x00000004
++#define IW_AUTH_CIPHER_CCMP	0x00000008
++#define IW_AUTH_CIPHER_WEP104	0x00000010
++
++/* IW_AUTH_KEY_MGMT values (bit field) */
++#define IW_AUTH_KEY_MGMT_802_1X	1
++#define IW_AUTH_KEY_MGMT_PSK	2
++
++/* IW_AUTH_80211_AUTH_ALG values (bit field) */
++#define IW_AUTH_ALG_OPEN_SYSTEM	0x00000001
++#define IW_AUTH_ALG_SHARED_KEY	0x00000002
++#define IW_AUTH_ALG_LEAP	0x00000004
++
++/* IW_AUTH_ROAMING_CONTROL values */
++#define IW_AUTH_ROAMING_ENABLE	0	/* driver/firmware based roaming */
++#define IW_AUTH_ROAMING_DISABLE	1	/* user space program used for roaming
++					 * control */
++
++/* SIOCSIWENCODEEXT definitions */
++#define IW_ENCODE_SEQ_MAX_SIZE	8
++/* struct iw_encode_ext ->alg */
++#define IW_ENCODE_ALG_NONE	0
++#define IW_ENCODE_ALG_WEP	1
++#define IW_ENCODE_ALG_TKIP	2
++#define IW_ENCODE_ALG_CCMP	3
++/* struct iw_encode_ext ->ext_flags */
++#define IW_ENCODE_EXT_TX_SEQ_VALID	0x00000001
++#define IW_ENCODE_EXT_RX_SEQ_VALID	0x00000002
++#define IW_ENCODE_EXT_GROUP_KEY		0x00000004
++#define IW_ENCODE_EXT_SET_TX_KEY	0x00000008
++
++/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
++#define IW_MICFAILURE_KEY_ID	0x00000003 /* Key ID 0..3 */
++#define IW_MICFAILURE_GROUP	0x00000004
++#define IW_MICFAILURE_PAIRWISE	0x00000008
++#define IW_MICFAILURE_STAKEY	0x00000010
++#define IW_MICFAILURE_COUNT	0x00000060 /* 1 or 2 (0 = count not supported)
++					    */
++
++/* Bit field values for enc_capa in struct iw_range */
++#define IW_ENC_CAPA_WPA		0x00000001
++#define IW_ENC_CAPA_WPA2	0x00000002
++#define IW_ENC_CAPA_CIPHER_TKIP	0x00000004
++#define IW_ENC_CAPA_CIPHER_CCMP	0x00000008
++
++/* 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 +644,7 @@
+ 	__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) */
+ };
+ 
+ /*
+@@ -507,6 +695,132 @@
+ 	struct iw_quality	high;		/* High threshold */
+ };
+ 
++/*
++ *	Optional data for scan request
++ *
++ *	Note: these optional parameters are controlling parameters for the
++ *	scanning behavior, these do not apply to getting scan results
++ *	(SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
++ *	provide a merged results with all BSSes even if the previous scan
++ *	request limited scanning to a subset, e.g., by specifying an SSID.
++ *	Especially, scan results are required to include an entry for the
++ *	current BSS if the driver is in Managed mode and associated with an AP.
++ */
++struct	iw_scan_req
++{
++	__u8		scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
++	__u8		essid_len;
++	__u8		num_channels; /* num entries in channel_list;
++				       * 0 = scan all allowed channels */
++	__u8		flags; /* reserved as padding; use zero, this may
++				* be used in the future for adding flags
++				* to request different scan behavior */
++	struct sockaddr	bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
++				* individual address of a specific BSS */
++
++	/*
++	 * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
++	 * the current ESSID. This allows scan requests for specific ESSID
++	 * without having to change the current ESSID and potentially breaking
++	 * the current association.
++	 */
++	__u8		essid[IW_ESSID_MAX_SIZE];
++
++	/*
++	 * Optional parameters for changing the default scanning behavior.
++	 * These are based on the MLME-SCAN.request from IEEE Std 802.11.
++	 * TU is 1.024 ms. If these are set to 0, driver is expected to use
++	 * reasonable default values. min_channel_time defines the time that
++	 * will be used to wait for the first reply on each channel. If no
++	 * replies are received, next channel will be scanned after this. If
++	 * replies are received, total time waited on the channel is defined by
++	 * max_channel_time.
++	 */
++	__u32		min_channel_time; /* in TU */
++	__u32		max_channel_time; /* in TU */
++
++	struct iw_freq	channel_list[IW_MAX_FREQUENCIES];
++};
++
++/* ------------------------- WPA SUPPORT ------------------------- */
++
++/*
++ *	Extended data structure for get/set encoding (this is used with
++ *	SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
++ *	flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
++ *	only the data contents changes (key data -> this structure, including
++ *	key data).
++ *
++ *	If the new key is the first group key, it will be set as the default
++ *	TX key. Otherwise, default TX key index is only changed if
++ *	IW_ENCODE_EXT_SET_TX_KEY flag is set.
++ *
++ *	Key will be changed with SIOCSIWENCODEEXT in all cases except for
++ *	special "change TX key index" operation which is indicated by setting
++ *	key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
++ *
++ *	tx_seq/rx_seq are only used when respective
++ *	IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
++ *	TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
++ *	TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
++ *	used only by an Authenticator (AP or an IBSS station) to get the
++ *	current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
++ *	RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
++ *	debugging/testing.
++ */
++struct	iw_encode_ext
++{
++	__u32		ext_flags; /* IW_ENCODE_EXT_* */
++	__u8		tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
++	__u8		rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
++	struct sockaddr	addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
++			       * (group) keys or unicast address for
++			       * individual keys */
++	__u16		alg; /* IW_ENCODE_ALG_* */
++	__u16		key_len;
++	__u8		key[0];
++};
++
++/* SIOCSIWMLME data */
++struct	iw_mlme
++{
++	__u16		cmd; /* IW_MLME_* */
++	__u16		reason_code;
++	struct sockaddr	addr;
++};
++
++/* SIOCSIWPMKSA data */
++#define IW_PMKSA_ADD		1
++#define IW_PMKSA_REMOVE		2
++#define IW_PMKSA_FLUSH		3
++
++#define IW_PMKID_LEN	16
++
++struct	iw_pmksa
++{
++	__u32		cmd; /* IW_PMKSA_* */
++	struct sockaddr	bssid;
++	__u8		pmkid[IW_PMKID_LEN];
++};
++
++/* IWEVMICHAELMICFAILURE data */
++struct	iw_michaelmicfailure
++{
++	__u32		flags;
++	struct sockaddr	src_addr;
++	__u8		tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
++};
++
++/* IWEVPMKIDCAND data */
++#define IW_PMKID_CAND_PREAUTH	0x00000001 /* RNS pre-authentication enabled */
++struct	iw_pmkid_cand
++{
++	__u32		flags; /* IW_PMKID_CAND_* */
++	__u32		index; /* the smaller the index, the higher the
++				* priority */
++	struct sockaddr	bssid;
++};
++
+ /* ------------------------ WIRELESS STATS ------------------------ */
+ /*
+  * Wireless statistics (used for /proc/net/wireless)
+@@ -610,11 +924,12 @@
+ 	/* 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)
+@@ -685,6 +1000,8 @@
+ 	struct iw_freq	freq[IW_MAX_FREQUENCIES];	/* list */
+ 	/* Note : this frequency list doesn't need to fit channel numbers,
+ 	 * because each entry contain its channel index */
++
++	__u32		enc_capa; /* IW_ENC_CAPA_* bit field */
+ };
+ 
+ /*
+diff -Nur linux-2.4.32/include/net/iw_handler.h linux-2.4.32-we/include/net/iw_handler.h
+--- linux-2.4.32/include/net/iw_handler.h	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.32-we/include/net/iw_handler.h	2006-03-13 12:10:57.000000000 +0100
+@@ -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 @@
+ 	/* 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_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 -Nur linux-2.4.32/net/core/dev.c linux-2.4.32-we/net/core/dev.c
+--- linux-2.4.32/net/core/dev.c	2005-04-04 03:42:20.000000000 +0200
++++ linux-2.4.32-we/net/core/dev.c	2006-03-13 12:10:57.000000000 +0100
+@@ -2426,7 +2426,7 @@
+ 				/* 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 -Nur linux-2.4.32/net/core/wireless.c linux-2.4.32-we/net/core/wireless.c
+--- linux-2.4.32/net/core/wireless.c	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.32-we/net/core/wireless.c	2006-03-13 12:11:02.000000000 +0100
+@@ -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-2005 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 */
+@@ -131,14 +137,14 @@
+ 	{ 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},
++	/* SIOCSIWMLME */
++	{ IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_mlme), sizeof(struct iw_mlme), 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},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_scan_req), 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 */
+@@ -179,6 +185,25 @@
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ 	/* SIOCGIWPOWER */
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWGENIE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++	/* SIOCGIWGENIE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++	/* SIOCSIWAUTH */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWAUTH */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWENCODEEXT */
++	{ IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_encode_ext), sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX, 0},
++	/* SIOCGIWENCODEEXT */
++	{ IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_encode_ext), sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX, 0},
++	/* SIOCSIWPMKSA */
++	{ IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_pmksa), sizeof(struct iw_pmksa), 0},
++	/* -- hole -- */
+ };
+ static const int standard_ioctl_num = (sizeof(standard_ioctl) /
+ 				       sizeof(struct iw_ioctl_description));
+@@ -198,12 +223,22 @@
+ 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ 	/* IWEVEXPIRED */
+ 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* IWEVGENIE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++	/* IWEVMICHAELMICFAILURE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_michaelmicfailure), 0},
++	/* IWEVASSOCREQIE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++	/* IWEVASSOCRESPIE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++	/* IWEVPMKIDCAND */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_pmkid_cand), 0},
+ };
+ static const int standard_event_num = (sizeof(standard_event) /
+ 				       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 +305,15 @@
+  */
+ 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 +348,32 @@
+ 
+ /* ---------------------------------------------------------------- */
+ /*
+- * 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 +406,14 @@
+ 			       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 +529,15 @@
+ 	/* 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 +566,6 @@
+ 	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 +596,14 @@
+ #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 +620,33 @@
+ 			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 +672,11 @@
+ 
+ 		/* 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 +739,7 @@
+ 				     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 +779,7 @@
+ 			   ((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 +849,14 @@
+ 
+ 		/* 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 +1128,25 @@
+  * 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 +1156,26 @@
+ 		       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 +1201,14 @@
+ 			       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 +1220,14 @@
+ 		       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 +1244,6 @@
+ 	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 +1255,13 @@
+ 			  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 +1274,6 @@
+ #endif	/* WE_SPY_DEBUG */
+ 
+ 	return 0;
+-#else /* IW_WIRELESS_THRSPY */
+-	return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_THRSPY */
+ }
+ 
+ /*------------------------------------------------------------------*/
+@@ -1174,22 +1285,20 @@
+ 			  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 +1336,6 @@
+ 	/* Send event to user space */
+ 	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+ }
+-#endif /* IW_WIRELESS_THRSPY */
+ 
+ /* ---------------------------------------------------------------- */
+ /*
+@@ -1240,12 +1348,14 @@
+ 			 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 +1367,7 @@
+ 			       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 +1387,4 @@
+ 			}
+ 		}
+ 	}
+-#endif /* IW_WIRELESS_THRSPY */
+-#endif /* IW_WIRELESS_SPY */
+ }
-- 
cgit v1.2.3