diff -u -p linux/include/linux/wireless.15.h linux/include/linux/wireless.h --- linux/include/linux/wireless.15.h 2004-11-05 14:59:33.000000000 -0800 +++ linux/include/linux/wireless.h 2004-11-05 15:00:42.000000000 -0800 @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 15 12.7.02 + * Version : 16 2.4.03 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. @@ -69,6 +69,8 @@ /***************************** INCLUDES *****************************/ +/* To minimise problems in user space, I might remove those headers + * at some point. Jean II */ #include /* for "caddr_t" et al */ #include /* for "struct sockaddr" et al */ #include /* for IFNAMSIZ and co... */ @@ -80,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 15 +#define WIRELESS_EXT 16 /* * Changes : @@ -163,6 +165,16 @@ * - Add IW_TXPOW_RANGE for range of Tx Powers * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points * - Add IW_MODE_MONITOR for passive monitor + * + * V15 to V16 + * ---------- + * - Increase the number of bitrates in iw_range to 32 (for 802.11g) + * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) + * - Reshuffle struct iw_range for increases, add filler + * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses + * - 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 */ /**************************** CONSTANTS ****************************/ @@ -196,9 +208,11 @@ /* SIOCGIWSTATS is strictly used between user space and the kernel, and * is never passed to the driver (i.e. the driver will never see it). */ -/* Mobile IP support (statistics per MAC address) */ +/* Spy support (statistics per MAC address - used for Mobile IP support) */ #define SIOCSIWSPY 0x8B10 /* set spy addresses */ #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ +#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ +#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ /* Access Point manipulation */ #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ @@ -294,7 +308,7 @@ #define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ #define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ -#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ +#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ #define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ @@ -306,13 +320,13 @@ /* ----------------------- OTHER CONSTANTS ----------------------- */ /* Maximum frequencies in the range struct */ -#define IW_MAX_FREQUENCIES 16 +#define IW_MAX_FREQUENCIES 32 /* Note : if you have something like 80 frequencies, * don't increase this constant and don't fill the frequency list. * The user will be able to set by channel anyway... */ /* Maximum bit rates in the range struct */ -#define IW_MAX_BITRATES 8 +#define IW_MAX_BITRATES 32 /* Maximum tx powers in the range struct */ #define IW_MAX_TXPOWER 8 @@ -320,8 +334,7 @@ * a few of them in the struct iw_range. */ /* Maximum of address that you may set with SPY */ -#define IW_MAX_SPY 8 /* set */ -#define IW_MAX_GET_SPY 64 /* get */ +#define IW_MAX_SPY 8 /* Maximum of address that you may get in the list of access points in range */ @@ -354,7 +367,8 @@ #define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ #define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ #define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ -#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ /* Power management flags available (along with the value, if any) */ #define IW_POWER_ON 0x0000 /* No details... */ @@ -482,6 +496,17 @@ struct iw_missed __u32 beacon; /* Missed beacons/superframe */ }; +/* + * Quality range (for spy threshold) + */ +struct iw_thrspy +{ + struct sockaddr addr; /* Source address (hw/mac) */ + struct iw_quality qual; /* Quality of the link */ + struct iw_quality low; /* Low threshold */ + struct iw_quality high; /* High threshold */ +}; + /* ------------------------ WIRELESS STATS ------------------------ */ /* * Wireless statistics (used for /proc/net/wireless) @@ -534,7 +559,7 @@ union iwreq_data struct iw_quality qual; /* Quality part of statistics */ struct sockaddr ap_addr; /* Access point address */ - struct sockaddr addr; /* Destination address (hw) */ + struct sockaddr addr; /* Destination address (hw/mac) */ struct iw_param param; /* Other small parameters */ struct iw_point data; /* Other large parameters */ @@ -582,17 +607,31 @@ struct iw_range __u32 min_nwid; /* Minimal NWID we are able to set */ __u32 max_nwid; /* Maximal NWID we are able to set */ - /* Frequency */ - __u16 num_channels; /* Number of channels [0; num - 1] */ - __u8 num_frequency; /* Number of entry in the list */ - struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ - /* Note : this frequency list doesn't need to fit channel numbers */ + /* 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]; /* signal level threshold range */ __s32 sensitivity; /* Quality of link & SNR stuff */ + /* Quality range (link, level, noise) + * If the quality is absolute, it will be in the range [0 ; max_qual], + * if the quality is dBm, it will be in the range [max_qual ; 0]. + * Don't forget that we use 8 bit arithmetics... */ struct iw_quality max_qual; /* Quality of the link */ + /* This should contain the average/typical values of the quality + * indicator. This should be the threshold between a "good" and + * a "bad" link (example : monitor going from green to orange). + * Currently, user space apps like quality monitors don't have any + * way to calibrate the measurement. With this, they can split + * the range between 0 and max_qual in different quality level + * (using a geometric subdivision centered on the average). + * I expect that people doing the user space apps will feedback + * us on which value we need to put in each driver... */ + struct iw_quality avg_qual; /* Quality of the link */ /* Rates */ __u8 num_bitrates; /* Number of entries in the list */ @@ -619,6 +658,8 @@ struct iw_range __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ __u8 num_encoding_sizes; /* Number of entry in the list */ __u8 max_encoding_tokens; /* Max number of tokens */ + /* For drivers that need a "login/passwd" form */ + __u8 encoding_login_index; /* token index for login token */ /* Transmit power */ __u16 txpower_capa; /* What options are supported */ @@ -638,18 +679,12 @@ struct iw_range __s32 min_r_time; /* Minimal retry lifetime */ __s32 max_r_time; /* Maximal retry lifetime */ - /* Average quality of link & SNR */ - struct iw_quality avg_qual; /* Quality of the link */ - /* This should contain the average/typical values of the quality - * indicator. This should be the threshold between a "good" and - * a "bad" link (example : monitor going from green to orange). - * Currently, user space apps like quality monitors don't have any - * way to calibrate the measurement. With this, they can split - * the range between 0 and max_qual in different quality level - * (using a geometric subdivision centered on the average). - * I expect that people doing the user space apps will feedback - * us on which value we need to put in each driver... - */ + /* Frequency */ + __u16 num_channels; /* Number of channels [0; num - 1] */ + __u8 num_frequency; /* Number of entry in the list */ + 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 */ }; /* diff -u -p linux/include/net/iw_handler.15.h linux/include/net/iw_handler.h --- linux/include/net/iw_handler.15.h 2004-11-05 14:59:47.000000000 -0800 +++ linux/include/net/iw_handler.h 2004-11-05 15:00:42.000000000 -0800 @@ -1,7 +1,7 @@ /* * This file define the new driver API for Wireless Extensions * - * Version : 4 21.6.02 + * Version : 5 4.12.02 * * Authors : Jean Tourrilhes - HPL - * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. @@ -206,7 +206,7 @@ * will be needed... * I just plan to increment with each new version. */ -#define IW_HANDLER_VERSION 4 +#define IW_HANDLER_VERSION 5 /* * Changes : @@ -220,10 +220,18 @@ * V3 to V4 * -------- * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + * + * V4 to V5 + * -------- + * - Add new spy support : struct iw_spy_data & prototypes */ /**************************** CONSTANTS ****************************/ +/* Enable enhanced spy support. Disable to reduce footprint */ +#define IW_WIRELESS_SPY +#define IW_WIRELESS_THRSPY + /* Special error message for the driver to indicate that we * should do a commit after return from the iw_handler */ #define EIWCOMMIT EINPROGRESS @@ -315,6 +323,9 @@ struct iw_handler_def * We will automatically export that to user space... */ struct iw_priv_args * private_args; + /* Driver enhanced spy support */ + long spy_offset; /* Spy data offset */ + /* In the long term, get_wireless_stats will move from * 'struct net_device' to here, to minimise bloat. */ }; @@ -350,6 +361,33 @@ struct iw_ioctl_description /* Need to think of short header translation table. Later. */ +/* --------------------- ENHANCED SPY SUPPORT --------------------- */ +/* + * In the old days, the driver was handling spy support all by itself. + * Now, the driver can delegate this task to Wireless Extensions. + * It needs to include this struct in its private part and use the + * standard spy iw_handler. + */ + +/* + * Instance specific spy data, i.e. addresses spied and quality for them. + */ +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 */ +}; + /**************************** PROTOTYPES ****************************/ /* * Functions part of the Wireless Extensions (defined in net/core/wireless.c). @@ -376,6 +414,31 @@ extern void wireless_send_event(struct n /* We may need a function to send a stream of events to user space. * More on that later... */ +/* Standard handler for SIOCSIWSPY */ +extern int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCGIWSPY */ +extern int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCSIWTHRSPY */ +extern int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra); +/* Standard handler for SIOCGIWTHRSPY */ +extern int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra); +/* Driver call to update spy records */ +extern void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats); + /************************* INLINE FUNTIONS *************************/ /* * Function that are so simple that it's more efficient inlining them diff -u -p linux/net/core/wireless.15.c linux/net/core/wireless.c --- linux/net/core/wireless.15.c 2004-11-05 15:00:11.000000000 -0800 +++ linux/net/core/wireless.c 2004-11-05 15:00:42.000000000 -0800 @@ -2,7 +2,7 @@ * This file implement the Wireless Extensions APIs. * * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved. * * (As all part of the Linux kernel, this file is GPL) */ @@ -43,6 +43,11 @@ * o Turn on WE_STRICT_WRITE by default + kernel warning * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) * o Fix off-by-one in test (extra_size <= IFNAMSIZ) + * + * v6 - 9.01.03 - Jean II + * 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 */ /***************************** INCLUDES *****************************/ @@ -52,6 +57,7 @@ #include /* off_t */ #include /* struct ifreq, dev_get_by_name() */ #include /* rtnetlink stuff */ +#include /* ARPHRD_ETHER */ #include /* Pretty obvious */ #include /* New driver API */ @@ -65,6 +71,7 @@ /* Debuging stuff */ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ #undef WE_EVENT_DEBUG /* Debug Event dispatcher */ +#undef WE_SPY_DEBUG /* Debug enhanced spy support */ /* Options */ #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ @@ -72,7 +79,7 @@ /************************* GLOBAL VARIABLES *************************/ /* - * You should not use global variables, because or re-entrancy. + * You should not use global variables, because of re-entrancy. * On our case, it's only const, so it's OK... */ /* @@ -115,11 +122,11 @@ static const struct iw_ioctl_description /* SIOCSIWSPY */ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, /* SIOCGIWSPY */ - { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0}, - /* -- hole -- */ - { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, - /* -- hole -- */ - { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, + /* SIOCSIWTHRSPY */ + { IW_HEADER_TYPE_POINT, 0, sizeof(struct iw_thrspy), 1, 1, 0}, + /* SIOCGIWTHRSPY */ + { IW_HEADER_TYPE_POINT, 0, sizeof(struct iw_thrspy), 1, 1, 0}, /* SIOCSIWAP */ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, /* SIOCGIWAP */ @@ -377,9 +384,9 @@ int dev_get_wireless_info(char * buffer, struct net_device * dev; size = sprintf(buffer, - "Inter-| sta-| Quality | Discarded packets | Missed\n" - " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" - ); + "Inter-| sta-| Quality | Discarded packets | Missed | WE\n" + " face | tus | link level noise | nwid crypt frag retry misc | beacon | %d\n", + WIRELESS_EXT); pos += size; len += size; @@ -1024,3 +1031,252 @@ void wireless_send_event(struct net_devi return; /* Always success, I guess ;-) */ } + +/********************** ENHANCED IWSPY SUPPORT **********************/ +/* + * In the old days, the driver was handling spy support all by itself. + * Now, the driver can delegate this task to Wireless Extensions. + * It needs to use those standard spy iw_handler in struct iw_handler_def, + * push data to us via XXX and include struct iw_spy_data in its + * private part. + * 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 + */ + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set Spy List + */ +int iw_handler_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_SPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct sockaddr * address = (struct sockaddr *) extra; + + /* 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. */ + spydata->spy_number = 0; + + /* Are there are addresses to copy? */ + if(wrqu->data.length > 0) { + int i; + + /* Copy addresses */ + for(i = 0; i < wrqu->data.length; i++) + memcpy(spydata->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(spydata->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + +#ifdef WE_SPY_DEBUG + printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length); + for (i = 0; i < wrqu->data.length; i++) + printk(KERN_DEBUG + "%02X:%02X:%02X:%02X:%02X:%02X \n", + spydata->spy_address[i][0], + spydata->spy_address[i][1], + spydata->spy_address[i][2], + spydata->spy_address[i][3], + spydata->spy_address[i][4], + spydata->spy_address[i][5]); +#endif /* WE_SPY_DEBUG */ + } + /* Enable addresses */ + spydata->spy_number = wrqu->data.length; + + return 0; +#else /* IW_WIRELESS_SPY */ + return -EOPNOTSUPP; +#endif /* IW_WIRELESS_SPY */ +} + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get Spy List + */ +int iw_handler_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_SPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct sockaddr * address = (struct sockaddr *) extra; + int i; + + wrqu->data.length = spydata->spy_number; + + /* Copy addresses. */ + for(i = 0; i < spydata->spy_number; i++) { + memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if(spydata->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), + spydata->spy_stat, + sizeof(struct iw_quality) * spydata->spy_number); + /* Reset updated flags. */ + 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 */ +} + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set spy threshold + */ +int iw_handler_set_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_THRSPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Just do it */ + memcpy(&(spydata->spy_thr_low), &(threshold->low), + 2 * sizeof(struct iw_quality)); + + /* Clear flag */ + memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); + +#ifdef WE_SPY_DEBUG + printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level); +#endif /* WE_SPY_DEBUG */ + + return 0; +#else /* IW_WIRELESS_THRSPY */ + return -EOPNOTSUPP; +#endif /* IW_WIRELESS_THRSPY */ +} + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get spy threshold + */ +int iw_handler_get_thrspy(struct net_device * dev, + struct iw_request_info *info, + union iwreq_data * wrqu, + char * extra) +{ +#ifdef IW_WIRELESS_THRSPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* 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 + */ +static void iw_send_thrspy_event(struct net_device * dev, + struct iw_spy_data * spydata, + unsigned char * address, + struct iw_quality * wstats) +{ + union iwreq_data wrqu; + struct iw_thrspy threshold; + + /* Init */ + wrqu.data.length = 1; + wrqu.data.flags = 0; + /* Copy address */ + memcpy(threshold.addr.sa_data, address, ETH_ALEN); + threshold.addr.sa_family = ARPHRD_ETHER; + /* Copy stats */ + memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); + /* Copy also thresholds */ + memcpy(&(threshold.low), &(spydata->spy_thr_low), + 2 * sizeof(struct iw_quality)); + +#ifdef WE_SPY_DEBUG + printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n", + threshold.addr.sa_data[0], + threshold.addr.sa_data[1], + threshold.addr.sa_data[2], + threshold.addr.sa_data[3], + threshold.addr.sa_data[4], + threshold.addr.sa_data[5], threshold.qual.level); +#endif /* WE_SPY_DEBUG */ + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); +} +#endif /* IW_WIRELESS_THRSPY */ + +/* ---------------------------------------------------------------- */ +/* + * Call for the driver to update the spy data. + * For now, the spy data is a simple array. As the size of the array is + * small, this is good enough. If we wanted to support larger number of + * spy addresses, we should use something more efficient... + */ +void wireless_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats) +{ +#ifdef IW_WIRELESS_SPY + struct iw_spy_data * spydata = (dev->priv + + dev->wireless_handlers->spy_offset); + int i; + int match = -1; + +#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 */ + + /* Update all records that match */ + for(i = 0; i < spydata->spy_number; i++) + if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) { + memcpy(&(spydata->spy_stat[i]), wstats, + 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 + * high threshold. */ + if(match >= 0) { + if(spydata->spy_thr_under[match]) { + if(wstats->level > spydata->spy_thr_high.level) { + spydata->spy_thr_under[match] = 0; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } else { + if(wstats->level < spydata->spy_thr_low.level) { + spydata->spy_thr_under[match] = 1; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } + } +#endif /* IW_WIRELESS_THRSPY */ +#endif /* IW_WIRELESS_SPY */ +} diff -u -p linux/net/netsyms.15.c linux/net/netsyms.c --- linux/net/netsyms.15.c 2004-11-05 15:00:25.000000000 -0800 +++ linux/net/netsyms.c 2004-11-05 15:01:38.000000000 -0800 @@ -589,9 +589,13 @@ EXPORT_SYMBOL(net_call_rx_atomic); EXPORT_SYMBOL(softnet_data); #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) -/* Don't include the whole header mess for a single function */ -extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); +#include EXPORT_SYMBOL(wireless_send_event); +EXPORT_SYMBOL(iw_handler_set_spy); +EXPORT_SYMBOL(iw_handler_get_spy); +EXPORT_SYMBOL(iw_handler_set_thrspy); +EXPORT_SYMBOL(iw_handler_get_thrspy); +EXPORT_SYMBOL(wireless_spy_update); #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ #endif /* CONFIG_NET */