2 * This file implement the Wireless Extensions APIs.
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2002 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)
48 /***************************** INCLUDES *****************************/
50 #include <asm/uaccess.h> /* copy_to_user() */
51 #include <linux/config.h> /* Not needed ??? */
52 #include <linux/types.h> /* off_t */
53 #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
54 #include <linux/rtnetlink.h> /* rtnetlink stuff */
56 #include <linux/wireless.h> /* Pretty obvious */
57 #include <net/iw_handler.h> /* New driver API */
59 /**************************** CONSTANTS ****************************/
61 /* Enough lenience, let's make sure things are proper... */
62 #define WE_STRICT_WRITE /* Check write buffer size */
63 /* I'll probably drop both the define and kernel message in the next version */
66 #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
67 #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
70 #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
71 #define WE_SET_EVENT /* Generate an event on some set commands */
73 /************************* GLOBAL VARIABLES *************************/
75 * You should not use global variables, because or re-entrancy.
76 * On our case, it's only const, so it's OK...
79 * Meta-data about all the standard Wireless Extension request we
82 static const struct iw_ioctl_description standard_ioctl[] = {
84 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
86 { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
88 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
90 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
92 { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
94 { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
96 { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
98 { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
100 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
102 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
104 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
106 { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
108 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
109 /* SIOCGIWPRIV (handled directly by us) */
110 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
112 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
113 /* SIOCGIWSTATS (handled directly by us) */
114 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
116 { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
118 { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
120 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
122 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
124 { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
126 { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
128 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
130 { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
132 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
134 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
136 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
138 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
140 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
142 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
144 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
146 { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
148 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
150 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
152 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
154 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
156 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
158 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
160 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
162 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
164 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
166 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
168 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
170 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
172 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
174 { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
176 static const int standard_ioctl_num = (sizeof(standard_ioctl) /
177 sizeof(struct iw_ioctl_description));
180 * Meta-data about all the additional standard Wireless Extension events
183 static const struct iw_ioctl_description standard_event[] = {
185 { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
187 { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
189 { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
191 { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
193 { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
195 static const int standard_event_num = (sizeof(standard_event) /
196 sizeof(struct iw_ioctl_description));
198 /* Size (in bytes) of the various private data types */
199 static const char priv_type_size[] = {
200 0, /* IW_PRIV_TYPE_NONE */
201 1, /* IW_PRIV_TYPE_BYTE */
202 1, /* IW_PRIV_TYPE_CHAR */
204 sizeof(__u32), /* IW_PRIV_TYPE_INT */
205 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
206 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
210 /* Size (in bytes) of various events */
211 static const int event_type_size[] = {
212 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
214 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
216 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */
217 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
218 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
220 IW_EV_POINT_LEN, /* Without variable payload */
221 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
222 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
225 /************************ COMMON SUBROUTINES ************************/
227 * Stuff that may be used in various place or doesn't fit in one
228 * of the section below.
231 /* ---------------------------------------------------------------- */
233 * Return the driver handler associated with a specific Wireless Extension.
234 * Called from various place, so make sure it remains efficient.
236 static inline iw_handler get_handler(struct net_device *dev,
239 /* Don't "optimise" the following variable, it will crash */
240 unsigned int index; /* *MUST* be unsigned */
242 /* Check if we have some wireless handlers defined */
243 if(dev->wireless_handlers == NULL)
246 /* Try as a standard command */
247 index = cmd - SIOCIWFIRST;
248 if(index < dev->wireless_handlers->num_standard)
249 return dev->wireless_handlers->standard[index];
251 /* Try as a private command */
252 index = cmd - SIOCIWFIRSTPRIV;
253 if(index < dev->wireless_handlers->num_private)
254 return dev->wireless_handlers->private[index];
260 /* ---------------------------------------------------------------- */
262 * Get statistics out of the driver
264 static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
266 return (dev->get_wireless_stats ?
267 dev->get_wireless_stats(dev) :
268 (struct iw_statistics *) NULL);
269 /* In the future, get_wireless_stats may move from 'struct net_device'
270 * to 'struct iw_handler_def', to de-bloat struct net_device.
271 * Definitely worse a thought... */
274 /* ---------------------------------------------------------------- */
276 * Call the commit handler in the driver
277 * (if exist and if conditions are right)
279 * Note : our current commit strategy is currently pretty dumb,
280 * but we will be able to improve on that...
281 * The goal is to try to agreagate as many changes as possible
282 * before doing the commit. Drivers that will define a commit handler
283 * are usually those that need a reset after changing parameters, so
284 * we want to minimise the number of reset.
285 * A cool idea is to use a timer : at each "set" command, we re-set the
286 * timer, when the timer eventually fires, we call the driver.
287 * Hopefully, more on that later.
289 * Also, I'm waiting to see how many people will complain about the
290 * netif_running(dev) test. I'm open on that one...
291 * Hopefully, the driver will remember to do a commit in "open()" ;-)
293 static inline int call_commit_handler(struct net_device * dev)
295 if((netif_running(dev)) &&
296 (dev->wireless_handlers->standard[0] != NULL)) {
297 /* Call the commit handler on the driver */
298 return dev->wireless_handlers->standard[0](dev, NULL,
301 return 0; /* Command completed successfully */
304 /* ---------------------------------------------------------------- */
306 * Number of private arguments
308 static inline int get_priv_size(__u16 args)
310 int num = args & IW_PRIV_SIZE_MASK;
311 int type = (args & IW_PRIV_TYPE_MASK) >> 12;
313 return num * priv_type_size[type];
317 /******************** /proc/net/wireless SUPPORT ********************/
319 * The /proc/net/wireless file is a human readable user-space interface
320 * exporting various wireless specific statistics from the wireless devices.
321 * This is the most popular part of the Wireless Extensions ;-)
323 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
324 * The content of the file is basically the content of "struct iw_statistics".
327 #ifdef CONFIG_PROC_FS
329 /* ---------------------------------------------------------------- */
331 * Print one entry (line) of /proc/net/wireless
333 static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
335 /* Get stats from the driver */
336 struct iw_statistics *stats;
339 stats = get_wireless_stats(dev);
340 if (stats != (struct iw_statistics *) NULL) {
341 size = sprintf(buffer,
342 "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n",
346 stats->qual.updated & 1 ? '.' : ' ',
347 ((__u8) stats->qual.level),
348 stats->qual.updated & 2 ? '.' : ' ',
349 ((__u8) stats->qual.noise),
350 stats->qual.updated & 4 ? '.' : ' ',
353 stats->discard.fragment,
354 stats->discard.retries,
357 stats->qual.updated = 0;
365 /* ---------------------------------------------------------------- */
367 * Print info for /proc/net/wireless (print all entries)
369 int dev_get_wireless_info(char * buffer, char **start, off_t offset,
377 struct net_device * dev;
379 size = sprintf(buffer,
380 "Inter-| sta-| Quality | Discarded packets | Missed\n"
381 " face | tus | link level noise | nwid crypt frag retry misc | beacon\n"
387 read_lock(&dev_base_lock);
388 for (dev = dev_base; dev != NULL; dev = dev->next) {
389 size = sprintf_wireless_stats(buffer + len, dev);
397 if (pos > offset + length)
400 read_unlock(&dev_base_lock);
402 *start = buffer + (offset - begin); /* Start of wanted data */
403 len -= (offset - begin); /* Start slop */
405 len = length; /* Ending slop */
411 #endif /* CONFIG_PROC_FS */
413 /************************** IOCTL SUPPORT **************************/
415 * The original user space API to configure all those Wireless Extensions
417 * In there, we check if we need to call the new driver API (iw_handler)
418 * or just call the driver ioctl handler.
421 /* ---------------------------------------------------------------- */
423 * Allow programatic access to /proc/net/wireless even if /proc
424 * doesn't exist... Also more efficient...
426 static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
428 /* Get stats from the driver */
429 struct iw_statistics *stats;
431 stats = get_wireless_stats(dev);
432 if (stats != (struct iw_statistics *) NULL) {
433 struct iwreq * wrq = (struct iwreq *)ifr;
435 /* Copy statistics to the user buffer */
436 if(copy_to_user(wrq->u.data.pointer, stats,
437 sizeof(struct iw_statistics)))
440 /* Check if we need to clear the update flag */
441 if(wrq->u.data.flags != 0)
442 stats->qual.updated = 0;
448 /* ---------------------------------------------------------------- */
450 * Export the driver private handler definition
451 * They will be picked up by tools like iwpriv...
453 static inline int ioctl_export_private(struct net_device * dev,
456 struct iwreq * iwr = (struct iwreq *) ifr;
458 /* Check if the driver has something to export */
459 if((dev->wireless_handlers->num_private_args == 0) ||
460 (dev->wireless_handlers->private_args == NULL))
463 /* Check NULL pointer */
464 if(iwr->u.data.pointer == NULL)
466 #ifdef WE_STRICT_WRITE
467 /* Check if there is enough buffer up there */
468 if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
469 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);
472 #endif /* WE_STRICT_WRITE */
474 /* Set the number of available ioctls. */
475 iwr->u.data.length = dev->wireless_handlers->num_private_args;
477 /* Copy structure to the user buffer. */
478 if (copy_to_user(iwr->u.data.pointer,
479 dev->wireless_handlers->private_args,
480 sizeof(struct iw_priv_args) * iwr->u.data.length))
486 /* ---------------------------------------------------------------- */
488 * Wrapper to call a standard Wireless Extension handler.
489 * We do various checks and also take care of moving data between
490 * user space and kernel space.
492 static inline int ioctl_standard_call(struct net_device * dev,
497 struct iwreq * iwr = (struct iwreq *) ifr;
498 const struct iw_ioctl_description * descr;
499 struct iw_request_info info;
503 /* Get the description of the IOCTL */
504 if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
506 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
508 #ifdef WE_IOCTL_DEBUG
509 printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
511 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);
512 #endif /* WE_IOCTL_DEBUG */
514 /* Prepare the call */
518 /* Check if we have a pointer to user space data or not */
519 if(descr->header_type != IW_HEADER_TYPE_POINT) {
521 /* No extra arguments. Trivial to handle */
522 ret = handler(dev, &info, &(iwr->u), NULL);
525 /* Generate an event to notify listeners of the change */
526 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
527 ((ret == 0) || (ret == -EIWCOMMIT)))
528 wireless_send_event(dev, cmd, &(iwr->u), NULL);
529 #endif /* WE_SET_EVENT */
534 /* Check what user space is giving us */
536 /* Check NULL pointer */
537 if((iwr->u.data.pointer == NULL) &&
538 (iwr->u.data.length != 0))
540 /* Check if number of token fits within bounds */
541 if(iwr->u.data.length > descr->max_tokens)
543 if(iwr->u.data.length < descr->min_tokens)
546 /* Check NULL pointer */
547 if(iwr->u.data.pointer == NULL)
549 /* Save user space buffer size for checking */
550 user_size = iwr->u.data.length;
553 #ifdef WE_IOCTL_DEBUG
554 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
555 dev->name, descr->max_tokens * descr->token_size);
556 #endif /* WE_IOCTL_DEBUG */
558 /* Always allocate for max space. Easier, and won't last
560 extra = kmalloc(descr->max_tokens * descr->token_size,
566 /* If it is a SET, get all the extra data in here */
567 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
568 err = copy_from_user(extra, iwr->u.data.pointer,
575 #ifdef WE_IOCTL_DEBUG
576 printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
578 iwr->u.data.length * descr->token_size);
579 #endif /* WE_IOCTL_DEBUG */
582 /* Call the handler */
583 ret = handler(dev, &info, &(iwr->u), extra);
585 /* If we have something to return to the user */
586 if (!ret && IW_IS_GET(cmd)) {
587 #ifdef WE_STRICT_WRITE
588 /* Check if there is enough buffer up there */
589 if(user_size < iwr->u.data.length) {
590 printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
594 #endif /* WE_STRICT_WRITE */
596 err = copy_to_user(iwr->u.data.pointer, extra,
601 #ifdef WE_IOCTL_DEBUG
602 printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
604 iwr->u.data.length * descr->token_size);
605 #endif /* WE_IOCTL_DEBUG */
609 /* Generate an event to notify listeners of the change */
610 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
611 ((ret == 0) || (ret == -EIWCOMMIT))) {
612 if(descr->flags & IW_DESCR_FLAG_RESTRICT)
613 /* If the event is restricted, don't
614 * export the payload */
615 wireless_send_event(dev, cmd, &(iwr->u), NULL);
617 wireless_send_event(dev, cmd, &(iwr->u),
620 #endif /* WE_SET_EVENT */
622 /* Cleanup - I told you it wasn't that long ;-) */
626 /* Call commit handler if needed and defined */
627 if(ret == -EIWCOMMIT)
628 ret = call_commit_handler(dev);
630 /* Here, we will generate the appropriate event if needed */
635 /* ---------------------------------------------------------------- */
637 * Wrapper to call a private Wireless Extension handler.
638 * We do various checks and also take care of moving data between
639 * user space and kernel space.
640 * It's not as nice and slimline as the standard wrapper. The cause
641 * is struct iw_priv_args, which was not really designed for the
642 * job we are going here.
644 * IMPORTANT : This function prevent to set and get data on the same
645 * IOCTL and enforce the SET/GET convention. Not doing it would be
647 * If you need to set and get data at the same time, please don't use
648 * a iw_handler but process it in your ioctl handler (i.e. use the
651 static inline int ioctl_private_call(struct net_device * dev,
656 struct iwreq * iwr = (struct iwreq *) ifr;
657 struct iw_priv_args * descr = NULL;
658 struct iw_request_info info;
663 /* Get the description of the IOCTL */
664 for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
665 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
666 descr = &(dev->wireless_handlers->private_args[i]);
670 #ifdef WE_IOCTL_DEBUG
671 printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
674 printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
675 dev->name, descr->name,
676 descr->set_args, descr->get_args);
678 #endif /* WE_IOCTL_DEBUG */
680 /* Compute the size of the set/get arguments */
683 int offset = 0; /* For sub-ioctls */
684 /* Check for sub-ioctl handler */
685 if(descr->name[0] == '\0')
686 /* Reserve one int for sub-ioctl index */
687 offset = sizeof(__u32);
689 /* Size of set arguments */
690 extra_size = get_priv_size(descr->set_args);
692 /* Does it fits in iwr ? */
693 if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
694 ((extra_size + offset) <= IFNAMSIZ))
697 /* Size of set arguments */
698 extra_size = get_priv_size(descr->get_args);
700 /* Does it fits in iwr ? */
701 if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
702 (extra_size <= IFNAMSIZ))
707 /* Prepare the call */
711 /* Check if we have a pointer to user space data or not. */
712 if(extra_size == 0) {
713 /* No extra arguments. Trivial to handle */
714 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
719 /* Check what user space is giving us */
721 /* Check NULL pointer */
722 if((iwr->u.data.pointer == NULL) &&
723 (iwr->u.data.length != 0))
726 /* Does it fits within bounds ? */
727 if(iwr->u.data.length > (descr->set_args &
731 /* Check NULL pointer */
732 if(iwr->u.data.pointer == NULL)
736 #ifdef WE_IOCTL_DEBUG
737 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
738 dev->name, extra_size);
739 #endif /* WE_IOCTL_DEBUG */
741 /* Always allocate for max space. Easier, and won't last
743 extra = kmalloc(extra_size, GFP_KERNEL);
748 /* If it is a SET, get all the extra data in here */
749 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
750 err = copy_from_user(extra, iwr->u.data.pointer,
756 #ifdef WE_IOCTL_DEBUG
757 printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
758 dev->name, iwr->u.data.length);
759 #endif /* WE_IOCTL_DEBUG */
762 /* Call the handler */
763 ret = handler(dev, &info, &(iwr->u), extra);
765 /* If we have something to return to the user */
766 if (!ret && IW_IS_GET(cmd)) {
767 err = copy_to_user(iwr->u.data.pointer, extra,
771 #ifdef WE_IOCTL_DEBUG
772 printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
773 dev->name, iwr->u.data.length);
774 #endif /* WE_IOCTL_DEBUG */
777 /* Cleanup - I told you it wasn't that long ;-) */
782 /* Call commit handler if needed and defined */
783 if(ret == -EIWCOMMIT)
784 ret = call_commit_handler(dev);
789 /* ---------------------------------------------------------------- */
791 * Main IOCTl dispatcher. Called from the main networking code
792 * (dev_ioctl() in net/core/dev.c).
793 * Check the type of IOCTL and call the appropriate wrapper...
795 int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
797 struct net_device *dev;
800 /* Permissions are already checked in dev_ioctl() before calling us.
801 * The copy_to/from_user() of ifr is also dealt with in there */
803 /* Make sure the device exist */
804 if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
807 /* A bunch of special cases, then the generic case...
808 * Note that 'cmd' is already filtered in dev_ioctl() with
809 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
813 /* Get Wireless Stats */
814 return dev_iwstats(dev, ifr);
817 /* Check if we have some wireless handlers defined */
818 if(dev->wireless_handlers != NULL) {
819 /* We export to user space the definition of
820 * the private handler ourselves */
821 return ioctl_export_private(dev, ifr);
823 // ## Fall-through for old API ##
827 if (!netif_device_present(dev))
829 /* New driver API : try to find the handler */
830 handler = get_handler(dev, cmd);
831 if(handler != NULL) {
832 /* Standard and private are not the same */
833 if(cmd < SIOCIWFIRSTPRIV)
834 return ioctl_standard_call(dev,
839 return ioctl_private_call(dev,
844 /* Old driver API : call driver ioctl handler */
846 return dev->do_ioctl(dev, ifr, cmd);
854 /************************* EVENT PROCESSING *************************/
856 * Process events generated by the wireless layer or the driver.
857 * Most often, the event will be propagated through rtnetlink
860 #ifdef WE_EVENT_NETLINK
861 /* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
862 * It is declared in <linux/rtnetlink.h> */
864 /* ---------------------------------------------------------------- */
866 * Fill a rtnetlink message with our event data.
867 * Note that we propage only the specified event and don't dump the
868 * current wireless config. Dumping the wireless config is far too
869 * expensive (for each parameter, the driver need to query the hardware).
871 static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb,
872 struct net_device * dev,
878 struct nlmsghdr *nlh;
879 unsigned char *b = skb->tail;
881 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
883 r->ifi_family = AF_UNSPEC;
884 r->ifi_type = dev->type;
885 r->ifi_index = dev->ifindex;
886 r->ifi_flags = dev->flags;
887 r->ifi_change = 0; /* Wireless changes don't affect those flags */
889 /* Add the wireless events in the netlink packet */
890 RTA_PUT(skb, IFLA_WIRELESS,
893 nlh->nlmsg_len = skb->tail - b;
898 skb_trim(skb, b - skb->data);
902 /* ---------------------------------------------------------------- */
904 * Create and broadcast and send it on the standard rtnetlink socket
905 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
906 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
907 * within a RTM_NEWLINK event.
909 static inline void rtmsg_iwinfo(struct net_device * dev,
914 int size = NLMSG_GOODSIZE;
916 skb = alloc_skb(size, GFP_ATOMIC);
920 if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
921 event, event_len) < 0) {
925 NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
926 netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
928 #endif /* WE_EVENT_NETLINK */
930 /* ---------------------------------------------------------------- */
932 * Main event dispatcher. Called from other parts and drivers.
933 * Send the event on the apropriate channels.
934 * May be called from interrupt context.
936 void wireless_send_event(struct net_device * dev,
938 union iwreq_data * wrqu,
941 const struct iw_ioctl_description * descr = NULL;
943 struct iw_event *event; /* Mallocated whole event */
944 int event_len; /* Its size */
945 int hdr_len; /* Size of the event header */
946 /* Don't "optimise" the following variable, it will crash */
947 unsigned cmd_index; /* *MUST* be unsigned */
949 /* Get the description of the IOCTL */
950 if(cmd <= SIOCIWLAST) {
951 cmd_index = cmd - SIOCIWFIRST;
952 if(cmd_index < standard_ioctl_num)
953 descr = &(standard_ioctl[cmd_index]);
955 cmd_index = cmd - IWEVFIRST;
956 if(cmd_index < standard_event_num)
957 descr = &(standard_event[cmd_index]);
959 /* Don't accept unknown events */
961 /* Note : we don't return an error to the driver, because
962 * the driver would not know what to do about it. It can't
963 * return an error to the user, because the event is not
964 * initiated by a user request.
965 * The best the driver could do is to log an error message.
966 * We will do it ourselves instead...
968 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
972 #ifdef WE_EVENT_DEBUG
973 printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
975 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);
976 #endif /* WE_EVENT_DEBUG */
978 /* Check extra parameters and set extra_len */
979 if(descr->header_type == IW_HEADER_TYPE_POINT) {
980 /* Check if number of token fits within bounds */
981 if(wrqu->data.length > descr->max_tokens) {
982 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
985 if(wrqu->data.length < descr->min_tokens) {
986 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
989 /* Calculate extra_len - extra is NULL for restricted events */
991 extra_len = wrqu->data.length * descr->token_size;
992 #ifdef WE_EVENT_DEBUG
993 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
994 #endif /* WE_EVENT_DEBUG */
997 /* Total length of the event */
998 hdr_len = event_type_size[descr->header_type];
999 event_len = hdr_len + extra_len;
1001 #ifdef WE_EVENT_DEBUG
1002 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
1003 #endif /* WE_EVENT_DEBUG */
1005 /* Create temporary buffer to hold the event */
1006 event = kmalloc(event_len, GFP_ATOMIC);
1011 event->len = event_len;
1013 memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
1015 memcpy(((char *) event) + hdr_len, extra, extra_len);
1017 #ifdef WE_EVENT_NETLINK
1018 /* rtnetlink event channel */
1019 rtmsg_iwinfo(dev, (char *) event, event_len);
1020 #endif /* WE_EVENT_NETLINK */
1025 return; /* Always success, I guess ;-) */