mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-25 06:36:15 +02:00
0ec45ff596
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@15860 3c298f89-4303-0410-b956-a3cf2f4a3e73
1117 lines
40 KiB
Diff
1117 lines
40 KiB
Diff
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -295,7 +295,9 @@ struct net_device
|
|
|
|
/* List of functions to handle Wireless Extensions (instead of ioctl).
|
|
* See <net/iw_handler.h> for details. Jean II */
|
|
- struct iw_handler_def * wireless_handlers;
|
|
+ const struct iw_handler_def * wireless_handlers;
|
|
+ /* Instance data managed by the core of Wireless Extensions. */
|
|
+ struct iw_public_data * wireless_data;
|
|
|
|
struct ethtool_ops *ethtool_ops;
|
|
|
|
--- a/include/linux/wireless.h
|
|
+++ b/include/linux/wireless.h
|
|
@@ -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 @@ struct iw_freq
|
|
__s32 m; /* Mantissa */
|
|
__s16 e; /* Exponent */
|
|
__u8 i; /* List index (when in range struct) */
|
|
- __u8 pad; /* Unused - just for alignement */
|
|
+ __u8 flags; /* Flags (fixed/auto) */
|
|
};
|
|
|
|
/*
|
|
@@ -507,6 +695,132 @@ struct iw_thrspy
|
|
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 @@ struct iw_range
|
|
/* Old Frequency (backward compat - moved lower ) */
|
|
__u16 old_num_channels;
|
|
__u8 old_num_frequency;
|
|
- /* Filler to keep "version" at the same offset */
|
|
- __s32 old_freq[6];
|
|
+
|
|
+ /* Wireless event capability bitmasks */
|
|
+ __u32 event_capa[6];
|
|
|
|
/* signal level threshold range */
|
|
- __s32 sensitivity;
|
|
+ __s32 sensitivity;
|
|
|
|
/* Quality of link & SNR stuff */
|
|
/* Quality range (link, level, noise)
|
|
@@ -685,6 +1000,8 @@ struct iw_range
|
|
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 */
|
|
};
|
|
|
|
/*
|
|
--- a/include/net/iw_handler.h
|
|
+++ b/include/net/iw_handler.h
|
|
@@ -1,10 +1,10 @@
|
|
/*
|
|
* This file define the new driver API for Wireless Extensions
|
|
*
|
|
- * Version : 5 4.12.02
|
|
+ * Version : 6 21.6.04
|
|
*
|
|
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
|
|
- * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
|
|
+ * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
|
|
*/
|
|
|
|
#ifndef _IW_HANDLER_H
|
|
@@ -206,7 +206,7 @@
|
|
* will be needed...
|
|
* I just plan to increment with each new version.
|
|
*/
|
|
-#define IW_HANDLER_VERSION 5
|
|
+#define IW_HANDLER_VERSION 6
|
|
|
|
/*
|
|
* Changes :
|
|
@@ -224,11 +224,18 @@
|
|
* V4 to V5
|
|
* --------
|
|
* - Add new spy support : struct iw_spy_data & prototypes
|
|
+ *
|
|
+ * V5 to V6
|
|
+ * --------
|
|
+ * - Change the way we get to spy_data method for added safety
|
|
+ * - Remove spy #ifdef, they are always on -> cleaner code
|
|
+ * - Add IW_DESCR_FLAG_NOMAX flag for very large requests
|
|
+ * - Start migrating get_wireless_stats to struct iw_handler_def
|
|
*/
|
|
|
|
/**************************** CONSTANTS ****************************/
|
|
|
|
-/* Enable enhanced spy support. Disable to reduce footprint */
|
|
+/* Enhanced spy support available */
|
|
#define IW_WIRELESS_SPY
|
|
#define IW_WIRELESS_THRSPY
|
|
|
|
@@ -258,6 +265,7 @@
|
|
#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
|
|
#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
|
|
/* SET : Omit payload from generated iwevent */
|
|
+#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
|
|
/* Driver level flags */
|
|
#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
|
|
|
|
@@ -311,23 +319,25 @@ struct iw_handler_def
|
|
/* Array of handlers for standard ioctls
|
|
* We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
|
|
*/
|
|
- iw_handler * standard;
|
|
+ const iw_handler * standard;
|
|
|
|
/* Array of handlers for private ioctls
|
|
* Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
|
|
*/
|
|
- iw_handler * private;
|
|
+ const iw_handler * private;
|
|
|
|
/* Arguments of private handler. This one is just a list, so you
|
|
* can put it in any order you want and should not leave holes...
|
|
* We will automatically export that to user space... */
|
|
- struct iw_priv_args * private_args;
|
|
+ const struct iw_priv_args * private_args;
|
|
|
|
- /* Driver enhanced spy support */
|
|
- long spy_offset; /* Spy data offset */
|
|
+ /* This field will be *removed* in the next version of WE */
|
|
+ long spy_offset; /* DO NOT USE */
|
|
|
|
- /* In the long term, get_wireless_stats will move from
|
|
- * 'struct net_device' to here, to minimise bloat. */
|
|
+ /* New location of get_wireless_stats, to de-bloat struct net_device.
|
|
+ * The old pointer in struct net_device will be gradually phased
|
|
+ * out, and drivers are encouraged to use this one... */
|
|
+ struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
|
|
};
|
|
|
|
/* ---------------------- IOCTL DESCRIPTION ---------------------- */
|
|
@@ -374,18 +384,29 @@ struct iw_ioctl_description
|
|
*/
|
|
struct iw_spy_data
|
|
{
|
|
-#ifdef IW_WIRELESS_SPY
|
|
/* --- Standard spy support --- */
|
|
int spy_number;
|
|
u_char spy_address[IW_MAX_SPY][ETH_ALEN];
|
|
struct iw_quality spy_stat[IW_MAX_SPY];
|
|
-#ifdef IW_WIRELESS_THRSPY
|
|
/* --- Enhanced spy support (event) */
|
|
struct iw_quality spy_thr_low; /* Low threshold */
|
|
struct iw_quality spy_thr_high; /* High threshold */
|
|
u_char spy_thr_under[IW_MAX_SPY];
|
|
-#endif /* IW_WIRELESS_THRSPY */
|
|
-#endif /* IW_WIRELESS_SPY */
|
|
+};
|
|
+
|
|
+/* --------------------- DEVICE WIRELESS DATA --------------------- */
|
|
+/*
|
|
+ * This is all the wireless data specific to a device instance that
|
|
+ * is managed by the core of Wireless Extensions.
|
|
+ * We only keep pointer to those structures, so that a driver is free
|
|
+ * to share them between instances.
|
|
+ * This structure should be initialised before registering the device.
|
|
+ * Access to this data follow the same rules as any other struct net_device
|
|
+ * data (i.e. valid as long as struct net_device exist, same locking rules).
|
|
+ */
|
|
+struct iw_public_data {
|
|
+ /* Driver enhanced spy support */
|
|
+ struct iw_spy_data * spy_data;
|
|
};
|
|
|
|
/**************************** PROTOTYPES ****************************/
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -2426,7 +2426,7 @@ int dev_ioctl(unsigned int cmd, void *ar
|
|
/* Follow me in net/core/wireless.c */
|
|
ret = wireless_process_ioctl(&ifr, cmd);
|
|
rtnl_unlock();
|
|
- if (!ret && IW_IS_GET(cmd) &&
|
|
+ if (IW_IS_GET(cmd) &&
|
|
copy_to_user(arg, &ifr, sizeof(struct ifreq)))
|
|
return -EFAULT;
|
|
return ret;
|
|
--- a/net/core/wireless.c
|
|
+++ b/net/core/wireless.c
|
|
@@ -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 @@ static const struct iw_ioctl_description
|
|
{ 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 @@ static const struct iw_ioctl_description
|
|
{ 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 @@ static const struct iw_ioctl_description
|
|
{ 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 iw_handler get_handler(str
|
|
*/
|
|
static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
|
|
{
|
|
+ /* New location */
|
|
+ if((dev->wireless_handlers != NULL) &&
|
|
+ (dev->wireless_handlers->get_wireless_stats != NULL))
|
|
+ return dev->wireless_handlers->get_wireless_stats(dev);
|
|
+
|
|
+ /* Old location, will be phased out in next WE */
|
|
return (dev->get_wireless_stats ?
|
|
dev->get_wireless_stats(dev) :
|
|
(struct iw_statistics *) NULL);
|
|
- /* In the future, get_wireless_stats may move from 'struct net_device'
|
|
- * to 'struct iw_handler_def', to de-bloat struct net_device.
|
|
- * Definitely worse a thought... */
|
|
}
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
@@ -310,14 +348,32 @@ static inline int call_commit_handler(st
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
/*
|
|
- * Number of private arguments
|
|
+ * Calculate size of private arguments
|
|
*/
|
|
static inline int get_priv_size(__u16 args)
|
|
{
|
|
int num = args & IW_PRIV_SIZE_MASK;
|
|
int type = (args & IW_PRIV_TYPE_MASK) >> 12;
|
|
|
|
- return num * priv_type_size[type];
|
|
+ return num * iw_priv_type_size[type];
|
|
+}
|
|
+
|
|
+/* ---------------------------------------------------------------- */
|
|
+/*
|
|
+ * Re-calculate the size of private arguments
|
|
+ */
|
|
+static inline int adjust_priv_size(__u16 args,
|
|
+ union iwreq_data * wrqu)
|
|
+{
|
|
+ int num = wrqu->data.length;
|
|
+ int max = args & IW_PRIV_SIZE_MASK;
|
|
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
|
|
+
|
|
+ /* Make sure the driver doesn't goof up */
|
|
+ if (max < num)
|
|
+ num = max;
|
|
+
|
|
+ return num * iw_priv_type_size[type];
|
|
}
|
|
|
|
|
|
@@ -350,11 +406,14 @@ static inline int sprintf_wireless_stats
|
|
dev->name,
|
|
stats->status,
|
|
stats->qual.qual,
|
|
- stats->qual.updated & 1 ? '.' : ' ',
|
|
+ stats->qual.updated & IW_QUAL_QUAL_UPDATED
|
|
+ ? '.' : ' ',
|
|
((__u8) stats->qual.level),
|
|
- stats->qual.updated & 2 ? '.' : ' ',
|
|
+ stats->qual.updated & IW_QUAL_LEVEL_UPDATED
|
|
+ ? '.' : ' ',
|
|
((__u8) stats->qual.noise),
|
|
- stats->qual.updated & 4 ? '.' : ' ',
|
|
+ stats->qual.updated & IW_QUAL_NOISE_UPDATED
|
|
+ ? '.' : ' ',
|
|
stats->discard.nwid,
|
|
stats->discard.code,
|
|
stats->discard.fragment,
|
|
@@ -470,13 +529,15 @@ static inline int ioctl_export_private(s
|
|
/* Check NULL pointer */
|
|
if(iwr->u.data.pointer == NULL)
|
|
return -EFAULT;
|
|
-#ifdef WE_STRICT_WRITE
|
|
+
|
|
/* Check if there is enough buffer up there */
|
|
if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
|
|
- printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
|
|
+ /* User space can't know in advance how large the buffer
|
|
+ * needs to be. Give it a hint, so that we can support
|
|
+ * any size buffer we want somewhat efficiently... */
|
|
+ iwr->u.data.length = dev->wireless_handlers->num_private_args;
|
|
return -E2BIG;
|
|
}
|
|
-#endif /* WE_STRICT_WRITE */
|
|
|
|
/* Set the number of available ioctls. */
|
|
iwr->u.data.length = dev->wireless_handlers->num_private_args;
|
|
@@ -505,7 +566,6 @@ static inline int ioctl_standard_call(st
|
|
const struct iw_ioctl_description * descr;
|
|
struct iw_request_info info;
|
|
int ret = -EINVAL;
|
|
- int user_size = 0;
|
|
|
|
/* Get the description of the IOCTL */
|
|
if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
|
|
@@ -536,8 +596,14 @@ static inline int ioctl_standard_call(st
|
|
#endif /* WE_SET_EVENT */
|
|
} else {
|
|
char * extra;
|
|
+ int extra_size;
|
|
+ int user_length = 0;
|
|
int err;
|
|
|
|
+ /* Calculate space needed by arguments. Always allocate
|
|
+ * for max space. Easier, and won't last long... */
|
|
+ extra_size = descr->max_tokens * descr->token_size;
|
|
+
|
|
/* Check what user space is giving us */
|
|
if(IW_IS_SET(cmd)) {
|
|
/* Check NULL pointer */
|
|
@@ -554,18 +620,33 @@ static inline int ioctl_standard_call(st
|
|
if(iwr->u.data.pointer == NULL)
|
|
return -EFAULT;
|
|
/* Save user space buffer size for checking */
|
|
- user_size = iwr->u.data.length;
|
|
+ user_length = iwr->u.data.length;
|
|
+
|
|
+ /* Don't check if user_length > max to allow forward
|
|
+ * compatibility. The test user_length < min is
|
|
+ * implied by the test at the end. */
|
|
+
|
|
+ /* Support for very large requests */
|
|
+ if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
|
|
+ (user_length > descr->max_tokens)) {
|
|
+ /* Allow userspace to GET more than max so
|
|
+ * we can support any size GET requests.
|
|
+ * There is still a limit : -ENOMEM. */
|
|
+ extra_size = user_length * descr->token_size;
|
|
+ /* Note : user_length is originally a __u16,
|
|
+ * and token_size is controlled by us,
|
|
+ * so extra_size won't get negative and
|
|
+ * won't overflow... */
|
|
+ }
|
|
}
|
|
|
|
#ifdef WE_IOCTL_DEBUG
|
|
printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
|
|
- dev->name, descr->max_tokens * descr->token_size);
|
|
+ dev->name, extra_size);
|
|
#endif /* WE_IOCTL_DEBUG */
|
|
|
|
- /* Always allocate for max space. Easier, and won't last
|
|
- * long... */
|
|
- extra = kmalloc(descr->max_tokens * descr->token_size,
|
|
- GFP_KERNEL);
|
|
+ /* Create the kernel buffer */
|
|
+ extra = kmalloc(extra_size, GFP_KERNEL);
|
|
if (extra == NULL) {
|
|
return -ENOMEM;
|
|
}
|
|
@@ -591,14 +672,11 @@ static inline int ioctl_standard_call(st
|
|
|
|
/* If we have something to return to the user */
|
|
if (!ret && IW_IS_GET(cmd)) {
|
|
-#ifdef WE_STRICT_WRITE
|
|
/* Check if there is enough buffer up there */
|
|
- if(user_size < iwr->u.data.length) {
|
|
- printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
|
|
+ if(user_length < iwr->u.data.length) {
|
|
kfree(extra);
|
|
return -E2BIG;
|
|
}
|
|
-#endif /* WE_STRICT_WRITE */
|
|
|
|
err = copy_to_user(iwr->u.data.pointer, extra,
|
|
iwr->u.data.length *
|
|
@@ -661,7 +739,7 @@ static inline int ioctl_private_call(str
|
|
iw_handler handler)
|
|
{
|
|
struct iwreq * iwr = (struct iwreq *) ifr;
|
|
- struct iw_priv_args * descr = NULL;
|
|
+ const struct iw_priv_args * descr = NULL;
|
|
struct iw_request_info info;
|
|
int extra_size = 0;
|
|
int i;
|
|
@@ -701,7 +779,7 @@ static inline int ioctl_private_call(str
|
|
((extra_size + offset) <= IFNAMSIZ))
|
|
extra_size = 0;
|
|
} else {
|
|
- /* Size of set arguments */
|
|
+ /* Size of get arguments */
|
|
extra_size = get_priv_size(descr->get_args);
|
|
|
|
/* Does it fits in iwr ? */
|
|
@@ -771,6 +849,14 @@ static inline int ioctl_private_call(str
|
|
|
|
/* If we have something to return to the user */
|
|
if (!ret && IW_IS_GET(cmd)) {
|
|
+
|
|
+ /* Adjust for the actual length if it's variable,
|
|
+ * avoid leaking kernel bits outside. */
|
|
+ if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
|
|
+ extra_size = adjust_priv_size(descr->get_args,
|
|
+ &(iwr->u));
|
|
+ }
|
|
+
|
|
err = copy_to_user(iwr->u.data.pointer, extra,
|
|
extra_size);
|
|
if (err)
|
|
@@ -1042,9 +1128,25 @@ void wireless_send_event(struct net_devi
|
|
* One of the main advantage of centralising spy support here is that
|
|
* it becomes much easier to improve and extend it without having to touch
|
|
* the drivers. One example is the addition of the Spy-Threshold events.
|
|
- * Note : IW_WIRELESS_SPY is defined in iw_handler.h
|
|
*/
|
|
|
|
+/* ---------------------------------------------------------------- */
|
|
+/*
|
|
+ * Return the pointer to the spy data in the driver.
|
|
+ * Because this is called on the Rx path via wireless_spy_update(),
|
|
+ * we want it to be efficient...
|
|
+ */
|
|
+static inline struct iw_spy_data * get_spydata(struct net_device *dev)
|
|
+{
|
|
+ /* This is the new way */
|
|
+ if(dev->wireless_data)
|
|
+ return(dev->wireless_data->spy_data);
|
|
+
|
|
+ /* This is the old way. Doesn't work for multi-headed drivers.
|
|
+ * It will be removed in the next version of WE. */
|
|
+ return (dev->priv + dev->wireless_handlers->spy_offset);
|
|
+}
|
|
+
|
|
/*------------------------------------------------------------------*/
|
|
/*
|
|
* Standard Wireless Handler : set Spy List
|
|
@@ -1054,16 +1156,26 @@ int iw_handler_set_spy(struct net_device
|
|
union iwreq_data * wrqu,
|
|
char * extra)
|
|
{
|
|
-#ifdef IW_WIRELESS_SPY
|
|
- struct iw_spy_data * spydata = (dev->priv +
|
|
- dev->wireless_handlers->spy_offset);
|
|
+ struct iw_spy_data * spydata = get_spydata(dev);
|
|
struct sockaddr * address = (struct sockaddr *) extra;
|
|
|
|
+ /* Make sure driver is not buggy or using the old API */
|
|
+ if(!spydata)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
/* Disable spy collection while we copy the addresses.
|
|
- * As we don't disable interrupts, we need to do this to avoid races.
|
|
- * As we are the only writer, this is good enough. */
|
|
+ * While we copy addresses, any call to wireless_spy_update()
|
|
+ * will NOP. This is OK, as anyway the addresses are changing. */
|
|
spydata->spy_number = 0;
|
|
|
|
+ /* We want to operate without locking, because wireless_spy_update()
|
|
+ * most likely will happen in the interrupt handler, and therefore
|
|
+ * have its own locking constraints and needs performance.
|
|
+ * The rtnl_lock() make sure we don't race with the other iw_handlers.
|
|
+ * This make sure wireless_spy_update() "see" that the spy list
|
|
+ * is temporarily disabled. */
|
|
+ wmb();
|
|
+
|
|
/* Are there are addresses to copy? */
|
|
if(wrqu->data.length > 0) {
|
|
int i;
|
|
@@ -1089,13 +1201,14 @@ int iw_handler_set_spy(struct net_device
|
|
spydata->spy_address[i][5]);
|
|
#endif /* WE_SPY_DEBUG */
|
|
}
|
|
+
|
|
+ /* Make sure above is updated before re-enabling */
|
|
+ wmb();
|
|
+
|
|
/* Enable addresses */
|
|
spydata->spy_number = wrqu->data.length;
|
|
|
|
return 0;
|
|
-#else /* IW_WIRELESS_SPY */
|
|
- return -EOPNOTSUPP;
|
|
-#endif /* IW_WIRELESS_SPY */
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
@@ -1107,12 +1220,14 @@ int iw_handler_get_spy(struct net_device
|
|
union iwreq_data * wrqu,
|
|
char * extra)
|
|
{
|
|
-#ifdef IW_WIRELESS_SPY
|
|
- struct iw_spy_data * spydata = (dev->priv +
|
|
- dev->wireless_handlers->spy_offset);
|
|
+ struct iw_spy_data * spydata = get_spydata(dev);
|
|
struct sockaddr * address = (struct sockaddr *) extra;
|
|
int i;
|
|
|
|
+ /* Make sure driver is not buggy or using the old API */
|
|
+ if(!spydata)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
wrqu->data.length = spydata->spy_number;
|
|
|
|
/* Copy addresses. */
|
|
@@ -1129,9 +1244,6 @@ int iw_handler_get_spy(struct net_device
|
|
for(i = 0; i < spydata->spy_number; i++)
|
|
spydata->spy_stat[i].updated = 0;
|
|
return 0;
|
|
-#else /* IW_WIRELESS_SPY */
|
|
- return -EOPNOTSUPP;
|
|
-#endif /* IW_WIRELESS_SPY */
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
@@ -1143,11 +1255,13 @@ int iw_handler_set_thrspy(struct net_dev
|
|
union iwreq_data * wrqu,
|
|
char * extra)
|
|
{
|
|
-#ifdef IW_WIRELESS_THRSPY
|
|
- struct iw_spy_data * spydata = (dev->priv +
|
|
- dev->wireless_handlers->spy_offset);
|
|
+ struct iw_spy_data * spydata = get_spydata(dev);
|
|
struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
|
|
|
|
+ /* Make sure driver is not buggy or using the old API */
|
|
+ if(!spydata)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
/* Just do it */
|
|
memcpy(&(spydata->spy_thr_low), &(threshold->low),
|
|
2 * sizeof(struct iw_quality));
|
|
@@ -1160,9 +1274,6 @@ int iw_handler_set_thrspy(struct net_dev
|
|
#endif /* WE_SPY_DEBUG */
|
|
|
|
return 0;
|
|
-#else /* IW_WIRELESS_THRSPY */
|
|
- return -EOPNOTSUPP;
|
|
-#endif /* IW_WIRELESS_THRSPY */
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
@@ -1174,22 +1285,20 @@ int iw_handler_get_thrspy(struct net_dev
|
|
union iwreq_data * wrqu,
|
|
char * extra)
|
|
{
|
|
-#ifdef IW_WIRELESS_THRSPY
|
|
- struct iw_spy_data * spydata = (dev->priv +
|
|
- dev->wireless_handlers->spy_offset);
|
|
+ struct iw_spy_data * spydata = get_spydata(dev);
|
|
struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
|
|
|
|
+ /* Make sure driver is not buggy or using the old API */
|
|
+ if(!spydata)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
/* Just do it */
|
|
memcpy(&(threshold->low), &(spydata->spy_thr_low),
|
|
2 * sizeof(struct iw_quality));
|
|
|
|
return 0;
|
|
-#else /* IW_WIRELESS_THRSPY */
|
|
- return -EOPNOTSUPP;
|
|
-#endif /* IW_WIRELESS_THRSPY */
|
|
}
|
|
|
|
-#ifdef IW_WIRELESS_THRSPY
|
|
/*------------------------------------------------------------------*/
|
|
/*
|
|
* Prepare and send a Spy Threshold event
|
|
@@ -1227,7 +1336,6 @@ static void iw_send_thrspy_event(struct
|
|
/* Send event to user space */
|
|
wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
|
|
}
|
|
-#endif /* IW_WIRELESS_THRSPY */
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
/*
|
|
@@ -1240,12 +1348,14 @@ void wireless_spy_update(struct net_devi
|
|
unsigned char * address,
|
|
struct iw_quality * wstats)
|
|
{
|
|
-#ifdef IW_WIRELESS_SPY
|
|
- struct iw_spy_data * spydata = (dev->priv +
|
|
- dev->wireless_handlers->spy_offset);
|
|
+ struct iw_spy_data * spydata = get_spydata(dev);
|
|
int i;
|
|
int match = -1;
|
|
|
|
+ /* Make sure driver is not buggy or using the old API */
|
|
+ if(!spydata)
|
|
+ return;
|
|
+
|
|
#ifdef WE_SPY_DEBUG
|
|
printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
|
|
#endif /* WE_SPY_DEBUG */
|
|
@@ -1257,7 +1367,7 @@ void wireless_spy_update(struct net_devi
|
|
sizeof(struct iw_quality));
|
|
match = i;
|
|
}
|
|
-#ifdef IW_WIRELESS_THRSPY
|
|
+
|
|
/* Generate an event if we cross the spy threshold.
|
|
* To avoid event storms, we have a simple hysteresis : we generate
|
|
* event only when we go under the low threshold or above the
|
|
@@ -1277,6 +1387,4 @@ void wireless_spy_update(struct net_devi
|
|
}
|
|
}
|
|
}
|
|
-#endif /* IW_WIRELESS_THRSPY */
|
|
-#endif /* IW_WIRELESS_SPY */
|
|
}
|