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);