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