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 spydata->spy_thr_low = threshold->low;
124 spydata->spy_thr_high = threshold->high;
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 threshold->low = spydata->spy_thr_low;
151 threshold->high = spydata->spy_thr_high;
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 threshold.qual = *wstats;
177 /* Copy also thresholds */
178 threshold.low = spydata->spy_thr_low;
179 threshold.high = spydata->spy_thr_high;
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 (ether_addr_equal(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);