1
2
3
4
5
6
7
8
9
10#include <linux/wireless.h>
11#include <linux/netdevice.h>
12#include <linux/etherdevice.h>
13#include <net/iw_handler.h>
14#include <net/arp.h>
15#include <net/wext.h>
16
17static inline struct iw_spy_data *get_spydata(struct net_device *dev)
18{
19
20 if (dev->wireless_data)
21 return dev->wireless_data->spy_data;
22 return NULL;
23}
24
25int iw_handler_set_spy(struct net_device * dev,
26 struct iw_request_info * info,
27 union iwreq_data * wrqu,
28 char * extra)
29{
30 struct iw_spy_data * spydata = get_spydata(dev);
31 struct sockaddr * address = (struct sockaddr *) extra;
32
33
34 if (!spydata)
35 return -EOPNOTSUPP;
36
37
38
39
40 spydata->spy_number = 0;
41
42
43
44
45
46
47
48 smp_wmb();
49
50
51 if (wrqu->data.length > 0) {
52 int i;
53
54
55 for (i = 0; i < wrqu->data.length; i++)
56 memcpy(spydata->spy_address[i], address[i].sa_data,
57 ETH_ALEN);
58
59 memset(spydata->spy_stat, 0,
60 sizeof(struct iw_quality) * IW_MAX_SPY);
61 }
62
63
64 smp_wmb();
65
66
67 spydata->spy_number = wrqu->data.length;
68
69 return 0;
70}
71EXPORT_SYMBOL(iw_handler_set_spy);
72
73int iw_handler_get_spy(struct net_device * dev,
74 struct iw_request_info * info,
75 union iwreq_data * wrqu,
76 char * extra)
77{
78 struct iw_spy_data * spydata = get_spydata(dev);
79 struct sockaddr * address = (struct sockaddr *) extra;
80 int i;
81
82
83 if (!spydata)
84 return -EOPNOTSUPP;
85
86 wrqu->data.length = spydata->spy_number;
87
88
89 for (i = 0; i < spydata->spy_number; i++) {
90 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
91 address[i].sa_family = AF_UNIX;
92 }
93
94 if (spydata->spy_number > 0)
95 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
96 spydata->spy_stat,
97 sizeof(struct iw_quality) * spydata->spy_number);
98
99 for (i = 0; i < spydata->spy_number; i++)
100 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
101 return 0;
102}
103EXPORT_SYMBOL(iw_handler_get_spy);
104
105
106
107
108
109int iw_handler_set_thrspy(struct net_device * dev,
110 struct iw_request_info *info,
111 union iwreq_data * wrqu,
112 char * extra)
113{
114 struct iw_spy_data * spydata = get_spydata(dev);
115 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
116
117
118 if (!spydata)
119 return -EOPNOTSUPP;
120
121
122 memcpy(&(spydata->spy_thr_low), &(threshold->low),
123 2 * sizeof(struct iw_quality));
124
125
126 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
127
128 return 0;
129}
130EXPORT_SYMBOL(iw_handler_set_thrspy);
131
132
133
134
135
136int iw_handler_get_thrspy(struct net_device * dev,
137 struct iw_request_info *info,
138 union iwreq_data * wrqu,
139 char * extra)
140{
141 struct iw_spy_data * spydata = get_spydata(dev);
142 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
143
144
145 if (!spydata)
146 return -EOPNOTSUPP;
147
148
149 memcpy(&(threshold->low), &(spydata->spy_thr_low),
150 2 * sizeof(struct iw_quality));
151
152 return 0;
153}
154EXPORT_SYMBOL(iw_handler_get_thrspy);
155
156
157
158
159
160static void iw_send_thrspy_event(struct net_device * dev,
161 struct iw_spy_data * spydata,
162 unsigned char * address,
163 struct iw_quality * wstats)
164{
165 union iwreq_data wrqu;
166 struct iw_thrspy threshold;
167
168
169 wrqu.data.length = 1;
170 wrqu.data.flags = 0;
171
172 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
173 threshold.addr.sa_family = ARPHRD_ETHER;
174
175 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
176
177 memcpy(&(threshold.low), &(spydata->spy_thr_low),
178 2 * sizeof(struct iw_quality));
179
180
181 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
182}
183
184
185
186
187
188
189
190
191void wireless_spy_update(struct net_device * dev,
192 unsigned char * address,
193 struct iw_quality * wstats)
194{
195 struct iw_spy_data * spydata = get_spydata(dev);
196 int i;
197 int match = -1;
198
199
200 if (!spydata)
201 return;
202
203
204 for (i = 0; i < spydata->spy_number; i++)
205 if (!compare_ether_addr(address, spydata->spy_address[i])) {
206 memcpy(&(spydata->spy_stat[i]), wstats,
207 sizeof(struct iw_quality));
208 match = i;
209 }
210
211
212
213
214
215 if (match >= 0) {
216 if (spydata->spy_thr_under[match]) {
217 if (wstats->level > spydata->spy_thr_high.level) {
218 spydata->spy_thr_under[match] = 0;
219 iw_send_thrspy_event(dev, spydata,
220 address, wstats);
221 }
222 } else {
223 if (wstats->level < spydata->spy_thr_low.level) {
224 spydata->spy_thr_under[match] = 1;
225 iw_send_thrspy_event(dev, spydata,
226 address, wstats);
227 }
228 }
229 }
230}
231EXPORT_SYMBOL(wireless_spy_update);
232