Merge branch 'master' into upstream
[linux-2.6] / 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-2006 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  * v6 - 18.06.04 - Jean II
53  *      o Change get_spydata() method for added safety
54  *      o Remove spy #ifdef, they are always on -> cleaner code
55  *      o Allow any size GET request if user specifies length > max
56  *              and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
57  *      o Start migrating get_wireless_stats to struct iw_handler_def
58  *      o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
59  * Based on patch from Pavel Roskin <proski@gnu.org> :
60  *      o Fix kernel data leak to user space in private handler handling
61  *
62  * v7 - 18.3.05 - Jean II
63  *      o Remove (struct iw_point *)->pointer from events and streams
64  *      o Remove spy_offset from struct iw_handler_def
65  *      o Start deprecating dev->get_wireless_stats, output a warning
66  *      o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
67  *      o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
68  *
69  * v8 - 17.02.06 - Jean II
70  *      o RtNetlink requests support (SET/GET)
71  */
72
73 /***************************** INCLUDES *****************************/
74
75 #include <linux/config.h>               /* Not needed ??? */
76 #include <linux/module.h>
77 #include <linux/types.h>                /* off_t */
78 #include <linux/netdevice.h>            /* struct ifreq, dev_get_by_name() */
79 #include <linux/proc_fs.h>
80 #include <linux/rtnetlink.h>            /* rtnetlink stuff */
81 #include <linux/seq_file.h>
82 #include <linux/init.h>                 /* for __init */
83 #include <linux/if_arp.h>               /* ARPHRD_ETHER */
84 #include <linux/etherdevice.h>          /* compare_ether_addr */
85
86 #include <linux/wireless.h>             /* Pretty obvious */
87 #include <net/iw_handler.h>             /* New driver API */
88
89 #include <asm/uaccess.h>                /* copy_to_user() */
90
91 /**************************** CONSTANTS ****************************/
92
93 /* Debugging stuff */
94 #undef WE_IOCTL_DEBUG           /* Debug IOCTL API */
95 #undef WE_RTNETLINK_DEBUG       /* Debug RtNetlink API */
96 #undef WE_EVENT_DEBUG           /* Debug Event dispatcher */
97 #undef WE_SPY_DEBUG             /* Debug enhanced spy support */
98
99 /* Options */
100 //CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */
101 #define WE_EVENT_RTNETLINK      /* Propagate events using RtNetlink */
102 #define WE_SET_EVENT            /* Generate an event on some set commands */
103
104 /************************* GLOBAL VARIABLES *************************/
105 /*
106  * You should not use global variables, because of re-entrancy.
107  * On our case, it's only const, so it's OK...
108  */
109 /*
110  * Meta-data about all the standard Wireless Extension request we
111  * know about.
112  */
113 static const struct iw_ioctl_description standard_ioctl[] = {
114         [SIOCSIWCOMMIT  - SIOCIWFIRST] = {
115                 .header_type    = IW_HEADER_TYPE_NULL,
116         },
117         [SIOCGIWNAME    - SIOCIWFIRST] = {
118                 .header_type    = IW_HEADER_TYPE_CHAR,
119                 .flags          = IW_DESCR_FLAG_DUMP,
120         },
121         [SIOCSIWNWID    - SIOCIWFIRST] = {
122                 .header_type    = IW_HEADER_TYPE_PARAM,
123                 .flags          = IW_DESCR_FLAG_EVENT,
124         },
125         [SIOCGIWNWID    - SIOCIWFIRST] = {
126                 .header_type    = IW_HEADER_TYPE_PARAM,
127                 .flags          = IW_DESCR_FLAG_DUMP,
128         },
129         [SIOCSIWFREQ    - SIOCIWFIRST] = {
130                 .header_type    = IW_HEADER_TYPE_FREQ,
131                 .flags          = IW_DESCR_FLAG_EVENT,
132         },
133         [SIOCGIWFREQ    - SIOCIWFIRST] = {
134                 .header_type    = IW_HEADER_TYPE_FREQ,
135                 .flags          = IW_DESCR_FLAG_DUMP,
136         },
137         [SIOCSIWMODE    - SIOCIWFIRST] = {
138                 .header_type    = IW_HEADER_TYPE_UINT,
139                 .flags          = IW_DESCR_FLAG_EVENT,
140         },
141         [SIOCGIWMODE    - SIOCIWFIRST] = {
142                 .header_type    = IW_HEADER_TYPE_UINT,
143                 .flags          = IW_DESCR_FLAG_DUMP,
144         },
145         [SIOCSIWSENS    - SIOCIWFIRST] = {
146                 .header_type    = IW_HEADER_TYPE_PARAM,
147         },
148         [SIOCGIWSENS    - SIOCIWFIRST] = {
149                 .header_type    = IW_HEADER_TYPE_PARAM,
150         },
151         [SIOCSIWRANGE   - SIOCIWFIRST] = {
152                 .header_type    = IW_HEADER_TYPE_NULL,
153         },
154         [SIOCGIWRANGE   - SIOCIWFIRST] = {
155                 .header_type    = IW_HEADER_TYPE_POINT,
156                 .token_size     = 1,
157                 .max_tokens     = sizeof(struct iw_range),
158                 .flags          = IW_DESCR_FLAG_DUMP,
159         },
160         [SIOCSIWPRIV    - SIOCIWFIRST] = {
161                 .header_type    = IW_HEADER_TYPE_NULL,
162         },
163         [SIOCGIWPRIV    - SIOCIWFIRST] = { /* (handled directly by us) */
164                 .header_type    = IW_HEADER_TYPE_POINT,
165                 .token_size     = sizeof(struct iw_priv_args),
166                 .max_tokens     = 16,
167                 .flags          = IW_DESCR_FLAG_NOMAX,
168         },
169         [SIOCSIWSTATS   - SIOCIWFIRST] = {
170                 .header_type    = IW_HEADER_TYPE_NULL,
171         },
172         [SIOCGIWSTATS   - SIOCIWFIRST] = { /* (handled directly by us) */
173                 .header_type    = IW_HEADER_TYPE_POINT,
174                 .token_size     = 1,
175                 .max_tokens     = sizeof(struct iw_statistics),
176                 .flags          = IW_DESCR_FLAG_DUMP,
177         },
178         [SIOCSIWSPY     - SIOCIWFIRST] = {
179                 .header_type    = IW_HEADER_TYPE_POINT,
180                 .token_size     = sizeof(struct sockaddr),
181                 .max_tokens     = IW_MAX_SPY,
182         },
183         [SIOCGIWSPY     - SIOCIWFIRST] = {
184                 .header_type    = IW_HEADER_TYPE_POINT,
185                 .token_size     = sizeof(struct sockaddr) +
186                                   sizeof(struct iw_quality),
187                 .max_tokens     = IW_MAX_SPY,
188         },
189         [SIOCSIWTHRSPY  - SIOCIWFIRST] = {
190                 .header_type    = IW_HEADER_TYPE_POINT,
191                 .token_size     = sizeof(struct iw_thrspy),
192                 .min_tokens     = 1,
193                 .max_tokens     = 1,
194         },
195         [SIOCGIWTHRSPY  - SIOCIWFIRST] = {
196                 .header_type    = IW_HEADER_TYPE_POINT,
197                 .token_size     = sizeof(struct iw_thrspy),
198                 .min_tokens     = 1,
199                 .max_tokens     = 1,
200         },
201         [SIOCSIWAP      - SIOCIWFIRST] = {
202                 .header_type    = IW_HEADER_TYPE_ADDR,
203         },
204         [SIOCGIWAP      - SIOCIWFIRST] = {
205                 .header_type    = IW_HEADER_TYPE_ADDR,
206                 .flags          = IW_DESCR_FLAG_DUMP,
207         },
208         [SIOCSIWMLME    - SIOCIWFIRST] = {
209                 .header_type    = IW_HEADER_TYPE_POINT,
210                 .token_size     = 1,
211                 .min_tokens     = sizeof(struct iw_mlme),
212                 .max_tokens     = sizeof(struct iw_mlme),
213         },
214         [SIOCGIWAPLIST  - SIOCIWFIRST] = {
215                 .header_type    = IW_HEADER_TYPE_POINT,
216                 .token_size     = sizeof(struct sockaddr) +
217                                   sizeof(struct iw_quality),
218                 .max_tokens     = IW_MAX_AP,
219                 .flags          = IW_DESCR_FLAG_NOMAX,
220         },
221         [SIOCSIWSCAN    - SIOCIWFIRST] = {
222                 .header_type    = IW_HEADER_TYPE_POINT,
223                 .token_size     = 1,
224                 .min_tokens     = 0,
225                 .max_tokens     = sizeof(struct iw_scan_req),
226         },
227         [SIOCGIWSCAN    - SIOCIWFIRST] = {
228                 .header_type    = IW_HEADER_TYPE_POINT,
229                 .token_size     = 1,
230                 .max_tokens     = IW_SCAN_MAX_DATA,
231                 .flags          = IW_DESCR_FLAG_NOMAX,
232         },
233         [SIOCSIWESSID   - SIOCIWFIRST] = {
234                 .header_type    = IW_HEADER_TYPE_POINT,
235                 .token_size     = 1,
236                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
237                 .flags          = IW_DESCR_FLAG_EVENT,
238         },
239         [SIOCGIWESSID   - SIOCIWFIRST] = {
240                 .header_type    = IW_HEADER_TYPE_POINT,
241                 .token_size     = 1,
242                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
243                 .flags          = IW_DESCR_FLAG_DUMP,
244         },
245         [SIOCSIWNICKN   - SIOCIWFIRST] = {
246                 .header_type    = IW_HEADER_TYPE_POINT,
247                 .token_size     = 1,
248                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
249         },
250         [SIOCGIWNICKN   - SIOCIWFIRST] = {
251                 .header_type    = IW_HEADER_TYPE_POINT,
252                 .token_size     = 1,
253                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
254         },
255         [SIOCSIWRATE    - SIOCIWFIRST] = {
256                 .header_type    = IW_HEADER_TYPE_PARAM,
257         },
258         [SIOCGIWRATE    - SIOCIWFIRST] = {
259                 .header_type    = IW_HEADER_TYPE_PARAM,
260         },
261         [SIOCSIWRTS     - SIOCIWFIRST] = {
262                 .header_type    = IW_HEADER_TYPE_PARAM,
263         },
264         [SIOCGIWRTS     - SIOCIWFIRST] = {
265                 .header_type    = IW_HEADER_TYPE_PARAM,
266         },
267         [SIOCSIWFRAG    - SIOCIWFIRST] = {
268                 .header_type    = IW_HEADER_TYPE_PARAM,
269         },
270         [SIOCGIWFRAG    - SIOCIWFIRST] = {
271                 .header_type    = IW_HEADER_TYPE_PARAM,
272         },
273         [SIOCSIWTXPOW   - SIOCIWFIRST] = {
274                 .header_type    = IW_HEADER_TYPE_PARAM,
275         },
276         [SIOCGIWTXPOW   - SIOCIWFIRST] = {
277                 .header_type    = IW_HEADER_TYPE_PARAM,
278         },
279         [SIOCSIWRETRY   - SIOCIWFIRST] = {
280                 .header_type    = IW_HEADER_TYPE_PARAM,
281         },
282         [SIOCGIWRETRY   - SIOCIWFIRST] = {
283                 .header_type    = IW_HEADER_TYPE_PARAM,
284         },
285         [SIOCSIWENCODE  - SIOCIWFIRST] = {
286                 .header_type    = IW_HEADER_TYPE_POINT,
287                 .token_size     = 1,
288                 .max_tokens     = IW_ENCODING_TOKEN_MAX,
289                 .flags          = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
290         },
291         [SIOCGIWENCODE  - SIOCIWFIRST] = {
292                 .header_type    = IW_HEADER_TYPE_POINT,
293                 .token_size     = 1,
294                 .max_tokens     = IW_ENCODING_TOKEN_MAX,
295                 .flags          = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
296         },
297         [SIOCSIWPOWER   - SIOCIWFIRST] = {
298                 .header_type    = IW_HEADER_TYPE_PARAM,
299         },
300         [SIOCGIWPOWER   - SIOCIWFIRST] = {
301                 .header_type    = IW_HEADER_TYPE_PARAM,
302         },
303         [SIOCSIWGENIE   - SIOCIWFIRST] = {
304                 .header_type    = IW_HEADER_TYPE_POINT,
305                 .token_size     = 1,
306                 .max_tokens     = IW_GENERIC_IE_MAX,
307         },
308         [SIOCGIWGENIE   - SIOCIWFIRST] = {
309                 .header_type    = IW_HEADER_TYPE_POINT,
310                 .token_size     = 1,
311                 .max_tokens     = IW_GENERIC_IE_MAX,
312         },
313         [SIOCSIWAUTH    - SIOCIWFIRST] = {
314                 .header_type    = IW_HEADER_TYPE_PARAM,
315         },
316         [SIOCGIWAUTH    - SIOCIWFIRST] = {
317                 .header_type    = IW_HEADER_TYPE_PARAM,
318         },
319         [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
320                 .header_type    = IW_HEADER_TYPE_POINT,
321                 .token_size     = 1,
322                 .min_tokens     = sizeof(struct iw_encode_ext),
323                 .max_tokens     = sizeof(struct iw_encode_ext) +
324                                   IW_ENCODING_TOKEN_MAX,
325         },
326         [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
327                 .header_type    = IW_HEADER_TYPE_POINT,
328                 .token_size     = 1,
329                 .min_tokens     = sizeof(struct iw_encode_ext),
330                 .max_tokens     = sizeof(struct iw_encode_ext) +
331                                   IW_ENCODING_TOKEN_MAX,
332         },
333         [SIOCSIWPMKSA - SIOCIWFIRST] = {
334                 .header_type    = IW_HEADER_TYPE_POINT,
335                 .token_size     = 1,
336                 .min_tokens     = sizeof(struct iw_pmksa),
337                 .max_tokens     = sizeof(struct iw_pmksa),
338         },
339 };
340 static const int standard_ioctl_num = (sizeof(standard_ioctl) /
341                                        sizeof(struct iw_ioctl_description));
342
343 /*
344  * Meta-data about all the additional standard Wireless Extension events
345  * we know about.
346  */
347 static const struct iw_ioctl_description standard_event[] = {
348         [IWEVTXDROP     - IWEVFIRST] = {
349                 .header_type    = IW_HEADER_TYPE_ADDR,
350         },
351         [IWEVQUAL       - IWEVFIRST] = {
352                 .header_type    = IW_HEADER_TYPE_QUAL,
353         },
354         [IWEVCUSTOM     - IWEVFIRST] = {
355                 .header_type    = IW_HEADER_TYPE_POINT,
356                 .token_size     = 1,
357                 .max_tokens     = IW_CUSTOM_MAX,
358         },
359         [IWEVREGISTERED - IWEVFIRST] = {
360                 .header_type    = IW_HEADER_TYPE_ADDR,
361         },
362         [IWEVEXPIRED    - IWEVFIRST] = {
363                 .header_type    = IW_HEADER_TYPE_ADDR, 
364         },
365         [IWEVGENIE      - IWEVFIRST] = {
366                 .header_type    = IW_HEADER_TYPE_POINT,
367                 .token_size     = 1,
368                 .max_tokens     = IW_GENERIC_IE_MAX,
369         },
370         [IWEVMICHAELMICFAILURE  - IWEVFIRST] = {
371                 .header_type    = IW_HEADER_TYPE_POINT, 
372                 .token_size     = 1,
373                 .max_tokens     = sizeof(struct iw_michaelmicfailure),
374         },
375         [IWEVASSOCREQIE - IWEVFIRST] = {
376                 .header_type    = IW_HEADER_TYPE_POINT,
377                 .token_size     = 1,
378                 .max_tokens     = IW_GENERIC_IE_MAX,
379         },
380         [IWEVASSOCRESPIE        - IWEVFIRST] = {
381                 .header_type    = IW_HEADER_TYPE_POINT,
382                 .token_size     = 1,
383                 .max_tokens     = IW_GENERIC_IE_MAX,
384         },
385         [IWEVPMKIDCAND  - IWEVFIRST] = {
386                 .header_type    = IW_HEADER_TYPE_POINT,
387                 .token_size     = 1,
388                 .max_tokens     = sizeof(struct iw_pmkid_cand),
389         },
390 };
391 static const int standard_event_num = (sizeof(standard_event) /
392                                        sizeof(struct iw_ioctl_description));
393
394 /* Size (in bytes) of the various private data types */
395 static const char iw_priv_type_size[] = {
396         0,                              /* IW_PRIV_TYPE_NONE */
397         1,                              /* IW_PRIV_TYPE_BYTE */
398         1,                              /* IW_PRIV_TYPE_CHAR */
399         0,                              /* Not defined */
400         sizeof(__u32),                  /* IW_PRIV_TYPE_INT */
401         sizeof(struct iw_freq),         /* IW_PRIV_TYPE_FLOAT */
402         sizeof(struct sockaddr),        /* IW_PRIV_TYPE_ADDR */
403         0,                              /* Not defined */
404 };
405
406 /* Size (in bytes) of various events */
407 static const int event_type_size[] = {
408         IW_EV_LCP_LEN,                  /* IW_HEADER_TYPE_NULL */
409         0,
410         IW_EV_CHAR_LEN,                 /* IW_HEADER_TYPE_CHAR */
411         0,
412         IW_EV_UINT_LEN,                 /* IW_HEADER_TYPE_UINT */
413         IW_EV_FREQ_LEN,                 /* IW_HEADER_TYPE_FREQ */
414         IW_EV_ADDR_LEN,                 /* IW_HEADER_TYPE_ADDR */
415         0,
416         IW_EV_POINT_LEN,                /* Without variable payload */
417         IW_EV_PARAM_LEN,                /* IW_HEADER_TYPE_PARAM */
418         IW_EV_QUAL_LEN,                 /* IW_HEADER_TYPE_QUAL */
419 };
420
421 /************************ COMMON SUBROUTINES ************************/
422 /*
423  * Stuff that may be used in various place or doesn't fit in one
424  * of the section below.
425  */
426
427 /* ---------------------------------------------------------------- */
428 /*
429  * Return the driver handler associated with a specific Wireless Extension.
430  * Called from various place, so make sure it remains efficient.
431  */
432 static inline iw_handler get_handler(struct net_device *dev,
433                                      unsigned int cmd)
434 {
435         /* Don't "optimise" the following variable, it will crash */
436         unsigned int    index;          /* *MUST* be unsigned */
437
438         /* Check if we have some wireless handlers defined */
439         if(dev->wireless_handlers == NULL)
440                 return NULL;
441
442         /* Try as a standard command */
443         index = cmd - SIOCIWFIRST;
444         if(index < dev->wireless_handlers->num_standard)
445                 return dev->wireless_handlers->standard[index];
446
447         /* Try as a private command */
448         index = cmd - SIOCIWFIRSTPRIV;
449         if(index < dev->wireless_handlers->num_private)
450                 return dev->wireless_handlers->private[index];
451
452         /* Not found */
453         return NULL;
454 }
455
456 /* ---------------------------------------------------------------- */
457 /*
458  * Get statistics out of the driver
459  */
460 static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
461 {
462         /* New location */
463         if((dev->wireless_handlers != NULL) &&
464            (dev->wireless_handlers->get_wireless_stats != NULL))
465                 return dev->wireless_handlers->get_wireless_stats(dev);
466
467         /* Old location, field to be removed in next WE */
468         if(dev->get_wireless_stats) {
469                 static int printed_message;
470
471                 if (!printed_message++)
472                         printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n",
473                                 dev->name);
474
475                 return dev->get_wireless_stats(dev);
476         }
477
478         /* Not found */
479         return (struct iw_statistics *) NULL;
480 }
481
482 /* ---------------------------------------------------------------- */
483 /*
484  * Call the commit handler in the driver
485  * (if exist and if conditions are right)
486  *
487  * Note : our current commit strategy is currently pretty dumb,
488  * but we will be able to improve on that...
489  * The goal is to try to agreagate as many changes as possible
490  * before doing the commit. Drivers that will define a commit handler
491  * are usually those that need a reset after changing parameters, so
492  * we want to minimise the number of reset.
493  * A cool idea is to use a timer : at each "set" command, we re-set the
494  * timer, when the timer eventually fires, we call the driver.
495  * Hopefully, more on that later.
496  *
497  * Also, I'm waiting to see how many people will complain about the
498  * netif_running(dev) test. I'm open on that one...
499  * Hopefully, the driver will remember to do a commit in "open()" ;-)
500  */
501 static inline int call_commit_handler(struct net_device *       dev)
502 {
503         if((netif_running(dev)) &&
504            (dev->wireless_handlers->standard[0] != NULL)) {
505                 /* Call the commit handler on the driver */
506                 return dev->wireless_handlers->standard[0](dev, NULL,
507                                                            NULL, NULL);
508         } else
509                 return 0;               /* Command completed successfully */
510 }
511
512 /* ---------------------------------------------------------------- */
513 /*
514  * Calculate size of private arguments
515  */
516 static inline int get_priv_size(__u16   args)
517 {
518         int     num = args & IW_PRIV_SIZE_MASK;
519         int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
520
521         return num * iw_priv_type_size[type];
522 }
523
524 /* ---------------------------------------------------------------- */
525 /*
526  * Re-calculate the size of private arguments
527  */
528 static inline int adjust_priv_size(__u16                args,
529                                    union iwreq_data *   wrqu)
530 {
531         int     num = wrqu->data.length;
532         int     max = args & IW_PRIV_SIZE_MASK;
533         int     type = (args & IW_PRIV_TYPE_MASK) >> 12;
534
535         /* Make sure the driver doesn't goof up */
536         if (max < num)
537                 num = max;
538
539         return num * iw_priv_type_size[type];
540 }
541
542 /* ---------------------------------------------------------------- */
543 /*
544  * Standard Wireless Handler : get wireless stats
545  *      Allow programatic access to /proc/net/wireless even if /proc
546  *      doesn't exist... Also more efficient...
547  */
548 static int iw_handler_get_iwstats(struct net_device *           dev,
549                                   struct iw_request_info *      info,
550                                   union iwreq_data *            wrqu,
551                                   char *                        extra)
552 {
553         /* Get stats from the driver */
554         struct iw_statistics *stats;
555
556         stats = get_wireless_stats(dev);
557         if (stats != (struct iw_statistics *) NULL) {
558
559                 /* Copy statistics to extra */
560                 memcpy(extra, stats, sizeof(struct iw_statistics));
561                 wrqu->data.length = sizeof(struct iw_statistics);
562
563                 /* Check if we need to clear the updated flag */
564                 if(wrqu->data.flags != 0)
565                         stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
566                 return 0;
567         } else
568                 return -EOPNOTSUPP;
569 }
570
571 /* ---------------------------------------------------------------- */
572 /*
573  * Standard Wireless Handler : get iwpriv definitions
574  * Export the driver private handler definition
575  * They will be picked up by tools like iwpriv...
576  */
577 static int iw_handler_get_private(struct net_device *           dev,
578                                   struct iw_request_info *      info,
579                                   union iwreq_data *            wrqu,
580                                   char *                        extra)
581 {
582         /* Check if the driver has something to export */
583         if((dev->wireless_handlers->num_private_args == 0) ||
584            (dev->wireless_handlers->private_args == NULL))
585                 return -EOPNOTSUPP;
586
587         /* Check if there is enough buffer up there */
588         if(wrqu->data.length < dev->wireless_handlers->num_private_args) {
589                 /* User space can't know in advance how large the buffer
590                  * needs to be. Give it a hint, so that we can support
591                  * any size buffer we want somewhat efficiently... */
592                 wrqu->data.length = dev->wireless_handlers->num_private_args;
593                 return -E2BIG;
594         }
595
596         /* Set the number of available ioctls. */
597         wrqu->data.length = dev->wireless_handlers->num_private_args;
598
599         /* Copy structure to the user buffer. */
600         memcpy(extra, dev->wireless_handlers->private_args,
601                sizeof(struct iw_priv_args) * wrqu->data.length);
602
603         return 0;
604 }
605
606
607 /******************** /proc/net/wireless SUPPORT ********************/
608 /*
609  * The /proc/net/wireless file is a human readable user-space interface
610  * exporting various wireless specific statistics from the wireless devices.
611  * This is the most popular part of the Wireless Extensions ;-)
612  *
613  * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
614  * The content of the file is basically the content of "struct iw_statistics".
615  */
616
617 #ifdef CONFIG_PROC_FS
618
619 /* ---------------------------------------------------------------- */
620 /*
621  * Print one entry (line) of /proc/net/wireless
622  */
623 static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
624                                                  struct net_device *dev)
625 {
626         /* Get stats from the driver */
627         struct iw_statistics *stats = get_wireless_stats(dev);
628
629         if (stats) {
630                 seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
631                                 "%6d %6d   %6d\n",
632                            dev->name, stats->status, stats->qual.qual,
633                            stats->qual.updated & IW_QUAL_QUAL_UPDATED
634                            ? '.' : ' ',
635                            ((__s32) stats->qual.level) - 
636                            ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
637                            stats->qual.updated & IW_QUAL_LEVEL_UPDATED
638                            ? '.' : ' ',
639                            ((__s32) stats->qual.noise) - 
640                            ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
641                            stats->qual.updated & IW_QUAL_NOISE_UPDATED
642                            ? '.' : ' ',
643                            stats->discard.nwid, stats->discard.code,
644                            stats->discard.fragment, stats->discard.retries,
645                            stats->discard.misc, stats->miss.beacon);
646                 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
647         }
648 }
649
650 /* ---------------------------------------------------------------- */
651 /*
652  * Print info for /proc/net/wireless (print all entries)
653  */
654 static int wireless_seq_show(struct seq_file *seq, void *v)
655 {
656         if (v == SEQ_START_TOKEN)
657                 seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
658                                 "packets               | Missed | WE\n"
659                                 " face | tus | link level noise |  nwid  "
660                                 "crypt   frag  retry   misc | beacon | %d\n",
661                            WIRELESS_EXT);
662         else
663                 wireless_seq_printf_stats(seq, v);
664         return 0;
665 }
666
667 static struct seq_operations wireless_seq_ops = {
668         .start = dev_seq_start,
669         .next  = dev_seq_next,
670         .stop  = dev_seq_stop,
671         .show  = wireless_seq_show,
672 };
673
674 static int wireless_seq_open(struct inode *inode, struct file *file)
675 {
676         return seq_open(file, &wireless_seq_ops);
677 }
678
679 static struct file_operations wireless_seq_fops = {
680         .owner   = THIS_MODULE,
681         .open    = wireless_seq_open,
682         .read    = seq_read,
683         .llseek  = seq_lseek,
684         .release = seq_release,
685 };
686
687 int __init wireless_proc_init(void)
688 {
689         /* Create /proc/net/wireless entry */
690         if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
691                 return -ENOMEM;
692
693         return 0;
694 }
695 #endif  /* CONFIG_PROC_FS */
696
697 /************************** IOCTL SUPPORT **************************/
698 /*
699  * The original user space API to configure all those Wireless Extensions
700  * is through IOCTLs.
701  * In there, we check if we need to call the new driver API (iw_handler)
702  * or just call the driver ioctl handler.
703  */
704
705 /* ---------------------------------------------------------------- */
706 /*
707  * Wrapper to call a standard Wireless Extension handler.
708  * We do various checks and also take care of moving data between
709  * user space and kernel space.
710  */
711 static int ioctl_standard_call(struct net_device *      dev,
712                                struct ifreq *           ifr,
713                                unsigned int             cmd,
714                                iw_handler               handler)
715 {
716         struct iwreq *                          iwr = (struct iwreq *) ifr;
717         const struct iw_ioctl_description *     descr;
718         struct iw_request_info                  info;
719         int                                     ret = -EINVAL;
720
721         /* Get the description of the IOCTL */
722         if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
723                 return -EOPNOTSUPP;
724         descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
725
726 #ifdef WE_IOCTL_DEBUG
727         printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
728                ifr->ifr_name, cmd);
729         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);
730 #endif  /* WE_IOCTL_DEBUG */
731
732         /* Prepare the call */
733         info.cmd = cmd;
734         info.flags = 0;
735
736         /* Check if we have a pointer to user space data or not */
737         if(descr->header_type != IW_HEADER_TYPE_POINT) {
738
739                 /* No extra arguments. Trivial to handle */
740                 ret = handler(dev, &info, &(iwr->u), NULL);
741
742 #ifdef WE_SET_EVENT
743                 /* Generate an event to notify listeners of the change */
744                 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
745                    ((ret == 0) || (ret == -EIWCOMMIT)))
746                         wireless_send_event(dev, cmd, &(iwr->u), NULL);
747 #endif  /* WE_SET_EVENT */
748         } else {
749                 char *  extra;
750                 int     extra_size;
751                 int     user_length = 0;
752                 int     err;
753
754                 /* Calculate space needed by arguments. Always allocate
755                  * for max space. Easier, and won't last long... */
756                 extra_size = descr->max_tokens * descr->token_size;
757
758                 /* Check what user space is giving us */
759                 if(IW_IS_SET(cmd)) {
760                         /* Check NULL pointer */
761                         if((iwr->u.data.pointer == NULL) &&
762                            (iwr->u.data.length != 0))
763                                 return -EFAULT;
764                         /* Check if number of token fits within bounds */
765                         if(iwr->u.data.length > descr->max_tokens)
766                                 return -E2BIG;
767                         if(iwr->u.data.length < descr->min_tokens)
768                                 return -EINVAL;
769                 } else {
770                         /* Check NULL pointer */
771                         if(iwr->u.data.pointer == NULL)
772                                 return -EFAULT;
773                         /* Save user space buffer size for checking */
774                         user_length = iwr->u.data.length;
775
776                         /* Don't check if user_length > max to allow forward
777                          * compatibility. The test user_length < min is
778                          * implied by the test at the end. */
779
780                         /* Support for very large requests */
781                         if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
782                            (user_length > descr->max_tokens)) {
783                                 /* Allow userspace to GET more than max so
784                                  * we can support any size GET requests.
785                                  * There is still a limit : -ENOMEM. */
786                                 extra_size = user_length * descr->token_size;
787                                 /* Note : user_length is originally a __u16,
788                                  * and token_size is controlled by us,
789                                  * so extra_size won't get negative and
790                                  * won't overflow... */
791                         }
792                 }
793
794 #ifdef WE_IOCTL_DEBUG
795                 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
796                        dev->name, extra_size);
797 #endif  /* WE_IOCTL_DEBUG */
798
799                 /* Create the kernel buffer */
800                 extra = kmalloc(extra_size, GFP_KERNEL);
801                 if (extra == NULL) {
802                         return -ENOMEM;
803                 }
804
805                 /* If it is a SET, get all the extra data in here */
806                 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
807                         err = copy_from_user(extra, iwr->u.data.pointer,
808                                              iwr->u.data.length *
809                                              descr->token_size);
810                         if (err) {
811                                 kfree(extra);
812                                 return -EFAULT;
813                         }
814 #ifdef WE_IOCTL_DEBUG
815                         printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
816                                dev->name,
817                                iwr->u.data.length * descr->token_size);
818 #endif  /* WE_IOCTL_DEBUG */
819                 }
820
821                 /* Call the handler */
822                 ret = handler(dev, &info, &(iwr->u), extra);
823
824                 /* If we have something to return to the user */
825                 if (!ret && IW_IS_GET(cmd)) {
826                         /* Check if there is enough buffer up there */
827                         if(user_length < iwr->u.data.length) {
828                                 kfree(extra);
829                                 return -E2BIG;
830                         }
831
832                         err = copy_to_user(iwr->u.data.pointer, extra,
833                                            iwr->u.data.length *
834                                            descr->token_size);
835                         if (err)
836                                 ret =  -EFAULT;                            
837 #ifdef WE_IOCTL_DEBUG
838                         printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
839                                dev->name,
840                                iwr->u.data.length * descr->token_size);
841 #endif  /* WE_IOCTL_DEBUG */
842                 }
843
844 #ifdef WE_SET_EVENT
845                 /* Generate an event to notify listeners of the change */
846                 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
847                    ((ret == 0) || (ret == -EIWCOMMIT))) {
848                         if(descr->flags & IW_DESCR_FLAG_RESTRICT)
849                                 /* If the event is restricted, don't
850                                  * export the payload */
851                                 wireless_send_event(dev, cmd, &(iwr->u), NULL);
852                         else
853                                 wireless_send_event(dev, cmd, &(iwr->u),
854                                                     extra);
855                 }
856 #endif  /* WE_SET_EVENT */
857
858                 /* Cleanup - I told you it wasn't that long ;-) */
859                 kfree(extra);
860         }
861
862         /* Call commit handler if needed and defined */
863         if(ret == -EIWCOMMIT)
864                 ret = call_commit_handler(dev);
865
866         /* Here, we will generate the appropriate event if needed */
867
868         return ret;
869 }
870
871 /* ---------------------------------------------------------------- */
872 /*
873  * Wrapper to call a private Wireless Extension handler.
874  * We do various checks and also take care of moving data between
875  * user space and kernel space.
876  * It's not as nice and slimline as the standard wrapper. The cause
877  * is struct iw_priv_args, which was not really designed for the
878  * job we are going here.
879  *
880  * IMPORTANT : This function prevent to set and get data on the same
881  * IOCTL and enforce the SET/GET convention. Not doing it would be
882  * far too hairy...
883  * If you need to set and get data at the same time, please don't use
884  * a iw_handler but process it in your ioctl handler (i.e. use the
885  * old driver API).
886  */
887 static inline int ioctl_private_call(struct net_device *        dev,
888                                      struct ifreq *             ifr,
889                                      unsigned int               cmd,
890                                      iw_handler         handler)
891 {
892         struct iwreq *                  iwr = (struct iwreq *) ifr;
893         const struct iw_priv_args *     descr = NULL;
894         struct iw_request_info          info;
895         int                             extra_size = 0;
896         int                             i;
897         int                             ret = -EINVAL;
898
899         /* Get the description of the IOCTL */
900         for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
901                 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
902                         descr = &(dev->wireless_handlers->private_args[i]);
903                         break;
904                 }
905
906 #ifdef WE_IOCTL_DEBUG
907         printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
908                ifr->ifr_name, cmd);
909         if(descr) {
910                 printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
911                        dev->name, descr->name,
912                        descr->set_args, descr->get_args);
913         }
914 #endif  /* WE_IOCTL_DEBUG */
915
916         /* Compute the size of the set/get arguments */
917         if(descr != NULL) {
918                 if(IW_IS_SET(cmd)) {
919                         int     offset = 0;     /* For sub-ioctls */
920                         /* Check for sub-ioctl handler */
921                         if(descr->name[0] == '\0')
922                                 /* Reserve one int for sub-ioctl index */
923                                 offset = sizeof(__u32);
924
925                         /* Size of set arguments */
926                         extra_size = get_priv_size(descr->set_args);
927
928                         /* Does it fits in iwr ? */
929                         if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
930                            ((extra_size + offset) <= IFNAMSIZ))
931                                 extra_size = 0;
932                 } else {
933                         /* Size of get arguments */
934                         extra_size = get_priv_size(descr->get_args);
935
936                         /* Does it fits in iwr ? */
937                         if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
938                            (extra_size <= IFNAMSIZ))
939                                 extra_size = 0;
940                 }
941         }
942
943         /* Prepare the call */
944         info.cmd = cmd;
945         info.flags = 0;
946
947         /* Check if we have a pointer to user space data or not. */
948         if(extra_size == 0) {
949                 /* No extra arguments. Trivial to handle */
950                 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
951         } else {
952                 char *  extra;
953                 int     err;
954
955                 /* Check what user space is giving us */
956                 if(IW_IS_SET(cmd)) {
957                         /* Check NULL pointer */
958                         if((iwr->u.data.pointer == NULL) &&
959                            (iwr->u.data.length != 0))
960                                 return -EFAULT;
961
962                         /* Does it fits within bounds ? */
963                         if(iwr->u.data.length > (descr->set_args &
964                                                  IW_PRIV_SIZE_MASK))
965                                 return -E2BIG;
966                 } else {
967                         /* Check NULL pointer */
968                         if(iwr->u.data.pointer == NULL)
969                                 return -EFAULT;
970                 }
971
972 #ifdef WE_IOCTL_DEBUG
973                 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
974                        dev->name, extra_size);
975 #endif  /* WE_IOCTL_DEBUG */
976
977                 /* Always allocate for max space. Easier, and won't last
978                  * long... */
979                 extra = kmalloc(extra_size, GFP_KERNEL);
980                 if (extra == NULL) {
981                         return -ENOMEM;
982                 }
983
984                 /* If it is a SET, get all the extra data in here */
985                 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
986                         err = copy_from_user(extra, iwr->u.data.pointer,
987                                              extra_size);
988                         if (err) {
989                                 kfree(extra);
990                                 return -EFAULT;
991                         }
992 #ifdef WE_IOCTL_DEBUG
993                         printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
994                                dev->name, iwr->u.data.length);
995 #endif  /* WE_IOCTL_DEBUG */
996                 }
997
998                 /* Call the handler */
999                 ret = handler(dev, &info, &(iwr->u), extra);
1000
1001                 /* If we have something to return to the user */
1002                 if (!ret && IW_IS_GET(cmd)) {
1003
1004                         /* Adjust for the actual length if it's variable,
1005                          * avoid leaking kernel bits outside. */
1006                         if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
1007                                 extra_size = adjust_priv_size(descr->get_args,
1008                                                               &(iwr->u));
1009                         }
1010
1011                         err = copy_to_user(iwr->u.data.pointer, extra,
1012                                            extra_size);
1013                         if (err)
1014                                 ret =  -EFAULT;                            
1015 #ifdef WE_IOCTL_DEBUG
1016                         printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
1017                                dev->name, iwr->u.data.length);
1018 #endif  /* WE_IOCTL_DEBUG */
1019                 }
1020
1021                 /* Cleanup - I told you it wasn't that long ;-) */
1022                 kfree(extra);
1023         }
1024
1025
1026         /* Call commit handler if needed and defined */
1027         if(ret == -EIWCOMMIT)
1028                 ret = call_commit_handler(dev);
1029
1030         return ret;
1031 }
1032
1033 /* ---------------------------------------------------------------- */
1034 /*
1035  * Main IOCTl dispatcher. Called from the main networking code
1036  * (dev_ioctl() in net/core/dev.c).
1037  * Check the type of IOCTL and call the appropriate wrapper...
1038  */
1039 int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
1040 {
1041         struct net_device *dev;
1042         iw_handler      handler;
1043
1044         /* Permissions are already checked in dev_ioctl() before calling us.
1045          * The copy_to/from_user() of ifr is also dealt with in there */
1046
1047         /* Make sure the device exist */
1048         if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
1049                 return -ENODEV;
1050
1051         /* A bunch of special cases, then the generic case...
1052          * Note that 'cmd' is already filtered in dev_ioctl() with
1053          * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
1054         switch(cmd) 
1055         {
1056                 case SIOCGIWSTATS:
1057                         /* Get Wireless Stats */
1058                         return ioctl_standard_call(dev,
1059                                                    ifr,
1060                                                    cmd,
1061                                                    &iw_handler_get_iwstats);
1062
1063                 case SIOCGIWPRIV:
1064                         /* Check if we have some wireless handlers defined */
1065                         if(dev->wireless_handlers != NULL) {
1066                                 /* We export to user space the definition of
1067                                  * the private handler ourselves */
1068                                 return ioctl_standard_call(dev,
1069                                                            ifr,
1070                                                            cmd,
1071                                                            &iw_handler_get_private);
1072                         }
1073                         // ## Fall-through for old API ##
1074                 default:
1075                         /* Generic IOCTL */
1076                         /* Basic check */
1077                         if (!netif_device_present(dev))
1078                                 return -ENODEV;
1079                         /* New driver API : try to find the handler */
1080                         handler = get_handler(dev, cmd);
1081                         if(handler != NULL) {
1082                                 /* Standard and private are not the same */
1083                                 if(cmd < SIOCIWFIRSTPRIV)
1084                                         return ioctl_standard_call(dev,
1085                                                                    ifr,
1086                                                                    cmd,
1087                                                                    handler);
1088                                 else
1089                                         return ioctl_private_call(dev,
1090                                                                   ifr,
1091                                                                   cmd,
1092                                                                   handler);
1093                         }
1094                         /* Old driver API : call driver ioctl handler */
1095                         if (dev->do_ioctl) {
1096                                 return dev->do_ioctl(dev, ifr, cmd);
1097                         }
1098                         return -EOPNOTSUPP;
1099         }
1100         /* Not reached */
1101         return -EINVAL;
1102 }
1103
1104 /********************** RTNETLINK REQUEST API **********************/
1105 /*
1106  * The alternate user space API to configure all those Wireless Extensions
1107  * is through RtNetlink.
1108  * This API support only the new driver API (iw_handler).
1109  *
1110  * This RtNetlink API use the same query/reply model as the ioctl API.
1111  * Maximum effort has been done to fit in the RtNetlink model, and
1112  * we support both RtNetlink Set and RtNelink Get operations.
1113  * On the other hand, we don't offer Dump operations because of the
1114  * following reasons :
1115  *      o Large number of parameters, most optional
1116  *      o Large size of some parameters (> 100 bytes)
1117  *      o Each parameters need to be extracted from hardware
1118  *      o Scan requests can take seconds and disable network activity.
1119  * Because of this high cost/overhead, we want to return only the
1120  * parameters the user application is really interested in.
1121  * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag.
1122  *
1123  * The API uses the standard RtNetlink socket. When the RtNetlink code
1124  * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request,
1125  * it calls here.
1126  */
1127
1128 #ifdef CONFIG_NET_WIRELESS_RTNETLINK
1129 /* ---------------------------------------------------------------- */
1130 /*
1131  * Wrapper to call a standard Wireless Extension GET handler.
1132  * We do various checks and call the handler with the proper args.
1133  */
1134 static int rtnetlink_standard_get(struct net_device *   dev,
1135                                   struct iw_event *     request,
1136                                   int                   request_len,
1137                                   iw_handler            handler,
1138                                   char **               p_buf,
1139                                   int *                 p_len)
1140 {
1141         const struct iw_ioctl_description *     descr = NULL;
1142         unsigned int                            cmd;
1143         union iwreq_data *                      wrqu;
1144         int                                     hdr_len;
1145         struct iw_request_info                  info;
1146         char *                                  buffer = NULL;
1147         int                                     buffer_size = 0;
1148         int                                     ret = -EINVAL;
1149
1150         /* Get the description of the Request */
1151         cmd = request->cmd;
1152         if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
1153                 return -EOPNOTSUPP;
1154         descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
1155
1156 #ifdef WE_RTNETLINK_DEBUG
1157         printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n",
1158                dev->name, cmd);
1159         printk(KERN_DEBUG "%s (WE.r) : 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);
1160 #endif  /* WE_RTNETLINK_DEBUG */
1161
1162         /* Check if wrqu is complete */
1163         hdr_len = event_type_size[descr->header_type];
1164         if(request_len < hdr_len) {
1165 #ifdef WE_RTNETLINK_DEBUG
1166                 printk(KERN_DEBUG
1167                        "%s (WE.r) : Wireless request too short (%d)\n",
1168                        dev->name, request_len);
1169 #endif  /* WE_RTNETLINK_DEBUG */
1170                 return -EINVAL;
1171         }
1172
1173         /* Prepare the call */
1174         info.cmd = cmd;
1175         info.flags = 0;
1176
1177         /* Check if we have extra data in the reply or not */
1178         if(descr->header_type != IW_HEADER_TYPE_POINT) {
1179
1180                 /* Create the kernel buffer that we will return.
1181                  * It's at an offset to match the TYPE_POINT case... */
1182                 buffer_size = request_len + IW_EV_POINT_OFF;
1183                 buffer = kmalloc(buffer_size, GFP_KERNEL);
1184                 if (buffer == NULL) {
1185                         return -ENOMEM;
1186                 }
1187                 /* Copy event data */
1188                 memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
1189                 /* Use our own copy of wrqu */
1190                 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
1191                                              + IW_EV_LCP_LEN);
1192
1193                 /* No extra arguments. Trivial to handle */
1194                 ret = handler(dev, &info, wrqu, NULL);
1195
1196         } else {
1197                 union iwreq_data        wrqu_point;
1198                 char *                  extra = NULL;
1199                 int                     extra_size = 0;
1200
1201                 /* Get a temp copy of wrqu (skip pointer) */
1202                 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
1203                        ((char *) request) + IW_EV_LCP_LEN,
1204                        IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1205
1206                 /* Calculate space needed by arguments. Always allocate
1207                  * for max space. Easier, and won't last long... */
1208                 extra_size = descr->max_tokens * descr->token_size;
1209                 /* Support for very large requests */
1210                 if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
1211                    (wrqu_point.data.length > descr->max_tokens))
1212                         extra_size = (wrqu_point.data.length
1213                                       * descr->token_size);
1214                 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
1215 #ifdef WE_RTNETLINK_DEBUG
1216                 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
1217                        dev->name, extra_size, buffer_size);
1218 #endif  /* WE_RTNETLINK_DEBUG */
1219
1220                 /* Create the kernel buffer that we will return */
1221                 buffer = kmalloc(buffer_size, GFP_KERNEL);
1222                 if (buffer == NULL) {
1223                         return -ENOMEM;
1224                 }
1225
1226                 /* Put wrqu in the right place (just before extra).
1227                  * Leave space for IWE header and dummy pointer...
1228                  * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
1229                  */
1230                 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
1231                        ((char *) &wrqu_point) + IW_EV_POINT_OFF,
1232                        IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1233                 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
1234
1235                 /* Extra comes logically after that. Offset +12 bytes. */
1236                 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
1237
1238                 /* Call the handler */
1239                 ret = handler(dev, &info, wrqu, extra);
1240
1241                 /* Calculate real returned length */
1242                 extra_size = (wrqu->data.length * descr->token_size);
1243                 /* Re-adjust reply size */
1244                 request->len = extra_size + IW_EV_POINT_LEN;
1245
1246                 /* Put the iwe header where it should, i.e. scrap the
1247                  * dummy pointer. */
1248                 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
1249
1250 #ifdef WE_RTNETLINK_DEBUG
1251                 printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
1252 #endif  /* WE_RTNETLINK_DEBUG */
1253
1254                 /* Check if there is enough buffer up there */
1255                 if(wrqu_point.data.length < wrqu->data.length)
1256                         ret = -E2BIG;
1257         }
1258
1259         /* Return the buffer to the caller */
1260         if (!ret) {
1261                 *p_buf = buffer;
1262                 *p_len = request->len;
1263         } else {
1264                 /* Cleanup */
1265                 if(buffer)
1266                         kfree(buffer);
1267         }
1268
1269         return ret;
1270 }
1271
1272 /* ---------------------------------------------------------------- */
1273 /*
1274  * Wrapper to call a standard Wireless Extension SET handler.
1275  * We do various checks and call the handler with the proper args.
1276  */
1277 static inline int rtnetlink_standard_set(struct net_device *    dev,
1278                                          struct iw_event *      request,
1279                                          int                    request_len,
1280                                          iw_handler             handler)
1281 {
1282         const struct iw_ioctl_description *     descr = NULL;
1283         unsigned int                            cmd;
1284         union iwreq_data *                      wrqu;
1285         union iwreq_data                        wrqu_point;
1286         int                                     hdr_len;
1287         char *                                  extra = NULL;
1288         int                                     extra_size = 0;
1289         struct iw_request_info                  info;
1290         int                                     ret = -EINVAL;
1291
1292         /* Get the description of the Request */
1293         cmd = request->cmd;
1294         if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
1295                 return -EOPNOTSUPP;
1296         descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
1297
1298 #ifdef WE_RTNETLINK_DEBUG
1299         printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n",
1300                dev->name, cmd);
1301         printk(KERN_DEBUG "%s (WE.r) : 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);
1302 #endif  /* WE_RTNETLINK_DEBUG */
1303
1304         /* Extract fixed header from request. This is properly aligned. */
1305         wrqu = &request->u;
1306
1307         /* Check if wrqu is complete */
1308         hdr_len = event_type_size[descr->header_type];
1309         if(request_len < hdr_len) {
1310 #ifdef WE_RTNETLINK_DEBUG
1311                 printk(KERN_DEBUG
1312                        "%s (WE.r) : Wireless request too short (%d)\n",
1313                        dev->name, request_len);
1314 #endif  /* WE_RTNETLINK_DEBUG */
1315                 return -EINVAL;
1316         }
1317
1318         /* Prepare the call */
1319         info.cmd = cmd;
1320         info.flags = 0;
1321
1322         /* Check if we have extra data in the request or not */
1323         if(descr->header_type != IW_HEADER_TYPE_POINT) {
1324
1325                 /* No extra arguments. Trivial to handle */
1326                 ret = handler(dev, &info, wrqu, NULL);
1327
1328         } else {
1329                 int     extra_len;
1330
1331                 /* Put wrqu in the right place (skip pointer) */
1332                 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
1333                        wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1334                 /* Don't forget about the event code... */
1335                 wrqu = &wrqu_point;
1336
1337                 /* Check if number of token fits within bounds */
1338                 if(wrqu_point.data.length > descr->max_tokens)
1339                         return -E2BIG;
1340                 if(wrqu_point.data.length < descr->min_tokens)
1341                         return -EINVAL;
1342
1343                 /* Real length of payload */
1344                 extra_len = wrqu_point.data.length * descr->token_size;
1345
1346                 /* Check if request is self consistent */
1347                 if((request_len - hdr_len) < extra_len) {
1348 #ifdef WE_RTNETLINK_DEBUG
1349                         printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
1350                                dev->name, extra_size);
1351 #endif  /* WE_RTNETLINK_DEBUG */
1352                         return -EINVAL;
1353                 }
1354
1355 #ifdef WE_RTNETLINK_DEBUG
1356                 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
1357                        dev->name, extra_size);
1358 #endif  /* WE_RTNETLINK_DEBUG */
1359
1360                 /* Always allocate for max space. Easier, and won't last
1361                  * long... */
1362                 extra_size = descr->max_tokens * descr->token_size;
1363                 extra = kmalloc(extra_size, GFP_KERNEL);
1364                 if (extra == NULL)
1365                         return -ENOMEM;
1366
1367                 /* Copy extra in aligned buffer */
1368                 memcpy(extra, ((char *) request) + hdr_len, extra_len);
1369
1370                 /* Call the handler */
1371                 ret = handler(dev, &info, &wrqu_point, extra);
1372         }
1373
1374 #ifdef WE_SET_EVENT
1375         /* Generate an event to notify listeners of the change */
1376         if((descr->flags & IW_DESCR_FLAG_EVENT) &&
1377            ((ret == 0) || (ret == -EIWCOMMIT))) {
1378                 if(descr->flags & IW_DESCR_FLAG_RESTRICT)
1379                         /* If the event is restricted, don't
1380                          * export the payload */
1381                         wireless_send_event(dev, cmd, wrqu, NULL);
1382                 else
1383                         wireless_send_event(dev, cmd, wrqu, extra);
1384         }
1385 #endif  /* WE_SET_EVENT */
1386
1387         /* Cleanup - I told you it wasn't that long ;-) */
1388         if(extra)
1389                 kfree(extra);
1390
1391         /* Call commit handler if needed and defined */
1392         if(ret == -EIWCOMMIT)
1393                 ret = call_commit_handler(dev);
1394
1395         return ret;
1396 }
1397
1398 /* ---------------------------------------------------------------- */
1399 /*
1400  * Wrapper to call a private Wireless Extension GET handler.
1401  * Same as above...
1402  * It's not as nice and slimline as the standard wrapper. The cause
1403  * is struct iw_priv_args, which was not really designed for the
1404  * job we are going here.
1405  *
1406  * IMPORTANT : This function prevent to set and get data on the same
1407  * IOCTL and enforce the SET/GET convention. Not doing it would be
1408  * far too hairy...
1409  * If you need to set and get data at the same time, please don't use
1410  * a iw_handler but process it in your ioctl handler (i.e. use the
1411  * old driver API).
1412  */
1413 static inline int rtnetlink_private_get(struct net_device *     dev,
1414                                         struct iw_event *       request,
1415                                         int                     request_len,
1416                                         iw_handler              handler,
1417                                         char **                 p_buf,
1418                                         int *                   p_len)
1419 {
1420         const struct iw_priv_args *     descr = NULL;
1421         unsigned int                    cmd;
1422         union iwreq_data *              wrqu;
1423         int                             hdr_len;
1424         struct iw_request_info          info;
1425         int                             extra_size = 0;
1426         int                             i;
1427         char *                          buffer = NULL;
1428         int                             buffer_size = 0;
1429         int                             ret = -EINVAL;
1430
1431         /* Get the description of the Request */
1432         cmd = request->cmd;
1433         for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
1434                 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
1435                         descr = &(dev->wireless_handlers->private_args[i]);
1436                         break;
1437                 }
1438         if(descr == NULL)
1439                 return -EOPNOTSUPP;
1440
1441 #ifdef WE_RTNETLINK_DEBUG
1442         printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
1443                dev->name, cmd);
1444         printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
1445                dev->name, descr->name, descr->set_args, descr->get_args);
1446 #endif  /* WE_RTNETLINK_DEBUG */
1447
1448         /* Compute the max size of the get arguments */
1449         extra_size = get_priv_size(descr->get_args);
1450
1451         /* Does it fits in wrqu ? */
1452         if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
1453            (extra_size <= IFNAMSIZ)) {
1454                 hdr_len = extra_size;
1455                 extra_size = 0;
1456         } else {
1457                 hdr_len = IW_EV_POINT_LEN;
1458         }
1459
1460         /* Check if wrqu is complete */
1461         if(request_len < hdr_len) {
1462 #ifdef WE_RTNETLINK_DEBUG
1463                 printk(KERN_DEBUG
1464                        "%s (WE.r) : Wireless request too short (%d)\n",
1465                        dev->name, request_len);
1466 #endif  /* WE_RTNETLINK_DEBUG */
1467                 return -EINVAL;
1468         }
1469
1470         /* Prepare the call */
1471         info.cmd = cmd;
1472         info.flags = 0;
1473
1474         /* Check if we have a pointer to user space data or not. */
1475         if(extra_size == 0) {
1476
1477                 /* Create the kernel buffer that we will return.
1478                  * It's at an offset to match the TYPE_POINT case... */
1479                 buffer_size = request_len + IW_EV_POINT_OFF;
1480                 buffer = kmalloc(buffer_size, GFP_KERNEL);
1481                 if (buffer == NULL) {
1482                         return -ENOMEM;
1483                 }
1484                 /* Copy event data */
1485                 memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
1486                 /* Use our own copy of wrqu */
1487                 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
1488                                              + IW_EV_LCP_LEN);
1489
1490                 /* No extra arguments. Trivial to handle */
1491                 ret = handler(dev, &info, wrqu, (char *) wrqu);
1492
1493         } else {
1494                 char *  extra;
1495
1496                 /* Buffer for full reply */
1497                 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
1498
1499 #ifdef WE_RTNETLINK_DEBUG
1500                 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
1501                        dev->name, extra_size, buffer_size);
1502 #endif  /* WE_RTNETLINK_DEBUG */
1503
1504                 /* Create the kernel buffer that we will return */
1505                 buffer = kmalloc(buffer_size, GFP_KERNEL);
1506                 if (buffer == NULL) {
1507                         return -ENOMEM;
1508                 }
1509
1510                 /* Put wrqu in the right place (just before extra).
1511                  * Leave space for IWE header and dummy pointer...
1512                  * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
1513                  */
1514                 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
1515                        ((char *) request) + IW_EV_LCP_LEN,
1516                        IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1517                 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
1518
1519                 /* Extra comes logically after that. Offset +12 bytes. */
1520                 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
1521
1522                 /* Call the handler */
1523                 ret = handler(dev, &info, wrqu, extra);
1524
1525                 /* Adjust for the actual length if it's variable,
1526                  * avoid leaking kernel bits outside. */
1527                 if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
1528                         extra_size = adjust_priv_size(descr->get_args, wrqu);
1529                 /* Re-adjust reply size */
1530                 request->len = extra_size + IW_EV_POINT_LEN;
1531
1532                 /* Put the iwe header where it should, i.e. scrap the
1533                  * dummy pointer. */
1534                 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
1535
1536 #ifdef WE_RTNETLINK_DEBUG
1537                 printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
1538 #endif  /* WE_RTNETLINK_DEBUG */
1539         }
1540
1541         /* Return the buffer to the caller */
1542         if (!ret) {
1543                 *p_buf = buffer;
1544                 *p_len = request->len;
1545         } else {
1546                 /* Cleanup */
1547                 if(buffer)
1548                         kfree(buffer);
1549         }
1550
1551         return ret;
1552 }
1553
1554 /* ---------------------------------------------------------------- */
1555 /*
1556  * Wrapper to call a private Wireless Extension SET handler.
1557  * Same as above...
1558  * It's not as nice and slimline as the standard wrapper. The cause
1559  * is struct iw_priv_args, which was not really designed for the
1560  * job we are going here.
1561  *
1562  * IMPORTANT : This function prevent to set and get data on the same
1563  * IOCTL and enforce the SET/GET convention. Not doing it would be
1564  * far too hairy...
1565  * If you need to set and get data at the same time, please don't use
1566  * a iw_handler but process it in your ioctl handler (i.e. use the
1567  * old driver API).
1568  */
1569 static inline int rtnetlink_private_set(struct net_device *     dev,
1570                                         struct iw_event *       request,
1571                                         int                     request_len,
1572                                         iw_handler              handler)
1573 {
1574         const struct iw_priv_args *     descr = NULL;
1575         unsigned int                    cmd;
1576         union iwreq_data *              wrqu;
1577         union iwreq_data                wrqu_point;
1578         int                             hdr_len;
1579         char *                          extra = NULL;
1580         int                             extra_size = 0;
1581         int                             offset = 0;     /* For sub-ioctls */
1582         struct iw_request_info          info;
1583         int                             i;
1584         int                             ret = -EINVAL;
1585
1586         /* Get the description of the Request */
1587         cmd = request->cmd;
1588         for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
1589                 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
1590                         descr = &(dev->wireless_handlers->private_args[i]);
1591                         break;
1592                 }
1593         if(descr == NULL)
1594                 return -EOPNOTSUPP;
1595
1596 #ifdef WE_RTNETLINK_DEBUG
1597         printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
1598                ifr->ifr_name, cmd);
1599         printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
1600                dev->name, descr->name, descr->set_args, descr->get_args);
1601 #endif  /* WE_RTNETLINK_DEBUG */
1602
1603         /* Compute the size of the set arguments */
1604         /* Check for sub-ioctl handler */
1605         if(descr->name[0] == '\0')
1606                 /* Reserve one int for sub-ioctl index */
1607                 offset = sizeof(__u32);
1608
1609         /* Size of set arguments */
1610         extra_size = get_priv_size(descr->set_args);
1611
1612         /* Does it fits in wrqu ? */
1613         if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
1614            (extra_size <= IFNAMSIZ)) {
1615                 hdr_len = IW_EV_LCP_LEN + extra_size;
1616                 extra_size = 0;
1617         } else {
1618                 hdr_len = IW_EV_POINT_LEN;
1619         }
1620
1621         /* Extract fixed header from request. This is properly aligned. */
1622         wrqu = &request->u;
1623
1624         /* Check if wrqu is complete */
1625         if(request_len < hdr_len) {
1626 #ifdef WE_RTNETLINK_DEBUG
1627                 printk(KERN_DEBUG
1628                        "%s (WE.r) : Wireless request too short (%d)\n",
1629                        dev->name, request_len);
1630 #endif  /* WE_RTNETLINK_DEBUG */
1631                 return -EINVAL;
1632         }
1633
1634         /* Prepare the call */
1635         info.cmd = cmd;
1636         info.flags = 0;
1637
1638         /* Check if we have a pointer to user space data or not. */
1639         if(extra_size == 0) {
1640
1641                 /* No extra arguments. Trivial to handle */
1642                 ret = handler(dev, &info, wrqu, (char *) wrqu);
1643
1644         } else {
1645                 int     extra_len;
1646
1647                 /* Put wrqu in the right place (skip pointer) */
1648                 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
1649                        wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1650
1651                 /* Does it fits within bounds ? */
1652                 if(wrqu_point.data.length > (descr->set_args &
1653                                              IW_PRIV_SIZE_MASK))
1654                         return -E2BIG;
1655
1656                 /* Real length of payload */
1657                 extra_len = adjust_priv_size(descr->set_args, &wrqu_point);
1658
1659                 /* Check if request is self consistent */
1660                 if((request_len - hdr_len) < extra_len) {
1661 #ifdef WE_RTNETLINK_DEBUG
1662                         printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
1663                                dev->name, extra_size);
1664 #endif  /* WE_RTNETLINK_DEBUG */
1665                         return -EINVAL;
1666                 }
1667
1668 #ifdef WE_RTNETLINK_DEBUG
1669                 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
1670                        dev->name, extra_size);
1671 #endif  /* WE_RTNETLINK_DEBUG */
1672
1673                 /* Always allocate for max space. Easier, and won't last
1674                  * long... */
1675                 extra = kmalloc(extra_size, GFP_KERNEL);
1676                 if (extra == NULL)
1677                         return -ENOMEM;
1678
1679                 /* Copy extra in aligned buffer */
1680                 memcpy(extra, ((char *) request) + hdr_len, extra_len);
1681
1682                 /* Call the handler */
1683                 ret = handler(dev, &info, &wrqu_point, extra);
1684
1685                 /* Cleanup - I told you it wasn't that long ;-) */
1686                 kfree(extra);
1687         }
1688
1689         /* Call commit handler if needed and defined */
1690         if(ret == -EIWCOMMIT)
1691                 ret = call_commit_handler(dev);
1692
1693         return ret;
1694 }
1695
1696 /* ---------------------------------------------------------------- */
1697 /*
1698  * Main RtNetlink dispatcher. Called from the main networking code
1699  * (do_getlink() in net/core/rtnetlink.c).
1700  * Check the type of Request and call the appropriate wrapper...
1701  */
1702 int wireless_rtnetlink_get(struct net_device *  dev,
1703                            char *               data,
1704                            int                  len,
1705                            char **              p_buf,
1706                            int *                p_len)
1707 {
1708         struct iw_event *       request = (struct iw_event *) data;
1709         iw_handler              handler;
1710
1711         /* Check length */
1712         if(len < IW_EV_LCP_LEN) {
1713                 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
1714                        dev->name, len);
1715                 return -EINVAL;
1716         }
1717
1718         /* ReCheck length (len may have padding) */
1719         if(request->len > len) {
1720                 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
1721                        dev->name, request->len, len);
1722                 return -EINVAL;
1723         }
1724
1725         /* Only accept GET requests in here */
1726         if(!IW_IS_GET(request->cmd))
1727                 return -EOPNOTSUPP;
1728
1729         /* If command is `get the encoding parameters', check if
1730          * the user has the right to do it */
1731         if (request->cmd == SIOCGIWENCODE ||
1732             request->cmd == SIOCGIWENCODEEXT) {
1733                 if (!capable(CAP_NET_ADMIN))
1734                         return -EPERM;
1735         }
1736
1737         /* Special cases */
1738         if(request->cmd == SIOCGIWSTATS)
1739                 /* Get Wireless Stats */
1740                 return rtnetlink_standard_get(dev,
1741                                               request,
1742                                               request->len,
1743                                               &iw_handler_get_iwstats,
1744                                               p_buf, p_len);
1745         if(request->cmd == SIOCGIWPRIV) {
1746                 /* Check if we have some wireless handlers defined */
1747                 if(dev->wireless_handlers == NULL)
1748                         return -EOPNOTSUPP;
1749                 /* Get Wireless Stats */
1750                 return rtnetlink_standard_get(dev,
1751                                               request,
1752                                               request->len,
1753                                               &iw_handler_get_private,
1754                                               p_buf, p_len);
1755         }
1756
1757         /* Basic check */
1758         if (!netif_device_present(dev))
1759                 return -ENODEV;
1760
1761         /* Try to find the handler */
1762         handler = get_handler(dev, request->cmd);
1763         if(handler != NULL) {
1764                 /* Standard and private are not the same */
1765                 if(request->cmd < SIOCIWFIRSTPRIV)
1766                         return rtnetlink_standard_get(dev,
1767                                                       request,
1768                                                       request->len,
1769                                                       handler,
1770                                                       p_buf, p_len);
1771                 else
1772                         return rtnetlink_private_get(dev,
1773                                                      request,
1774                                                      request->len,
1775                                                      handler,
1776                                                      p_buf, p_len);
1777         }
1778
1779         return -EOPNOTSUPP;
1780 }
1781
1782 /* ---------------------------------------------------------------- */
1783 /*
1784  * Main RtNetlink dispatcher. Called from the main networking code
1785  * (do_setlink() in net/core/rtnetlink.c).
1786  * Check the type of Request and call the appropriate wrapper...
1787  */
1788 int wireless_rtnetlink_set(struct net_device *  dev,
1789                            char *               data,
1790                            int                  len)
1791 {
1792         struct iw_event *       request = (struct iw_event *) data;
1793         iw_handler              handler;
1794
1795         /* Check length */
1796         if(len < IW_EV_LCP_LEN) {
1797                 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
1798                        dev->name, len);
1799                 return -EINVAL;
1800         }
1801
1802         /* ReCheck length (len may have padding) */
1803         if(request->len > len) {
1804                 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
1805                        dev->name, request->len, len);
1806                 return -EINVAL;
1807         }
1808
1809         /* Only accept SET requests in here */
1810         if(!IW_IS_SET(request->cmd))
1811                 return -EOPNOTSUPP;
1812
1813         /* Basic check */
1814         if (!netif_device_present(dev))
1815                 return -ENODEV;
1816
1817         /* New driver API : try to find the handler */
1818         handler = get_handler(dev, request->cmd);
1819         if(handler != NULL) {
1820                 /* Standard and private are not the same */
1821                 if(request->cmd < SIOCIWFIRSTPRIV)
1822                         return rtnetlink_standard_set(dev,
1823                                                       request,
1824                                                       request->len,
1825                                                       handler);
1826                 else
1827                         return rtnetlink_private_set(dev,
1828                                                      request,
1829                                                      request->len,
1830                                                      handler);
1831         }
1832
1833         return -EOPNOTSUPP;
1834 }
1835 #endif  /* CONFIG_NET_WIRELESS_RTNETLINK */
1836
1837
1838 /************************* EVENT PROCESSING *************************/
1839 /*
1840  * Process events generated by the wireless layer or the driver.
1841  * Most often, the event will be propagated through rtnetlink
1842  */
1843
1844 #ifdef WE_EVENT_RTNETLINK
1845 /* ---------------------------------------------------------------- */
1846 /*
1847  * Fill a rtnetlink message with our event data.
1848  * Note that we propage only the specified event and don't dump the
1849  * current wireless config. Dumping the wireless config is far too
1850  * expensive (for each parameter, the driver need to query the hardware).
1851  */
1852 static inline int rtnetlink_fill_iwinfo(struct sk_buff *        skb,
1853                                         struct net_device *     dev,
1854                                         int                     type,
1855                                         char *                  event,
1856                                         int                     event_len)
1857 {
1858         struct ifinfomsg *r;
1859         struct nlmsghdr  *nlh;
1860         unsigned char    *b = skb->tail;
1861
1862         nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
1863         r = NLMSG_DATA(nlh);
1864         r->ifi_family = AF_UNSPEC;
1865         r->__ifi_pad = 0;
1866         r->ifi_type = dev->type;
1867         r->ifi_index = dev->ifindex;
1868         r->ifi_flags = dev_get_flags(dev);
1869         r->ifi_change = 0;      /* Wireless changes don't affect those flags */
1870
1871         /* Add the wireless events in the netlink packet */
1872         RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
1873
1874         nlh->nlmsg_len = skb->tail - b;
1875         return skb->len;
1876
1877 nlmsg_failure:
1878 rtattr_failure:
1879         skb_trim(skb, b - skb->data);
1880         return -1;
1881 }
1882
1883 /* ---------------------------------------------------------------- */
1884 /*
1885  * Create and broadcast and send it on the standard rtnetlink socket
1886  * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
1887  * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
1888  * within a RTM_NEWLINK event.
1889  */
1890 static inline void rtmsg_iwinfo(struct net_device *     dev,
1891                                 char *                  event,
1892                                 int                     event_len)
1893 {
1894         struct sk_buff *skb;
1895         int size = NLMSG_GOODSIZE;
1896
1897         skb = alloc_skb(size, GFP_ATOMIC);
1898         if (!skb)
1899                 return;
1900
1901         if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
1902                                   event, event_len) < 0) {
1903                 kfree_skb(skb);
1904                 return;
1905         }
1906         NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
1907         netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC);
1908 }
1909 #endif  /* WE_EVENT_RTNETLINK */
1910
1911 /* ---------------------------------------------------------------- */
1912 /*
1913  * Main event dispatcher. Called from other parts and drivers.
1914  * Send the event on the appropriate channels.
1915  * May be called from interrupt context.
1916  */
1917 void wireless_send_event(struct net_device *    dev,
1918                          unsigned int           cmd,
1919                          union iwreq_data *     wrqu,
1920                          char *                 extra)
1921 {
1922         const struct iw_ioctl_description *     descr = NULL;
1923         int extra_len = 0;
1924         struct iw_event  *event;                /* Mallocated whole event */
1925         int event_len;                          /* Its size */
1926         int hdr_len;                            /* Size of the event header */
1927         int wrqu_off = 0;                       /* Offset in wrqu */
1928         /* Don't "optimise" the following variable, it will crash */
1929         unsigned        cmd_index;              /* *MUST* be unsigned */
1930
1931         /* Get the description of the Event */
1932         if(cmd <= SIOCIWLAST) {
1933                 cmd_index = cmd - SIOCIWFIRST;
1934                 if(cmd_index < standard_ioctl_num)
1935                         descr = &(standard_ioctl[cmd_index]);
1936         } else {
1937                 cmd_index = cmd - IWEVFIRST;
1938                 if(cmd_index < standard_event_num)
1939                         descr = &(standard_event[cmd_index]);
1940         }
1941         /* Don't accept unknown events */
1942         if(descr == NULL) {
1943                 /* Note : we don't return an error to the driver, because
1944                  * the driver would not know what to do about it. It can't
1945                  * return an error to the user, because the event is not
1946                  * initiated by a user request.
1947                  * The best the driver could do is to log an error message.
1948                  * We will do it ourselves instead...
1949                  */
1950                 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
1951                        dev->name, cmd);
1952                 return;
1953         }
1954 #ifdef WE_EVENT_DEBUG
1955         printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
1956                dev->name, cmd);
1957         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);
1958 #endif  /* WE_EVENT_DEBUG */
1959
1960         /* Check extra parameters and set extra_len */
1961         if(descr->header_type == IW_HEADER_TYPE_POINT) {
1962                 /* Check if number of token fits within bounds */
1963                 if(wrqu->data.length > descr->max_tokens) {
1964                         printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
1965                         return;
1966                 }
1967                 if(wrqu->data.length < descr->min_tokens) {
1968                         printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
1969                         return;
1970                 }
1971                 /* Calculate extra_len - extra is NULL for restricted events */
1972                 if(extra != NULL)
1973                         extra_len = wrqu->data.length * descr->token_size;
1974                 /* Always at an offset in wrqu */
1975                 wrqu_off = IW_EV_POINT_OFF;
1976 #ifdef WE_EVENT_DEBUG
1977                 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
1978 #endif  /* WE_EVENT_DEBUG */
1979         }
1980
1981         /* Total length of the event */
1982         hdr_len = event_type_size[descr->header_type];
1983         event_len = hdr_len + extra_len;
1984
1985 #ifdef WE_EVENT_DEBUG
1986         printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len);
1987 #endif  /* WE_EVENT_DEBUG */
1988
1989         /* Create temporary buffer to hold the event */
1990         event = kmalloc(event_len, GFP_ATOMIC);
1991         if(event == NULL)
1992                 return;
1993
1994         /* Fill event */
1995         event->len = event_len;
1996         event->cmd = cmd;
1997         memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
1998         if(extra != NULL)
1999                 memcpy(((char *) event) + hdr_len, extra, extra_len);
2000
2001 #ifdef WE_EVENT_RTNETLINK
2002         /* Send via the RtNetlink event channel */
2003         rtmsg_iwinfo(dev, (char *) event, event_len);
2004 #endif  /* WE_EVENT_RTNETLINK */
2005
2006         /* Cleanup */
2007         kfree(event);
2008
2009         return;         /* Always success, I guess ;-) */
2010 }
2011
2012 /********************** ENHANCED IWSPY SUPPORT **********************/
2013 /*
2014  * In the old days, the driver was handling spy support all by itself.
2015  * Now, the driver can delegate this task to Wireless Extensions.
2016  * It needs to use those standard spy iw_handler in struct iw_handler_def,
2017  * push data to us via wireless_spy_update() and include struct iw_spy_data
2018  * in its private part (and export it in net_device->wireless_data->spy_data).
2019  * One of the main advantage of centralising spy support here is that
2020  * it becomes much easier to improve and extend it without having to touch
2021  * the drivers. One example is the addition of the Spy-Threshold events.
2022  */
2023
2024 /* ---------------------------------------------------------------- */
2025 /*
2026  * Return the pointer to the spy data in the driver.
2027  * Because this is called on the Rx path via wireless_spy_update(),
2028  * we want it to be efficient...
2029  */
2030 static inline struct iw_spy_data * get_spydata(struct net_device *dev)
2031 {
2032         /* This is the new way */
2033         if(dev->wireless_data)
2034                 return(dev->wireless_data->spy_data);
2035         return NULL;
2036 }
2037
2038 /*------------------------------------------------------------------*/
2039 /*
2040  * Standard Wireless Handler : set Spy List
2041  */
2042 int iw_handler_set_spy(struct net_device *      dev,
2043                        struct iw_request_info * info,
2044                        union iwreq_data *       wrqu,
2045                        char *                   extra)
2046 {
2047         struct iw_spy_data *    spydata = get_spydata(dev);
2048         struct sockaddr *       address = (struct sockaddr *) extra;
2049
2050         /* Make sure driver is not buggy or using the old API */
2051         if(!spydata)
2052                 return -EOPNOTSUPP;
2053
2054         /* Disable spy collection while we copy the addresses.
2055          * While we copy addresses, any call to wireless_spy_update()
2056          * will NOP. This is OK, as anyway the addresses are changing. */
2057         spydata->spy_number = 0;
2058
2059         /* We want to operate without locking, because wireless_spy_update()
2060          * most likely will happen in the interrupt handler, and therefore
2061          * have its own locking constraints and needs performance.
2062          * The rtnl_lock() make sure we don't race with the other iw_handlers.
2063          * This make sure wireless_spy_update() "see" that the spy list
2064          * is temporarily disabled. */
2065         wmb();
2066
2067         /* Are there are addresses to copy? */
2068         if(wrqu->data.length > 0) {
2069                 int i;
2070
2071                 /* Copy addresses */
2072                 for(i = 0; i < wrqu->data.length; i++)
2073                         memcpy(spydata->spy_address[i], address[i].sa_data,
2074                                ETH_ALEN);
2075                 /* Reset stats */
2076                 memset(spydata->spy_stat, 0,
2077                        sizeof(struct iw_quality) * IW_MAX_SPY);
2078
2079 #ifdef WE_SPY_DEBUG
2080                 printk(KERN_DEBUG "iw_handler_set_spy() :  wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length);
2081                 for (i = 0; i < wrqu->data.length; i++)
2082                         printk(KERN_DEBUG
2083                                "%02X:%02X:%02X:%02X:%02X:%02X \n",
2084                                spydata->spy_address[i][0],
2085                                spydata->spy_address[i][1],
2086                                spydata->spy_address[i][2],
2087                                spydata->spy_address[i][3],
2088                                spydata->spy_address[i][4],
2089                                spydata->spy_address[i][5]);
2090 #endif  /* WE_SPY_DEBUG */
2091         }
2092
2093         /* Make sure above is updated before re-enabling */
2094         wmb();
2095
2096         /* Enable addresses */
2097         spydata->spy_number = wrqu->data.length;
2098
2099         return 0;
2100 }
2101
2102 /*------------------------------------------------------------------*/
2103 /*
2104  * Standard Wireless Handler : get Spy List
2105  */
2106 int iw_handler_get_spy(struct net_device *      dev,
2107                        struct iw_request_info * info,
2108                        union iwreq_data *       wrqu,
2109                        char *                   extra)
2110 {
2111         struct iw_spy_data *    spydata = get_spydata(dev);
2112         struct sockaddr *       address = (struct sockaddr *) extra;
2113         int                     i;
2114
2115         /* Make sure driver is not buggy or using the old API */
2116         if(!spydata)
2117                 return -EOPNOTSUPP;
2118
2119         wrqu->data.length = spydata->spy_number;
2120
2121         /* Copy addresses. */
2122         for(i = 0; i < spydata->spy_number; i++)        {
2123                 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
2124                 address[i].sa_family = AF_UNIX;
2125         }
2126         /* Copy stats to the user buffer (just after). */
2127         if(spydata->spy_number > 0)
2128                 memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
2129                        spydata->spy_stat,
2130                        sizeof(struct iw_quality) * spydata->spy_number);
2131         /* Reset updated flags. */
2132         for(i = 0; i < spydata->spy_number; i++)
2133                 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
2134         return 0;
2135 }
2136
2137 /*------------------------------------------------------------------*/
2138 /*
2139  * Standard Wireless Handler : set spy threshold
2140  */
2141 int iw_handler_set_thrspy(struct net_device *   dev,
2142                           struct iw_request_info *info,
2143                           union iwreq_data *    wrqu,
2144                           char *                extra)
2145 {
2146         struct iw_spy_data *    spydata = get_spydata(dev);
2147         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
2148
2149         /* Make sure driver is not buggy or using the old API */
2150         if(!spydata)
2151                 return -EOPNOTSUPP;
2152
2153         /* Just do it */
2154         memcpy(&(spydata->spy_thr_low), &(threshold->low),
2155                2 * sizeof(struct iw_quality));
2156
2157         /* Clear flag */
2158         memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
2159
2160 #ifdef WE_SPY_DEBUG
2161         printk(KERN_DEBUG "iw_handler_set_thrspy() :  low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
2162 #endif  /* WE_SPY_DEBUG */
2163
2164         return 0;
2165 }
2166
2167 /*------------------------------------------------------------------*/
2168 /*
2169  * Standard Wireless Handler : get spy threshold
2170  */
2171 int iw_handler_get_thrspy(struct net_device *   dev,
2172                           struct iw_request_info *info,
2173                           union iwreq_data *    wrqu,
2174                           char *                extra)
2175 {
2176         struct iw_spy_data *    spydata = get_spydata(dev);
2177         struct iw_thrspy *      threshold = (struct iw_thrspy *) extra;
2178
2179         /* Make sure driver is not buggy or using the old API */
2180         if(!spydata)
2181                 return -EOPNOTSUPP;
2182
2183         /* Just do it */
2184         memcpy(&(threshold->low), &(spydata->spy_thr_low),
2185                2 * sizeof(struct iw_quality));
2186
2187         return 0;
2188 }
2189
2190 /*------------------------------------------------------------------*/
2191 /*
2192  * Prepare and send a Spy Threshold event
2193  */
2194 static void iw_send_thrspy_event(struct net_device *    dev,
2195                                  struct iw_spy_data *   spydata,
2196                                  unsigned char *        address,
2197                                  struct iw_quality *    wstats)
2198 {
2199         union iwreq_data        wrqu;
2200         struct iw_thrspy        threshold;
2201
2202         /* Init */
2203         wrqu.data.length = 1;
2204         wrqu.data.flags = 0;
2205         /* Copy address */
2206         memcpy(threshold.addr.sa_data, address, ETH_ALEN);
2207         threshold.addr.sa_family = ARPHRD_ETHER;
2208         /* Copy stats */
2209         memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
2210         /* Copy also thresholds */
2211         memcpy(&(threshold.low), &(spydata->spy_thr_low),
2212                2 * sizeof(struct iw_quality));
2213
2214 #ifdef WE_SPY_DEBUG
2215         printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
2216                threshold.addr.sa_data[0],
2217                threshold.addr.sa_data[1],
2218                threshold.addr.sa_data[2],
2219                threshold.addr.sa_data[3],
2220                threshold.addr.sa_data[4],
2221                threshold.addr.sa_data[5], threshold.qual.level);
2222 #endif  /* WE_SPY_DEBUG */
2223
2224         /* Send event to user space */
2225         wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
2226 }
2227
2228 /* ---------------------------------------------------------------- */
2229 /*
2230  * Call for the driver to update the spy data.
2231  * For now, the spy data is a simple array. As the size of the array is
2232  * small, this is good enough. If we wanted to support larger number of
2233  * spy addresses, we should use something more efficient...
2234  */
2235 void wireless_spy_update(struct net_device *    dev,
2236                          unsigned char *        address,
2237                          struct iw_quality *    wstats)
2238 {
2239         struct iw_spy_data *    spydata = get_spydata(dev);
2240         int                     i;
2241         int                     match = -1;
2242
2243         /* Make sure driver is not buggy or using the old API */
2244         if(!spydata)
2245                 return;
2246
2247 #ifdef WE_SPY_DEBUG
2248         printk(KERN_DEBUG "wireless_spy_update() :  wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
2249 #endif  /* WE_SPY_DEBUG */
2250
2251         /* Update all records that match */
2252         for(i = 0; i < spydata->spy_number; i++)
2253                 if(!compare_ether_addr(address, spydata->spy_address[i])) {
2254                         memcpy(&(spydata->spy_stat[i]), wstats,
2255                                sizeof(struct iw_quality));
2256                         match = i;
2257                 }
2258
2259         /* Generate an event if we cross the spy threshold.
2260          * To avoid event storms, we have a simple hysteresis : we generate
2261          * event only when we go under the low threshold or above the
2262          * high threshold. */
2263         if(match >= 0) {
2264                 if(spydata->spy_thr_under[match]) {
2265                         if(wstats->level > spydata->spy_thr_high.level) {
2266                                 spydata->spy_thr_under[match] = 0;
2267                                 iw_send_thrspy_event(dev, spydata,
2268                                                      address, wstats);
2269                         }
2270                 } else {
2271                         if(wstats->level < spydata->spy_thr_low.level) {
2272                                 spydata->spy_thr_under[match] = 1;
2273                                 iw_send_thrspy_event(dev, spydata,
2274                                                      address, wstats);
2275                         }
2276                 }
2277         }
2278 }
2279
2280 EXPORT_SYMBOL(iw_handler_get_spy);
2281 EXPORT_SYMBOL(iw_handler_get_thrspy);
2282 EXPORT_SYMBOL(iw_handler_set_spy);
2283 EXPORT_SYMBOL(iw_handler_set_thrspy);
2284 EXPORT_SYMBOL(wireless_send_event);
2285 EXPORT_SYMBOL(wireless_spy_update);