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 <linux/export.h>
14#include <net/iw_handler.h>
15#include <net/arp.h>
16#include <net/wext.h>
17
18static inline struct iw_spy_data *get_spydata(struct net_device *dev)
19{
20
21 if (dev->wireless_data)
22 return dev->wireless_data->spy_data;
23 return NULL;
24}
25
26int 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
35 if (!spydata)
36 return -EOPNOTSUPP;
37
38
39
40
41 spydata->spy_number = 0;
42
43
44
45
46
47
48
49 smp_wmb();
50
51
52 if (wrqu->data.length > 0) {
53 int i;
54
55
56 for (i = 0; i < wrqu->data.length; i++)
57 memcpy(spydata->spy_address[i], address[i].sa_data,
58 ETH_ALEN);
59
60 memset(spydata->spy_stat, 0,
61 sizeof(struct iw_quality) * IW_MAX_SPY);
62 }
63
64
65 smp_wmb();
66
67
68 spydata->spy_number = wrqu->data.length;
69
70 return 0;
71}
72EXPORT_SYMBOL(iw_handler_set_spy);
73
74int 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
84 if (!spydata)
85 return -EOPNOTSUPP;
86
87 wrqu->data.length = spydata->spy_number;
88
89
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
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
100 for (i = 0; i < spydata->spy_number; i++)
101 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
102 return 0;
103}
104EXPORT_SYMBOL(iw_handler_get_spy);
105
106
107
108
109
110int 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
119 if (!spydata)
120 return -EOPNOTSUPP;
121
122
123 memcpy(&(spydata->spy_thr_low), &(threshold->low),
124 2 * sizeof(struct iw_quality));
125
126
127 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
128
129 return 0;
130}
131EXPORT_SYMBOL(iw_handler_set_thrspy);
132
133
134
135
136
137int 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
146 if (!spydata)
147 return -EOPNOTSUPP;
148
149
150 memcpy(&(threshold->low), &(spydata->spy_thr_low),
151 2 * sizeof(struct iw_quality));
152
153 return 0;
154}
155EXPORT_SYMBOL(iw_handler_get_thrspy);
156
157
158
159
160
161static 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
170 wrqu.data.length = 1;
171 wrqu.data.flags = 0;
172
173 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
174 threshold.addr.sa_family = ARPHRD_ETHER;
175
176 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
177
178 memcpy(&(threshold.low), &(spydata->spy_thr_low),
179 2 * sizeof(struct iw_quality));
180
181
182 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
183}
184
185
186
187
188
189
190
191
192void 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
201 if (!spydata)
202 return;
203
204
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
213
214
215
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}
232EXPORT_SYMBOL(wireless_spy_update);
233