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>
19 static struct iw_spy_data
*get_spydata(struct net_device
*dev
)
21 struct libipw_device
*ieee
= netdev_priv(dev
);
23 if (ieee
->spy_enabled
)
24 return &ieee
->spy_data
;
28 int ipw_wx_set_spy(struct net_device
* dev
,
29 struct iw_request_info
* info
,
30 union iwreq_data
* wrqu
,
33 struct iw_spy_data
* spydata
= get_spydata(dev
);
34 struct sockaddr
* address
= (struct sockaddr
*) extra
;
36 /* Make sure driver is not buggy or using the old API */
40 /* Disable spy collection while we copy the addresses.
41 * While we copy addresses, any call to libipw_spy_update()
42 * will NOP. This is OK, as anyway the addresses are changing. */
43 spydata
->spy_number
= 0;
45 /* We want to operate without locking, because libipw_spy_update()
46 * most likely will happen in the interrupt handler, and therefore
47 * have its own locking constraints and needs performance.
48 * The rtnl_lock() make sure we don't race with the other iw_handlers.
49 * This make sure libipw_spy_update() "see" that the spy list
50 * is temporarily disabled. */
53 /* Are there are addresses to copy? */
54 if (wrqu
->data
.length
> 0) {
58 for (i
= 0; i
< wrqu
->data
.length
; i
++)
59 memcpy(spydata
->spy_address
[i
], address
[i
].sa_data
,
62 memset(spydata
->spy_stat
, 0,
63 sizeof(struct iw_quality
) * IW_MAX_SPY
);
66 /* Make sure above is updated before re-enabling */
69 /* Enable addresses */
70 spydata
->spy_number
= wrqu
->data
.length
;
74 EXPORT_SYMBOL(ipw_wx_set_spy
);
76 int ipw_wx_get_spy(struct net_device
* dev
,
77 struct iw_request_info
* info
,
78 union iwreq_data
* wrqu
,
81 struct iw_spy_data
* spydata
= get_spydata(dev
);
82 struct sockaddr
* address
= (struct sockaddr
*) extra
;
85 /* Make sure driver is not buggy or using the old API */
89 wrqu
->data
.length
= spydata
->spy_number
;
92 for (i
= 0; i
< spydata
->spy_number
; i
++) {
93 memcpy(address
[i
].sa_data
, spydata
->spy_address
[i
], ETH_ALEN
);
94 address
[i
].sa_family
= AF_UNIX
;
96 /* Copy stats to the user buffer (just after). */
97 if (spydata
->spy_number
> 0)
98 memcpy(extra
+ (sizeof(struct sockaddr
) *spydata
->spy_number
),
100 sizeof(struct iw_quality
) * spydata
->spy_number
);
101 /* Reset updated flags. */
102 for (i
= 0; i
< spydata
->spy_number
; i
++)
103 spydata
->spy_stat
[i
].updated
&= ~IW_QUAL_ALL_UPDATED
;
106 EXPORT_SYMBOL(ipw_wx_get_spy
);
108 /*------------------------------------------------------------------*/
110 * Standard Wireless Handler : set spy threshold
112 int ipw_wx_set_thrspy(struct net_device
* dev
,
113 struct iw_request_info
* info
,
114 union iwreq_data
* wrqu
,
117 struct iw_spy_data
* spydata
= get_spydata(dev
);
118 struct iw_thrspy
* threshold
= (struct iw_thrspy
*) extra
;
120 /* Make sure driver is not buggy or using the old API */
125 spydata
->spy_thr_low
= threshold
->low
;
126 spydata
->spy_thr_high
= threshold
->high
;
129 memset(spydata
->spy_thr_under
, '\0', sizeof(spydata
->spy_thr_under
));
133 EXPORT_SYMBOL(ipw_wx_set_thrspy
);
135 /*------------------------------------------------------------------*/
137 * Standard Wireless Handler : get spy threshold
139 int ipw_wx_get_thrspy(struct net_device
* dev
,
140 struct iw_request_info
* info
,
141 union iwreq_data
* wrqu
,
144 struct iw_spy_data
* spydata
= get_spydata(dev
);
145 struct iw_thrspy
* threshold
= (struct iw_thrspy
*) extra
;
147 /* Make sure driver is not buggy or using the old API */
152 threshold
->low
= spydata
->spy_thr_low
;
153 threshold
->high
= spydata
->spy_thr_high
;
157 EXPORT_SYMBOL(ipw_wx_get_thrspy
);
159 /*------------------------------------------------------------------*/
161 * Prepare and send a Spy Threshold event
163 static void iw_send_thrspy_event(struct net_device
* dev
,
164 struct iw_spy_data
* spydata
,
165 unsigned char * address
,
166 struct iw_quality
* wstats
)
168 union iwreq_data wrqu
;
169 struct iw_thrspy threshold
;
172 wrqu
.data
.length
= 1;
175 memcpy(threshold
.addr
.sa_data
, address
, ETH_ALEN
);
176 threshold
.addr
.sa_family
= ARPHRD_ETHER
;
178 threshold
.qual
= *wstats
;
179 /* Copy also thresholds */
180 threshold
.low
= spydata
->spy_thr_low
;
181 threshold
.high
= spydata
->spy_thr_high
;
183 /* Send event to user space */
184 wireless_send_event(dev
, SIOCGIWTHRSPY
, &wrqu
, (char *) &threshold
);
187 /* ---------------------------------------------------------------- */
189 * Call for the driver to update the spy data.
190 * For now, the spy data is a simple array. As the size of the array is
191 * small, this is good enough. If we wanted to support larger number of
192 * spy addresses, we should use something more efficient...
194 void libipw_spy_update(struct net_device
* dev
,
195 unsigned char * address
,
196 struct iw_quality
* wstats
)
198 struct iw_spy_data
* spydata
= get_spydata(dev
);
202 /* Make sure driver is not buggy or using the old API */
206 /* Update all records that match */
207 for (i
= 0; i
< spydata
->spy_number
; i
++)
208 if (ether_addr_equal(address
, spydata
->spy_address
[i
])) {
209 memcpy(&(spydata
->spy_stat
[i
]), wstats
,
210 sizeof(struct iw_quality
));
214 /* Generate an event if we cross the spy threshold.
215 * To avoid event storms, we have a simple hysteresis : we generate
216 * event only when we go under the low threshold or above the
219 if (spydata
->spy_thr_under
[match
]) {
220 if (wstats
->level
> spydata
->spy_thr_high
.level
) {
221 spydata
->spy_thr_under
[match
] = 0;
222 iw_send_thrspy_event(dev
, spydata
,
226 if (wstats
->level
< spydata
->spy_thr_low
.level
) {
227 spydata
->spy_thr_under
[match
] = 1;
228 iw_send_thrspy_event(dev
, spydata
,