2 * This file implement the Wireless Extensions APIs.
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
7 * (As all part of the Linux kernel, this file is GPL)
10 /************************** DOCUMENTATION **************************/
14 * See <linux/wireless.h> for details of the APIs and the rest.
19 * v1 - 5.12.01 - Jean II
20 * o Created this file.
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
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
36 * v4 - 18.04.02 - Jean II
37 * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
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)
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
53 /***************************** INCLUDES *****************************/
55 #include <linux/config.h> /* Not needed ??? */
56 #include <linux/module.h>
57 #include <linux/types.h> /* off_t */
58 #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
59 #include <linux/proc_fs.h>
60 #include <linux/rtnetlink.h> /* rtnetlink stuff */
61 #include <linux/seq_file.h>
62 #include <linux/init.h> /* for __init */
63 #include <linux/if_arp.h> /* ARPHRD_ETHER */
65 #include <linux/wireless.h> /* Pretty obvious */
66 #include <net/iw_handler.h> /* New driver API */
68 #include <asm/uaccess.h> /* copy_to_user() */
70 /**************************** CONSTANTS ****************************/
72 /* Enough lenience, let's make sure things are proper... */
73 #define WE_STRICT_WRITE /* Check write buffer size */
74 /* I'll probably drop both the define and kernel message in the next version */
77 #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
78 #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
79 #undef WE_SPY_DEBUG /* Debug enhanced spy support */
82 #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
83 #define WE_SET_EVENT /* Generate an event on some set commands */
85 /************************* GLOBAL VARIABLES *************************/
87 * You should not use global variables, because of re-entrancy.
88 * On our case, it's only const, so it's OK...
91 * Meta-data about all the standard Wireless Extension request we
94 static const struct iw_ioctl_description standard_ioctl[] = {
95 [SIOCSIWCOMMIT - SIOCIWFIRST] = {
96 .header_type = IW_HEADER_TYPE_NULL,
98 [SIOCGIWNAME - SIOCIWFIRST] = {
99 .header_type = IW_HEADER_TYPE_CHAR,
100 .flags = IW_DESCR_FLAG_DUMP,
102 [SIOCSIWNWID - SIOCIWFIRST] = {
103 .header_type = IW_HEADER_TYPE_PARAM,
104 .flags = IW_DESCR_FLAG_EVENT,
106 [SIOCGIWNWID - SIOCIWFIRST] = {
107 .header_type = IW_HEADER_TYPE_PARAM,
108 .flags = IW_DESCR_FLAG_DUMP,
110 [SIOCSIWFREQ - SIOCIWFIRST] = {
111 .header_type = IW_HEADER_TYPE_FREQ,
112 .flags = IW_DESCR_FLAG_EVENT,
114 [SIOCGIWFREQ - SIOCIWFIRST] = {
115 .header_type = IW_HEADER_TYPE_FREQ,
116 .flags = IW_DESCR_FLAG_DUMP,
118 [SIOCSIWMODE - SIOCIWFIRST] = {
119 .header_type = IW_HEADER_TYPE_UINT,
120 .flags = IW_DESCR_FLAG_EVENT,
122 [SIOCGIWMODE - SIOCIWFIRST] = {
123 .header_type = IW_HEADER_TYPE_UINT,
124 .flags = IW_DESCR_FLAG_DUMP,
126 [SIOCSIWSENS - SIOCIWFIRST] = {
127 .header_type = IW_HEADER_TYPE_PARAM,
129 [SIOCGIWSENS - SIOCIWFIRST] = {
130 .header_type = IW_HEADER_TYPE_PARAM,
132 [SIOCSIWRANGE - SIOCIWFIRST] = {
133 .header_type = IW_HEADER_TYPE_NULL,
135 [SIOCGIWRANGE - SIOCIWFIRST] = {
136 .header_type = IW_HEADER_TYPE_POINT,
138 .max_tokens = sizeof(struct iw_range),
139 .flags = IW_DESCR_FLAG_DUMP,
141 [SIOCSIWPRIV - SIOCIWFIRST] = {
142 .header_type = IW_HEADER_TYPE_NULL,
144 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
145 .header_type = IW_HEADER_TYPE_NULL,
147 [SIOCSIWSTATS - SIOCIWFIRST] = {
148 .header_type = IW_HEADER_TYPE_NULL,
150 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
151 .header_type = IW_HEADER_TYPE_NULL,
152 .flags = IW_DESCR_FLAG_DUMP,
154 [SIOCSIWSPY - SIOCIWFIRST] = {
155 .header_type = IW_HEADER_TYPE_POINT,
156 .token_size = sizeof(struct sockaddr),
157 .max_tokens = IW_MAX_SPY,
159 [SIOCGIWSPY - SIOCIWFIRST] = {
160 .header_type = IW_HEADER_TYPE_POINT,
161 .token_size = sizeof(struct sockaddr) +
162 sizeof(struct iw_quality),
163 .max_tokens = IW_MAX_SPY,
165 [SIOCSIWTHRSPY - SIOCIWFIRST] = {
166 .header_type = IW_HEADER_TYPE_POINT,
167 .token_size = sizeof(struct iw_thrspy),
171 [SIOCGIWTHRSPY - SIOCIWFIRST] = {
172 .header_type = IW_HEADER_TYPE_POINT,
173 .token_size = sizeof(struct iw_thrspy),
177 [SIOCSIWAP - SIOCIWFIRST] = {
178 .header_type = IW_HEADER_TYPE_ADDR,
180 [SIOCGIWAP - SIOCIWFIRST] = {
181 .header_type = IW_HEADER_TYPE_ADDR,
182 .flags = IW_DESCR_FLAG_DUMP,
184 [SIOCGIWAPLIST - SIOCIWFIRST] = {
185 .header_type = IW_HEADER_TYPE_POINT,
186 .token_size = sizeof(struct sockaddr) +
187 sizeof(struct iw_quality),
188 .max_tokens = IW_MAX_AP,
190 [SIOCSIWSCAN - SIOCIWFIRST] = {
191 .header_type = IW_HEADER_TYPE_PARAM,
193 [SIOCGIWSCAN - SIOCIWFIRST] = {
194 .header_type = IW_HEADER_TYPE_POINT,
196 .max_tokens = IW_SCAN_MAX_DATA,
198 [SIOCSIWESSID - SIOCIWFIRST] = {
199 .header_type = IW_HEADER_TYPE_POINT,
201 .max_tokens = IW_ESSID_MAX_SIZE + 1,
202 .flags = IW_DESCR_FLAG_EVENT,
204 [SIOCGIWESSID - SIOCIWFIRST] = {
205 .header_type = IW_HEADER_TYPE_POINT,
207 .max_tokens = IW_ESSID_MAX_SIZE + 1,
208 .flags = IW_DESCR_FLAG_DUMP,
210 [SIOCSIWNICKN - SIOCIWFIRST] = {
211 .header_type = IW_HEADER_TYPE_POINT,
213 .max_tokens = IW_ESSID_MAX_SIZE + 1,
215 [SIOCGIWNICKN - SIOCIWFIRST] = {
216 .header_type = IW_HEADER_TYPE_POINT,
218 .max_tokens = IW_ESSID_MAX_SIZE + 1,
220 [SIOCSIWRATE - SIOCIWFIRST] = {
221 .header_type = IW_HEADER_TYPE_PARAM,
223 [SIOCGIWRATE - SIOCIWFIRST] = {
224 .header_type = IW_HEADER_TYPE_PARAM,
226 [SIOCSIWRTS - SIOCIWFIRST] = {
227 .header_type = IW_HEADER_TYPE_PARAM,
229 [SIOCGIWRTS - SIOCIWFIRST] = {
230 .header_type = IW_HEADER_TYPE_PARAM,
232 [SIOCSIWFRAG - SIOCIWFIRST] = {
233 .header_type = IW_HEADER_TYPE_PARAM,
235 [SIOCGIWFRAG - SIOCIWFIRST] = {
236 .header_type = IW_HEADER_TYPE_PARAM,
238 [SIOCSIWTXPOW - SIOCIWFIRST] = {
239 .header_type = IW_HEADER_TYPE_PARAM,
241 [SIOCGIWTXPOW - SIOCIWFIRST] = {
242 .header_type = IW_HEADER_TYPE_PARAM,
244 [SIOCSIWRETRY - SIOCIWFIRST] = {
245 .header_type = IW_HEADER_TYPE_PARAM,
247 [SIOCGIWRETRY - SIOCIWFIRST] = {
248 .header_type = IW_HEADER_TYPE_PARAM,
250 [SIOCSIWENCODE - SIOCIWFIRST] = {
251 .header_type = IW_HEADER_TYPE_POINT,
253 .max_tokens = IW_ENCODING_TOKEN_MAX,
254 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
256 [SIOCGIWENCODE - SIOCIWFIRST] = {
257 .header_type = IW_HEADER_TYPE_POINT,
259 .max_tokens = IW_ENCODING_TOKEN_MAX,
260 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
262 [SIOCSIWPOWER - SIOCIWFIRST] = {
263 .header_type = IW_HEADER_TYPE_PARAM,
265 [SIOCGIWPOWER - SIOCIWFIRST] = {
266 .header_type = IW_HEADER_TYPE_PARAM,
269 static const int standard_ioctl_num = (sizeof(standard_ioctl) /
270 sizeof(struct iw_ioctl_description));
273 * Meta-data about all the additional standard Wireless Extension events
276 static const struct iw_ioctl_description standard_event[] = {
277 [IWEVTXDROP - IWEVFIRST] = {
278 .header_type = IW_HEADER_TYPE_ADDR,
280 [IWEVQUAL - IWEVFIRST] = {
281 .header_type = IW_HEADER_TYPE_QUAL,
283 [IWEVCUSTOM - IWEVFIRST] = {
284 .header_type = IW_HEADER_TYPE_POINT,
286 .max_tokens = IW_CUSTOM_MAX,
288 [IWEVREGISTERED - IWEVFIRST] = {
289 .header_type = IW_HEADER_TYPE_ADDR,
291 [IWEVEXPIRED - IWEVFIRST] = {
292 .header_type = IW_HEADER_TYPE_ADDR,
295 static const int standard_event_num = (sizeof(standard_event) /
296 sizeof(struct iw_ioctl_description));
298 /* Size (in bytes) of the various private data types */
299 static const char priv_type_size[] = {
300 0, /* IW_PRIV_TYPE_NONE */
301 1, /* IW_PRIV_TYPE_BYTE */
302 1, /* IW_PRIV_TYPE_CHAR */
304 sizeof(__u32), /* IW_PRIV_TYPE_INT */
305 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
306 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
310 /* Size (in bytes) of various events */
311 static const int event_type_size[] = {
312 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
314 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
316 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */
317 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
318 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
320 IW_EV_POINT_LEN, /* Without variable payload */
321 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
322 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
325 /************************ COMMON SUBROUTINES ************************/
327 * Stuff that may be used in various place or doesn't fit in one
328 * of the section below.
331 /* ---------------------------------------------------------------- */
333 * Return the driver handler associated with a specific Wireless Extension.
334 * Called from various place, so make sure it remains efficient.
336 static inline iw_handler get_handler(struct net_device *dev,
339 /* Don't "optimise" the following variable, it will crash */
340 unsigned int index; /* *MUST* be unsigned */
342 /* Check if we have some wireless handlers defined */
343 if(dev->wireless_handlers == NULL)
346 /* Try as a standard command */
347 index = cmd - SIOCIWFIRST;
348 if(index < dev->wireless_handlers->num_standard)
349 return dev->wireless_handlers->standard[index];
351 /* Try as a private command */
352 index = cmd - SIOCIWFIRSTPRIV;
353 if(index < dev->wireless_handlers->num_private)
354 return dev->wireless_handlers->private[index];
360 /* ---------------------------------------------------------------- */
362 * Get statistics out of the driver
364 static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
366 return (dev->get_wireless_stats ?
367 dev->get_wireless_stats(dev) :
368 (struct iw_statistics *) NULL);
369 /* In the future, get_wireless_stats may move from 'struct net_device'
370 * to 'struct iw_handler_def', to de-bloat struct net_device.
371 * Definitely worse a thought... */
374 /* ---------------------------------------------------------------- */
376 * Call the commit handler in the driver
377 * (if exist and if conditions are right)
379 * Note : our current commit strategy is currently pretty dumb,
380 * but we will be able to improve on that...
381 * The goal is to try to agreagate as many changes as possible
382 * before doing the commit. Drivers that will define a commit handler
383 * are usually those that need a reset after changing parameters, so
384 * we want to minimise the number of reset.
385 * A cool idea is to use a timer : at each "set" command, we re-set the
386 * timer, when the timer eventually fires, we call the driver.
387 * Hopefully, more on that later.
389 * Also, I'm waiting to see how many people will complain about the
390 * netif_running(dev) test. I'm open on that one...
391 * Hopefully, the driver will remember to do a commit in "open()" ;-)
393 static inline int call_commit_handler(struct net_device * dev)
395 if((netif_running(dev)) &&
396 (dev->wireless_handlers->standard[0] != NULL)) {
397 /* Call the commit handler on the driver */
398 return dev->wireless_handlers->standard[0](dev, NULL,
401 return 0; /* Command completed successfully */
404 /* ---------------------------------------------------------------- */
406 * Number of private arguments
408 static inline int get_priv_size(__u16 args)
410 int num = args & IW_PRIV_SIZE_MASK;
411 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
413 return num * priv_type_size[type];
417 /******************** /proc/net/wireless SUPPORT ********************/
419 * The /proc/net/wireless file is a human readable user-space interface
420 * exporting various wireless specific statistics from the wireless devices.
421 * This is the most popular part of the Wireless Extensions ;-)
423 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
424 * The content of the file is basically the content of "struct iw_statistics".
427 #ifdef CONFIG_PROC_FS
429 /* ---------------------------------------------------------------- */
431 * Print one entry (line) of /proc/net/wireless
433 static __inline__ void wireless_seq_printf_stats(struct seq_file *seq,
434 struct net_device *dev)
436 /* Get stats from the driver */
437 struct iw_statistics *stats = get_wireless_stats(dev);
440 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
442 dev->name, stats->status, stats->qual.qual,
443 stats->qual.updated & 1 ? '.' : ' ',
444 ((__u8) stats->qual.level),
445 stats->qual.updated & 2 ? '.' : ' ',
446 ((__u8) stats->qual.noise),
447 stats->qual.updated & 4 ? '.' : ' ',
448 stats->discard.nwid, stats->discard.code,
449 stats->discard.fragment, stats->discard.retries,
450 stats->discard.misc, stats->miss.beacon);
451 stats->qual.updated = 0;
455 /* ---------------------------------------------------------------- */
457 * Print info for /proc/net/wireless (print all entries)
459 static int wireless_seq_show(struct seq_file *seq, void *v)
461 if (v == SEQ_START_TOKEN)
462 seq_printf(seq, "Inter-| sta-| Quality | Discarded "
463 "packets | Missed | WE\n"
464 " face | tus | link level noise | nwid "
465 "crypt frag retry misc | beacon | %d\n",
468 wireless_seq_printf_stats(seq, v);
472 extern void *dev_seq_start(struct seq_file *seq, loff_t *pos);
473 extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos);
474 extern void dev_seq_stop(struct seq_file *seq, void *v);
476 static struct seq_operations wireless_seq_ops = {
477 .start = dev_seq_start,
478 .next = dev_seq_next,
479 .stop = dev_seq_stop,
480 .show = wireless_seq_show,
483 static int wireless_seq_open(struct inode *inode, struct file *file)
485 return seq_open(file, &wireless_seq_ops);
488 static struct file_operations wireless_seq_fops = {
489 .owner = THIS_MODULE,
490 .open = wireless_seq_open,
493 .release = seq_release,
496 int __init wireless_proc_init(void)
498 if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops))
503 #endif /* CONFIG_PROC_FS */
505 /************************** IOCTL SUPPORT **************************/
507 * The original user space API to configure all those Wireless Extensions
509 * In there, we check if we need to call the new driver API (iw_handler)
510 * or just call the driver ioctl handler.
513 /* ---------------------------------------------------------------- */
515 * Allow programatic access to /proc/net/wireless even if /proc
516 * doesn't exist... Also more efficient...
518 static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
520 /* Get stats from the driver */
521 struct iw_statistics *stats;
523 stats = get_wireless_stats(dev);
524 if (stats != (struct iw_statistics *) NULL) {
525 struct iwreq * wrq = (struct iwreq *)ifr;
527 /* Copy statistics to the user buffer */
528 if(copy_to_user(wrq->u.data.pointer, stats,
529 sizeof(struct iw_statistics)))
532 /* Check if we need to clear the update flag */
533 if(wrq->u.data.flags != 0)
534 stats->qual.updated = 0;
540 /* ---------------------------------------------------------------- */
542 * Export the driver private handler definition
543 * They will be picked up by tools like iwpriv...
545 static inline int ioctl_export_private(struct net_device * dev,
548 struct iwreq * iwr = (struct iwreq *) ifr;
550 /* Check if the driver has something to export */
551 if((dev->wireless_handlers->num_private_args == 0) ||
552 (dev->wireless_handlers->private_args == NULL))
555 /* Check NULL pointer */
556 if(iwr->u.data.pointer == NULL)
558 #ifdef WE_STRICT_WRITE
559 /* Check if there is enough buffer up there */
560 if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
561 printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
564 #endif /* WE_STRICT_WRITE */
566 /* Set the number of available ioctls. */
567 iwr->u.data.length = dev->wireless_handlers->num_private_args;
569 /* Copy structure to the user buffer. */
570 if (copy_to_user(iwr->u.data.pointer,
571 dev->wireless_handlers->private_args,
572 sizeof(struct iw_priv_args) * iwr->u.data.length))
578 /* ---------------------------------------------------------------- */
580 * Wrapper to call a standard Wireless Extension handler.
581 * We do various checks and also take care of moving data between
582 * user space and kernel space.
584 static inline int ioctl_standard_call(struct net_device * dev,
589 struct iwreq * iwr = (struct iwreq *) ifr;
590 const struct iw_ioctl_description * descr;
591 struct iw_request_info info;
595 /* Get the description of the IOCTL */
596 if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
598 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
600 #ifdef WE_IOCTL_DEBUG
601 printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
603 printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
604 #endif /* WE_IOCTL_DEBUG */
606 /* Prepare the call */
610 /* Check if we have a pointer to user space data or not */
611 if(descr->header_type != IW_HEADER_TYPE_POINT) {
613 /* No extra arguments. Trivial to handle */
614 ret = handler(dev, &info, &(iwr->u), NULL);
617 /* Generate an event to notify listeners of the change */
618 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
619 ((ret == 0) || (ret == -EIWCOMMIT)))
620 wireless_send_event(dev, cmd, &(iwr->u), NULL);
621 #endif /* WE_SET_EVENT */
626 /* Check what user space is giving us */
628 /* Check NULL pointer */
629 if((iwr->u.data.pointer == NULL) &&
630 (iwr->u.data.length != 0))
632 /* Check if number of token fits within bounds */
633 if(iwr->u.data.length > descr->max_tokens)
635 if(iwr->u.data.length < descr->min_tokens)
638 /* Check NULL pointer */
639 if(iwr->u.data.pointer == NULL)
641 /* Save user space buffer size for checking */
642 user_size = iwr->u.data.length;
645 #ifdef WE_IOCTL_DEBUG
646 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
647 dev->name, descr->max_tokens * descr->token_size);
648 #endif /* WE_IOCTL_DEBUG */
650 /* Always allocate for max space. Easier, and won't last
652 extra = kmalloc(descr->max_tokens * descr->token_size,
658 /* If it is a SET, get all the extra data in here */
659 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
660 err = copy_from_user(extra, iwr->u.data.pointer,
667 #ifdef WE_IOCTL_DEBUG
668 printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
670 iwr->u.data.length * descr->token_size);
671 #endif /* WE_IOCTL_DEBUG */
674 /* Call the handler */
675 ret = handler(dev, &info, &(iwr->u), extra);
677 /* If we have something to return to the user */
678 if (!ret && IW_IS_GET(cmd)) {
679 #ifdef WE_STRICT_WRITE
680 /* Check if there is enough buffer up there */
681 if(user_size < iwr->u.data.length) {
682 printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
686 #endif /* WE_STRICT_WRITE */
688 err = copy_to_user(iwr->u.data.pointer, extra,
693 #ifdef WE_IOCTL_DEBUG
694 printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
696 iwr->u.data.length * descr->token_size);
697 #endif /* WE_IOCTL_DEBUG */
701 /* Generate an event to notify listeners of the change */
702 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
703 ((ret == 0) || (ret == -EIWCOMMIT))) {
704 if(descr->flags & IW_DESCR_FLAG_RESTRICT)
705 /* If the event is restricted, don't
706 * export the payload */
707 wireless_send_event(dev, cmd, &(iwr->u), NULL);
709 wireless_send_event(dev, cmd, &(iwr->u),
712 #endif /* WE_SET_EVENT */
714 /* Cleanup - I told you it wasn't that long ;-) */
718 /* Call commit handler if needed and defined */
719 if(ret == -EIWCOMMIT)
720 ret = call_commit_handler(dev);
722 /* Here, we will generate the appropriate event if needed */
727 /* ---------------------------------------------------------------- */
729 * Wrapper to call a private Wireless Extension handler.
730 * We do various checks and also take care of moving data between
731 * user space and kernel space.
732 * It's not as nice and slimline as the standard wrapper. The cause
733 * is struct iw_priv_args, which was not really designed for the
734 * job we are going here.
736 * IMPORTANT : This function prevent to set and get data on the same
737 * IOCTL and enforce the SET/GET convention. Not doing it would be
739 * If you need to set and get data at the same time, please don't use
740 * a iw_handler but process it in your ioctl handler (i.e. use the
743 static inline int ioctl_private_call(struct net_device * dev,
748 struct iwreq * iwr = (struct iwreq *) ifr;
749 struct iw_priv_args * descr = NULL;
750 struct iw_request_info info;
755 /* Get the description of the IOCTL */
756 for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
757 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
758 descr = &(dev->wireless_handlers->private_args[i]);
762 #ifdef WE_IOCTL_DEBUG
763 printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
766 printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
767 dev->name, descr->name,
768 descr->set_args, descr->get_args);
770 #endif /* WE_IOCTL_DEBUG */
772 /* Compute the size of the set/get arguments */
775 int offset = 0; /* For sub-ioctls */
776 /* Check for sub-ioctl handler */
777 if(descr->name[0] == '\0')
778 /* Reserve one int for sub-ioctl index */
779 offset = sizeof(__u32);
781 /* Size of set arguments */
782 extra_size = get_priv_size(descr->set_args);
784 /* Does it fits in iwr ? */
785 if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
786 ((extra_size + offset) <= IFNAMSIZ))
789 /* Size of set arguments */
790 extra_size = get_priv_size(descr->get_args);
792 /* Does it fits in iwr ? */
793 if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
794 (extra_size <= IFNAMSIZ))
799 /* Prepare the call */
803 /* Check if we have a pointer to user space data or not. */
804 if(extra_size == 0) {
805 /* No extra arguments. Trivial to handle */
806 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
811 /* Check what user space is giving us */
813 /* Check NULL pointer */
814 if((iwr->u.data.pointer == NULL) &&
815 (iwr->u.data.length != 0))
818 /* Does it fits within bounds ? */
819 if(iwr->u.data.length > (descr->set_args &
823 /* Check NULL pointer */
824 if(iwr->u.data.pointer == NULL)
828 #ifdef WE_IOCTL_DEBUG
829 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
830 dev->name, extra_size);
831 #endif /* WE_IOCTL_DEBUG */
833 /* Always allocate for max space. Easier, and won't last
835 extra = kmalloc(extra_size, GFP_KERNEL);
840 /* If it is a SET, get all the extra data in here */
841 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
842 err = copy_from_user(extra, iwr->u.data.pointer,
848 #ifdef WE_IOCTL_DEBUG
849 printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
850 dev->name, iwr->u.data.length);
851 #endif /* WE_IOCTL_DEBUG */
854 /* Call the handler */
855 ret = handler(dev, &info, &(iwr->u), extra);
857 /* If we have something to return to the user */
858 if (!ret && IW_IS_GET(cmd)) {
859 err = copy_to_user(iwr->u.data.pointer, extra,
863 #ifdef WE_IOCTL_DEBUG
864 printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
865 dev->name, iwr->u.data.length);
866 #endif /* WE_IOCTL_DEBUG */
869 /* Cleanup - I told you it wasn't that long ;-) */
874 /* Call commit handler if needed and defined */
875 if(ret == -EIWCOMMIT)
876 ret = call_commit_handler(dev);
881 /* ---------------------------------------------------------------- */
883 * Main IOCTl dispatcher. Called from the main networking code
884 * (dev_ioctl() in net/core/dev.c).
885 * Check the type of IOCTL and call the appropriate wrapper...
887 int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
889 struct net_device *dev;
892 /* Permissions are already checked in dev_ioctl() before calling us.
893 * The copy_to/from_user() of ifr is also dealt with in there */
895 /* Make sure the device exist */
896 if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
899 /* A bunch of special cases, then the generic case...
900 * Note that 'cmd' is already filtered in dev_ioctl() with
901 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
905 /* Get Wireless Stats */
906 return dev_iwstats(dev, ifr);
909 /* Check if we have some wireless handlers defined */
910 if(dev->wireless_handlers != NULL) {
911 /* We export to user space the definition of
912 * the private handler ourselves */
913 return ioctl_export_private(dev, ifr);
915 // ## Fall-through for old API ##
919 if (!netif_device_present(dev))
921 /* New driver API : try to find the handler */
922 handler = get_handler(dev, cmd);
923 if(handler != NULL) {
924 /* Standard and private are not the same */
925 if(cmd < SIOCIWFIRSTPRIV)
926 return ioctl_standard_call(dev,
931 return ioctl_private_call(dev,
936 /* Old driver API : call driver ioctl handler */
938 return dev->do_ioctl(dev, ifr, cmd);
946 /************************* EVENT PROCESSING *************************/
948 * Process events generated by the wireless layer or the driver.
949 * Most often, the event will be propagated through rtnetlink
952 #ifdef WE_EVENT_NETLINK
953 /* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
954 * It is declared in <linux/rtnetlink.h> */
956 /* ---------------------------------------------------------------- */
958 * Fill a rtnetlink message with our event data.
959 * Note that we propage only the specified event and don't dump the
960 * current wireless config. Dumping the wireless config is far too
961 * expensive (for each parameter, the driver need to query the hardware).
963 static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb,
964 struct net_device * dev,
970 struct nlmsghdr *nlh;
971 unsigned char *b = skb->tail;
973 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
975 r->ifi_family = AF_UNSPEC;
976 r->ifi_type = dev->type;
977 r->ifi_index = dev->ifindex;
978 r->ifi_flags = dev->flags;
979 r->ifi_change = 0; /* Wireless changes don't affect those flags */
981 /* Add the wireless events in the netlink packet */
982 RTA_PUT(skb, IFLA_WIRELESS,
985 nlh->nlmsg_len = skb->tail - b;
990 skb_trim(skb, b - skb->data);
994 /* ---------------------------------------------------------------- */
996 * Create and broadcast and send it on the standard rtnetlink socket
997 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
998 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
999 * within a RTM_NEWLINK event.
1001 static inline void rtmsg_iwinfo(struct net_device * dev,
1005 struct sk_buff *skb;
1006 int size = NLMSG_GOODSIZE;
1008 skb = alloc_skb(size, GFP_ATOMIC);
1012 if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
1013 event, event_len) < 0) {
1017 NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
1018 netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
1020 #endif /* WE_EVENT_NETLINK */
1022 /* ---------------------------------------------------------------- */
1024 * Main event dispatcher. Called from other parts and drivers.
1025 * Send the event on the appropriate channels.
1026 * May be called from interrupt context.
1028 void wireless_send_event(struct net_device * dev,
1030 union iwreq_data * wrqu,
1033 const struct iw_ioctl_description * descr = NULL;
1035 struct iw_event *event; /* Mallocated whole event */
1036 int event_len; /* Its size */
1037 int hdr_len; /* Size of the event header */
1038 /* Don't "optimise" the following variable, it will crash */
1039 unsigned cmd_index; /* *MUST* be unsigned */
1041 /* Get the description of the IOCTL */
1042 if(cmd <= SIOCIWLAST) {
1043 cmd_index = cmd - SIOCIWFIRST;
1044 if(cmd_index < standard_ioctl_num)
1045 descr = &(standard_ioctl[cmd_index]);
1047 cmd_index = cmd - IWEVFIRST;
1048 if(cmd_index < standard_event_num)
1049 descr = &(standard_event[cmd_index]);
1051 /* Don't accept unknown events */
1053 /* Note : we don't return an error to the driver, because
1054 * the driver would not know what to do about it. It can't
1055 * return an error to the user, because the event is not
1056 * initiated by a user request.
1057 * The best the driver could do is to log an error message.
1058 * We will do it ourselves instead...
1060 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
1064 #ifdef WE_EVENT_DEBUG
1065 printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
1067 printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
1068 #endif /* WE_EVENT_DEBUG */
1070 /* Check extra parameters and set extra_len */
1071 if(descr->header_type == IW_HEADER_TYPE_POINT) {
1072 /* Check if number of token fits within bounds */
1073 if(wrqu->data.length > descr->max_tokens) {
1074 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
1077 if(wrqu->data.length < descr->min_tokens) {
1078 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
1081 /* Calculate extra_len - extra is NULL for restricted events */
1083 extra_len = wrqu->data.length * descr->token_size;
1084 #ifdef WE_EVENT_DEBUG
1085 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
1086 #endif /* WE_EVENT_DEBUG */
1089 /* Total length of the event */
1090 hdr_len = event_type_size[descr->header_type];
1091 event_len = hdr_len + extra_len;
1093 #ifdef WE_EVENT_DEBUG
1094 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
1095 #endif /* WE_EVENT_DEBUG */
1097 /* Create temporary buffer to hold the event */
1098 event = kmalloc(event_len, GFP_ATOMIC);
1103 event->len = event_len;
1105 memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
1107 memcpy(((char *) event) + hdr_len, extra, extra_len);
1109 #ifdef WE_EVENT_NETLINK
1110 /* rtnetlink event channel */
1111 rtmsg_iwinfo(dev, (char *) event, event_len);
1112 #endif /* WE_EVENT_NETLINK */
1117 return; /* Always success, I guess ;-) */
1120 /********************** ENHANCED IWSPY SUPPORT **********************/
1122 * In the old days, the driver was handling spy support all by itself.
1123 * Now, the driver can delegate this task to Wireless Extensions.
1124 * It needs to use those standard spy iw_handler in struct iw_handler_def,
1125 * push data to us via wireless_spy_update() and include struct iw_spy_data
1126 * in its private part (and advertise it in iw_handler_def->spy_offset).
1127 * One of the main advantage of centralising spy support here is that
1128 * it becomes much easier to improve and extend it without having to touch
1129 * the drivers. One example is the addition of the Spy-Threshold events.
1130 * Note : IW_WIRELESS_SPY is defined in iw_handler.h
1133 /*------------------------------------------------------------------*/
1135 * Standard Wireless Handler : set Spy List
1137 int iw_handler_set_spy(struct net_device * dev,
1138 struct iw_request_info * info,
1139 union iwreq_data * wrqu,
1142 #ifdef IW_WIRELESS_SPY
1143 struct iw_spy_data * spydata = (dev->priv +
1144 dev->wireless_handlers->spy_offset);
1145 struct sockaddr * address = (struct sockaddr *) extra;
1147 /* Disable spy collection while we copy the addresses.
1148 * As we don't disable interrupts, we need to do this to avoid races.
1149 * As we are the only writer, this is good enough. */
1150 spydata->spy_number = 0;
1152 /* Are there are addresses to copy? */
1153 if(wrqu->data.length > 0) {
1156 /* Copy addresses */
1157 for(i = 0; i < wrqu->data.length; i++)
1158 memcpy(spydata->spy_address[i], address[i].sa_data,
1161 memset(spydata->spy_stat, 0,
1162 sizeof(struct iw_quality) * IW_MAX_SPY);
1165 printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);
1166 for (i = 0; i < wrqu->data.length; i++)
1168 "%02X:%02X:%02X:%02X:%02X:%02X \n",
1169 spydata->spy_address[i][0],
1170 spydata->spy_address[i][1],
1171 spydata->spy_address[i][2],
1172 spydata->spy_address[i][3],
1173 spydata->spy_address[i][4],
1174 spydata->spy_address[i][5]);
1175 #endif /* WE_SPY_DEBUG */
1177 /* Enable addresses */
1178 spydata->spy_number = wrqu->data.length;
1181 #else /* IW_WIRELESS_SPY */
1183 #endif /* IW_WIRELESS_SPY */
1186 /*------------------------------------------------------------------*/
1188 * Standard Wireless Handler : get Spy List
1190 int iw_handler_get_spy(struct net_device * dev,
1191 struct iw_request_info * info,
1192 union iwreq_data * wrqu,
1195 #ifdef IW_WIRELESS_SPY
1196 struct iw_spy_data * spydata = (dev->priv +
1197 dev->wireless_handlers->spy_offset);
1198 struct sockaddr * address = (struct sockaddr *) extra;
1201 wrqu->data.length = spydata->spy_number;
1203 /* Copy addresses. */
1204 for(i = 0; i < spydata->spy_number; i++) {
1205 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
1206 address[i].sa_family = AF_UNIX;
1208 /* Copy stats to the user buffer (just after). */
1209 if(spydata->spy_number > 0)
1210 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
1212 sizeof(struct iw_quality) * spydata->spy_number);
1213 /* Reset updated flags. */
1214 for(i = 0; i < spydata->spy_number; i++)
1215 spydata->spy_stat[i].updated = 0;
1217 #else /* IW_WIRELESS_SPY */
1219 #endif /* IW_WIRELESS_SPY */
1222 /*------------------------------------------------------------------*/
1224 * Standard Wireless Handler : set spy threshold
1226 int iw_handler_set_thrspy(struct net_device * dev,
1227 struct iw_request_info *info,
1228 union iwreq_data * wrqu,
1231 #ifdef IW_WIRELESS_THRSPY
1232 struct iw_spy_data * spydata = (dev->priv +
1233 dev->wireless_handlers->spy_offset);
1234 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
1237 memcpy(&(spydata->spy_thr_low), &(threshold->low),
1238 2 * sizeof(struct iw_quality));
1241 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
1244 printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
1245 #endif /* WE_SPY_DEBUG */
1248 #else /* IW_WIRELESS_THRSPY */
1250 #endif /* IW_WIRELESS_THRSPY */
1253 /*------------------------------------------------------------------*/
1255 * Standard Wireless Handler : get spy threshold
1257 int iw_handler_get_thrspy(struct net_device * dev,
1258 struct iw_request_info *info,
1259 union iwreq_data * wrqu,
1262 #ifdef IW_WIRELESS_THRSPY
1263 struct iw_spy_data * spydata = (dev->priv +
1264 dev->wireless_handlers->spy_offset);
1265 struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
1268 memcpy(&(threshold->low), &(spydata->spy_thr_low),
1269 2 * sizeof(struct iw_quality));
1272 #else /* IW_WIRELESS_THRSPY */
1274 #endif /* IW_WIRELESS_THRSPY */
1277 #ifdef IW_WIRELESS_THRSPY
1278 /*------------------------------------------------------------------*/
1280 * Prepare and send a Spy Threshold event
1282 static void iw_send_thrspy_event(struct net_device * dev,
1283 struct iw_spy_data * spydata,
1284 unsigned char * address,
1285 struct iw_quality * wstats)
1287 union iwreq_data wrqu;
1288 struct iw_thrspy threshold;
1291 wrqu.data.length = 1;
1292 wrqu.data.flags = 0;
1294 memcpy(threshold.addr.sa_data, address, ETH_ALEN);
1295 threshold.addr.sa_family = ARPHRD_ETHER;
1297 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
1298 /* Copy also thresholds */
1299 memcpy(&(threshold.low), &(spydata->spy_thr_low),
1300 2 * sizeof(struct iw_quality));
1303 printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
1304 threshold.addr.sa_data[0],
1305 threshold.addr.sa_data[1],
1306 threshold.addr.sa_data[2],
1307 threshold.addr.sa_data[3],
1308 threshold.addr.sa_data[4],
1309 threshold.addr.sa_data[5], threshold.qual.level);
1310 #endif /* WE_SPY_DEBUG */
1312 /* Send event to user space */
1313 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
1315 #endif /* IW_WIRELESS_THRSPY */
1317 /* ---------------------------------------------------------------- */
1319 * Call for the driver to update the spy data.
1320 * For now, the spy data is a simple array. As the size of the array is
1321 * small, this is good enough. If we wanted to support larger number of
1322 * spy addresses, we should use something more efficient...
1324 void wireless_spy_update(struct net_device * dev,
1325 unsigned char * address,
1326 struct iw_quality * wstats)
1328 #ifdef IW_WIRELESS_SPY
1329 struct iw_spy_data * spydata = (dev->priv +
1330 dev->wireless_handlers->spy_offset);
1335 printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
1336 #endif /* WE_SPY_DEBUG */
1338 /* Update all records that match */
1339 for(i = 0; i < spydata->spy_number; i++)
1340 if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) {
1341 memcpy(&(spydata->spy_stat[i]), wstats,
1342 sizeof(struct iw_quality));
1345 #ifdef IW_WIRELESS_THRSPY
1346 /* Generate an event if we cross the spy threshold.
1347 * To avoid event storms, we have a simple hysteresis : we generate
1348 * event only when we go under the low threshold or above the
1349 * high threshold. */
1351 if(spydata->spy_thr_under[match]) {
1352 if(wstats->level > spydata->spy_thr_high.level) {
1353 spydata->spy_thr_under[match] = 0;
1354 iw_send_thrspy_event(dev, spydata,
1358 if(wstats->level < spydata->spy_thr_low.level) {
1359 spydata->spy_thr_under[match] = 1;
1360 iw_send_thrspy_event(dev, spydata,
1365 #endif /* IW_WIRELESS_THRSPY */
1366 #endif /* IW_WIRELESS_SPY */
1369 EXPORT_SYMBOL(iw_handler_get_spy);
1370 EXPORT_SYMBOL(iw_handler_get_thrspy);
1371 EXPORT_SYMBOL(iw_handler_set_spy);
1372 EXPORT_SYMBOL(iw_handler_set_thrspy);
1373 EXPORT_SYMBOL(wireless_send_event);
1374 EXPORT_SYMBOL(wireless_spy_update);