Branch data Line data Source code
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 : 0 : if (dev->wireless_data) 22 : 0 : return dev->wireless_data->spy_data; 23 : : return NULL; 24 : : } 25 : : 26 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : smp_wmb(); 50 : : 51 : : /* Are there are addresses to copy? */ 52 : 0 : if (wrqu->data.length > 0) { 53 : : int i; 54 : : 55 : : /* Copy addresses */ 56 : 0 : for (i = 0; i < wrqu->data.length; i++) 57 : 0 : memcpy(spydata->spy_address[i], address[i].sa_data, 58 : : ETH_ALEN); 59 : : /* Reset stats */ 60 : 0 : 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 : 0 : smp_wmb(); 66 : : 67 : : /* Enable addresses */ 68 : 0 : spydata->spy_number = wrqu->data.length; 69 : : 70 : 0 : return 0; 71 : : } 72 : : EXPORT_SYMBOL(iw_handler_set_spy); 73 : : 74 : 0 : 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 : 0 : if (!spydata) 85 : : return -EOPNOTSUPP; 86 : : 87 : 0 : wrqu->data.length = spydata->spy_number; 88 : : 89 : : /* Copy addresses. */ 90 : 0 : for (i = 0; i < spydata->spy_number; i++) { 91 : 0 : memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); 92 : 0 : address[i].sa_family = AF_UNIX; 93 : : } 94 : : /* Copy stats to the user buffer (just after). */ 95 : 0 : if (spydata->spy_number > 0) 96 : 0 : memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), 97 : 0 : spydata->spy_stat, 98 : : sizeof(struct iw_quality) * spydata->spy_number); 99 : : /* Reset updated flags. */ 100 : 0 : for (i = 0; i < spydata->spy_number; i++) 101 : 0 : 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 : 0 : 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 : 0 : if (!spydata) 120 : : return -EOPNOTSUPP; 121 : : 122 : : /* Just do it */ 123 : 0 : memcpy(&(spydata->spy_thr_low), &(threshold->low), 124 : : 2 * sizeof(struct iw_quality)); 125 : : 126 : : /* Clear flag */ 127 : 0 : memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); 128 : : 129 : 0 : return 0; 130 : : } 131 : : EXPORT_SYMBOL(iw_handler_set_thrspy); 132 : : 133 : : /*------------------------------------------------------------------*/ 134 : : /* 135 : : * Standard Wireless Handler : get spy threshold 136 : : */ 137 : 0 : 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 : 0 : if (!spydata) 147 : : return -EOPNOTSUPP; 148 : : 149 : : /* Just do it */ 150 : 0 : memcpy(&(threshold->low), &(spydata->spy_thr_low), 151 : : 2 * sizeof(struct iw_quality)); 152 : : 153 : 0 : return 0; 154 : : } 155 : : EXPORT_SYMBOL(iw_handler_get_thrspy); 156 : : 157 : : /*------------------------------------------------------------------*/ 158 : : /* 159 : : * Prepare and send a Spy Threshold event 160 : : */ 161 : 0 : 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 : 0 : wrqu.data.length = 1; 171 : 0 : wrqu.data.flags = 0; 172 : : /* Copy address */ 173 : 0 : memcpy(threshold.addr.sa_data, address, ETH_ALEN); 174 : 0 : threshold.addr.sa_family = ARPHRD_ETHER; 175 : : /* Copy stats */ 176 : 0 : memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); 177 : : /* Copy also thresholds */ 178 : 0 : memcpy(&(threshold.low), &(spydata->spy_thr_low), 179 : : 2 * sizeof(struct iw_quality)); 180 : : 181 : : /* Send event to user space */ 182 : 0 : wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); 183 : 0 : } 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 : 0 : 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 : 0 : if (!spydata) 202 : 0 : return; 203 : : 204 : : /* Update all records that match */ 205 : 0 : for (i = 0; i < spydata->spy_number; i++) 206 : 0 : if (ether_addr_equal(address, spydata->spy_address[i])) { 207 : 0 : 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 : 0 : if (match >= 0) { 217 : 0 : if (spydata->spy_thr_under[match]) { 218 : 0 : if (wstats->level > spydata->spy_thr_high.level) { 219 : 0 : spydata->spy_thr_under[match] = 0; 220 : 0 : iw_send_thrspy_event(dev, spydata, 221 : : address, wstats); 222 : : } 223 : : } else { 224 : 0 : if (wstats->level < spydata->spy_thr_low.level) { 225 : 0 : spydata->spy_thr_under[match] = 1; 226 : 0 : iw_send_thrspy_event(dev, spydata, 227 : : address, wstats); 228 : : } 229 : : } 230 : : } 231 : : } 232 : : EXPORT_SYMBOL(wireless_spy_update);