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 : 0 : 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 [ # # ]: 0 : struct iw_spy_data * spydata = get_spydata(dev);
32 : 0 : 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 [ # # ]: 0 : struct iw_spy_data * spydata = get_spydata(dev);
80 : 0 : struct sockaddr * address = (struct sockaddr *) extra;
81 : 0 : 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 : 0 : 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 [ # # ]: 0 : struct iw_spy_data * spydata = get_spydata(dev);
116 : 0 : 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 [ # # ]: 0 : struct iw_spy_data * spydata = get_spydata(dev);
143 : 0 : 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 : 0 : union iwreq_data wrqu;
167 : 0 : 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 [ # # ]: 0 : struct iw_spy_data * spydata = get_spydata(dev);
197 : 0 : int i;
198 : 0 : int match = -1;
199 : :
200 : : /* Make sure driver is not buggy or using the old API */
201 [ # # ]: 0 : if (!spydata)
202 : : 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 : 0 : 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);
|