root/net/wireless/wext-spy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_spydata
  2. iw_handler_set_spy
  3. iw_handler_get_spy
  4. iw_handler_set_thrspy
  5. iw_handler_get_thrspy
  6. iw_send_thrspy_event
  7. wireless_spy_update

   1 /*
   2  * This file implement the Wireless Extensions spy API.
   3  *
   4  * Authors :    Jean Tourrilhes - HPL - <jt@hpl.hp.com>
   5  * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
   6  *
   7  * (As all part of the Linux kernel, this file is GPL)
   8  */
   9 
  10 #include <linux/wireless.h>
  11 #include <linux/netdevice.h>
  12 #include <linux/etherdevice.h>
  13 #include <linux/export.h>
  14 #include <net/iw_handler.h>
  15 #include <net/arp.h>
  16 #include <net/wext.h>
  17 
  18 static inline struct iw_spy_data *get_spydata(struct net_device *dev)
  19 {
  20         /* This is the new way */
  21         if (dev->wireless_data)
  22                 return dev->wireless_data->spy_data;
  23         return NULL;
  24 }
  25 
  26 int iw_handler_set_spy(struct net_device *      dev,
  27                        struct iw_request_info * info,
  28                        union iwreq_data *       wrqu,
  29                        char *                   extra)
  30 {
  31         struct iw_spy_data *    spydata = get_spydata(dev);
  32         struct sockaddr *       address = (struct sockaddr *) extra;
  33 
  34         /* Make sure driver is not buggy or using the old API */
  35         if (!spydata)
  36                 return -EOPNOTSUPP;
  37 
  38         /* Disable spy collection while we copy the addresses.
  39          * While we copy addresses, any call to wireless_spy_update()
  40          * will NOP. This is OK, as anyway the addresses are changing. */
  41         spydata->spy_number = 0;
  42 
  43         /* We want to operate without locking, because wireless_spy_update()
  44          * most likely will happen in the interrupt handler, and therefore
  45          * have its own locking constraints and needs performance.
  46          * The rtnl_lock() make sure we don't race with the other iw_handlers.
  47          * This make sure wireless_spy_update() "see" that the spy list
  48          * is temporarily disabled. */
  49         smp_wmb();
  50 
  51         /* Are there are addresses to copy? */
  52         if (wrqu->data.length > 0) {
  53                 int i;
  54 
  55                 /* Copy addresses */
  56                 for (i = 0; i < wrqu->data.length; i++)
  57                         memcpy(spydata->spy_address[i], address[i].sa_data,
  58                                ETH_ALEN);
  59                 /* Reset stats */
  60                 memset(spydata->spy_stat, 0,
  61                        sizeof(struct iw_quality) * IW_MAX_SPY);
  62         }
  63 
  64         /* Make sure above is updated before re-enabling */
  65         smp_wmb();
  66 
  67         /* Enable addresses */
  68         spydata->spy_number = wrqu->data.length;
  69 
  70         return 0;
  71 }
  72 EXPORT_SYMBOL(iw_handler_set_spy);
  73 
  74 int iw_handler_get_spy(struct net_device *      dev,
  75                        struct iw_request_info * info,
  76                        union iwreq_data *       wrqu,
  77                        char *                   extra)
  78 {
  79         struct iw_spy_data *    spydata = get_spydata(dev);
  80         struct sockaddr *       address = (struct sockaddr *) extra;
  81         int                     i;
  82 
  83         /* Make sure driver is not buggy or using the old API */
  84         if (!spydata)
  85                 return -EOPNOTSUPP;
  86 
  87         wrqu->data.length = spydata->spy_number;
  88 
  89         /* Copy addresses. */
  90         for (i = 0; i < spydata->spy_number; i++)       {
  91                 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
  92                 address[i].sa_family = AF_UNIX;
  93         }
  94         /* Copy stats to the user buffer (just after). */
  95         if (spydata->spy_number > 0)
  96                 memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
  97                        spydata->spy_stat,
  98                        sizeof(struct iw_quality) * spydata->spy_number);
  99         /* Reset updated flags. */
 100         for (i = 0; i < spydata->spy_number; i++)
 101                 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
 102         return 0;
 103 }
 104 EXPORT_SYMBOL(iw_handler_get_spy);
 105 
 106 /*------------------------------------------------------------------*/
 107 /*
 108  * Standard Wireless Handler : set spy threshold
 109  */
 110 int iw_handler_set_thrspy(struct net_device *   dev,
 111                           struct iw_request_info *info,
 112                           union iwreq_data *    wrqu,
 113                           char *                extra)
 114 {
 115         struct iw_spy_data *    spydata = get_spydata(dev);
 116         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
 117 
 118         /* Make sure driver is not buggy or using the old API */
 119         if (!spydata)
 120                 return -EOPNOTSUPP;
 121 
 122         /* Just do it */
 123         memcpy(&(spydata->spy_thr_low), &(threshold->low),
 124                2 * sizeof(struct iw_quality));
 125 
 126         /* Clear flag */
 127         memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
 128 
 129         return 0;
 130 }
 131 EXPORT_SYMBOL(iw_handler_set_thrspy);
 132 
 133 /*------------------------------------------------------------------*/
 134 /*
 135  * Standard Wireless Handler : get spy threshold
 136  */
 137 int iw_handler_get_thrspy(struct net_device *   dev,
 138                           struct iw_request_info *info,
 139                           union iwreq_data *    wrqu,
 140                           char *                extra)
 141 {
 142         struct iw_spy_data *    spydata = get_spydata(dev);
 143         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
 144 
 145         /* Make sure driver is not buggy or using the old API */
 146         if (!spydata)
 147                 return -EOPNOTSUPP;
 148 
 149         /* Just do it */
 150         memcpy(&(threshold->low), &(spydata->spy_thr_low),
 151                2 * sizeof(struct iw_quality));
 152 
 153         return 0;
 154 }
 155 EXPORT_SYMBOL(iw_handler_get_thrspy);
 156 
 157 /*------------------------------------------------------------------*/
 158 /*
 159  * Prepare and send a Spy Threshold event
 160  */
 161 static void iw_send_thrspy_event(struct net_device *    dev,
 162                                  struct iw_spy_data *   spydata,
 163                                  unsigned char *        address,
 164                                  struct iw_quality *    wstats)
 165 {
 166         union iwreq_data        wrqu;
 167         struct iw_thrspy        threshold;
 168 
 169         /* Init */
 170         wrqu.data.length = 1;
 171         wrqu.data.flags = 0;
 172         /* Copy address */
 173         memcpy(threshold.addr.sa_data, address, ETH_ALEN);
 174         threshold.addr.sa_family = ARPHRD_ETHER;
 175         /* Copy stats */
 176         memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
 177         /* Copy also thresholds */
 178         memcpy(&(threshold.low), &(spydata->spy_thr_low),
 179                2 * sizeof(struct iw_quality));
 180 
 181         /* Send event to user space */
 182         wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
 183 }
 184 
 185 /* ---------------------------------------------------------------- */
 186 /*
 187  * Call for the driver to update the spy data.
 188  * For now, the spy data is a simple array. As the size of the array is
 189  * small, this is good enough. If we wanted to support larger number of
 190  * spy addresses, we should use something more efficient...
 191  */
 192 void wireless_spy_update(struct net_device *    dev,
 193                          unsigned char *        address,
 194                          struct iw_quality *    wstats)
 195 {
 196         struct iw_spy_data *    spydata = get_spydata(dev);
 197         int                     i;
 198         int                     match = -1;
 199 
 200         /* Make sure driver is not buggy or using the old API */
 201         if (!spydata)
 202                 return;
 203 
 204         /* Update all records that match */
 205         for (i = 0; i < spydata->spy_number; i++)
 206                 if (ether_addr_equal(address, spydata->spy_address[i])) {
 207                         memcpy(&(spydata->spy_stat[i]), wstats,
 208                                sizeof(struct iw_quality));
 209                         match = i;
 210                 }
 211 
 212         /* Generate an event if we cross the spy threshold.
 213          * To avoid event storms, we have a simple hysteresis : we generate
 214          * event only when we go under the low threshold or above the
 215          * high threshold. */
 216         if (match >= 0) {
 217                 if (spydata->spy_thr_under[match]) {
 218                         if (wstats->level > spydata->spy_thr_high.level) {
 219                                 spydata->spy_thr_under[match] = 0;
 220                                 iw_send_thrspy_event(dev, spydata,
 221                                                      address, wstats);
 222                         }
 223                 } else {
 224                         if (wstats->level < spydata->spy_thr_low.level) {
 225                                 spydata->spy_thr_under[match] = 1;
 226                                 iw_send_thrspy_event(dev, spydata,
 227                                                      address, wstats);
 228                         }
 229                 }
 230         }
 231 }
 232 EXPORT_SYMBOL(wireless_spy_update);

/* [<][>][^][v][top][bottom][index][help] */