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 <net/iw_handler.h>
17 static inline struct iw_spy_data
*get_spydata(struct net_device
*dev
)
19 /* This is the new way */
20 if (dev
->wireless_data
)
21 return dev
->wireless_data
->spy_data
;
25 int iw_handler_set_spy(struct net_device
* dev
,
26 struct iw_request_info
* info
,
27 union iwreq_data
* wrqu
,
30 struct iw_spy_data
* spydata
= get_spydata(dev
);
31 struct sockaddr
* address
= (struct sockaddr
*) extra
;
33 /* Make sure driver is not buggy or using the old API */
37 /* Disable spy collection while we copy the addresses.
38 * While we copy addresses, any call to wireless_spy_update()
39 * will NOP. This is OK, as anyway the addresses are changing. */
40 spydata
->spy_number
= 0;
42 /* We want to operate without locking, because wireless_spy_update()
43 * most likely will happen in the interrupt handler, and therefore
44 * have its own locking constraints and needs performance.
45 * The rtnl_lock() make sure we don't race with the other iw_handlers.
46 * This make sure wireless_spy_update() "see" that the spy list
47 * is temporarily disabled. */
50 /* Are there are addresses to copy? */
51 if (wrqu
->data
.length
> 0) {
55 for (i
= 0; i
< wrqu
->data
.length
; i
++)
56 memcpy(spydata
->spy_address
[i
], address
[i
].sa_data
,
59 memset(spydata
->spy_stat
, 0,
60 sizeof(struct iw_quality
) * IW_MAX_SPY
);
63 /* Make sure above is updated before re-enabling */
66 /* Enable addresses */
67 spydata
->spy_number
= wrqu
->data
.length
;
71 EXPORT_SYMBOL(iw_handler_set_spy
);
73 int iw_handler_get_spy(struct net_device
* dev
,
74 struct iw_request_info
* info
,
75 union iwreq_data
* wrqu
,
78 struct iw_spy_data
* spydata
= get_spydata(dev
);
79 struct sockaddr
* address
= (struct sockaddr
*) extra
;
82 /* Make sure driver is not buggy or using the old API */
86 wrqu
->data
.length
= spydata
->spy_number
;
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
;
93 /* Copy stats to the user buffer (just after). */
94 if (spydata
->spy_number
> 0)
95 memcpy(extra
+ (sizeof(struct sockaddr
) *spydata
->spy_number
),
97 sizeof(struct iw_quality
) * spydata
->spy_number
);
98 /* Reset updated flags. */
99 for (i
= 0; i
< spydata
->spy_number
; i
++)
100 spydata
->spy_stat
[i
].updated
&= ~IW_QUAL_ALL_UPDATED
;
103 EXPORT_SYMBOL(iw_handler_get_spy
);
105 /*------------------------------------------------------------------*/
107 * Standard Wireless Handler : set spy threshold
109 int iw_handler_set_thrspy(struct net_device
* dev
,
110 struct iw_request_info
*info
,
111 union iwreq_data
* wrqu
,
114 struct iw_spy_data
* spydata
= get_spydata(dev
);
115 struct iw_thrspy
* threshold
= (struct iw_thrspy
*) extra
;
117 /* Make sure driver is not buggy or using the old API */
122 memcpy(&(spydata
->spy_thr_low
), &(threshold
->low
),
123 2 * sizeof(struct iw_quality
));
126 memset(spydata
->spy_thr_under
, '\0', sizeof(spydata
->spy_thr_under
));
130 EXPORT_SYMBOL(iw_handler_set_thrspy
);
132 /*------------------------------------------------------------------*/
134 * Standard Wireless Handler : get spy threshold
136 int iw_handler_get_thrspy(struct net_device
* dev
,
137 struct iw_request_info
*info
,
138 union iwreq_data
* wrqu
,
141 struct iw_spy_data
* spydata
= get_spydata(dev
);
142 struct iw_thrspy
* threshold
= (struct iw_thrspy
*) extra
;
144 /* Make sure driver is not buggy or using the old API */
149 memcpy(&(threshold
->low
), &(spydata
->spy_thr_low
),
150 2 * sizeof(struct iw_quality
));
154 EXPORT_SYMBOL(iw_handler_get_thrspy
);
156 /*------------------------------------------------------------------*/
158 * Prepare and send a Spy Threshold event
160 static void iw_send_thrspy_event(struct net_device
* dev
,
161 struct iw_spy_data
* spydata
,
162 unsigned char * address
,
163 struct iw_quality
* wstats
)
165 union iwreq_data wrqu
;
166 struct iw_thrspy threshold
;
169 wrqu
.data
.length
= 1;
172 memcpy(threshold
.addr
.sa_data
, address
, ETH_ALEN
);
173 threshold
.addr
.sa_family
= ARPHRD_ETHER
;
175 memcpy(&(threshold
.qual
), wstats
, sizeof(struct iw_quality
));
176 /* Copy also thresholds */
177 memcpy(&(threshold
.low
), &(spydata
->spy_thr_low
),
178 2 * sizeof(struct iw_quality
));
180 /* Send event to user space */
181 wireless_send_event(dev
, SIOCGIWTHRSPY
, &wrqu
, (char *) &threshold
);
184 /* ---------------------------------------------------------------- */
186 * Call for the driver to update the spy data.
187 * For now, the spy data is a simple array. As the size of the array is
188 * small, this is good enough. If we wanted to support larger number of
189 * spy addresses, we should use something more efficient...
191 void wireless_spy_update(struct net_device
* dev
,
192 unsigned char * address
,
193 struct iw_quality
* wstats
)
195 struct iw_spy_data
* spydata
= get_spydata(dev
);
199 /* Make sure driver is not buggy or using the old API */
203 /* Update all records that match */
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
));
211 /* Generate an event if we cross the spy threshold.
212 * To avoid event storms, we have a simple hysteresis : we generate
213 * event only when we go under the low threshold or above the
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
,
223 if (wstats
->level
< spydata
->spy_thr_low
.level
) {
224 spydata
->spy_thr_under
[match
] = 1;
225 iw_send_thrspy_event(dev
, spydata
,
231 EXPORT_SYMBOL(wireless_spy_update
);