ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / core / wireless.c
1 /*
2  * This file implement the Wireless Extensions APIs.
3  *
4  * Authors :    Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5  * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
6  *
7  * (As all part of the Linux kernel, this file is GPL)
8  */
9
10 /************************** DOCUMENTATION **************************/
11 /*
12  * API definition :
13  * --------------
14  * See <linux/wireless.h> for details of the APIs and the rest.
15  *
16  * History :
17  * -------
18  *
19  * v1 - 5.12.01 - Jean II
20  *      o Created this file.
21  *
22  * v2 - 13.12.01 - Jean II
23  *      o Move /proc/net/wireless stuff from net/core/dev.c to here
24  *      o Make Wireless Extension IOCTLs go through here
25  *      o Added iw_handler handling ;-)
26  *      o Added standard ioctl description
27  *      o Initial dumb commit strategy based on orinoco.c
28  *
29  * v3 - 19.12.01 - Jean II
30  *      o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
31  *      o Add event dispatcher function
32  *      o Add event description
33  *      o Propagate events as rtnetlink IFLA_WIRELESS option
34  *      o Generate event on selected SET requests
35  *
36  * v4 - 18.04.02 - Jean II
37  *      o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
38  *
39  * v5 - 21.06.02 - Jean II
40  *      o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
41  *      o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
42  *      o Add IWEVCUSTOM for driver specific event/scanning token
43  *      o Turn on WE_STRICT_WRITE by default + kernel warning
44  *      o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
45  *      o Fix off-by-one in test (extra_size <= IFNAMSIZ)
46  *
47  * v6 - 9.01.03 - Jean II
48  *      o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
49  *      o Add enhanced spy support : iw_handler_set_thrspy() and event.
50  *      o Add WIRELESS_EXT version display in /proc/net/wireless
51  */
52
53 /***************************** INCLUDES *****************************/
54
55 #include <linux/config.h>               /* Not needed ??? */
56 #include <linux/module.h>
57 #include <linux/types.h>                /* off_t */
58 #include <linux/netdevice.h>            /* struct ifreq, dev_get_by_name() */
59 #include <linux/proc_fs.h>
60 #include <linux/rtnetlink.h>            /* rtnetlink stuff */
61 #include <linux/seq_file.h>
62 #include <linux/init.h>                 /* for __init */
63 #include <linux/if_arp.h>               /* ARPHRD_ETHER */
64
65 #include <linux/wireless.h>             /* Pretty obvious */
66 #include <net/iw_handler.h>             /* New driver API */
67
68 #include <asm/uaccess.h>                /* copy_to_user() */
69
70 /**************************** CONSTANTS ****************************/
71
72 /* Enough lenience, let's make sure things are proper... */
73 #define WE_STRICT_WRITE         /* Check write buffer size */
74 /* I'll probably drop both the define and kernel message in the next version */
75
76 /* Debugging stuff */
77 #undef WE_IOCTL_DEBUG           /* Debug IOCTL API */
78 #undef WE_EVENT_DEBUG           /* Debug Event dispatcher */
79 #undef WE_SPY_DEBUG             /* Debug enhanced spy support */
80
81 /* Options */
82 #define WE_EVENT_NETLINK        /* Propagate events using rtnetlink */
83 #define WE_SET_EVENT            /* Generate an event on some set commands */
84
85 /************************* GLOBAL VARIABLES *************************/
86 /*
87  * You should not use global variables, because of re-entrancy.
88  * On our case, it's only const, so it's OK...
89  */
90 /*
91  * Meta-data about all the standard Wireless Extension request we
92  * know about.
93  */
94 static const struct iw_ioctl_description standard_ioctl[] = {
95         [SIOCSIWCOMMIT  - SIOCIWFIRST] = {
96                 .header_type    = IW_HEADER_TYPE_NULL,
97         },
98         [SIOCGIWNAME    - SIOCIWFIRST] = {
99                 .header_type    = IW_HEADER_TYPE_CHAR,
100                 .flags          = IW_DESCR_FLAG_DUMP,
101         },
102         [SIOCSIWNWID    - SIOCIWFIRST] = {
103                 .header_type    = IW_HEADER_TYPE_PARAM,
104                 .flags          = IW_DESCR_FLAG_EVENT,
105         },
106         [SIOCGIWNWID    - SIOCIWFIRST] = {
107                 .header_type    = IW_HEADER_TYPE_PARAM,
108                 .flags          = IW_DESCR_FLAG_DUMP,
109         },
110         [SIOCSIWFREQ    - SIOCIWFIRST] = {
111                 .header_type    = IW_HEADER_TYPE_FREQ,
112                 .flags          = IW_DESCR_FLAG_EVENT,
113         },
114         [SIOCGIWFREQ    - SIOCIWFIRST] = {
115                 .header_type    = IW_HEADER_TYPE_FREQ,
116                 .flags          = IW_DESCR_FLAG_DUMP,
117         },
118         [SIOCSIWMODE    - SIOCIWFIRST] = {
119                 .header_type    = IW_HEADER_TYPE_UINT,
120                 .flags          = IW_DESCR_FLAG_EVENT,
121         },
122         [SIOCGIWMODE    - SIOCIWFIRST] = {
123                 .header_type    = IW_HEADER_TYPE_UINT,
124                 .flags          = IW_DESCR_FLAG_DUMP,
125         },
126         [SIOCSIWSENS    - SIOCIWFIRST] = {
127                 .header_type    = IW_HEADER_TYPE_PARAM,
128         },
129         [SIOCGIWSENS    - SIOCIWFIRST] = {
130                 .header_type    = IW_HEADER_TYPE_PARAM,
131         },
132         [SIOCSIWRANGE   - SIOCIWFIRST] = {
133                 .header_type    = IW_HEADER_TYPE_NULL,
134         },
135         [SIOCGIWRANGE   - SIOCIWFIRST] = {
136                 .header_type    = IW_HEADER_TYPE_POINT,
137                 .token_size     = 1,
138                 .max_tokens     = sizeof(struct iw_range),
139                 .flags          = IW_DESCR_FLAG_DUMP,
140         },
141         [SIOCSIWPRIV    - SIOCIWFIRST] = {
142                 .header_type    = IW_HEADER_TYPE_NULL,
143         },
144         [SIOCGIWPRIV    - SIOCIWFIRST] = { /* (handled directly by us) */
145                 .header_type    = IW_HEADER_TYPE_NULL,
146         },
147         [SIOCSIWSTATS   - SIOCIWFIRST] = {
148                 .header_type    = IW_HEADER_TYPE_NULL,
149         },
150         [SIOCGIWSTATS   - SIOCIWFIRST] = { /* (handled directly by us) */
151                 .header_type    = IW_HEADER_TYPE_NULL,
152                 .flags          = IW_DESCR_FLAG_DUMP,
153         },
154         [SIOCSIWSPY     - SIOCIWFIRST] = {
155                 .header_type    = IW_HEADER_TYPE_POINT,
156                 .token_size     = sizeof(struct sockaddr),
157                 .max_tokens     = IW_MAX_SPY,
158         },
159         [SIOCGIWSPY     - SIOCIWFIRST] = {
160                 .header_type    = IW_HEADER_TYPE_POINT,
161                 .token_size     = sizeof(struct sockaddr) +
162                                   sizeof(struct iw_quality),
163                 .max_tokens     = IW_MAX_SPY,
164         },
165         [SIOCSIWTHRSPY  - SIOCIWFIRST] = {
166                 .header_type    = IW_HEADER_TYPE_POINT,
167                 .token_size     = sizeof(struct iw_thrspy),
168                 .min_tokens     = 1,
169                 .max_tokens     = 1,
170         },
171         [SIOCGIWTHRSPY  - SIOCIWFIRST] = {
172                 .header_type    = IW_HEADER_TYPE_POINT,
173                 .token_size     = sizeof(struct iw_thrspy),
174                 .min_tokens     = 1,
175                 .max_tokens     = 1,
176         },
177         [SIOCSIWAP      - SIOCIWFIRST] = {
178                 .header_type    = IW_HEADER_TYPE_ADDR,
179         },
180         [SIOCGIWAP      - SIOCIWFIRST] = {
181                 .header_type    = IW_HEADER_TYPE_ADDR,
182                 .flags          = IW_DESCR_FLAG_DUMP,
183         },
184         [SIOCGIWAPLIST  - SIOCIWFIRST] = {
185                 .header_type    = IW_HEADER_TYPE_POINT,
186                 .token_size     = sizeof(struct sockaddr) +
187                                   sizeof(struct iw_quality),
188                 .max_tokens     = IW_MAX_AP,
189         },
190         [SIOCSIWSCAN    - SIOCIWFIRST] = {
191                 .header_type    = IW_HEADER_TYPE_PARAM,
192         },
193         [SIOCGIWSCAN    - SIOCIWFIRST] = {
194                 .header_type    = IW_HEADER_TYPE_POINT,
195                 .token_size     = 1,
196                 .max_tokens     = IW_SCAN_MAX_DATA,
197         },
198         [SIOCSIWESSID   - SIOCIWFIRST] = {
199                 .header_type    = IW_HEADER_TYPE_POINT,
200                 .token_size     = 1,
201                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
202                 .flags          = IW_DESCR_FLAG_EVENT,
203         },
204         [SIOCGIWESSID   - SIOCIWFIRST] = {
205                 .header_type    = IW_HEADER_TYPE_POINT,
206                 .token_size     = 1,
207                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
208                 .flags          = IW_DESCR_FLAG_DUMP,
209         },
210         [SIOCSIWNICKN   - SIOCIWFIRST] = {
211                 .header_type    = IW_HEADER_TYPE_POINT,
212                 .token_size     = 1,
213                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
214         },
215         [SIOCGIWNICKN   - SIOCIWFIRST] = {
216                 .header_type    = IW_HEADER_TYPE_POINT,
217                 .token_size     = 1,
218                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
219         },
220         [SIOCSIWRATE    - SIOCIWFIRST] = {
221                 .header_type    = IW_HEADER_TYPE_PARAM,
222         },
223         [SIOCGIWRATE    - SIOCIWFIRST] = {
224                 .header_type    = IW_HEADER_TYPE_PARAM,
225         },
226         [SIOCSIWRTS     - SIOCIWFIRST] = {
227                 .header_type    = IW_HEADER_TYPE_PARAM,
228         },
229         [SIOCGIWRTS     - SIOCIWFIRST] = {
230                 .header_type    = IW_HEADER_TYPE_PARAM,
231         },
232         [SIOCSIWFRAG    - SIOCIWFIRST] = {
233                 .header_type    = IW_HEADER_TYPE_PARAM,
234         },
235         [SIOCGIWFRAG    - SIOCIWFIRST] = {
236                 .header_type    = IW_HEADER_TYPE_PARAM,
237         },
238         [SIOCSIWTXPOW   - SIOCIWFIRST] = {
239                 .header_type    = IW_HEADER_TYPE_PARAM,
240         },
241         [SIOCGIWTXPOW   - SIOCIWFIRST] = {
242                 .header_type    = IW_HEADER_TYPE_PARAM,
243         },
244         [SIOCSIWRETRY   - SIOCIWFIRST] = {
245                 .header_type    = IW_HEADER_TYPE_PARAM,
246         },
247         [SIOCGIWRETRY   - SIOCIWFIRST] = {
248                 .header_type    = IW_HEADER_TYPE_PARAM,
249         },
250         [SIOCSIWENCODE  - SIOCIWFIRST] = {
251                 .header_type    = IW_HEADER_TYPE_POINT,
252                 .token_size     = 1,
253                 .max_tokens     = IW_ENCODING_TOKEN_MAX,
254                 .flags          = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
255         },
256         [SIOCGIWENCODE  - SIOCIWFIRST] = {
257                 .header_type    = IW_HEADER_TYPE_POINT,
258                 .token_size     = 1,
259                 .max_tokens     = IW_ENCODING_TOKEN_MAX,
260                 .flags          = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
261         },
262         [SIOCSIWPOWER   - SIOCIWFIRST] = {
263                 .header_type    = IW_HEADER_TYPE_PARAM,
264         },
265         [SIOCGIWPOWER   - SIOCIWFIRST] = {
266                 .header_type    = IW_HEADER_TYPE_PARAM,
267         },
268 };
269 static const int standard_ioctl_num = (sizeof(standard_ioctl) /
270                                        sizeof(struct iw_ioctl_description));
271
272 /*
273  * Meta-data about all the additional standard Wireless Extension events
274  * we know about.
275  */
276 static const struct iw_ioctl_description standard_event[] = {
277         [IWEVTXDROP     - IWEVFIRST] = {
278                 .header_type    = IW_HEADER_TYPE_ADDR,
279         },
280         [IWEVQUAL       - IWEVFIRST] = {
281                 .header_type    = IW_HEADER_TYPE_QUAL,
282         },
283         [IWEVCUSTOM     - IWEVFIRST] = {
284                 .header_type    = IW_HEADER_TYPE_POINT,
285                 .token_size     = 1,
286                 .max_tokens     = IW_CUSTOM_MAX,
287         },
288         [IWEVREGISTERED - IWEVFIRST] = {
289                 .header_type    = IW_HEADER_TYPE_ADDR,
290         },
291         [IWEVEXPIRED    - IWEVFIRST] = {
292                 .header_type    = IW_HEADER_TYPE_ADDR, 
293         },
294 };
295 static const int standard_event_num = (sizeof(standard_event) /
296                                        sizeof(struct iw_ioctl_description));
297
298 /* Size (in bytes) of the various private data types */
299 static const char priv_type_size[] = {
300         0,                              /* IW_PRIV_TYPE_NONE */
301         1,                              /* IW_PRIV_TYPE_BYTE */
302         1,                              /* IW_PRIV_TYPE_CHAR */
303         0,                              /* Not defined */
304         sizeof(__u32),                  /* IW_PRIV_TYPE_INT */
305         sizeof(struct iw_freq),         /* IW_PRIV_TYPE_FLOAT */
306         sizeof(struct sockaddr),        /* IW_PRIV_TYPE_ADDR */
307         0,                              /* Not defined */
308 };
309
310 /* Size (in bytes) of various events */
311 static const int event_type_size[] = {
312         IW_EV_LCP_LEN,                  /* IW_HEADER_TYPE_NULL */
313         0,
314         IW_EV_CHAR_LEN,                 /* IW_HEADER_TYPE_CHAR */
315         0,
316         IW_EV_UINT_LEN,                 /* IW_HEADER_TYPE_UINT */
317         IW_EV_FREQ_LEN,                 /* IW_HEADER_TYPE_FREQ */
318         IW_EV_ADDR_LEN,                 /* IW_HEADER_TYPE_ADDR */
319         0,
320         IW_EV_POINT_LEN,                /* Without variable payload */
321         IW_EV_PARAM_LEN,                /* IW_HEADER_TYPE_PARAM */
322         IW_EV_QUAL_LEN,                 /* IW_HEADER_TYPE_QUAL */
323 };
324
325 /************************ COMMON SUBROUTINES ************************/
326 /*
327  * Stuff that may be used in various place or doesn't fit in one
328  * of the section below.
329  */
330
331 /* ---------------------------------------------------------------- */
332 /*
333  * Return the driver handler associated with a specific Wireless Extension.
334  * Called from various place, so make sure it remains efficient.
335  */
336 static inline iw_handler get_handler(struct net_device *dev,
337                                      unsigned int cmd)
338 {
339         /* Don't "optimise" the following variable, it will crash */
340         unsigned int    index;          /* *MUST* be unsigned */
341
342         /* Check if we have some wireless handlers defined */
343         if(dev->wireless_handlers == NULL)
344                 return NULL;
345
346         /* Try as a standard command */
347         index = cmd - SIOCIWFIRST;
348         if(index < dev->wireless_handlers->num_standard)
349                 return dev->wireless_handlers->standard[index];
350
351         /* Try as a private command */
352         index = cmd - SIOCIWFIRSTPRIV;
353         if(index < dev->wireless_handlers->num_private)
354                 return dev->wireless_handlers->private[index];
355
356         /* Not found */
357         return NULL;
358 }
359
360 /* ---------------------------------------------------------------- */
361 /*
362  * Get statistics out of the driver
363  */
364 static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
365 {
366         return (dev->get_wireless_stats ?
367                 dev->get_wireless_stats(dev) :
368                 (struct iw_statistics *) NULL);
369         /* In the future, get_wireless_stats may move from 'struct net_device'
370          * to 'struct iw_handler_def', to de-bloat struct net_device.
371          * Definitely worse a thought... */
372 }
373
374 /* ---------------------------------------------------------------- */
375 /*
376  * Call the commit handler in the driver
377  * (if exist and if conditions are right)
378  *
379  * Note : our current commit strategy is currently pretty dumb,
380  * but we will be able to improve on that...
381  * The goal is to try to agreagate as many changes as possible
382  * before doing the commit. Drivers that will define a commit handler
383  * are usually those that need a reset after changing parameters, so
384  * we want to minimise the number of reset.
385  * A cool idea is to use a timer : at each "set" command, we re-set the
386  * timer, when the timer eventually fires, we call the driver.
387  * Hopefully, more on that later.
388  *
389  * Also, I'm waiting to see how many people will complain about the
390  * netif_running(dev) test. I'm open on that one...
391  * Hopefully, the driver will remember to do a commit in "open()" ;-)
392  */
393 static inline int call_commit_handler(struct net_device *       dev)
394 {
395         if((netif_running(dev)) &&
396            (dev->wireless_handlers->standard[0] != NULL)) {
397                 /* Call the commit handler on the driver */
398                 return dev->wireless_handlers->standard[0](dev, NULL,
399                                                            NULL, NULL);
400         } else
401                 return 0;               /* Command completed successfully */
402 }
403
404 /* ---------------------------------------------------------------- */
405 /*
406  * Number of private arguments
407  */
408 static inline int get_priv_size(__u16   args)
409 {
410         int     num = args & IW_PRIV_SIZE_MASK;
411         int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
412
413         return num * priv_type_size[type];
414 }
415
416
417 /******************** /proc/net/wireless SUPPORT ********************/
418 /*
419  * The /proc/net/wireless file is a human readable user-space interface
420  * exporting various wireless specific statistics from the wireless devices.
421  * This is the most popular part of the Wireless Extensions ;-)
422  *
423  * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
424  * The content of the file is basically the content of "struct iw_statistics".
425  */
426
427 #ifdef CONFIG_PROC_FS
428
429 /* ---------------------------------------------------------------- */
430 /*
431  * Print one entry (line) of /proc/net/wireless
432  */
433 static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
434                                                  struct net_device *dev)
435 {
436         /* Get stats from the driver */
437         struct iw_statistics *stats = get_wireless_stats(dev);
438
439         if (stats) {
440                 seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
441                                 "%6d %6d   %6d\n",
442                            dev->name, stats->status, stats->qual.qual,
443                            stats->qual.updated & 1 ? '.' : ' ',
444                            ((__u8) stats->qual.level),
445                            stats->qual.updated & 2 ? '.' : ' ',
446                            ((__u8) stats->qual.noise),
447                            stats->qual.updated & 4 ? '.' : ' ',
448                            stats->discard.nwid, stats->discard.code,
449                            stats->discard.fragment, stats->discard.retries,
450                            stats->discard.misc, stats->miss.beacon);
451                 stats->qual.updated = 0;
452         }
453 }
454
455 /* ---------------------------------------------------------------- */
456 /*
457  * Print info for /proc/net/wireless (print all entries)
458  */
459 static int wireless_seq_show(struct seq_file *seq, void *v)
460 {
461         if (v == SEQ_START_TOKEN)
462                 seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
463                                 "packets               | Missed | WE\n"
464                                 " face | tus | link level noise |  nwid  "
465                                 "crypt   frag  retry   misc | beacon | %d\n",
466                            WIRELESS_EXT);
467         else
468                 wireless_seq_printf_stats(seq, v);
469         return 0;
470 }
471
472 extern void *dev_seq_start(struct seq_file *seq, loff_t *pos);
473 extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);
474 extern void dev_seq_stop(struct seq_file *seq, void *v);
475
476 static struct seq_operations wireless_seq_ops = {
477         .start = dev_seq_start,
478         .next  = dev_seq_next,
479         .stop  = dev_seq_stop,
480         .show  = wireless_seq_show,
481 };
482
483 static int wireless_seq_open(struct inode *inode, struct file *file)
484 {
485         return seq_open(file, &wireless_seq_ops);
486 }
487
488 static struct file_operations wireless_seq_fops = {
489         .owner   = THIS_MODULE,
490         .open    = wireless_seq_open,
491         .read    = seq_read,
492         .llseek  = seq_lseek,
493         .release = seq_release,
494 };
495
496 int __init wireless_proc_init(void)
497 {
498         if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
499                 return -ENOMEM;
500
501         return 0;
502 }
503 #endif  /* CONFIG_PROC_FS */
504
505 /************************** IOCTL SUPPORT **************************/
506 /*
507  * The original user space API to configure all those Wireless Extensions
508  * is through IOCTLs.
509  * In there, we check if we need to call the new driver API (iw_handler)
510  * or just call the driver ioctl handler.
511  */
512
513 /* ---------------------------------------------------------------- */
514 /*
515  *      Allow programatic access to /proc/net/wireless even if /proc
516  *      doesn't exist... Also more efficient...
517  */
518 static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
519 {
520         /* Get stats from the driver */
521         struct iw_statistics *stats;
522
523         stats = get_wireless_stats(dev);
524         if (stats != (struct iw_statistics *) NULL) {
525                 struct iwreq *  wrq = (struct iwreq *)ifr;
526
527                 /* Copy statistics to the user buffer */
528                 if(copy_to_user(wrq->u.data.pointer, stats,
529                                 sizeof(struct iw_statistics)))
530                         return -EFAULT;
531
532                 /* Check if we need to clear the update flag */
533                 if(wrq->u.data.flags != 0)
534                         stats->qual.updated = 0;
535                 return 0;
536         } else
537                 return -EOPNOTSUPP;
538 }
539
540 /* ---------------------------------------------------------------- */
541 /*
542  * Export the driver private handler definition
543  * They will be picked up by tools like iwpriv...
544  */
545 static inline int ioctl_export_private(struct net_device *      dev,
546                                        struct ifreq *           ifr)
547 {
548         struct iwreq *                          iwr = (struct iwreq *) ifr;
549
550         /* Check if the driver has something to export */
551         if((dev->wireless_handlers->num_private_args == 0) ||
552            (dev->wireless_handlers->private_args == NULL))
553                 return -EOPNOTSUPP;
554
555         /* Check NULL pointer */
556         if(iwr->u.data.pointer == NULL)
557                 return -EFAULT;
558 #ifdef WE_STRICT_WRITE
559         /* Check if there is enough buffer up there */
560         if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
561                 printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
562                 return -E2BIG;
563         }
564 #endif  /* WE_STRICT_WRITE */
565
566         /* Set the number of available ioctls. */
567         iwr->u.data.length = dev->wireless_handlers->num_private_args;
568
569         /* Copy structure to the user buffer. */
570         if (copy_to_user(iwr->u.data.pointer,
571                          dev->wireless_handlers->private_args,
572                          sizeof(struct iw_priv_args) * iwr->u.data.length))
573                 return -EFAULT;
574
575         return 0;
576 }
577
578 /* ---------------------------------------------------------------- */
579 /*
580  * Wrapper to call a standard Wireless Extension handler.
581  * We do various checks and also take care of moving data between
582  * user space and kernel space.
583  */
584 static inline int ioctl_standard_call(struct net_device *       dev,
585                                       struct ifreq *            ifr,
586                                       unsigned int              cmd,
587                                       iw_handler                handler)
588 {
589         struct iwreq *                          iwr = (struct iwreq *) ifr;
590         const struct iw_ioctl_description *     descr;
591         struct iw_request_info                  info;
592         int                                     ret = -EINVAL;
593         int                                     user_size = 0;
594
595         /* Get the description of the IOCTL */
596         if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
597                 return -EOPNOTSUPP;
598         descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
599
600 #ifdef WE_IOCTL_DEBUG
601         printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
602                ifr->ifr_name, cmd);
603         printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
604 #endif  /* WE_IOCTL_DEBUG */
605
606         /* Prepare the call */
607         info.cmd = cmd;
608         info.flags = 0;
609
610         /* Check if we have a pointer to user space data or not */
611         if(descr->header_type != IW_HEADER_TYPE_POINT) {
612
613                 /* No extra arguments. Trivial to handle */
614                 ret = handler(dev, &info, &(iwr->u), NULL);
615
616 #ifdef WE_SET_EVENT
617                 /* Generate an event to notify listeners of the change */
618                 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
619                    ((ret == 0) || (ret == -EIWCOMMIT)))
620                         wireless_send_event(dev, cmd, &(iwr->u), NULL);
621 #endif  /* WE_SET_EVENT */
622         } else {
623                 char *  extra;
624                 int     err;
625
626                 /* Check what user space is giving us */
627                 if(IW_IS_SET(cmd)) {
628                         /* Check NULL pointer */
629                         if((iwr->u.data.pointer == NULL) &&
630                            (iwr->u.data.length != 0))
631                                 return -EFAULT;
632                         /* Check if number of token fits within bounds */
633                         if(iwr->u.data.length > descr->max_tokens)
634                                 return -E2BIG;
635                         if(iwr->u.data.length < descr->min_tokens)
636                                 return -EINVAL;
637                 } else {
638                         /* Check NULL pointer */
639                         if(iwr->u.data.pointer == NULL)
640                                 return -EFAULT;
641                         /* Save user space buffer size for checking */
642                         user_size = iwr->u.data.length;
643                 }
644
645 #ifdef WE_IOCTL_DEBUG
646                 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
647                        dev->name, descr->max_tokens * descr->token_size);
648 #endif  /* WE_IOCTL_DEBUG */
649
650                 /* Always allocate for max space. Easier, and won't last
651                  * long... */
652                 extra = kmalloc(descr->max_tokens * descr->token_size,
653                                 GFP_KERNEL);
654                 if (extra == NULL) {
655                         return -ENOMEM;
656                 }
657
658                 /* If it is a SET, get all the extra data in here */
659                 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
660                         err = copy_from_user(extra, iwr->u.data.pointer,
661                                              iwr->u.data.length *
662                                              descr->token_size);
663                         if (err) {
664                                 kfree(extra);
665                                 return -EFAULT;
666                         }
667 #ifdef WE_IOCTL_DEBUG
668                         printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
669                                dev->name,
670                                iwr->u.data.length * descr->token_size);
671 #endif  /* WE_IOCTL_DEBUG */
672                 }
673
674                 /* Call the handler */
675                 ret = handler(dev, &info, &(iwr->u), extra);
676
677                 /* If we have something to return to the user */
678                 if (!ret && IW_IS_GET(cmd)) {
679 #ifdef WE_STRICT_WRITE
680                         /* Check if there is enough buffer up there */
681                         if(user_size < iwr->u.data.length) {
682                                 printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
683                                 kfree(extra);
684                                 return -E2BIG;
685                         }
686 #endif  /* WE_STRICT_WRITE */
687
688                         err = copy_to_user(iwr->u.data.pointer, extra,
689                                            iwr->u.data.length *
690                                            descr->token_size);
691                         if (err)
692                                 ret =  -EFAULT;                            
693 #ifdef WE_IOCTL_DEBUG
694                         printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
695                                dev->name,
696                                iwr->u.data.length * descr->token_size);
697 #endif  /* WE_IOCTL_DEBUG */
698                 }
699
700 #ifdef WE_SET_EVENT
701                 /* Generate an event to notify listeners of the change */
702                 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
703                    ((ret == 0) || (ret == -EIWCOMMIT))) {
704                         if(descr->flags & IW_DESCR_FLAG_RESTRICT)
705                                 /* If the event is restricted, don't
706                                  * export the payload */
707                                 wireless_send_event(dev, cmd, &(iwr->u), NULL);
708                         else
709                                 wireless_send_event(dev, cmd, &(iwr->u),
710                                                     extra);
711                 }
712 #endif  /* WE_SET_EVENT */
713
714                 /* Cleanup - I told you it wasn't that long ;-) */
715                 kfree(extra);
716         }
717
718         /* Call commit handler if needed and defined */
719         if(ret == -EIWCOMMIT)
720                 ret = call_commit_handler(dev);
721
722         /* Here, we will generate the appropriate event if needed */
723
724         return ret;
725 }
726
727 /* ---------------------------------------------------------------- */
728 /*
729  * Wrapper to call a private Wireless Extension handler.
730  * We do various checks and also take care of moving data between
731  * user space and kernel space.
732  * It's not as nice and slimline as the standard wrapper. The cause
733  * is struct iw_priv_args, which was not really designed for the
734  * job we are going here.
735  *
736  * IMPORTANT : This function prevent to set and get data on the same
737  * IOCTL and enforce the SET/GET convention. Not doing it would be
738  * far too hairy...
739  * If you need to set and get data at the same time, please don't use
740  * a iw_handler but process it in your ioctl handler (i.e. use the
741  * old driver API).
742  */
743 static inline int ioctl_private_call(struct net_device *        dev,
744                                      struct ifreq *             ifr,
745                                      unsigned int               cmd,
746                                      iw_handler         handler)
747 {
748         struct iwreq *                  iwr = (struct iwreq *) ifr;
749         struct iw_priv_args *           descr = NULL;
750         struct iw_request_info          info;
751         int                             extra_size = 0;
752         int                             i;
753         int                             ret = -EINVAL;
754
755         /* Get the description of the IOCTL */
756         for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
757                 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
758                         descr = &(dev->wireless_handlers->private_args[i]);
759                         break;
760                 }
761
762 #ifdef WE_IOCTL_DEBUG
763         printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
764                ifr->ifr_name, cmd);
765         if(descr) {
766                 printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
767                        dev->name, descr->name,
768                        descr->set_args, descr->get_args);
769         }
770 #endif  /* WE_IOCTL_DEBUG */
771
772         /* Compute the size of the set/get arguments */
773         if(descr != NULL) {
774                 if(IW_IS_SET(cmd)) {
775                         int     offset = 0;     /* For sub-ioctls */
776                         /* Check for sub-ioctl handler */
777                         if(descr->name[0] == '\0')
778                                 /* Reserve one int for sub-ioctl index */
779                                 offset = sizeof(__u32);
780
781                         /* Size of set arguments */
782                         extra_size = get_priv_size(descr->set_args);
783
784                         /* Does it fits in iwr ? */
785                         if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
786                            ((extra_size + offset) <= IFNAMSIZ))
787                                 extra_size = 0;
788                 } else {
789                         /* Size of set arguments */
790                         extra_size = get_priv_size(descr->get_args);
791
792                         /* Does it fits in iwr ? */
793                         if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
794                            (extra_size <= IFNAMSIZ))
795                                 extra_size = 0;
796                 }
797         }
798
799         /* Prepare the call */
800         info.cmd = cmd;
801         info.flags = 0;
802
803         /* Check if we have a pointer to user space data or not. */
804         if(extra_size == 0) {
805                 /* No extra arguments. Trivial to handle */
806                 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
807         } else {
808                 char *  extra;
809                 int     err;
810
811                 /* Check what user space is giving us */
812                 if(IW_IS_SET(cmd)) {
813                         /* Check NULL pointer */
814                         if((iwr->u.data.pointer == NULL) &&
815                            (iwr->u.data.length != 0))
816                                 return -EFAULT;
817
818                         /* Does it fits within bounds ? */
819                         if(iwr->u.data.length > (descr->set_args &
820                                                  IW_PRIV_SIZE_MASK))
821                                 return -E2BIG;
822                 } else {
823                         /* Check NULL pointer */
824                         if(iwr->u.data.pointer == NULL)
825                                 return -EFAULT;
826                 }
827
828 #ifdef WE_IOCTL_DEBUG
829                 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
830                        dev->name, extra_size);
831 #endif  /* WE_IOCTL_DEBUG */
832
833                 /* Always allocate for max space. Easier, and won't last
834                  * long... */
835                 extra = kmalloc(extra_size, GFP_KERNEL);
836                 if (extra == NULL) {
837                         return -ENOMEM;
838                 }
839
840                 /* If it is a SET, get all the extra data in here */
841                 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
842                         err = copy_from_user(extra, iwr->u.data.pointer,
843                                              extra_size);
844                         if (err) {
845                                 kfree(extra);
846                                 return -EFAULT;
847                         }
848 #ifdef WE_IOCTL_DEBUG
849                         printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
850                                dev->name, iwr->u.data.length);
851 #endif  /* WE_IOCTL_DEBUG */
852                 }
853
854                 /* Call the handler */
855                 ret = handler(dev, &info, &(iwr->u), extra);
856
857                 /* If we have something to return to the user */
858                 if (!ret && IW_IS_GET(cmd)) {
859                         err = copy_to_user(iwr->u.data.pointer, extra,
860                                            extra_size);
861                         if (err)
862                                 ret =  -EFAULT;                            
863 #ifdef WE_IOCTL_DEBUG
864                         printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
865                                dev->name, iwr->u.data.length);
866 #endif  /* WE_IOCTL_DEBUG */
867                 }
868
869                 /* Cleanup - I told you it wasn't that long ;-) */
870                 kfree(extra);
871         }
872
873
874         /* Call commit handler if needed and defined */
875         if(ret == -EIWCOMMIT)
876                 ret = call_commit_handler(dev);
877
878         return ret;
879 }
880
881 /* ---------------------------------------------------------------- */
882 /*
883  * Main IOCTl dispatcher. Called from the main networking code
884  * (dev_ioctl() in net/core/dev.c).
885  * Check the type of IOCTL and call the appropriate wrapper...
886  */
887 int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
888 {
889         struct net_device *dev;
890         iw_handler      handler;
891
892         /* Permissions are already checked in dev_ioctl() before calling us.
893          * The copy_to/from_user() of ifr is also dealt with in there */
894
895         /* Make sure the device exist */
896         if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
897                 return -ENODEV;
898
899         /* A bunch of special cases, then the generic case...
900          * Note that 'cmd' is already filtered in dev_ioctl() with
901          * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
902         switch(cmd) 
903         {
904                 case SIOCGIWSTATS:
905                         /* Get Wireless Stats */
906                         return dev_iwstats(dev, ifr);
907
908                 case SIOCGIWPRIV:
909                         /* Check if we have some wireless handlers defined */
910                         if(dev->wireless_handlers != NULL) {
911                                 /* We export to user space the definition of
912                                  * the private handler ourselves */
913                                 return ioctl_export_private(dev, ifr);
914                         }
915                         // ## Fall-through for old API ##
916                 default:
917                         /* Generic IOCTL */
918                         /* Basic check */
919                         if (!netif_device_present(dev))
920                                 return -ENODEV;
921                         /* New driver API : try to find the handler */
922                         handler = get_handler(dev, cmd);
923                         if(handler != NULL) {
924                                 /* Standard and private are not the same */
925                                 if(cmd < SIOCIWFIRSTPRIV)
926                                         return ioctl_standard_call(dev,
927                                                                    ifr,
928                                                                    cmd,
929                                                                    handler);
930                                 else
931                                         return ioctl_private_call(dev,
932                                                                   ifr,
933                                                                   cmd,
934                                                                   handler);
935                         }
936                         /* Old driver API : call driver ioctl handler */
937                         if (dev->do_ioctl) {
938                                 return dev->do_ioctl(dev, ifr, cmd);
939                         }
940                         return -EOPNOTSUPP;
941         }
942         /* Not reached */
943         return -EINVAL;
944 }
945
946 /************************* EVENT PROCESSING *************************/
947 /*
948  * Process events generated by the wireless layer or the driver.
949  * Most often, the event will be propagated through rtnetlink
950  */
951
952 #ifdef WE_EVENT_NETLINK
953 /* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
954  * It is declared in <linux/rtnetlink.h> */
955
956 /* ---------------------------------------------------------------- */
957 /*
958  * Fill a rtnetlink message with our event data.
959  * Note that we propage only the specified event and don't dump the
960  * current wireless config. Dumping the wireless config is far too
961  * expensive (for each parameter, the driver need to query the hardware).
962  */
963 static inline int rtnetlink_fill_iwinfo(struct sk_buff *        skb,
964                                         struct net_device *     dev,
965                                         int                     type,
966                                         char *                  event,
967                                         int                     event_len)
968 {
969         struct ifinfomsg *r;
970         struct nlmsghdr  *nlh;
971         unsigned char    *b = skb->tail;
972
973         nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
974         r = NLMSG_DATA(nlh);
975         r->ifi_family = AF_UNSPEC;
976         r->ifi_type = dev->type;
977         r->ifi_index = dev->ifindex;
978         r->ifi_flags = dev->flags;
979         r->ifi_change = 0;      /* Wireless changes don't affect those flags */
980
981         /* Add the wireless events in the netlink packet */
982         RTA_PUT(skb, IFLA_WIRELESS,
983                 event_len, event);
984
985         nlh->nlmsg_len = skb->tail - b;
986         return skb->len;
987
988 nlmsg_failure:
989 rtattr_failure:
990         skb_trim(skb, b - skb->data);
991         return -1;
992 }
993
994 /* ---------------------------------------------------------------- */
995 /*
996  * Create and broadcast and send it on the standard rtnetlink socket
997  * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
998  * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
999  * within a RTM_NEWLINK event.
1000  */
1001 static inline void rtmsg_iwinfo(struct net_device *     dev,
1002                                 char *                  event,
1003                                 int                     event_len)
1004 {
1005         struct sk_buff *skb;
1006         int size = NLMSG_GOODSIZE;
1007
1008         skb = alloc_skb(size, GFP_ATOMIC);
1009         if (!skb)
1010                 return;
1011
1012         if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
1013                                   event, event_len) < 0) {
1014                 kfree_skb(skb);
1015                 return;
1016         }
1017         NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
1018         netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
1019 }
1020 #endif  /* WE_EVENT_NETLINK */
1021
1022 /* ---------------------------------------------------------------- */
1023 /*
1024  * Main event dispatcher. Called from other parts and drivers.
1025  * Send the event on the appropriate channels.
1026  * May be called from interrupt context.
1027  */
1028 void wireless_send_event(struct net_device *    dev,
1029                          unsigned int           cmd,
1030                          union iwreq_data *     wrqu,
1031                          char *                 extra)
1032 {
1033         const struct iw_ioctl_description *     descr = NULL;
1034         int extra_len = 0;
1035         struct iw_event  *event;                /* Mallocated whole event */
1036         int event_len;                          /* Its size */
1037         int hdr_len;                            /* Size of the event header */
1038         /* Don't "optimise" the following variable, it will crash */
1039         unsigned        cmd_index;              /* *MUST* be unsigned */
1040
1041         /* Get the description of the IOCTL */
1042         if(cmd <= SIOCIWLAST) {
1043                 cmd_index = cmd - SIOCIWFIRST;
1044                 if(cmd_index < standard_ioctl_num)
1045                         descr = &(standard_ioctl[cmd_index]);
1046         } else {
1047                 cmd_index = cmd - IWEVFIRST;
1048                 if(cmd_index < standard_event_num)
1049                         descr = &(standard_event[cmd_index]);
1050         }
1051         /* Don't accept unknown events */
1052         if(descr == NULL) {
1053                 /* Note : we don't return an error to the driver, because
1054                  * the driver would not know what to do about it. It can't
1055                  * return an error to the user, because the event is not
1056                  * initiated by a user request.
1057                  * The best the driver could do is to log an error message.
1058                  * We will do it ourselves instead...
1059                  */
1060                 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
1061                        dev->name, cmd);
1062                 return;
1063         }
1064 #ifdef WE_EVENT_DEBUG
1065         printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
1066                dev->name, cmd);
1067         printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
1068 #endif  /* WE_EVENT_DEBUG */
1069
1070         /* Check extra parameters and set extra_len */
1071         if(descr->header_type == IW_HEADER_TYPE_POINT) {
1072                 /* Check if number of token fits within bounds */
1073                 if(wrqu->data.length > descr->max_tokens) {
1074                         printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
1075                         return;
1076                 }
1077                 if(wrqu->data.length < descr->min_tokens) {
1078                         printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
1079                         return;
1080                 }
1081                 /* Calculate extra_len - extra is NULL for restricted events */
1082                 if(extra != NULL)
1083                         extra_len = wrqu->data.length * descr->token_size;
1084 #ifdef WE_EVENT_DEBUG
1085                 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
1086 #endif  /* WE_EVENT_DEBUG */
1087         }
1088
1089         /* Total length of the event */
1090         hdr_len = event_type_size[descr->header_type];
1091         event_len = hdr_len + extra_len;
1092
1093 #ifdef WE_EVENT_DEBUG
1094         printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
1095 #endif  /* WE_EVENT_DEBUG */
1096
1097         /* Create temporary buffer to hold the event */
1098         event = kmalloc(event_len, GFP_ATOMIC);
1099         if(event == NULL)
1100                 return;
1101
1102         /* Fill event */
1103         event->len = event_len;
1104         event->cmd = cmd;
1105         memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
1106         if(extra != NULL)
1107                 memcpy(((char *) event) + hdr_len, extra, extra_len);
1108
1109 #ifdef WE_EVENT_NETLINK
1110         /* rtnetlink event channel */
1111         rtmsg_iwinfo(dev, (char *) event, event_len);
1112 #endif  /* WE_EVENT_NETLINK */
1113
1114         /* Cleanup */
1115         kfree(event);
1116
1117         return;         /* Always success, I guess ;-) */
1118 }
1119
1120 /********************** ENHANCED IWSPY SUPPORT **********************/
1121 /*
1122  * In the old days, the driver was handling spy support all by itself.
1123  * Now, the driver can delegate this task to Wireless Extensions.
1124  * It needs to use those standard spy iw_handler in struct iw_handler_def,
1125  * push data to us via wireless_spy_update() and include struct iw_spy_data
1126  * in its private part (and advertise it in iw_handler_def->spy_offset).
1127  * One of the main advantage of centralising spy support here is that
1128  * it becomes much easier to improve and extend it without having to touch
1129  * the drivers. One example is the addition of the Spy-Threshold events.
1130  * Note : IW_WIRELESS_SPY is defined in iw_handler.h
1131  */
1132
1133 /*------------------------------------------------------------------*/
1134 /*
1135  * Standard Wireless Handler : set Spy List
1136  */
1137 int iw_handler_set_spy(struct net_device *      dev,
1138                        struct iw_request_info * info,
1139                        union iwreq_data *       wrqu,
1140                        char *                   extra)
1141 {
1142 #ifdef IW_WIRELESS_SPY
1143         struct iw_spy_data *    spydata = (dev->priv +
1144                                            dev->wireless_handlers->spy_offset);
1145         struct sockaddr *       address = (struct sockaddr *) extra;
1146
1147         /* Disable spy collection while we copy the addresses.
1148          * As we don't disable interrupts, we need to do this to avoid races.
1149          * As we are the only writer, this is good enough. */
1150         spydata->spy_number = 0;
1151
1152         /* Are there are addresses to copy? */
1153         if(wrqu->data.length > 0) {
1154                 int i;
1155
1156                 /* Copy addresses */
1157                 for(i = 0; i < wrqu->data.length; i++)
1158                         memcpy(spydata->spy_address[i], address[i].sa_data,
1159                                ETH_ALEN);
1160                 /* Reset stats */
1161                 memset(spydata->spy_stat, 0,
1162                        sizeof(struct iw_quality) * IW_MAX_SPY);
1163
1164 #ifdef WE_SPY_DEBUG
1165                 printk(KERN_DEBUG "iw_handler_set_spy() :  offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);
1166                 for (i = 0; i < wrqu->data.length; i++)
1167                         printk(KERN_DEBUG
1168                                "%02X:%02X:%02X:%02X:%02X:%02X \n",
1169                                spydata->spy_address[i][0],
1170                                spydata->spy_address[i][1],
1171                                spydata->spy_address[i][2],
1172                                spydata->spy_address[i][3],
1173                                spydata->spy_address[i][4],
1174                                spydata->spy_address[i][5]);
1175 #endif  /* WE_SPY_DEBUG */
1176         }
1177         /* Enable addresses */
1178         spydata->spy_number = wrqu->data.length;
1179
1180         return 0;
1181 #else /* IW_WIRELESS_SPY */
1182         return -EOPNOTSUPP;
1183 #endif /* IW_WIRELESS_SPY */
1184 }
1185
1186 /*------------------------------------------------------------------*/
1187 /*
1188  * Standard Wireless Handler : get Spy List
1189  */
1190 int iw_handler_get_spy(struct net_device *      dev,
1191                        struct iw_request_info * info,
1192                        union iwreq_data *       wrqu,
1193                        char *                   extra)
1194 {
1195 #ifdef IW_WIRELESS_SPY
1196         struct iw_spy_data *    spydata = (dev->priv +
1197                                            dev->wireless_handlers->spy_offset);
1198         struct sockaddr *       address = (struct sockaddr *) extra;
1199         int                     i;
1200
1201         wrqu->data.length = spydata->spy_number;
1202
1203         /* Copy addresses. */
1204         for(i = 0; i < spydata->spy_number; i++)        {
1205                 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
1206                 address[i].sa_family = AF_UNIX;
1207         }
1208         /* Copy stats to the user buffer (just after). */
1209         if(spydata->spy_number > 0)
1210                 memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
1211                        spydata->spy_stat,
1212                        sizeof(struct iw_quality) * spydata->spy_number);
1213         /* Reset updated flags. */
1214         for(i = 0; i < spydata->spy_number; i++)
1215                 spydata->spy_stat[i].updated = 0;
1216         return 0;
1217 #else /* IW_WIRELESS_SPY */
1218         return -EOPNOTSUPP;
1219 #endif /* IW_WIRELESS_SPY */
1220 }
1221
1222 /*------------------------------------------------------------------*/
1223 /*
1224  * Standard Wireless Handler : set spy threshold
1225  */
1226 int iw_handler_set_thrspy(struct net_device *   dev,
1227                           struct iw_request_info *info,
1228                           union iwreq_data *    wrqu,
1229                           char *                extra)
1230 {
1231 #ifdef IW_WIRELESS_THRSPY
1232         struct iw_spy_data *    spydata = (dev->priv +
1233                                            dev->wireless_handlers->spy_offset);
1234         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
1235
1236         /* Just do it */
1237         memcpy(&(spydata->spy_thr_low), &(threshold->low),
1238                2 * sizeof(struct iw_quality));
1239
1240         /* Clear flag */
1241         memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
1242
1243 #ifdef WE_SPY_DEBUG
1244         printk(KERN_DEBUG "iw_handler_set_thrspy() :  low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
1245 #endif  /* WE_SPY_DEBUG */
1246
1247         return 0;
1248 #else /* IW_WIRELESS_THRSPY */
1249         return -EOPNOTSUPP;
1250 #endif /* IW_WIRELESS_THRSPY */
1251 }
1252
1253 /*------------------------------------------------------------------*/
1254 /*
1255  * Standard Wireless Handler : get spy threshold
1256  */
1257 int iw_handler_get_thrspy(struct net_device *   dev,
1258                           struct iw_request_info *info,
1259                           union iwreq_data *    wrqu,
1260                           char *                extra)
1261 {
1262 #ifdef IW_WIRELESS_THRSPY
1263         struct iw_spy_data *    spydata = (dev->priv +
1264                                            dev->wireless_handlers->spy_offset);
1265         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
1266
1267         /* Just do it */
1268         memcpy(&(threshold->low), &(spydata->spy_thr_low),
1269                2 * sizeof(struct iw_quality));
1270
1271         return 0;
1272 #else /* IW_WIRELESS_THRSPY */
1273         return -EOPNOTSUPP;
1274 #endif /* IW_WIRELESS_THRSPY */
1275 }
1276
1277 #ifdef IW_WIRELESS_THRSPY
1278 /*------------------------------------------------------------------*/
1279 /*
1280  * Prepare and send a Spy Threshold event
1281  */
1282 static void iw_send_thrspy_event(struct net_device *    dev,
1283                                  struct iw_spy_data *   spydata,
1284                                  unsigned char *        address,
1285                                  struct iw_quality *    wstats)
1286 {
1287         union iwreq_data        wrqu;
1288         struct iw_thrspy        threshold;
1289
1290         /* Init */
1291         wrqu.data.length = 1;
1292         wrqu.data.flags = 0;
1293         /* Copy address */
1294         memcpy(threshold.addr.sa_data, address, ETH_ALEN);
1295         threshold.addr.sa_family = ARPHRD_ETHER;
1296         /* Copy stats */
1297         memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
1298         /* Copy also thresholds */
1299         memcpy(&(threshold.low), &(spydata->spy_thr_low),
1300                2 * sizeof(struct iw_quality));
1301
1302 #ifdef WE_SPY_DEBUG
1303         printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
1304                threshold.addr.sa_data[0],
1305                threshold.addr.sa_data[1],
1306                threshold.addr.sa_data[2],
1307                threshold.addr.sa_data[3],
1308                threshold.addr.sa_data[4],
1309                threshold.addr.sa_data[5], threshold.qual.level);
1310 #endif  /* WE_SPY_DEBUG */
1311
1312         /* Send event to user space */
1313         wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
1314 }
1315 #endif /* IW_WIRELESS_THRSPY */
1316
1317 /* ---------------------------------------------------------------- */
1318 /*
1319  * Call for the driver to update the spy data.
1320  * For now, the spy data is a simple array. As the size of the array is
1321  * small, this is good enough. If we wanted to support larger number of
1322  * spy addresses, we should use something more efficient...
1323  */
1324 void wireless_spy_update(struct net_device *    dev,
1325                          unsigned char *        address,
1326                          struct iw_quality *    wstats)
1327 {
1328 #ifdef IW_WIRELESS_SPY
1329         struct iw_spy_data *    spydata = (dev->priv +
1330                                            dev->wireless_handlers->spy_offset);
1331         int                     i;
1332         int                     match = -1;
1333
1334 #ifdef WE_SPY_DEBUG
1335         printk(KERN_DEBUG "wireless_spy_update() :  offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
1336 #endif  /* WE_SPY_DEBUG */
1337
1338         /* Update all records that match */
1339         for(i = 0; i < spydata->spy_number; i++)
1340                 if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) {
1341                         memcpy(&(spydata->spy_stat[i]), wstats,
1342                                sizeof(struct iw_quality));
1343                         match = i;
1344                 }
1345 #ifdef IW_WIRELESS_THRSPY
1346         /* Generate an event if we cross the spy threshold.
1347          * To avoid event storms, we have a simple hysteresis : we generate
1348          * event only when we go under the low threshold or above the
1349          * high threshold. */
1350         if(match >= 0) {
1351                 if(spydata->spy_thr_under[match]) {
1352                         if(wstats->level > spydata->spy_thr_high.level) {
1353                                 spydata->spy_thr_under[match] = 0;
1354                                 iw_send_thrspy_event(dev, spydata,
1355                                                      address, wstats);
1356                         }
1357                 } else {
1358                         if(wstats->level < spydata->spy_thr_low.level) {
1359                                 spydata->spy_thr_under[match] = 1;
1360                                 iw_send_thrspy_event(dev, spydata,
1361                                                      address, wstats);
1362                         }
1363                 }
1364         }
1365 #endif /* IW_WIRELESS_THRSPY */
1366 #endif /* IW_WIRELESS_SPY */
1367 }
1368
1369 EXPORT_SYMBOL(iw_handler_get_spy);
1370 EXPORT_SYMBOL(iw_handler_get_thrspy);
1371 EXPORT_SYMBOL(iw_handler_set_spy);
1372 EXPORT_SYMBOL(iw_handler_set_thrspy);
1373 EXPORT_SYMBOL(wireless_send_event);
1374 EXPORT_SYMBOL(wireless_spy_update);