wifi: wext/libipw: move spy implementation to libipw
authorJohannes Berg <johannes.berg@intel.com>
Mon, 7 Oct 2024 19:02:53 +0000 (21:02 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 8 Oct 2024 19:53:18 +0000 (21:53 +0200)
There's no driver left using this other than ipw2200,
so move the data bookkeeping and code into libipw.

Link: https://patch.msgid.link/20241007210254.037d864cda7d.Ib2197cb056ff05746d3521a5fba637062acb7314@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/ipw2x00/Kconfig
drivers/net/wireless/intel/ipw2x00/Makefile
drivers/net/wireless/intel/ipw2x00/ipw2200.c
drivers/net/wireless/intel/ipw2x00/libipw.h
drivers/net/wireless/intel/ipw2x00/libipw_rx.c
drivers/net/wireless/intel/ipw2x00/libipw_spy.c [new file with mode: 0644]
include/net/iw_handler.h
net/wireless/Kconfig
net/wireless/Makefile
net/wireless/wext-spy.c [deleted file]

index d9c042772399978303e698d223b142bdf293920e..ce34118f1e9011286b386c052fcfbc815c3bc8a2 100644 (file)
@@ -7,7 +7,6 @@ config IPW2100
        tristate "Intel PRO/Wireless 2100 Network Connection"
        depends on PCI && CFG80211
        select WIRELESS_EXT
-       select WEXT_SPY
        select WEXT_PRIV
        select FW_LOADER
        select LIBIPW
@@ -68,7 +67,6 @@ config IPW2200
        depends on PCI && CFG80211
        select CFG80211_WEXT_EXPORT
        select WIRELESS_EXT
-       select WEXT_SPY
        select WEXT_PRIV
        select FW_LOADER
        select LIBIPW
@@ -156,7 +154,6 @@ config LIBIPW
        tristate
        depends on PCI && CFG80211
        select WIRELESS_EXT
-       select WEXT_SPY
        select CRYPTO
        select CRYPTO_MICHAEL_MIC
        select CRC32
index 60c5faccbe1548285165a291fd3ca321f9347bc5..91e6091c4ebf116c83aa9620fec95fb6031d878c 100644 (file)
@@ -13,6 +13,7 @@ libipw-objs := \
        libipw_rx.o \
        libipw_wx.o \
        libipw_geo.o \
+       libipw_spy.o \
        libipw_crypto.o \
        libipw_crypto_ccmp.o \
        libipw_crypto_tkip.o \
index f4fd1fc784b77c7d5081cb67c224284f0f87cbd3..0008b4615731b7c65ba5458783b66fe6d3129a60 100644 (file)
@@ -9856,10 +9856,10 @@ static iw_handler ipw_wx_handlers[] = {
        IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode),
        IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power),
        IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power),
-       IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
-       IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
-       IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
-       IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
+       IW_HANDLER(SIOCSIWSPY, ipw_wx_set_spy),
+       IW_HANDLER(SIOCGIWSPY, ipw_wx_get_spy),
+       IW_HANDLER(SIOCSIWTHRSPY, ipw_wx_set_thrspy),
+       IW_HANDLER(SIOCGIWTHRSPY, ipw_wx_get_thrspy),
        IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie),
        IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie),
        IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme),
@@ -11636,7 +11636,7 @@ static int ipw_pci_probe(struct pci_dev *pdev,
        priv->ieee->worst_rssi = -85;
 
        net_dev->netdev_ops = &ipw_netdev_ops;
-       priv->wireless_data.spy_data = &priv->ieee->spy_data;
+       priv->ieee->spy_enabled = true;
        net_dev->wireless_data = &priv->wireless_data;
        net_dev->wireless_handlers = &ipw_wx_handler_def;
        net_dev->ethtool_ops = &ipw_ethtool_ops;
index bc727c99ff3c9faf59b2163119669718d66a5c4e..3c20353e5a41237f4f618c99eb3bac9d2f5e07b9 100644 (file)
@@ -788,6 +788,7 @@ struct libipw_device {
 
        int iw_mode;            /* operating mode (IW_MODE_*) */
        struct iw_spy_data spy_data;    /* iwspy support */
+       bool spy_enabled;
 
        spinlock_t lock;
 
@@ -1083,4 +1084,16 @@ void libipw_crypto_tkip_exit(void);
 void libipw_crypto_ccmp_exit(void);
 void libipw_crypto_exit(void);
 
+
+int ipw_wx_set_spy(struct net_device *dev, struct iw_request_info *info,
+                  union iwreq_data *wrqu, char *extra);
+int ipw_wx_get_spy(struct net_device *dev, struct iw_request_info *info,
+                  union iwreq_data *wrqu, char *extra);
+int ipw_wx_set_thrspy(struct net_device *dev, struct iw_request_info *info,
+                     union iwreq_data *wrqu, char *extra);
+int ipw_wx_get_thrspy(struct net_device *dev, struct iw_request_info *info,
+                     union iwreq_data *wrqu, char *extra);
+void libipw_spy_update(struct net_device *dev, unsigned char *address,
+                      struct iw_quality *wstats);
+
 #endif                         /* LIBIPW_H */
index 1fe05e73a17ca45e6ca0767054ae1257ecd8837b..7e41cb7bbfe017225fd55da8896cb35a0e034c13 100644 (file)
@@ -393,7 +393,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
                        wstats.updated |= IW_QUAL_QUAL_INVALID;
 
                /* Update spy records */
-               wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
+               libipw_spy_update(ieee->dev, hdr->addr2, &wstats);
        }
 #endif                         /* IW_WIRELESS_SPY */
 #endif                         /* CONFIG_WIRELESS_EXT */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_spy.c b/drivers/net/wireless/intel/ipw2x00/libipw_spy.c
new file mode 100644 (file)
index 0000000..979aeb1
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * This file implement the Wireless Extensions spy API.
+ *
+ * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/export.h>
+#include <net/iw_handler.h>
+#include <net/arp.h>
+#include <net/wext.h>
+#include "libipw.h"
+
+static struct iw_spy_data *get_spydata(struct net_device *dev)
+{
+       if (dev->wireless_data && dev->wireless_data->libipw &&
+           dev->wireless_data->libipw->spy_enabled)
+               return &dev->wireless_data->libipw->spy_data;
+       return NULL;
+}
+
+int ipw_wx_set_spy(struct net_device *         dev,
+                  struct iw_request_info *     info,
+                  union iwreq_data *           wrqu,
+                  char *                       extra)
+{
+       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.
+        * While we copy addresses, any call to libipw_spy_update()
+        * will NOP. This is OK, as anyway the addresses are changing. */
+       spydata->spy_number = 0;
+
+       /* We want to operate without locking, because libipw_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 libipw_spy_update() "see" that the spy list
+        * is temporarily disabled. */
+       smp_wmb();
+
+       /* 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);
+       }
+
+       /* Make sure above is updated before re-enabling */
+       smp_wmb();
+
+       /* Enable addresses */
+       spydata->spy_number = wrqu->data.length;
+
+       return 0;
+}
+EXPORT_SYMBOL(ipw_wx_set_spy);
+
+int ipw_wx_get_spy(struct net_device *         dev,
+                  struct iw_request_info *     info,
+                  union iwreq_data *           wrqu,
+                  char *                       extra)
+{
+       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. */
+       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 &= ~IW_QUAL_ALL_UPDATED;
+       return 0;
+}
+EXPORT_SYMBOL(ipw_wx_get_spy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set spy threshold
+ */
+int ipw_wx_set_thrspy(struct net_device *      dev,
+                     struct iw_request_info *  info,
+                     union iwreq_data *        wrqu,
+                     char *                    extra)
+{
+       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 */
+       spydata->spy_thr_low = threshold->low;
+       spydata->spy_thr_high = threshold->high;
+
+       /* Clear flag */
+       memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
+
+       return 0;
+}
+EXPORT_SYMBOL(ipw_wx_set_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get spy threshold
+ */
+int ipw_wx_get_thrspy(struct net_device *      dev,
+                     struct iw_request_info *  info,
+                     union iwreq_data *        wrqu,
+                     char *                    extra)
+{
+       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 */
+       threshold->low = spydata->spy_thr_low;
+       threshold->high = spydata->spy_thr_high;
+
+       return 0;
+}
+EXPORT_SYMBOL(ipw_wx_get_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 */
+       threshold.qual = *wstats;
+       /* Copy also thresholds */
+       threshold.low = spydata->spy_thr_low;
+       threshold.high = spydata->spy_thr_high;
+
+       /* Send event to user space */
+       wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * 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 libipw_spy_update(struct net_device *     dev,
+                      unsigned char *          address,
+                      struct iw_quality *      wstats)
+{
+       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;
+
+       /* Update all records that match */
+       for (i = 0; i < spydata->spy_number; i++)
+               if (ether_addr_equal(address, spydata->spy_address[i])) {
+                       memcpy(&(spydata->spy_stat[i]), wstats,
+                              sizeof(struct iw_quality));
+                       match = i;
+               }
+
+       /* 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);
+                       }
+               }
+       }
+}
index 7af1082ea9a0cc640fdf0e0e2d7ee4e9910c32bf..a7b502958d27626827ba78c1df021c26d840dafa 100644 (file)
@@ -418,8 +418,6 @@ struct iw_spy_data {
 struct libipw_device;
 /* The struct */
 struct iw_public_data {
-       /* Driver enhanced spy support */
-       struct iw_spy_data *            spy_data;
        /* Legacy structure managed by the ipw2x00-specific IEEE 802.11 layer */
        struct libipw_device *          libipw;
 };
@@ -443,22 +441,6 @@ static inline void wireless_nlevent_flush(void) {}
 /* We may need a function to send a stream of events to user space.
  * More on that later... */
 
-/* Standard handler for SIOCSIWSPY */
-int iw_handler_set_spy(struct net_device *dev, struct iw_request_info *info,
-                      union iwreq_data *wrqu, char *extra);
-/* Standard handler for SIOCGIWSPY */
-int iw_handler_get_spy(struct net_device *dev, struct iw_request_info *info,
-                      union iwreq_data *wrqu, char *extra);
-/* Standard handler for SIOCSIWTHRSPY */
-int iw_handler_set_thrspy(struct net_device *dev, struct iw_request_info *info,
-                         union iwreq_data *wrqu, char *extra);
-/* Standard handler for SIOCGIWTHRSPY */
-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 */
-void wireless_spy_update(struct net_device *dev, unsigned char *address,
-                        struct iw_quality *wstats);
-
 /************************* INLINE FUNCTIONS *************************/
 /*
  * Function that are so simple that it's more efficient inlining them
index 733c53ad4de51768b0a7218eeedf19207f24c04c..8c8bd8b7570873686038ccd4873d85df6e54d863 100644 (file)
@@ -11,9 +11,6 @@ config WEXT_PROC
        depends on PROC_FS
        depends on WEXT_CORE
 
-config WEXT_SPY
-       bool
-
 config WEXT_PRIV
        bool
 
index 27f211bd9954599d1d9d74efe5c983a61b2a9fd7..62a83faf0e07d089e64674c8c530de49f8e08dea 100644 (file)
@@ -4,7 +4,6 @@ obj-y += tests/
 
 obj-$(CONFIG_WEXT_CORE) += wext-core.o
 obj-$(CONFIG_WEXT_PROC) += wext-proc.o
-obj-$(CONFIG_WEXT_SPY) += wext-spy.o
 obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
diff --git a/net/wireless/wext-spy.c b/net/wireless/wext-spy.c
deleted file mode 100644 (file)
index b379a03..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * This file implement the Wireless Extensions spy API.
- *
- * Authors :   Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
- *
- * (As all part of the Linux kernel, this file is GPL)
- */
-
-#include <linux/wireless.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/export.h>
-#include <net/iw_handler.h>
-#include <net/arp.h>
-#include <net/wext.h>
-
-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;
-       return NULL;
-}
-
-int iw_handler_set_spy(struct net_device *     dev,
-                      struct iw_request_info * info,
-                      union iwreq_data *       wrqu,
-                      char *                   extra)
-{
-       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.
-        * 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. */
-       smp_wmb();
-
-       /* 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);
-       }
-
-       /* Make sure above is updated before re-enabling */
-       smp_wmb();
-
-       /* Enable addresses */
-       spydata->spy_number = wrqu->data.length;
-
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_spy);
-
-int iw_handler_get_spy(struct net_device *     dev,
-                      struct iw_request_info * info,
-                      union iwreq_data *       wrqu,
-                      char *                   extra)
-{
-       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. */
-       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 &= ~IW_QUAL_ALL_UPDATED;
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_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)
-{
-       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 */
-       spydata->spy_thr_low = threshold->low;
-       spydata->spy_thr_high = threshold->high;
-
-       /* Clear flag */
-       memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
-
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_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)
-{
-       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 */
-       threshold->low = spydata->spy_thr_low;
-       threshold->high = spydata->spy_thr_high;
-
-       return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_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 */
-       threshold.qual = *wstats;
-       /* Copy also thresholds */
-       threshold.low = spydata->spy_thr_low;
-       threshold.high = spydata->spy_thr_high;
-
-       /* Send event to user space */
-       wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * 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)
-{
-       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;
-
-       /* Update all records that match */
-       for (i = 0; i < spydata->spy_number; i++)
-               if (ether_addr_equal(address, spydata->spy_address[i])) {
-                       memcpy(&(spydata->spy_stat[i]), wstats,
-                              sizeof(struct iw_quality));
-                       match = i;
-               }
-
-       /* 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);
-                       }
-               }
-       }
-}
-EXPORT_SYMBOL(wireless_spy_update);