Commit deeee3bf authored by Jeff Garzik's avatar Jeff Garzik

Merge pobox.com:/spare/repo/netdev-2.6/wireless-ext

into pobox.com:/spare/repo/net-drivers-2.6
parents a4946826 4958c29f
...@@ -1189,6 +1189,7 @@ struct airo_info { ...@@ -1189,6 +1189,7 @@ struct airo_info {
struct iw_statistics wstats; // wireless stats struct iw_statistics wstats; // wireless stats
unsigned long scan_timestamp; /* Time started to scan */ unsigned long scan_timestamp; /* Time started to scan */
struct iw_spy_data spy_data; struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
#ifdef MICSUPPORT #ifdef MICSUPPORT
/* MIC stuff */ /* MIC stuff */
...@@ -2640,8 +2641,7 @@ static void wifi_setup(struct net_device *dev) ...@@ -2640,8 +2641,7 @@ static void wifi_setup(struct net_device *dev)
dev->set_mac_address = &airo_set_mac_address; dev->set_mac_address = &airo_set_mac_address;
dev->do_ioctl = &airo_ioctl; dev->do_ioctl = &airo_ioctl;
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
dev->get_wireless_stats = airo_get_wireless_stats; dev->wireless_handlers = &airo_handler_def;
dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu; dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open; dev->open = &airo_open;
...@@ -2668,6 +2668,9 @@ static struct net_device *init_wifidev(struct airo_info *ai, ...@@ -2668,6 +2668,9 @@ static struct net_device *init_wifidev(struct airo_info *ai,
dev->priv = ethdev->priv; dev->priv = ethdev->priv;
dev->irq = ethdev->irq; dev->irq = ethdev->irq;
dev->base_addr = ethdev->base_addr; dev->base_addr = ethdev->base_addr;
#ifdef WIRELESS_EXT
dev->wireless_data = ethdev->wireless_data;
#endif /* WIRELESS_EXT */
memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
err = register_netdev(dev); err = register_netdev(dev);
if (err<0) { if (err<0) {
...@@ -2747,8 +2750,9 @@ struct net_device *_init_airo_card( unsigned short irq, int port, ...@@ -2747,8 +2750,9 @@ struct net_device *_init_airo_card( unsigned short irq, int port,
dev->set_mac_address = &airo_set_mac_address; dev->set_mac_address = &airo_set_mac_address;
dev->do_ioctl = &airo_ioctl; dev->do_ioctl = &airo_ioctl;
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
dev->get_wireless_stats = airo_get_wireless_stats; dev->wireless_handlers = &airo_handler_def;
dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def; ai->wireless_data.spy_data = &ai->spy_data;
dev->wireless_data = &ai->wireless_data;
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
dev->change_mtu = &airo_change_mtu; dev->change_mtu = &airo_change_mtu;
dev->open = &airo_open; dev->open = &airo_open;
...@@ -3231,7 +3235,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -3231,7 +3235,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
goto exitrx; goto exitrx;
} }
} }
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ #ifdef WIRELESS_SPY
if (apriv->spy_data.spy_number > 0) { if (apriv->spy_data.spy_number > 0) {
char *sa; char *sa;
struct iw_quality wstats; struct iw_quality wstats;
...@@ -3251,7 +3255,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -3251,7 +3255,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
/* Update spy records */ /* Update spy records */
wireless_spy_update(dev, sa, &wstats); wireless_spy_update(dev, sa, &wstats);
} }
#endif /* IW_WIRELESS_SPY */ #endif /* WIRELESS_SPY */
OUT4500( apriv, EVACK, EV_RX); OUT4500( apriv, EVACK, EV_RX);
if (test_bit(FLAG_802_11, &apriv->flags)) { if (test_bit(FLAG_802_11, &apriv->flags)) {
...@@ -3476,7 +3480,7 @@ static void mpi_receive_802_3(struct airo_info *ai) ...@@ -3476,7 +3480,7 @@ static void mpi_receive_802_3(struct airo_info *ai)
#else #else
memcpy(buffer, ai->rxfids[0].virtual_host_addr, len); memcpy(buffer, ai->rxfids[0].virtual_host_addr, len);
#endif #endif
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ #ifdef WIRELESS_SPY
if (ai->spy_data.spy_number > 0) { if (ai->spy_data.spy_number > 0) {
char *sa; char *sa;
struct iw_quality wstats; struct iw_quality wstats;
...@@ -3488,7 +3492,7 @@ static void mpi_receive_802_3(struct airo_info *ai) ...@@ -3488,7 +3492,7 @@ static void mpi_receive_802_3(struct airo_info *ai)
/* Update spy records */ /* Update spy records */
wireless_spy_update(ai->dev, sa, &wstats); wireless_spy_update(ai->dev, sa, &wstats);
} }
#endif /* IW_WIRELESS_SPY */ #endif /* WIRELESS_SPY */
skb->dev = ai->dev; skb->dev = ai->dev;
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
...@@ -6520,6 +6524,13 @@ static int airo_get_range(struct net_device *dev, ...@@ -6520,6 +6524,13 @@ static int airo_get_range(struct net_device *dev,
range->avg_qual.level = 176; /* -80 dBm */ range->avg_qual.level = 176; /* -80 dBm */
range->avg_qual.noise = 0; range->avg_qual.noise = 0;
/* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
IW_EVENT_CAPA_MASK(SIOCGIWAP) |
IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
range->event_capa[1] = IW_EVENT_CAPA_K_1;
range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
return 0; return 0;
} }
...@@ -6887,9 +6898,15 @@ static int airo_get_scan(struct net_device *dev, ...@@ -6887,9 +6898,15 @@ static int airo_get_scan(struct net_device *dev,
while((!rc) && (BSSList.index != 0xffff)) { while((!rc) && (BSSList.index != 0xffff)) {
/* Translate to WE format this entry */ /* Translate to WE format this entry */
current_ev = airo_translate_scan(dev, current_ev, current_ev = airo_translate_scan(dev, current_ev,
extra + IW_SCAN_MAX_DATA, extra + dwrq->length,
&BSSList); &BSSList);
/* Check if there is space for one more entry */
if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
/* Ask user space to try again with a bigger buffer */
return -E2BIG;
}
/* Read next entry */ /* Read next entry */
rc = PC4500_readrid(ai, RID_BSSLISTNEXT, rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
&BSSList, sizeof(BSSList), 1); &BSSList, sizeof(BSSList), 1);
...@@ -7025,12 +7042,10 @@ static const struct iw_handler_def airo_handler_def = ...@@ -7025,12 +7042,10 @@ static const struct iw_handler_def airo_handler_def =
.num_standard = sizeof(airo_handler)/sizeof(iw_handler), .num_standard = sizeof(airo_handler)/sizeof(iw_handler),
.num_private = sizeof(airo_private_handler)/sizeof(iw_handler), .num_private = sizeof(airo_private_handler)/sizeof(iw_handler),
.num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args), .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args),
.standard = (iw_handler *) airo_handler, .standard = airo_handler,
.private = (iw_handler *) airo_private_handler, .private = airo_private_handler,
.private_args = (struct iw_priv_args *) airo_private_args, .private_args = airo_private_args,
.spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) - .get_wireless_stats = airo_get_wireless_stats,
(void *) NULL),
}; };
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
......
...@@ -2172,6 +2172,11 @@ static int wavelan_get_range(struct net_device *dev, ...@@ -2172,6 +2172,11 @@ static int wavelan_get_range(struct net_device *dev,
range->num_bitrates = 1; range->num_bitrates = 1;
range->bitrate[0] = 2000000; /* 2 Mb/s */ range->bitrate[0] = 2000000; /* 2 Mb/s */
/* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) |
IW_EVENT_CAPA_MASK(0x8B04));
range->event_capa[1] = IW_EVENT_CAPA_K_1;
/* Disable interrupts and save flags. */ /* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags); spin_lock_irqsave(&lp->spinlock, flags);
...@@ -2403,11 +2408,10 @@ static const struct iw_handler_def wavelan_handler_def = ...@@ -2403,11 +2408,10 @@ static const struct iw_handler_def wavelan_handler_def =
.num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler),
.num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler),
.num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
.standard = (iw_handler *) wavelan_handler, .standard = wavelan_handler,
.private = (iw_handler *) wavelan_private_handler, .private = wavelan_private_handler,
.private_args = (struct iw_priv_args *) wavelan_private_args, .private_args = wavelan_private_args,
.spy_offset = ((void *) (&((net_local *) NULL)->spy_data) - .get_wireless_stats = wavelan_get_wireless_stats,
(void *) NULL),
}; };
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -4191,8 +4195,9 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) ...@@ -4191,8 +4195,9 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr)
#endif /* SET_MAC_ADDRESS */ #endif /* SET_MAC_ADDRESS */
#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->get_wireless_stats = wavelan_get_wireless_stats; dev->wireless_handlers = &wavelan_handler_def;
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; lp->wireless_data.spy_data = &lp->spy_data;
dev->wireless_data = &lp->wireless_data;
#endif #endif
dev->mtu = WAVELAN_MTU; dev->mtu = WAVELAN_MTU;
......
...@@ -510,6 +510,7 @@ struct net_local ...@@ -510,6 +510,7 @@ struct net_local
iw_stats wstats; /* Wireless-specific statistics */ iw_stats wstats; /* Wireless-specific statistics */
struct iw_spy_data spy_data; struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
#endif #endif
#ifdef HISTOGRAM #ifdef HISTOGRAM
...@@ -614,6 +615,8 @@ static inline void ...@@ -614,6 +615,8 @@ static inline void
/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */
static en_stats * static en_stats *
wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */
static iw_stats *
wavelan_get_wireless_stats(struct net_device *);
static void static void
wavelan_set_multicast_list(struct net_device *); wavelan_set_multicast_list(struct net_device *);
/* ----------------------- PACKET RECEPTION ----------------------- */ /* ----------------------- PACKET RECEPTION ----------------------- */
......
...@@ -1550,7 +1550,6 @@ wavelan_set_mac_address(struct net_device * dev, ...@@ -1550,7 +1550,6 @@ wavelan_set_mac_address(struct net_device * dev,
/* /*
* Frequency setting (for hardware able of it) * Frequency setting (for hardware able of it)
* It's a bit complicated and you don't really want to look into it... * It's a bit complicated and you don't really want to look into it...
* (called in wavelan_ioctl)
*/ */
static inline int static inline int
wv_set_frequency(u_long base, /* i/o port of the card */ wv_set_frequency(u_long base, /* i/o port of the card */
...@@ -2438,6 +2437,12 @@ static int wavelan_get_range(struct net_device *dev, ...@@ -2438,6 +2437,12 @@ static int wavelan_get_range(struct net_device *dev,
range->num_bitrates = 1; range->num_bitrates = 1;
range->bitrate[0] = 2000000; /* 2 Mb/s */ range->bitrate[0] = 2000000; /* 2 Mb/s */
/* Event capability (kernel + driver) */
range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) |
IW_EVENT_CAPA_MASK(0x8B04) |
IW_EVENT_CAPA_MASK(0x8B06));
range->event_capa[1] = IW_EVENT_CAPA_K_1;
/* Disable interrupts and save flags. */ /* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags); spin_lock_irqsave(&lp->spinlock, flags);
...@@ -2737,11 +2742,10 @@ static const struct iw_handler_def wavelan_handler_def = ...@@ -2737,11 +2742,10 @@ static const struct iw_handler_def wavelan_handler_def =
.num_standard = sizeof(wavelan_handler)/sizeof(iw_handler), .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler),
.num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler), .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler),
.num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args), .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
.standard = (iw_handler *) wavelan_handler, .standard = wavelan_handler,
.private = (iw_handler *) wavelan_private_handler, .private = wavelan_private_handler,
.private_args = (struct iw_priv_args *) wavelan_private_args, .private_args = wavelan_private_args,
.spy_offset = ((void *) (&((net_local *) NULL)->spy_data) - .get_wireless_stats = wavelan_get_wireless_stats,
(void *) NULL),
}; };
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -4720,9 +4724,10 @@ wavelan_attach(void) ...@@ -4720,9 +4724,10 @@ wavelan_attach(void)
dev->watchdog_timeo = WATCHDOG_JIFFIES; dev->watchdog_timeo = WATCHDOG_JIFFIES;
#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def; dev->wireless_handlers = &wavelan_handler_def;
dev->do_ioctl = wavelan_ioctl; /* old wireless extensions */ dev->do_ioctl = wavelan_ioctl; /* ethtool */
dev->get_wireless_stats = wavelan_get_wireless_stats; lp->wireless_data.spy_data = &lp->spy_data;
dev->wireless_data = &lp->wireless_data;
#endif #endif
/* Other specific data */ /* Other specific data */
......
...@@ -629,6 +629,7 @@ struct net_local ...@@ -629,6 +629,7 @@ struct net_local
iw_stats wstats; /* Wireless specific stats */ iw_stats wstats; /* Wireless specific stats */
struct iw_spy_data spy_data; struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
#endif #endif
#ifdef HISTOGRAM #ifdef HISTOGRAM
...@@ -725,6 +726,8 @@ static inline void ...@@ -725,6 +726,8 @@ static inline void
/* ------------------- IOCTL, STATS & RECONFIG ------------------- */ /* ------------------- IOCTL, STATS & RECONFIG ------------------- */
static en_stats * static en_stats *
wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */ wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */
static iw_stats *
wavelan_get_wireless_stats(struct net_device *);
/* ----------------------- PACKET RECEPTION ----------------------- */ /* ----------------------- PACKET RECEPTION ----------------------- */
static inline int static inline int
wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */ wv_start_of_frame(struct net_device *, /* Seek beggining of current frame */
......
...@@ -309,7 +309,9 @@ struct net_device ...@@ -309,7 +309,9 @@ struct net_device
/* List of functions to handle Wireless Extensions (instead of ioctl). /* List of functions to handle Wireless Extensions (instead of ioctl).
* See <net/iw_handler.h> for details. Jean II */ * 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; struct ethtool_ops *ethtool_ops;
......
/* /*
* This file define a set of standard wireless extensions * This file define a set of standard wireless extensions
* *
* Version : 16 2.4.03 * Version : 17 21.6.04
* *
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
*/ */
#ifndef _LINUX_WIRELESS_H #ifndef _LINUX_WIRELESS_H
...@@ -47,12 +47,12 @@ ...@@ -47,12 +47,12 @@
* # include/net/iw_handler.h * # include/net/iw_handler.h
* *
* Note as well that /proc/net/wireless implementation has now moved in : * Note as well that /proc/net/wireless implementation has now moved in :
* # include/linux/wireless.c * # net/core/wireless.c
* *
* Wireless Events (2002 -> onward) : * Wireless Events (2002 -> onward) :
* -------------------------------- * --------------------------------
* Events are defined at the end of this file, and implemented in : * Events are defined at the end of this file, and implemented in :
* # include/linux/wireless.c * # net/core/wireless.c
* *
* Other comments : * Other comments :
* -------------- * --------------
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
* (there is some stuff that will be added in the future...) * (there is some stuff that will be added in the future...)
* I just plan to increment with each new version. * I just plan to increment with each new version.
*/ */
#define WIRELESS_EXT 16 #define WIRELESS_EXT 17
/* /*
* Changes : * Changes :
...@@ -175,6 +175,13 @@ ...@@ -175,6 +175,13 @@
* - Remove IW_MAX_GET_SPY because conflict with enhanced spy support * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
* - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
* - Add IW_ENCODE_TEMP and iw_range->encoding_login_index * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
*
* V16 to V17
* ----------
* - Add flags to frequency -> auto/fixed
* - Document (struct iw_quality *)->updated, add new flags (INVALID)
* - Wireless Event capability in struct iw_range
* - Add support for relative TxPower (yick !)
*/ */
/**************************** CONSTANTS ****************************/ /**************************** CONSTANTS ****************************/
...@@ -251,7 +258,7 @@ ...@@ -251,7 +258,7 @@
/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ /* -------------------- 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, * Each driver is free to use them for whatever purpose it chooses,
* however the driver *must* export the description of those ioctls * however the driver *must* export the description of those ioctls
* with SIOCGIWPRIV and *must* use arguments as defined below. * with SIOCGIWPRIV and *must* use arguments as defined below.
...@@ -266,8 +273,8 @@ ...@@ -266,8 +273,8 @@
* We now have 32 commands, so a bit more space ;-). * We now have 32 commands, so a bit more space ;-).
* Also, all 'odd' commands are only usable by root and don't return the * 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 * content of ifr/iwr to user (but you are not obliged to use the set/get
* convention, just use every other two command). * convention, just use every other two command). More details in iwpriv.c.
* And I repeat : you are not obliged to use them with iwspy, but you * And I repeat : you are not forced to use them with iwpriv, but you
* must be compliant with it. * must be compliant with it.
*/ */
...@@ -352,6 +359,18 @@ ...@@ -352,6 +359,18 @@
#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ #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 /* Maximum number of size of encoding token available
* they are listed in the range structure */ * they are listed in the range structure */
#define IW_MAX_ENCODING_SIZES 8 #define IW_MAX_ENCODING_SIZES 8
...@@ -390,6 +409,7 @@ ...@@ -390,6 +409,7 @@
#define IW_TXPOW_TYPE 0x00FF /* Type of value */ #define IW_TXPOW_TYPE 0x00FF /* Type of value */
#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ #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 */ #define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */
/* Retry limits and lifetime flags available */ /* Retry limits and lifetime flags available */
...@@ -418,6 +438,25 @@ ...@@ -418,6 +438,25 @@
/* Max number of char in custom event - use multiple of them if needed */ /* Max number of char in custom event - use multiple of them if needed */
#define IW_CUSTOM_MAX 256 /* In bytes */ #define IW_CUSTOM_MAX 256 /* In bytes */
/* Event capability macros - in (struct iw_range *)->event_capa
* Because we have more than 32 possible events, we use an array of
* 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \
(cmd - SIOCIWFIRSTPRIV + 0x60) : \
(cmd - SIOCSIWCOMMIT))
#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5)
#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
/* Event capability constants - event autogenerated by the kernel
* This list is valid for most 802.11 devices, customise as needed... */
#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \
IW_EVENT_CAPA_MASK(0x8B06) | \
IW_EVENT_CAPA_MASK(0x8B1A))
#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A))
/* "Easy" macro to set events in iw_range (less efficient) */
#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
/****************************** TYPES ******************************/ /****************************** TYPES ******************************/
/* --------------------------- SUBTYPES --------------------------- */ /* --------------------------- SUBTYPES --------------------------- */
...@@ -456,7 +495,7 @@ struct iw_freq ...@@ -456,7 +495,7 @@ struct iw_freq
__s32 m; /* Mantissa */ __s32 m; /* Mantissa */
__s16 e; /* Exponent */ __s16 e; /* Exponent */
__u8 i; /* List index (when in range struct) */ __u8 i; /* List index (when in range struct) */
__u8 pad; /* Unused - just for alignement */ __u8 flags; /* Flags (fixed/auto) */
}; };
/* /*
...@@ -610,11 +649,12 @@ struct iw_range ...@@ -610,11 +649,12 @@ struct iw_range
/* Old Frequency (backward compat - moved lower ) */ /* Old Frequency (backward compat - moved lower ) */
__u16 old_num_channels; __u16 old_num_channels;
__u8 old_num_frequency; __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 */ /* signal level threshold range */
__s32 sensitivity; __s32 sensitivity;
/* Quality of link & SNR stuff */ /* Quality of link & SNR stuff */
/* Quality range (link, level, noise) /* Quality range (link, level, noise)
......
/* /*
* This file define the new driver API for Wireless Extensions * 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> * 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 #ifndef _IW_HANDLER_H
...@@ -206,7 +206,7 @@ ...@@ -206,7 +206,7 @@
* will be needed... * will be needed...
* I just plan to increment with each new version. * I just plan to increment with each new version.
*/ */
#define IW_HANDLER_VERSION 5 #define IW_HANDLER_VERSION 6
/* /*
* Changes : * Changes :
...@@ -224,11 +224,18 @@ ...@@ -224,11 +224,18 @@
* V4 to V5 * V4 to V5
* -------- * --------
* - Add new spy support : struct iw_spy_data & prototypes * - 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 ****************************/ /**************************** CONSTANTS ****************************/
/* Enable enhanced spy support. Disable to reduce footprint */ /* Enhanced spy support available */
#define IW_WIRELESS_SPY #define IW_WIRELESS_SPY
#define IW_WIRELESS_THRSPY #define IW_WIRELESS_THRSPY
...@@ -258,6 +265,7 @@ ...@@ -258,6 +265,7 @@
#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
/* SET : Omit payload from generated iwevent */ /* SET : Omit payload from generated iwevent */
#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
/* Driver level flags */ /* Driver level flags */
#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
...@@ -303,31 +311,33 @@ struct iw_handler_def ...@@ -303,31 +311,33 @@ struct iw_handler_def
{ {
/* Number of handlers defined (more precisely, index of the /* Number of handlers defined (more precisely, index of the
* last defined handler + 1) */ * last defined handler + 1) */
__u16 num_standard; const __u16 num_standard;
__u16 num_private; const __u16 num_private;
/* Number of private arg description */ /* Number of private arg description */
__u16 num_private_args; const __u16 num_private_args;
/* Array of handlers for standard ioctls /* Array of handlers for standard ioctls
* We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME] * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
*/ */
iw_handler * standard; const iw_handler * standard;
/* Array of handlers for private ioctls /* Array of handlers for private ioctls
* Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] * 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 /* 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... * can put it in any order you want and should not leave holes...
* We will automatically export that to user space... */ * 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 */ /* This field will be *removed* in the next version of WE */
long spy_offset; /* Spy data offset */ const long spy_offset; /* DO NOT USE */
/* In the long term, get_wireless_stats will move from /* New location of get_wireless_stats, to de-bloat struct net_device.
* 'struct net_device' to here, to minimise bloat. */ * 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 ---------------------- */ /* ---------------------- IOCTL DESCRIPTION ---------------------- */
...@@ -374,18 +384,29 @@ struct iw_ioctl_description ...@@ -374,18 +384,29 @@ struct iw_ioctl_description
*/ */
struct iw_spy_data struct iw_spy_data
{ {
#ifdef IW_WIRELESS_SPY
/* --- Standard spy support --- */ /* --- Standard spy support --- */
int spy_number; int spy_number;
u_char spy_address[IW_MAX_SPY][ETH_ALEN]; u_char spy_address[IW_MAX_SPY][ETH_ALEN];
struct iw_quality spy_stat[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY];
#ifdef IW_WIRELESS_THRSPY
/* --- Enhanced spy support (event) */ /* --- Enhanced spy support (event) */
struct iw_quality spy_thr_low; /* Low threshold */ struct iw_quality spy_thr_low; /* Low threshold */
struct iw_quality spy_thr_high; /* High threshold */ struct iw_quality spy_thr_high; /* High threshold */
u_char spy_thr_under[IW_MAX_SPY]; 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 ****************************/ /**************************** PROTOTYPES ****************************/
...@@ -394,6 +415,9 @@ struct iw_spy_data ...@@ -394,6 +415,9 @@ struct iw_spy_data
* Those may be called only within the kernel. * Those may be called only within the kernel.
*/ */
/* Data needed by fs/compat_ioctl.c for 32->64 bit conversion */
extern const char iw_priv_type_size[];
/* First : function strictly used inside the kernel */ /* First : function strictly used inside the kernel */
/* Handle /proc/net/wireless, called in net/code/dev.c */ /* Handle /proc/net/wireless, called in net/code/dev.c */
......
...@@ -2745,7 +2745,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ...@@ -2745,7 +2745,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
/* Follow me in net/core/wireless.c */ /* Follow me in net/core/wireless.c */
ret = wireless_process_ioctl(&ifr, cmd); ret = wireless_process_ioctl(&ifr, cmd);
rtnl_unlock(); rtnl_unlock();
if (!ret && IW_IS_GET(cmd) && if (IW_IS_GET(cmd) &&
copy_to_user(arg, &ifr, copy_to_user(arg, &ifr,
sizeof(struct ifreq))) sizeof(struct ifreq)))
ret = -EFAULT; ret = -EFAULT;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* This file implement the Wireless Extensions APIs. * This file implement the Wireless Extensions APIs.
* *
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved. * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
* *
* (As all part of the Linux kernel, this file is GPL) * (As all part of the Linux kernel, this file is GPL)
*/ */
...@@ -48,6 +48,15 @@ ...@@ -48,6 +48,15 @@
* o Add common spy support : iw_handler_set_spy(), wireless_spy_update() * 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 enhanced spy support : iw_handler_set_thrspy() and event.
* o Add WIRELESS_EXT version display in /proc/net/wireless * 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 is user specifies length > max
* 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 *****************************/ /***************************** INCLUDES *****************************/
...@@ -69,10 +78,6 @@ ...@@ -69,10 +78,6 @@
/**************************** CONSTANTS ****************************/ /**************************** 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 */
/* Debugging stuff */ /* Debugging stuff */
#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
...@@ -186,6 +191,7 @@ static const struct iw_ioctl_description standard_ioctl[] = { ...@@ -186,6 +191,7 @@ static const struct iw_ioctl_description standard_ioctl[] = {
.token_size = sizeof(struct sockaddr) + .token_size = sizeof(struct sockaddr) +
sizeof(struct iw_quality), sizeof(struct iw_quality),
.max_tokens = IW_MAX_AP, .max_tokens = IW_MAX_AP,
.flags = IW_DESCR_FLAG_NOMAX,
}, },
[SIOCSIWSCAN - SIOCIWFIRST] = { [SIOCSIWSCAN - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM, .header_type = IW_HEADER_TYPE_PARAM,
...@@ -194,6 +200,7 @@ static const struct iw_ioctl_description standard_ioctl[] = { ...@@ -194,6 +200,7 @@ static const struct iw_ioctl_description standard_ioctl[] = {
.header_type = IW_HEADER_TYPE_POINT, .header_type = IW_HEADER_TYPE_POINT,
.token_size = 1, .token_size = 1,
.max_tokens = IW_SCAN_MAX_DATA, .max_tokens = IW_SCAN_MAX_DATA,
.flags = IW_DESCR_FLAG_NOMAX,
}, },
[SIOCSIWESSID - SIOCIWFIRST] = { [SIOCSIWESSID - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT, .header_type = IW_HEADER_TYPE_POINT,
...@@ -296,7 +303,7 @@ static const int standard_event_num = (sizeof(standard_event) / ...@@ -296,7 +303,7 @@ static const int standard_event_num = (sizeof(standard_event) /
sizeof(struct iw_ioctl_description)); sizeof(struct iw_ioctl_description));
/* Size (in bytes) of the various private data types */ /* Size (in bytes) of the various private data types */
static const char priv_type_size[] = { const char iw_priv_type_size[] = {
0, /* IW_PRIV_TYPE_NONE */ 0, /* IW_PRIV_TYPE_NONE */
1, /* IW_PRIV_TYPE_BYTE */ 1, /* IW_PRIV_TYPE_BYTE */
1, /* IW_PRIV_TYPE_CHAR */ 1, /* IW_PRIV_TYPE_CHAR */
...@@ -363,12 +370,15 @@ static inline iw_handler get_handler(struct net_device *dev, ...@@ -363,12 +370,15 @@ static inline iw_handler get_handler(struct net_device *dev,
*/ */
static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) 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 ? return (dev->get_wireless_stats ?
dev->get_wireless_stats(dev) : dev->get_wireless_stats(dev) :
(struct iw_statistics *) NULL); (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... */
} }
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
...@@ -403,14 +413,32 @@ static inline int call_commit_handler(struct net_device * dev) ...@@ -403,14 +413,32 @@ static inline int call_commit_handler(struct net_device * dev)
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
/* /*
* Number of private arguments * Calculate size of private arguments
*/ */
static inline int get_priv_size(__u16 args) static inline int get_priv_size(__u16 args)
{ {
int num = args & IW_PRIV_SIZE_MASK; int num = args & IW_PRIV_SIZE_MASK;
int type = (args & IW_PRIV_TYPE_MASK) >> 12; 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];
} }
...@@ -440,11 +468,14 @@ static __inline__ void wireless_seq_printf_stats(struct seq_file *seq, ...@@ -440,11 +468,14 @@ static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
"%6d %6d %6d\n", "%6d %6d %6d\n",
dev->name, stats->status, stats->qual.qual, dev->name, stats->status, stats->qual.qual,
stats->qual.updated & 1 ? '.' : ' ', stats->qual.updated & IW_QUAL_QUAL_UPDATED
? '.' : ' ',
((__u8) stats->qual.level), ((__u8) stats->qual.level),
stats->qual.updated & 2 ? '.' : ' ', stats->qual.updated & IW_QUAL_LEVEL_UPDATED
? '.' : ' ',
((__u8) stats->qual.noise), ((__u8) stats->qual.noise),
stats->qual.updated & 4 ? '.' : ' ', stats->qual.updated & IW_QUAL_NOISE_UPDATED
? '.' : ' ',
stats->discard.nwid, stats->discard.code, stats->discard.nwid, stats->discard.code,
stats->discard.fragment, stats->discard.retries, stats->discard.fragment, stats->discard.retries,
stats->discard.misc, stats->miss.beacon); stats->discard.misc, stats->miss.beacon);
...@@ -555,13 +586,15 @@ static inline int ioctl_export_private(struct net_device * dev, ...@@ -555,13 +586,15 @@ static inline int ioctl_export_private(struct net_device * dev,
/* Check NULL pointer */ /* Check NULL pointer */
if(iwr->u.data.pointer == NULL) if(iwr->u.data.pointer == NULL)
return -EFAULT; return -EFAULT;
#ifdef WE_STRICT_WRITE
/* Check if there is enough buffer up there */ /* Check if there is enough buffer up there */
if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { 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; return -E2BIG;
} }
#endif /* WE_STRICT_WRITE */
/* Set the number of available ioctls. */ /* Set the number of available ioctls. */
iwr->u.data.length = dev->wireless_handlers->num_private_args; iwr->u.data.length = dev->wireless_handlers->num_private_args;
...@@ -590,7 +623,6 @@ static inline int ioctl_standard_call(struct net_device * dev, ...@@ -590,7 +623,6 @@ static inline int ioctl_standard_call(struct net_device * dev,
const struct iw_ioctl_description * descr; const struct iw_ioctl_description * descr;
struct iw_request_info info; struct iw_request_info info;
int ret = -EINVAL; int ret = -EINVAL;
int user_size = 0;
/* Get the description of the IOCTL */ /* Get the description of the IOCTL */
if((cmd - SIOCIWFIRST) >= standard_ioctl_num) if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
...@@ -621,8 +653,14 @@ static inline int ioctl_standard_call(struct net_device * dev, ...@@ -621,8 +653,14 @@ static inline int ioctl_standard_call(struct net_device * dev,
#endif /* WE_SET_EVENT */ #endif /* WE_SET_EVENT */
} else { } else {
char * extra; char * extra;
int extra_size;
int user_length = 0;
int err; 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 */ /* Check what user space is giving us */
if(IW_IS_SET(cmd)) { if(IW_IS_SET(cmd)) {
/* Check NULL pointer */ /* Check NULL pointer */
...@@ -639,18 +677,29 @@ static inline int ioctl_standard_call(struct net_device * dev, ...@@ -639,18 +677,29 @@ static inline int ioctl_standard_call(struct net_device * dev,
if(iwr->u.data.pointer == NULL) if(iwr->u.data.pointer == NULL)
return -EFAULT; return -EFAULT;
/* Save user space buffer size for checking */ /* 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;
}
} }
#ifdef WE_IOCTL_DEBUG #ifdef WE_IOCTL_DEBUG
printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", 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 */ #endif /* WE_IOCTL_DEBUG */
/* Always allocate for max space. Easier, and won't last /* Create the kernel buffer */
* long... */ extra = kmalloc(extra_size, GFP_KERNEL);
extra = kmalloc(descr->max_tokens * descr->token_size,
GFP_KERNEL);
if (extra == NULL) { if (extra == NULL) {
return -ENOMEM; return -ENOMEM;
} }
...@@ -676,14 +725,11 @@ static inline int ioctl_standard_call(struct net_device * dev, ...@@ -676,14 +725,11 @@ static inline int ioctl_standard_call(struct net_device * dev,
/* If we have something to return to the user */ /* If we have something to return to the user */
if (!ret && IW_IS_GET(cmd)) { if (!ret && IW_IS_GET(cmd)) {
#ifdef WE_STRICT_WRITE
/* Check if there is enough buffer up there */ /* Check if there is enough buffer up there */
if(user_size < iwr->u.data.length) { if(user_length < 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);
kfree(extra); kfree(extra);
return -E2BIG; return -E2BIG;
} }
#endif /* WE_STRICT_WRITE */
err = copy_to_user(iwr->u.data.pointer, extra, err = copy_to_user(iwr->u.data.pointer, extra,
iwr->u.data.length * iwr->u.data.length *
...@@ -746,7 +792,7 @@ static inline int ioctl_private_call(struct net_device * dev, ...@@ -746,7 +792,7 @@ static inline int ioctl_private_call(struct net_device * dev,
iw_handler handler) iw_handler handler)
{ {
struct iwreq * iwr = (struct iwreq *) ifr; struct iwreq * iwr = (struct iwreq *) ifr;
struct iw_priv_args * descr = NULL; const struct iw_priv_args * descr = NULL;
struct iw_request_info info; struct iw_request_info info;
int extra_size = 0; int extra_size = 0;
int i; int i;
...@@ -786,7 +832,7 @@ static inline int ioctl_private_call(struct net_device * dev, ...@@ -786,7 +832,7 @@ static inline int ioctl_private_call(struct net_device * dev,
((extra_size + offset) <= IFNAMSIZ)) ((extra_size + offset) <= IFNAMSIZ))
extra_size = 0; extra_size = 0;
} else { } else {
/* Size of set arguments */ /* Size of get arguments */
extra_size = get_priv_size(descr->get_args); extra_size = get_priv_size(descr->get_args);
/* Does it fits in iwr ? */ /* Does it fits in iwr ? */
...@@ -856,6 +902,14 @@ static inline int ioctl_private_call(struct net_device * dev, ...@@ -856,6 +902,14 @@ static inline int ioctl_private_call(struct net_device * dev,
/* If we have something to return to the user */ /* If we have something to return to the user */
if (!ret && IW_IS_GET(cmd)) { 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, err = copy_to_user(iwr->u.data.pointer, extra,
extra_size); extra_size);
if (err) if (err)
...@@ -1127,9 +1181,25 @@ void wireless_send_event(struct net_device * dev, ...@@ -1127,9 +1181,25 @@ void wireless_send_event(struct net_device * dev,
* One of the main advantage of centralising spy support here is that * 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 * 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. * 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 * Standard Wireless Handler : set Spy List
...@@ -1139,16 +1209,30 @@ int iw_handler_set_spy(struct net_device * dev, ...@@ -1139,16 +1209,30 @@ int iw_handler_set_spy(struct net_device * dev,
union iwreq_data * wrqu, union iwreq_data * wrqu,
char * extra) char * extra)
{ {
#ifdef IW_WIRELESS_SPY struct iw_spy_data * spydata = get_spydata(dev);
struct iw_spy_data * spydata = (dev->priv +
dev->wireless_handlers->spy_offset);
struct sockaddr * address = (struct sockaddr *) extra; struct sockaddr * address = (struct sockaddr *) extra;
if(!dev->wireless_data)
/* Help user know that driver needs updating */
printk(KERN_DEBUG "%s (WE) : Driver using old/buggy spy support, please fix driver !\n",
dev->name);
/* Make sure driver is not buggy or using the old API */
if(!spydata)
return -EOPNOTSUPP;
/* Disable spy collection while we copy the addresses. /* Disable spy collection while we copy the addresses.
* As we don't disable interrupts, we need to do this to avoid races. * While we copy addresses, any call to wireless_spy_update()
* As we are the only writer, this is good enough. */ * will NOP. This is OK, as anyway the addresses are changing. */
spydata->spy_number = 0; 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 it 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? */ /* Are there are addresses to copy? */
if(wrqu->data.length > 0) { if(wrqu->data.length > 0) {
int i; int i;
...@@ -1174,13 +1258,14 @@ int iw_handler_set_spy(struct net_device * dev, ...@@ -1174,13 +1258,14 @@ int iw_handler_set_spy(struct net_device * dev,
spydata->spy_address[i][5]); spydata->spy_address[i][5]);
#endif /* WE_SPY_DEBUG */ #endif /* WE_SPY_DEBUG */
} }
/* Make sure above is updated before re-enabling */
wmb();
/* Enable addresses */ /* Enable addresses */
spydata->spy_number = wrqu->data.length; spydata->spy_number = wrqu->data.length;
return 0; return 0;
#else /* IW_WIRELESS_SPY */
return -EOPNOTSUPP;
#endif /* IW_WIRELESS_SPY */
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -1192,12 +1277,14 @@ int iw_handler_get_spy(struct net_device * dev, ...@@ -1192,12 +1277,14 @@ int iw_handler_get_spy(struct net_device * dev,
union iwreq_data * wrqu, union iwreq_data * wrqu,
char * extra) char * extra)
{ {
#ifdef IW_WIRELESS_SPY struct iw_spy_data * spydata = get_spydata(dev);
struct iw_spy_data * spydata = (dev->priv +
dev->wireless_handlers->spy_offset);
struct sockaddr * address = (struct sockaddr *) extra; struct sockaddr * address = (struct sockaddr *) extra;
int i; int i;
/* Make sure driver is not buggy or using the old API */
if(!spydata)
return -EOPNOTSUPP;
wrqu->data.length = spydata->spy_number; wrqu->data.length = spydata->spy_number;
/* Copy addresses. */ /* Copy addresses. */
...@@ -1214,9 +1301,6 @@ int iw_handler_get_spy(struct net_device * dev, ...@@ -1214,9 +1301,6 @@ int iw_handler_get_spy(struct net_device * dev,
for(i = 0; i < spydata->spy_number; i++) for(i = 0; i < spydata->spy_number; i++)
spydata->spy_stat[i].updated = 0; spydata->spy_stat[i].updated = 0;
return 0; return 0;
#else /* IW_WIRELESS_SPY */
return -EOPNOTSUPP;
#endif /* IW_WIRELESS_SPY */
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -1228,11 +1312,13 @@ int iw_handler_set_thrspy(struct net_device * dev, ...@@ -1228,11 +1312,13 @@ int iw_handler_set_thrspy(struct net_device * dev,
union iwreq_data * wrqu, union iwreq_data * wrqu,
char * extra) char * extra)
{ {
#ifdef IW_WIRELESS_THRSPY struct iw_spy_data * spydata = get_spydata(dev);
struct iw_spy_data * spydata = (dev->priv +
dev->wireless_handlers->spy_offset);
struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 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 */ /* Just do it */
memcpy(&(spydata->spy_thr_low), &(threshold->low), memcpy(&(spydata->spy_thr_low), &(threshold->low),
2 * sizeof(struct iw_quality)); 2 * sizeof(struct iw_quality));
...@@ -1245,9 +1331,6 @@ int iw_handler_set_thrspy(struct net_device * dev, ...@@ -1245,9 +1331,6 @@ int iw_handler_set_thrspy(struct net_device * dev,
#endif /* WE_SPY_DEBUG */ #endif /* WE_SPY_DEBUG */
return 0; return 0;
#else /* IW_WIRELESS_THRSPY */
return -EOPNOTSUPP;
#endif /* IW_WIRELESS_THRSPY */
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
...@@ -1259,22 +1342,20 @@ int iw_handler_get_thrspy(struct net_device * dev, ...@@ -1259,22 +1342,20 @@ int iw_handler_get_thrspy(struct net_device * dev,
union iwreq_data * wrqu, union iwreq_data * wrqu,
char * extra) char * extra)
{ {
#ifdef IW_WIRELESS_THRSPY struct iw_spy_data * spydata = get_spydata(dev);
struct iw_spy_data * spydata = (dev->priv +
dev->wireless_handlers->spy_offset);
struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 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 */ /* Just do it */
memcpy(&(threshold->low), &(spydata->spy_thr_low), memcpy(&(threshold->low), &(spydata->spy_thr_low),
2 * sizeof(struct iw_quality)); 2 * sizeof(struct iw_quality));
return 0; return 0;
#else /* IW_WIRELESS_THRSPY */
return -EOPNOTSUPP;
#endif /* IW_WIRELESS_THRSPY */
} }
#ifdef IW_WIRELESS_THRSPY
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Prepare and send a Spy Threshold event * Prepare and send a Spy Threshold event
...@@ -1312,7 +1393,6 @@ static void iw_send_thrspy_event(struct net_device * dev, ...@@ -1312,7 +1393,6 @@ static void iw_send_thrspy_event(struct net_device * dev,
/* Send event to user space */ /* Send event to user space */
wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
} }
#endif /* IW_WIRELESS_THRSPY */
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
/* /*
...@@ -1325,12 +1405,14 @@ void wireless_spy_update(struct net_device * dev, ...@@ -1325,12 +1405,14 @@ void wireless_spy_update(struct net_device * dev,
unsigned char * address, unsigned char * address,
struct iw_quality * wstats) struct iw_quality * wstats)
{ {
#ifdef IW_WIRELESS_SPY struct iw_spy_data * spydata = get_spydata(dev);
struct iw_spy_data * spydata = (dev->priv +
dev->wireless_handlers->spy_offset);
int i; int i;
int match = -1; int match = -1;
/* Make sure driver is not buggy or using the old API */
if(!spydata)
return;
#ifdef WE_SPY_DEBUG #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]); 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 */ #endif /* WE_SPY_DEBUG */
...@@ -1342,7 +1424,7 @@ void wireless_spy_update(struct net_device * dev, ...@@ -1342,7 +1424,7 @@ void wireless_spy_update(struct net_device * dev,
sizeof(struct iw_quality)); sizeof(struct iw_quality));
match = i; match = i;
} }
#ifdef IW_WIRELESS_THRSPY
/* Generate an event if we cross the spy threshold. /* Generate an event if we cross the spy threshold.
* To avoid event storms, we have a simple hysteresis : we generate * To avoid event storms, we have a simple hysteresis : we generate
* event only when we go under the low threshold or above the * event only when we go under the low threshold or above the
...@@ -1362,8 +1444,6 @@ void wireless_spy_update(struct net_device * dev, ...@@ -1362,8 +1444,6 @@ void wireless_spy_update(struct net_device * dev,
} }
} }
} }
#endif /* IW_WIRELESS_THRSPY */
#endif /* IW_WIRELESS_SPY */
} }
EXPORT_SYMBOL(iw_handler_get_spy); EXPORT_SYMBOL(iw_handler_get_spy);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment