Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / net / wireless / intel / ipw2x00 / libipw_spy.c
blobba876e92f7f6acdf83a88c4464953eebd7205ec0
1 /*
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)
8 */
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>
15 #include <net/arp.h>
16 #include <net/wext.h>
17 #include "libipw.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;
25 return NULL;
28 int ipw_wx_set_spy(struct net_device * dev,
29 struct iw_request_info * info,
30 union iwreq_data * wrqu,
31 char * extra)
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 */
37 if (!spydata)
38 return -EOPNOTSUPP;
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. */
51 smp_wmb();
53 /* Are there are addresses to copy? */
54 if (wrqu->data.length > 0) {
55 int i;
57 /* Copy addresses */
58 for (i = 0; i < wrqu->data.length; i++)
59 memcpy(spydata->spy_address[i], address[i].sa_data,
60 ETH_ALEN);
61 /* Reset stats */
62 memset(spydata->spy_stat, 0,
63 sizeof(struct iw_quality) * IW_MAX_SPY);
66 /* Make sure above is updated before re-enabling */
67 smp_wmb();
69 /* Enable addresses */
70 spydata->spy_number = wrqu->data.length;
72 return 0;
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,
79 char * extra)
81 struct iw_spy_data * spydata = get_spydata(dev);
82 struct sockaddr * address = (struct sockaddr *) extra;
83 int i;
85 /* Make sure driver is not buggy or using the old API */
86 if (!spydata)
87 return -EOPNOTSUPP;
89 wrqu->data.length = spydata->spy_number;
91 /* Copy addresses. */
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),
99 spydata->spy_stat,
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;
104 return 0;
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,
115 char * extra)
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 */
121 if (!spydata)
122 return -EOPNOTSUPP;
124 /* Just do it */
125 spydata->spy_thr_low = threshold->low;
126 spydata->spy_thr_high = threshold->high;
128 /* Clear flag */
129 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
131 return 0;
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,
142 char * extra)
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 */
148 if (!spydata)
149 return -EOPNOTSUPP;
151 /* Just do it */
152 threshold->low = spydata->spy_thr_low;
153 threshold->high = spydata->spy_thr_high;
155 return 0;
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;
171 /* Init */
172 wrqu.data.length = 1;
173 wrqu.data.flags = 0;
174 /* Copy address */
175 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
176 threshold.addr.sa_family = ARPHRD_ETHER;
177 /* Copy stats */
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);
199 int i;
200 int match = -1;
202 /* Make sure driver is not buggy or using the old API */
203 if (!spydata)
204 return;
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));
211 match = i;
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
217 * high threshold. */
218 if (match >= 0) {
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,
223 address, wstats);
225 } else {
226 if (wstats->level < spydata->spy_thr_low.level) {
227 spydata->spy_thr_under[match] = 1;
228 iw_send_thrspy_event(dev, spydata,
229 address, wstats);