]> Git Repo - J-linux.git/blob - drivers/net/wireless/intel/ipw2x00/libipw_spy.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / net / wireless / intel / ipw2x00 / libipw_spy.c
1 /*
2  * This file implement the Wireless Extensions spy API.
3  *
4  * Authors :    Jean Tourrilhes - HPL - <[email protected]>
5  * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
6  *
7  * (As all part of the Linux kernel, this file is GPL)
8  */
9
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"
18
19 static struct iw_spy_data *get_spydata(struct net_device *dev)
20 {
21         struct libipw_device *ieee = netdev_priv(dev);
22
23         if (ieee->spy_enabled)
24                 return &ieee->spy_data;
25         return NULL;
26 }
27
28 int ipw_wx_set_spy(struct net_device *          dev,
29                    struct iw_request_info *     info,
30                    union iwreq_data *           wrqu,
31                    char *                       extra)
32 {
33         struct iw_spy_data *    spydata = get_spydata(dev);
34         struct sockaddr *       address = (struct sockaddr *) extra;
35
36         /* Make sure driver is not buggy or using the old API */
37         if (!spydata)
38                 return -EOPNOTSUPP;
39
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;
44
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();
52
53         /* Are there are addresses to copy? */
54         if (wrqu->data.length > 0) {
55                 int i;
56
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);
64         }
65
66         /* Make sure above is updated before re-enabling */
67         smp_wmb();
68
69         /* Enable addresses */
70         spydata->spy_number = wrqu->data.length;
71
72         return 0;
73 }
74 EXPORT_SYMBOL(ipw_wx_set_spy);
75
76 int ipw_wx_get_spy(struct net_device *          dev,
77                    struct iw_request_info *     info,
78                    union iwreq_data *           wrqu,
79                    char *                       extra)
80 {
81         struct iw_spy_data *    spydata = get_spydata(dev);
82         struct sockaddr *       address = (struct sockaddr *) extra;
83         int                     i;
84
85         /* Make sure driver is not buggy or using the old API */
86         if (!spydata)
87                 return -EOPNOTSUPP;
88
89         wrqu->data.length = spydata->spy_number;
90
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;
95         }
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;
105 }
106 EXPORT_SYMBOL(ipw_wx_get_spy);
107
108 /*------------------------------------------------------------------*/
109 /*
110  * Standard Wireless Handler : set spy threshold
111  */
112 int ipw_wx_set_thrspy(struct net_device *       dev,
113                       struct iw_request_info *  info,
114                       union iwreq_data *        wrqu,
115                       char *                    extra)
116 {
117         struct iw_spy_data *    spydata = get_spydata(dev);
118         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
119
120         /* Make sure driver is not buggy or using the old API */
121         if (!spydata)
122                 return -EOPNOTSUPP;
123
124         /* Just do it */
125         spydata->spy_thr_low = threshold->low;
126         spydata->spy_thr_high = threshold->high;
127
128         /* Clear flag */
129         memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
130
131         return 0;
132 }
133 EXPORT_SYMBOL(ipw_wx_set_thrspy);
134
135 /*------------------------------------------------------------------*/
136 /*
137  * Standard Wireless Handler : get spy threshold
138  */
139 int ipw_wx_get_thrspy(struct net_device *       dev,
140                       struct iw_request_info *  info,
141                       union iwreq_data *        wrqu,
142                       char *                    extra)
143 {
144         struct iw_spy_data *    spydata = get_spydata(dev);
145         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
146
147         /* Make sure driver is not buggy or using the old API */
148         if (!spydata)
149                 return -EOPNOTSUPP;
150
151         /* Just do it */
152         threshold->low = spydata->spy_thr_low;
153         threshold->high = spydata->spy_thr_high;
154
155         return 0;
156 }
157 EXPORT_SYMBOL(ipw_wx_get_thrspy);
158
159 /*------------------------------------------------------------------*/
160 /*
161  * Prepare and send a Spy Threshold event
162  */
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)
167 {
168         union iwreq_data        wrqu;
169         struct iw_thrspy        threshold;
170
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;
182
183         /* Send event to user space */
184         wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
185 }
186
187 /* ---------------------------------------------------------------- */
188 /*
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...
193  */
194 void libipw_spy_update(struct net_device *      dev,
195                        unsigned char *          address,
196                        struct iw_quality *      wstats)
197 {
198         struct iw_spy_data *    spydata = get_spydata(dev);
199         int                     i;
200         int                     match = -1;
201
202         /* Make sure driver is not buggy or using the old API */
203         if (!spydata)
204                 return;
205
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;
212                 }
213
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);
224                         }
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);
230                         }
231                 }
232         }
233 }
This page took 0.040811 seconds and 4 git commands to generate.