From 08319bb355f622acca58f4f840f82c8fbdb98644 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Tue, 14 Mar 2006 21:11:36 +0000 Subject: [PATCH] wireless extension 18 for 2.4 kernels, needed for xsupplicant SVN-Revision: 3367 --- .../patches/100-wireless-extension.patch | 1121 +++++++++++++++++ 1 file changed, 1121 insertions(+) create mode 100644 openwrt/target/linux/generic-2.4/patches/100-wireless-extension.patch diff --git a/openwrt/target/linux/generic-2.4/patches/100-wireless-extension.patch b/openwrt/target/linux/generic-2.4/patches/100-wireless-extension.patch new file mode 100644 index 000000000000..88e91831ff91 --- /dev/null +++ b/openwrt/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 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 - +- * 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 ) ++ * ---------- ++ * - 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 - +- * 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 - +- * 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 : ++ * 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 */ + } -- 2.30.2