2 * This file implement the Wireless Extensions spy API.
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
7 * (As all part of the Linux kernel, this file is GPL)
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>
18 static inline struct iw_spy_data
*get_spydata(struct net_device
*dev
)
20 /* This is the new way */
21 if (dev
->wireless_data
)
22 return dev
->wireless_data
->spy_data
;
26 int iw_handler_set_spy(struct net_device
* dev
,
27 struct iw_request_info
* info
,
28 union iwreq_data
* wrqu
,
31 struct iw_spy_data
* spydata
= get_spydata(dev
);
32 struct sockaddr
* address
= (struct sockaddr
*) extra
;
34 /* Make sure driver is not buggy or using the old API */
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 spydata
->spy_number
= 0;
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. */
51 /* Are there are addresses to copy? */
52 if (wrqu
->data
.length
> 0) {
56 for (i
= 0; i
< wrqu
->data
.length
; i
++)
57 memcpy(spydata
->spy_address
[i
], address
[i
].sa_data
,
60 memset(spydata
->spy_stat
, 0,
61 sizeof(struct iw_quality
) * IW_MAX_SPY
);
64 /* Make sure above is updated before re-enabling */
67 /* Enable addresses */
68 spydata
->spy_number
= wrqu
->data
.length
;
72 EXPORT_SYMBOL(iw_handler_set_spy
);
74 int iw_handler_get_spy(struct net_device
* dev
,
75 struct iw_request_info
* info
,
76 union iwreq_data
* wrqu
,
79 struct iw_spy_data
* spydata
= get_spydata(dev
);
80 struct sockaddr
* address
= (struct sockaddr
*) extra
;
83 /* Make sure driver is not buggy or using the old API */
87 wrqu
->data
.length
= spydata
->spy_number
;
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
;
94 /* Copy stats to the user buffer (just after). */
95 if (spydata
->spy_number
> 0)
96 memcpy(extra
+ (sizeof(struct sockaddr
) *spydata
->spy_number
),
98 sizeof(struct iw_quality
) * spydata
->spy_number
);
99 /* Reset updated flags. */
100 for (i
= 0; i
< spydata
->spy_number
; i
++)
101 spydata
->spy_stat
[i
].updated
&= ~IW_QUAL_ALL_UPDATED
;
104 EXPORT_SYMBOL(iw_handler_get_spy
);
106 /*------------------------------------------------------------------*/
108 * Standard Wireless Handler : set spy threshold
110 int iw_handler_set_thrspy(struct net_device
* dev
,
111 struct iw_request_info
*info
,
112 union iwreq_data
* wrqu
,
115 struct iw_spy_data
* spydata
= get_spydata(dev
);
116 struct iw_thrspy
* threshold
= (struct iw_thrspy
*) extra
;
118 /* Make sure driver is not buggy or using the old API */
123 memcpy(&(spydata
->spy_thr_low
), &(threshold
->low
),
124 2 * sizeof(struct iw_quality
));
127 memset(spydata
->spy_thr_under
, '\0', sizeof(spydata
->spy_thr_under
));
131 EXPORT_SYMBOL(iw_handler_set_thrspy
);
133 /*------------------------------------------------------------------*/
135 * Standard Wireless Handler : get spy threshold
137 int iw_handler_get_thrspy(struct net_device
* dev
,
138 struct iw_request_info
*info
,
139 union iwreq_data
* wrqu
,
142 struct iw_spy_data
* spydata
= get_spydata(dev
);
143 struct iw_thrspy
* threshold
= (struct iw_thrspy
*) extra
;
145 /* Make sure driver is not buggy or using the old API */
150 memcpy(&(threshold
->low
), &(spydata
->spy_thr_low
),
151 2 * sizeof(struct iw_quality
));
155 EXPORT_SYMBOL(iw_handler_get_thrspy
);
157 /*------------------------------------------------------------------*/
159 * Prepare and send a Spy Threshold event
161 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
)
166 union iwreq_data wrqu
;
167 struct iw_thrspy threshold
;
170 wrqu
.data
.length
= 1;
173 memcpy(threshold
.addr
.sa_data
, address
, ETH_ALEN
);
174 threshold
.addr
.sa_family
= ARPHRD_ETHER
;
176 memcpy(&(threshold
.qual
), wstats
, sizeof(struct iw_quality
));
177 /* Copy also thresholds */
178 memcpy(&(threshold
.low
), &(spydata
->spy_thr_low
),
179 2 * sizeof(struct iw_quality
));
181 /* Send event to user space */
182 wireless_send_event(dev
, SIOCGIWTHRSPY
, &wrqu
, (char *) &threshold
);
185 /* ---------------------------------------------------------------- */
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...
192 void wireless_spy_update(struct net_device
* dev
,
193 unsigned char * address
,
194 struct iw_quality
* wstats
)
196 struct iw_spy_data
* spydata
= get_spydata(dev
);
200 /* Make sure driver is not buggy or using the old API */
204 /* Update all records that match */
205 for (i
= 0; i
< spydata
->spy_number
; i
++)
206 if (!compare_ether_addr(address
, spydata
->spy_address
[i
])) {
207 memcpy(&(spydata
->spy_stat
[i
]), wstats
,
208 sizeof(struct iw_quality
));
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
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
,
224 if (wstats
->level
< spydata
->spy_thr_low
.level
) {
225 spydata
->spy_thr_under
[match
] = 1;
226 iw_send_thrspy_event(dev
, spydata
,
232 EXPORT_SYMBOL(wireless_spy_update
);