0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/wireless.h>
0011 #include <linux/netdevice.h>
0012 #include <linux/etherdevice.h>
0013 #include <linux/export.h>
0014 #include <net/iw_handler.h>
0015 #include <net/arp.h>
0016 #include <net/wext.h>
0017
0018 static inline struct iw_spy_data *get_spydata(struct net_device *dev)
0019 {
0020
0021 if (dev->wireless_data)
0022 return dev->wireless_data->spy_data;
0023 return NULL;
0024 }
0025
0026 int iw_handler_set_spy(struct net_device * dev,
0027 struct iw_request_info * info,
0028 union iwreq_data * wrqu,
0029 char * extra)
0030 {
0031 struct iw_spy_data * spydata = get_spydata(dev);
0032 struct sockaddr * address = (struct sockaddr *) extra;
0033
0034
0035 if (!spydata)
0036 return -EOPNOTSUPP;
0037
0038
0039
0040
0041 spydata->spy_number = 0;
0042
0043
0044
0045
0046
0047
0048
0049 smp_wmb();
0050
0051
0052 if (wrqu->data.length > 0) {
0053 int i;
0054
0055
0056 for (i = 0; i < wrqu->data.length; i++)
0057 memcpy(spydata->spy_address[i], address[i].sa_data,
0058 ETH_ALEN);
0059
0060 memset(spydata->spy_stat, 0,
0061 sizeof(struct iw_quality) * IW_MAX_SPY);
0062 }
0063
0064
0065 smp_wmb();
0066
0067
0068 spydata->spy_number = wrqu->data.length;
0069
0070 return 0;
0071 }
0072 EXPORT_SYMBOL(iw_handler_set_spy);
0073
0074 int iw_handler_get_spy(struct net_device * dev,
0075 struct iw_request_info * info,
0076 union iwreq_data * wrqu,
0077 char * extra)
0078 {
0079 struct iw_spy_data * spydata = get_spydata(dev);
0080 struct sockaddr * address = (struct sockaddr *) extra;
0081 int i;
0082
0083
0084 if (!spydata)
0085 return -EOPNOTSUPP;
0086
0087 wrqu->data.length = spydata->spy_number;
0088
0089
0090 for (i = 0; i < spydata->spy_number; i++) {
0091 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
0092 address[i].sa_family = AF_UNIX;
0093 }
0094
0095 if (spydata->spy_number > 0)
0096 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
0097 spydata->spy_stat,
0098 sizeof(struct iw_quality) * spydata->spy_number);
0099
0100 for (i = 0; i < spydata->spy_number; i++)
0101 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
0102 return 0;
0103 }
0104 EXPORT_SYMBOL(iw_handler_get_spy);
0105
0106
0107
0108
0109
0110 int iw_handler_set_thrspy(struct net_device * dev,
0111 struct iw_request_info *info,
0112 union iwreq_data * wrqu,
0113 char * extra)
0114 {
0115 struct iw_spy_data * spydata = get_spydata(dev);
0116 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
0117
0118
0119 if (!spydata)
0120 return -EOPNOTSUPP;
0121
0122
0123 spydata->spy_thr_low = threshold->low;
0124 spydata->spy_thr_high = threshold->high;
0125
0126
0127 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
0128
0129 return 0;
0130 }
0131 EXPORT_SYMBOL(iw_handler_set_thrspy);
0132
0133
0134
0135
0136
0137 int iw_handler_get_thrspy(struct net_device * dev,
0138 struct iw_request_info *info,
0139 union iwreq_data * wrqu,
0140 char * extra)
0141 {
0142 struct iw_spy_data * spydata = get_spydata(dev);
0143 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
0144
0145
0146 if (!spydata)
0147 return -EOPNOTSUPP;
0148
0149
0150 threshold->low = spydata->spy_thr_low;
0151 threshold->high = spydata->spy_thr_high;
0152
0153 return 0;
0154 }
0155 EXPORT_SYMBOL(iw_handler_get_thrspy);
0156
0157
0158
0159
0160
0161 static void iw_send_thrspy_event(struct net_device * dev,
0162 struct iw_spy_data * spydata,
0163 unsigned char * address,
0164 struct iw_quality * wstats)
0165 {
0166 union iwreq_data wrqu;
0167 struct iw_thrspy threshold;
0168
0169
0170 wrqu.data.length = 1;
0171 wrqu.data.flags = 0;
0172
0173 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
0174 threshold.addr.sa_family = ARPHRD_ETHER;
0175
0176 threshold.qual = *wstats;
0177
0178 threshold.low = spydata->spy_thr_low;
0179 threshold.high = spydata->spy_thr_high;
0180
0181
0182 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
0183 }
0184
0185
0186
0187
0188
0189
0190
0191
0192 void wireless_spy_update(struct net_device * dev,
0193 unsigned char * address,
0194 struct iw_quality * wstats)
0195 {
0196 struct iw_spy_data * spydata = get_spydata(dev);
0197 int i;
0198 int match = -1;
0199
0200
0201 if (!spydata)
0202 return;
0203
0204
0205 for (i = 0; i < spydata->spy_number; i++)
0206 if (ether_addr_equal(address, spydata->spy_address[i])) {
0207 memcpy(&(spydata->spy_stat[i]), wstats,
0208 sizeof(struct iw_quality));
0209 match = i;
0210 }
0211
0212
0213
0214
0215
0216 if (match >= 0) {
0217 if (spydata->spy_thr_under[match]) {
0218 if (wstats->level > spydata->spy_thr_high.level) {
0219 spydata->spy_thr_under[match] = 0;
0220 iw_send_thrspy_event(dev, spydata,
0221 address, wstats);
0222 }
0223 } else {
0224 if (wstats->level < spydata->spy_thr_low.level) {
0225 spydata->spy_thr_under[match] = 1;
0226 iw_send_thrspy_event(dev, spydata,
0227 address, wstats);
0228 }
0229 }
0230 }
0231 }
0232 EXPORT_SYMBOL(wireless_spy_update);