1 diff -u -p linux/include/linux/wireless.19.h linux/include/linux/wireless.h
2 --- linux/include/linux/wireless.19.h 2006-02-17 10:49:04.000000000 -0800
3 +++ linux/include/linux/wireless.h 2006-02-17 17:58:10.000000000 -0800
6 * This file define a set of standard wireless extensions
8 - * Version : 19 18.3.05
9 + * Version : 20 17.2.06
11 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
12 - * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
13 + * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
16 #ifndef _LINUX_WIRELESS_H
18 * (there is some stuff that will be added in the future...)
19 * I just plan to increment with each new version.
21 -#define WIRELESS_EXT 19
22 +#define WIRELESS_EXT 20
27 * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
28 * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
29 * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
33 + * - RtNetlink requests support (SET/GET)
36 /**************************** CONSTANTS ****************************/
37 diff -u -p linux/include/net/iw_handler.19.h linux/include/net/iw_handler.h
38 --- linux/include/net/iw_handler.19.h 2006-02-17 10:49:15.000000000 -0800
39 +++ linux/include/net/iw_handler.h 2006-02-17 18:01:36.000000000 -0800
43 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
44 - * Copyright (c) 2001-2005 Jean Tourrilhes, All Rights Reserved.
45 + * Copyright (c) 2001-2006 Jean Tourrilhes, All Rights Reserved.
49 @@ -436,6 +436,16 @@ extern int dev_get_wireless_info(char *
50 /* Handle IOCTLs, called in net/core/dev.c */
51 extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
53 +/* Handle RtNetlink requests, called in net/core/rtnetlink.c */
54 +extern int wireless_rtnetlink_set(struct net_device * dev,
57 +extern int wireless_rtnetlink_get(struct net_device * dev,
63 /* Second : functions that may be called by driver modules */
65 /* Send a single event to user space */
66 diff -u -p linux/drivers/net/wireless/Kconfig.19 linux/drivers/net/wireless/Kconfig
67 --- linux/drivers/net/wireless/Kconfig.19 2006-02-21 13:11:34.000000000 -0800
68 +++ linux/drivers/net/wireless/Kconfig 2006-02-22 11:48:27.000000000 -0800
69 @@ -24,6 +24,15 @@ config NET_RADIO
71 <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
73 +config NET_WIRELESS_RTNETLINK
74 + bool "Wireless Extension API over RtNetlink"
76 + Support the Wireless Extension API over the RtNetlink socket
77 + in addition to the traditional ioctl interface (selected above).
79 + For now, few tools use this facility, but it might grow in the
80 + future. The only downside is that it adds 4.5 kB to your kernel.
82 # Note : the cards are obsolete (can't buy them anymore), but the drivers
83 # are not, as people are still using them...
84 comment "Obsolete Wireless cards support (pre-802.11)"
85 diff -u -p linux/net/core/rtnetlink.19.c linux/net/core/rtnetlink.c
86 --- linux/net/core/rtnetlink.19.c 2006-02-17 10:49:26.000000000 -0800
87 +++ linux/net/core/rtnetlink.c 2006-02-21 12:57:07.000000000 -0800
90 #include <net/pkt_sched.h>
91 #include <net/netlink.h>
92 +#ifdef CONFIG_NET_WIRELESS_RTNETLINK
93 +#include <linux/wireless.h>
94 +#include <net/iw_handler.h>
95 +#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
97 DECLARE_MUTEX(rtnl_sem);
99 @@ -410,6 +414,17 @@ static int do_setlink(struct sk_buff *sk
103 +#ifdef CONFIG_NET_WIRELESS_RTNETLINK
104 + if (ida[IFLA_WIRELESS - 1]) {
106 + /* Call Wireless Extensions.
107 + * Various stuff checked in there... */
108 + err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
112 +#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
117 @@ -420,6 +435,83 @@ out:
121 +#ifdef CONFIG_NET_WIRELESS_RTNETLINK
122 +static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg)
124 + struct ifinfomsg *ifm = NLMSG_DATA(in_nlh);
125 + struct rtattr **ida = arg;
126 + struct net_device *dev;
127 + struct ifinfomsg *r;
128 + struct nlmsghdr *nlh;
129 + int err = -ENOBUFS;
130 + struct sk_buff *skb;
132 + char *iw_buf = NULL;
133 + int iw_buf_len = 0;
135 + if (ifm->ifi_index >= 0)
136 + dev = dev_get_by_index(ifm->ifi_index);
142 +#ifdef CONFIG_NET_WIRELESS_RTNETLINK
143 + if (ida[IFLA_WIRELESS - 1]) {
145 + /* Call Wireless Extensions. We need to know the size before
146 + * we can alloc. Various stuff checked in there... */
147 + err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len);
151 +#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
153 + /* Create a skb big enough to include all the data.
154 + * Some requests are way bigger than 4k... Jean II */
155 + skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)),
161 + /* Put in the message the usual good stuff */
162 + nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq,
163 + RTM_NEWLINK, sizeof(*r));
164 + r = NLMSG_DATA(nlh);
165 + r->ifi_family = AF_UNSPEC;
167 + r->ifi_type = dev->type;
168 + r->ifi_index = dev->ifindex;
169 + r->ifi_flags = dev->flags;
172 + /* Put the wireless payload if it exist */
174 + RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len,
175 + iw_buf + IW_EV_POINT_OFF);
177 + nlh->nlmsg_len = skb->tail - b;
180 + NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
182 + err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
196 +#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
198 static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
201 @@ -585,7 +677,11 @@ static void rtnetlink_rcv(struct sock *s
203 static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
205 - [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
206 + [RTM_GETLINK - RTM_BASE] = {
207 +#ifdef CONFIG_NET_WIRELESS_RTNETLINK
208 + .doit = do_getlink,
209 +#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
210 + .dumpit = rtnetlink_dump_ifinfo },
211 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
212 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
213 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
214 diff -u -p linux/net/core/wireless.19.c linux/net/core/wireless.c
215 --- linux/net/core/wireless.19.c 2006-02-17 10:49:37.000000000 -0800
216 +++ linux/net/core/wireless.c 2006-02-22 11:46:52.000000000 -0800
218 * This file implement the Wireless Extensions APIs.
220 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
221 - * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
222 + * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
224 * (As all part of the Linux kernel, this file is GPL)
227 * o Start deprecating dev->get_wireless_stats, output a warning
228 * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
229 * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
231 + * v8 - 17.02.06 - Jean II
232 + * o RtNetlink requests support (SET/GET)
235 /***************************** INCLUDES *****************************/
238 /* Debugging stuff */
239 #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
240 +#undef WE_RTNETLINK_DEBUG /* Debug RtNetlink API */
241 #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
242 #undef WE_SPY_DEBUG /* Debug enhanced spy support */
245 -#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
246 +//CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */
247 +#define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */
248 #define WE_SET_EVENT /* Generate an event on some set commands */
250 /************************* GLOBAL VARIABLES *************************/
251 @@ -156,13 +161,18 @@ static const struct iw_ioctl_description
252 .header_type = IW_HEADER_TYPE_NULL,
254 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
255 - .header_type = IW_HEADER_TYPE_NULL,
256 + .header_type = IW_HEADER_TYPE_POINT,
257 + .token_size = sizeof(struct iw_priv_args),
259 + .flags = IW_DESCR_FLAG_NOMAX,
261 [SIOCSIWSTATS - SIOCIWFIRST] = {
262 .header_type = IW_HEADER_TYPE_NULL,
264 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
265 - .header_type = IW_HEADER_TYPE_NULL,
266 + .header_type = IW_HEADER_TYPE_POINT,
268 + .max_tokens = sizeof(struct iw_statistics),
269 .flags = IW_DESCR_FLAG_DUMP,
271 [SIOCSIWSPY - SIOCIWFIRST] = {
272 @@ -529,6 +539,70 @@ static inline int adjust_priv_size(__u16
273 return num * iw_priv_type_size[type];
276 +/* ---------------------------------------------------------------- */
278 + * Standard Wireless Handler : get wireless stats
279 + * Allow programatic access to /proc/net/wireless even if /proc
280 + * doesn't exist... Also more efficient...
282 +static int iw_handler_get_iwstats(struct net_device * dev,
283 + struct iw_request_info * info,
284 + union iwreq_data * wrqu,
287 + /* Get stats from the driver */
288 + struct iw_statistics *stats;
290 + stats = get_wireless_stats(dev);
291 + if (stats != (struct iw_statistics *) NULL) {
293 + /* Copy statistics to extra */
294 + memcpy(extra, stats, sizeof(struct iw_statistics));
295 + wrqu->data.length = sizeof(struct iw_statistics);
297 + /* Check if we need to clear the updated flag */
298 + if(wrqu->data.flags != 0)
299 + stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
302 + return -EOPNOTSUPP;
305 +/* ---------------------------------------------------------------- */
307 + * Standard Wireless Handler : get iwpriv definitions
308 + * Export the driver private handler definition
309 + * They will be picked up by tools like iwpriv...
311 +static int iw_handler_get_private(struct net_device * dev,
312 + struct iw_request_info * info,
313 + union iwreq_data * wrqu,
316 + /* Check if the driver has something to export */
317 + if((dev->wireless_handlers->num_private_args == 0) ||
318 + (dev->wireless_handlers->private_args == NULL))
319 + return -EOPNOTSUPP;
321 + /* Check if there is enough buffer up there */
322 + if(wrqu->data.length < dev->wireless_handlers->num_private_args) {
323 + /* User space can't know in advance how large the buffer
324 + * needs to be. Give it a hint, so that we can support
325 + * any size buffer we want somewhat efficiently... */
326 + wrqu->data.length = dev->wireless_handlers->num_private_args;
330 + /* Set the number of available ioctls. */
331 + wrqu->data.length = dev->wireless_handlers->num_private_args;
333 + /* Copy structure to the user buffer. */
334 + memcpy(extra, dev->wireless_handlers->private_args,
335 + sizeof(struct iw_priv_args) * wrqu->data.length);
341 /******************** /proc/net/wireless SUPPORT ********************/
343 @@ -630,81 +704,14 @@ int __init wireless_proc_init(void)
345 /* ---------------------------------------------------------------- */
347 - * Allow programatic access to /proc/net/wireless even if /proc
348 - * doesn't exist... Also more efficient...
350 -static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
352 - /* Get stats from the driver */
353 - struct iw_statistics *stats;
355 - stats = get_wireless_stats(dev);
356 - if (stats != (struct iw_statistics *) NULL) {
357 - struct iwreq * wrq = (struct iwreq *)ifr;
359 - /* Copy statistics to the user buffer */
360 - if(copy_to_user(wrq->u.data.pointer, stats,
361 - sizeof(struct iw_statistics)))
364 - /* Check if we need to clear the updated flag */
365 - if(wrq->u.data.flags != 0)
366 - stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
369 - return -EOPNOTSUPP;
372 -/* ---------------------------------------------------------------- */
374 - * Export the driver private handler definition
375 - * They will be picked up by tools like iwpriv...
377 -static inline int ioctl_export_private(struct net_device * dev,
378 - struct ifreq * ifr)
380 - struct iwreq * iwr = (struct iwreq *) ifr;
382 - /* Check if the driver has something to export */
383 - if((dev->wireless_handlers->num_private_args == 0) ||
384 - (dev->wireless_handlers->private_args == NULL))
385 - return -EOPNOTSUPP;
387 - /* Check NULL pointer */
388 - if(iwr->u.data.pointer == NULL)
391 - /* Check if there is enough buffer up there */
392 - if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
393 - /* User space can't know in advance how large the buffer
394 - * needs to be. Give it a hint, so that we can support
395 - * any size buffer we want somewhat efficiently... */
396 - iwr->u.data.length = dev->wireless_handlers->num_private_args;
400 - /* Set the number of available ioctls. */
401 - iwr->u.data.length = dev->wireless_handlers->num_private_args;
403 - /* Copy structure to the user buffer. */
404 - if (copy_to_user(iwr->u.data.pointer,
405 - dev->wireless_handlers->private_args,
406 - sizeof(struct iw_priv_args) * iwr->u.data.length))
412 -/* ---------------------------------------------------------------- */
414 * Wrapper to call a standard Wireless Extension handler.
415 * We do various checks and also take care of moving data between
416 * user space and kernel space.
418 -static inline int ioctl_standard_call(struct net_device * dev,
419 - struct ifreq * ifr,
421 - iw_handler handler)
422 +static int ioctl_standard_call(struct net_device * dev,
423 + struct ifreq * ifr,
425 + iw_handler handler)
427 struct iwreq * iwr = (struct iwreq *) ifr;
428 const struct iw_ioctl_description * descr;
429 @@ -1048,14 +1055,20 @@ int wireless_process_ioctl(struct ifreq
432 /* Get Wireless Stats */
433 - return dev_iwstats(dev, ifr);
434 + return ioctl_standard_call(dev,
437 + &iw_handler_get_iwstats);
440 /* Check if we have some wireless handlers defined */
441 if(dev->wireless_handlers != NULL) {
442 /* We export to user space the definition of
443 * the private handler ourselves */
444 - return ioctl_export_private(dev, ifr);
445 + return ioctl_standard_call(dev,
448 + &iw_handler_get_private);
450 // ## Fall-through for old API ##
452 @@ -1088,16 +1101,739 @@ int wireless_process_ioctl(struct ifreq
456 +/********************** RTNETLINK REQUEST API **********************/
458 + * The alternate user space API to configure all those Wireless Extensions
459 + * is through RtNetlink.
460 + * This API support only the new driver API (iw_handler).
462 + * This RtNetlink API use the same query/reply model as the ioctl API.
463 + * Maximum effort has been done to fit in the RtNetlink model, and
464 + * we support both RtNetlink Set and RtNelink Get operations.
465 + * On the other hand, we don't offer Dump operations because of the
466 + * following reasons :
467 + * o Large number of parameters, most optional
468 + * o Large size of some parameters (> 100 bytes)
469 + * o Each parameters need to be extracted from hardware
470 + * o Scan requests can take seconds and disable network activity.
471 + * Because of this high cost/overhead, we want to return only the
472 + * parameters the user application is really interested in.
473 + * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag.
475 + * The API uses the standard RtNetlink socket. When the RtNetlink code
476 + * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request,
480 +#ifdef CONFIG_NET_WIRELESS_RTNETLINK
481 +/* ---------------------------------------------------------------- */
483 + * Wrapper to call a standard Wireless Extension GET handler.
484 + * We do various checks and call the handler with the proper args.
486 +static int rtnetlink_standard_get(struct net_device * dev,
487 + struct iw_event * request,
489 + iw_handler handler,
493 + const struct iw_ioctl_description * descr = NULL;
495 + union iwreq_data * wrqu;
497 + struct iw_request_info info;
498 + char * buffer = NULL;
499 + int buffer_size = 0;
502 + /* Get the description of the Request */
503 + cmd = request->cmd;
504 + if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
505 + return -EOPNOTSUPP;
506 + descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
508 +#ifdef WE_RTNETLINK_DEBUG
509 + printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n",
511 + 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);
512 +#endif /* WE_RTNETLINK_DEBUG */
514 + /* Check if wrqu is complete */
515 + hdr_len = event_type_size[descr->header_type];
516 + if(request_len < hdr_len) {
517 +#ifdef WE_RTNETLINK_DEBUG
519 + "%s (WE.r) : Wireless request too short (%d)\n",
520 + dev->name, request_len);
521 +#endif /* WE_RTNETLINK_DEBUG */
525 + /* Prepare the call */
529 + /* Check if we have extra data in the reply or not */
530 + if(descr->header_type != IW_HEADER_TYPE_POINT) {
532 + /* Create the kernel buffer that we will return.
533 + * It's at an offset to match the TYPE_POINT case... */
534 + buffer_size = request_len + IW_EV_POINT_OFF;
535 + buffer = kmalloc(buffer_size, GFP_KERNEL);
536 + if (buffer == NULL) {
539 + /* Copy event data */
540 + memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
541 + /* Use our own copy of wrqu */
542 + wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
545 + /* No extra arguments. Trivial to handle */
546 + ret = handler(dev, &info, wrqu, NULL);
549 + union iwreq_data wrqu_point;
550 + char * extra = NULL;
551 + int extra_size = 0;
553 + /* Get a temp copy of wrqu (skip pointer) */
554 + memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
555 + ((char *) request) + IW_EV_LCP_LEN,
556 + IW_EV_POINT_LEN - IW_EV_LCP_LEN);
558 + /* Calculate space needed by arguments. Always allocate
559 + * for max space. Easier, and won't last long... */
560 + extra_size = descr->max_tokens * descr->token_size;
561 + /* Support for very large requests */
562 + if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
563 + (wrqu_point.data.length > descr->max_tokens))
564 + extra_size = (wrqu_point.data.length
565 + * descr->token_size);
566 + buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
567 +#ifdef WE_RTNETLINK_DEBUG
568 + printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
569 + dev->name, extra_size, buffer_size);
570 +#endif /* WE_RTNETLINK_DEBUG */
572 + /* Create the kernel buffer that we will return */
573 + buffer = kmalloc(buffer_size, GFP_KERNEL);
574 + if (buffer == NULL) {
578 + /* Put wrqu in the right place (just before extra).
579 + * Leave space for IWE header and dummy pointer...
580 + * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
582 + memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
583 + ((char *) &wrqu_point) + IW_EV_POINT_OFF,
584 + IW_EV_POINT_LEN - IW_EV_LCP_LEN);
585 + wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
587 + /* Extra comes logically after that. Offset +12 bytes. */
588 + extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
590 + /* Call the handler */
591 + ret = handler(dev, &info, wrqu, extra);
593 + /* Calculate real returned length */
594 + extra_size = (wrqu->data.length * descr->token_size);
595 + /* Re-adjust reply size */
596 + request->len = extra_size + IW_EV_POINT_LEN;
598 + /* Put the iwe header where it should, i.e. scrap the
599 + * dummy pointer. */
600 + memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
602 +#ifdef WE_RTNETLINK_DEBUG
603 + 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);
604 +#endif /* WE_RTNETLINK_DEBUG */
606 + /* Check if there is enough buffer up there */
607 + if(wrqu_point.data.length < wrqu->data.length)
611 + /* Return the buffer to the caller */
614 + *p_len = request->len;
624 +/* ---------------------------------------------------------------- */
626 + * Wrapper to call a standard Wireless Extension SET handler.
627 + * We do various checks and call the handler with the proper args.
629 +static inline int rtnetlink_standard_set(struct net_device * dev,
630 + struct iw_event * request,
632 + iw_handler handler)
634 + const struct iw_ioctl_description * descr = NULL;
636 + union iwreq_data * wrqu;
637 + union iwreq_data wrqu_point;
639 + char * extra = NULL;
640 + int extra_size = 0;
641 + struct iw_request_info info;
644 + /* Get the description of the Request */
645 + cmd = request->cmd;
646 + if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
647 + return -EOPNOTSUPP;
648 + descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
650 +#ifdef WE_RTNETLINK_DEBUG
651 + printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n",
653 + 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);
654 +#endif /* WE_RTNETLINK_DEBUG */
656 + /* Extract fixed header from request. This is properly aligned. */
657 + wrqu = &request->u;
659 + /* Check if wrqu is complete */
660 + hdr_len = event_type_size[descr->header_type];
661 + if(request_len < hdr_len) {
662 +#ifdef WE_RTNETLINK_DEBUG
664 + "%s (WE.r) : Wireless request too short (%d)\n",
665 + dev->name, request_len);
666 +#endif /* WE_RTNETLINK_DEBUG */
670 + /* Prepare the call */
674 + /* Check if we have extra data in the request or not */
675 + if(descr->header_type != IW_HEADER_TYPE_POINT) {
677 + /* No extra arguments. Trivial to handle */
678 + ret = handler(dev, &info, wrqu, NULL);
683 + /* Put wrqu in the right place (skip pointer) */
684 + memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
685 + wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
686 + /* Don't forget about the event code... */
687 + wrqu = &wrqu_point;
689 + /* Check if number of token fits within bounds */
690 + if(wrqu_point.data.length > descr->max_tokens)
692 + if(wrqu_point.data.length < descr->min_tokens)
695 + /* Real length of payload */
696 + extra_len = wrqu_point.data.length * descr->token_size;
698 + /* Check if request is self consistent */
699 + if((request_len - hdr_len) < extra_len) {
700 +#ifdef WE_RTNETLINK_DEBUG
701 + printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
702 + dev->name, extra_size);
703 +#endif /* WE_RTNETLINK_DEBUG */
707 +#ifdef WE_RTNETLINK_DEBUG
708 + printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
709 + dev->name, extra_size);
710 +#endif /* WE_RTNETLINK_DEBUG */
712 + /* Always allocate for max space. Easier, and won't last
714 + extra_size = descr->max_tokens * descr->token_size;
715 + extra = kmalloc(extra_size, GFP_KERNEL);
719 + /* Copy extra in aligned buffer */
720 + memcpy(extra, ((char *) request) + hdr_len, extra_len);
722 + /* Call the handler */
723 + ret = handler(dev, &info, &wrqu_point, extra);
727 + /* Generate an event to notify listeners of the change */
728 + if((descr->flags & IW_DESCR_FLAG_EVENT) &&
729 + ((ret == 0) || (ret == -EIWCOMMIT))) {
730 + if(descr->flags & IW_DESCR_FLAG_RESTRICT)
731 + /* If the event is restricted, don't
732 + * export the payload */
733 + wireless_send_event(dev, cmd, wrqu, NULL);
735 + wireless_send_event(dev, cmd, wrqu, extra);
737 +#endif /* WE_SET_EVENT */
739 + /* Cleanup - I told you it wasn't that long ;-) */
743 + /* Call commit handler if needed and defined */
744 + if(ret == -EIWCOMMIT)
745 + ret = call_commit_handler(dev);
750 +/* ---------------------------------------------------------------- */
752 + * Wrapper to call a private Wireless Extension GET handler.
754 + * It's not as nice and slimline as the standard wrapper. The cause
755 + * is struct iw_priv_args, which was not really designed for the
756 + * job we are going here.
758 + * IMPORTANT : This function prevent to set and get data on the same
759 + * IOCTL and enforce the SET/GET convention. Not doing it would be
761 + * If you need to set and get data at the same time, please don't use
762 + * a iw_handler but process it in your ioctl handler (i.e. use the
765 +static inline int rtnetlink_private_get(struct net_device * dev,
766 + struct iw_event * request,
768 + iw_handler handler,
772 + const struct iw_priv_args * descr = NULL;
774 + union iwreq_data * wrqu;
776 + struct iw_request_info info;
777 + int extra_size = 0;
779 + char * buffer = NULL;
780 + int buffer_size = 0;
783 + /* Get the description of the Request */
784 + cmd = request->cmd;
785 + for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
786 + if(cmd == dev->wireless_handlers->private_args[i].cmd) {
787 + descr = &(dev->wireless_handlers->private_args[i]);
791 + return -EOPNOTSUPP;
793 +#ifdef WE_RTNETLINK_DEBUG
794 + printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
796 + printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
797 + dev->name, descr->name, descr->set_args, descr->get_args);
798 +#endif /* WE_RTNETLINK_DEBUG */
800 + /* Compute the max size of the get arguments */
801 + extra_size = get_priv_size(descr->get_args);
803 + /* Does it fits in wrqu ? */
804 + if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
805 + (extra_size <= IFNAMSIZ)) {
806 + hdr_len = extra_size;
809 + hdr_len = IW_EV_POINT_LEN;
812 + /* Check if wrqu is complete */
813 + if(request_len < hdr_len) {
814 +#ifdef WE_RTNETLINK_DEBUG
816 + "%s (WE.r) : Wireless request too short (%d)\n",
817 + dev->name, request_len);
818 +#endif /* WE_RTNETLINK_DEBUG */
822 + /* Prepare the call */
826 + /* Check if we have a pointer to user space data or not. */
827 + if(extra_size == 0) {
829 + /* Create the kernel buffer that we will return.
830 + * It's at an offset to match the TYPE_POINT case... */
831 + buffer_size = request_len + IW_EV_POINT_OFF;
832 + buffer = kmalloc(buffer_size, GFP_KERNEL);
833 + if (buffer == NULL) {
836 + /* Copy event data */
837 + memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
838 + /* Use our own copy of wrqu */
839 + wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
842 + /* No extra arguments. Trivial to handle */
843 + ret = handler(dev, &info, wrqu, (char *) wrqu);
848 + /* Buffer for full reply */
849 + buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
851 +#ifdef WE_RTNETLINK_DEBUG
852 + printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
853 + dev->name, extra_size, buffer_size);
854 +#endif /* WE_RTNETLINK_DEBUG */
856 + /* Create the kernel buffer that we will return */
857 + buffer = kmalloc(buffer_size, GFP_KERNEL);
858 + if (buffer == NULL) {
862 + /* Put wrqu in the right place (just before extra).
863 + * Leave space for IWE header and dummy pointer...
864 + * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
866 + memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
867 + ((char *) request) + IW_EV_LCP_LEN,
868 + IW_EV_POINT_LEN - IW_EV_LCP_LEN);
869 + wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
871 + /* Extra comes logically after that. Offset +12 bytes. */
872 + extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
874 + /* Call the handler */
875 + ret = handler(dev, &info, wrqu, extra);
877 + /* Adjust for the actual length if it's variable,
878 + * avoid leaking kernel bits outside. */
879 + if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
880 + extra_size = adjust_priv_size(descr->get_args, wrqu);
881 + /* Re-adjust reply size */
882 + request->len = extra_size + IW_EV_POINT_LEN;
884 + /* Put the iwe header where it should, i.e. scrap the
885 + * dummy pointer. */
886 + memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
888 +#ifdef WE_RTNETLINK_DEBUG
889 + 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);
890 +#endif /* WE_RTNETLINK_DEBUG */
893 + /* Return the buffer to the caller */
896 + *p_len = request->len;
906 +/* ---------------------------------------------------------------- */
908 + * Wrapper to call a private Wireless Extension SET handler.
910 + * It's not as nice and slimline as the standard wrapper. The cause
911 + * is struct iw_priv_args, which was not really designed for the
912 + * job we are going here.
914 + * IMPORTANT : This function prevent to set and get data on the same
915 + * IOCTL and enforce the SET/GET convention. Not doing it would be
917 + * If you need to set and get data at the same time, please don't use
918 + * a iw_handler but process it in your ioctl handler (i.e. use the
921 +static inline int rtnetlink_private_set(struct net_device * dev,
922 + struct iw_event * request,
924 + iw_handler handler)
926 + const struct iw_priv_args * descr = NULL;
928 + union iwreq_data * wrqu;
929 + union iwreq_data wrqu_point;
931 + char * extra = NULL;
932 + int extra_size = 0;
933 + int offset = 0; /* For sub-ioctls */
934 + struct iw_request_info info;
938 + /* Get the description of the Request */
939 + cmd = request->cmd;
940 + for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
941 + if(cmd == dev->wireless_handlers->private_args[i].cmd) {
942 + descr = &(dev->wireless_handlers->private_args[i]);
946 + return -EOPNOTSUPP;
948 +#ifdef WE_RTNETLINK_DEBUG
949 + printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
950 + ifr->ifr_name, cmd);
951 + printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
952 + dev->name, descr->name, descr->set_args, descr->get_args);
953 +#endif /* WE_RTNETLINK_DEBUG */
955 + /* Compute the size of the set arguments */
956 + /* Check for sub-ioctl handler */
957 + if(descr->name[0] == '\0')
958 + /* Reserve one int for sub-ioctl index */
959 + offset = sizeof(__u32);
961 + /* Size of set arguments */
962 + extra_size = get_priv_size(descr->set_args);
964 + /* Does it fits in wrqu ? */
965 + if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
966 + (extra_size <= IFNAMSIZ)) {
967 + hdr_len = IW_EV_LCP_LEN + extra_size;
970 + hdr_len = IW_EV_POINT_LEN;
973 + /* Extract fixed header from request. This is properly aligned. */
974 + wrqu = &request->u;
976 + /* Check if wrqu is complete */
977 + if(request_len < hdr_len) {
978 +#ifdef WE_RTNETLINK_DEBUG
980 + "%s (WE.r) : Wireless request too short (%d)\n",
981 + dev->name, request_len);
982 +#endif /* WE_RTNETLINK_DEBUG */
986 + /* Prepare the call */
990 + /* Check if we have a pointer to user space data or not. */
991 + if(extra_size == 0) {
993 + /* No extra arguments. Trivial to handle */
994 + ret = handler(dev, &info, wrqu, (char *) wrqu);
999 + /* Put wrqu in the right place (skip pointer) */
1000 + memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
1001 + wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1003 + /* Does it fits within bounds ? */
1004 + if(wrqu_point.data.length > (descr->set_args &
1005 + IW_PRIV_SIZE_MASK))
1008 + /* Real length of payload */
1009 + extra_len = adjust_priv_size(descr->set_args, &wrqu_point);
1011 + /* Check if request is self consistent */
1012 + if((request_len - hdr_len) < extra_len) {
1013 +#ifdef WE_RTNETLINK_DEBUG
1014 + printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
1015 + dev->name, extra_size);
1016 +#endif /* WE_RTNETLINK_DEBUG */
1020 +#ifdef WE_RTNETLINK_DEBUG
1021 + printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
1022 + dev->name, extra_size);
1023 +#endif /* WE_RTNETLINK_DEBUG */
1025 + /* Always allocate for max space. Easier, and won't last
1027 + extra = kmalloc(extra_size, GFP_KERNEL);
1028 + if (extra == NULL)
1031 + /* Copy extra in aligned buffer */
1032 + memcpy(extra, ((char *) request) + hdr_len, extra_len);
1034 + /* Call the handler */
1035 + ret = handler(dev, &info, &wrqu_point, extra);
1037 + /* Cleanup - I told you it wasn't that long ;-) */
1041 + /* Call commit handler if needed and defined */
1042 + if(ret == -EIWCOMMIT)
1043 + ret = call_commit_handler(dev);
1048 +/* ---------------------------------------------------------------- */
1050 + * Main RtNetlink dispatcher. Called from the main networking code
1051 + * (do_getlink() in net/core/rtnetlink.c).
1052 + * Check the type of Request and call the appropriate wrapper...
1054 +int wireless_rtnetlink_get(struct net_device * dev,
1060 + struct iw_event * request = (struct iw_event *) data;
1061 + iw_handler handler;
1063 + /* Check length */
1064 + if(len < IW_EV_LCP_LEN) {
1065 + printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
1070 + /* ReCheck length (len may have padding) */
1071 + if(request->len > len) {
1072 + printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
1073 + dev->name, request->len, len);
1077 + /* Only accept GET requests in here */
1078 + if(!IW_IS_GET(request->cmd))
1079 + return -EOPNOTSUPP;
1081 + /* Special cases */
1082 + if(request->cmd == SIOCGIWSTATS)
1083 + /* Get Wireless Stats */
1084 + return rtnetlink_standard_get(dev,
1087 + &iw_handler_get_iwstats,
1089 + if(request->cmd == SIOCGIWPRIV) {
1090 + /* Check if we have some wireless handlers defined */
1091 + if(dev->wireless_handlers == NULL)
1092 + return -EOPNOTSUPP;
1093 + /* Get Wireless Stats */
1094 + return rtnetlink_standard_get(dev,
1097 + &iw_handler_get_private,
1102 + if (!netif_device_present(dev))
1105 + /* Try to find the handler */
1106 + handler = get_handler(dev, request->cmd);
1107 + if(handler != NULL) {
1108 + /* Standard and private are not the same */
1109 + if(request->cmd < SIOCIWFIRSTPRIV)
1110 + return rtnetlink_standard_get(dev,
1116 + return rtnetlink_private_get(dev,
1123 + return -EOPNOTSUPP;
1126 +/* ---------------------------------------------------------------- */
1128 + * Main RtNetlink dispatcher. Called from the main networking code
1129 + * (do_setlink() in net/core/rtnetlink.c).
1130 + * Check the type of Request and call the appropriate wrapper...
1132 +int wireless_rtnetlink_set(struct net_device * dev,
1136 + struct iw_event * request = (struct iw_event *) data;
1137 + iw_handler handler;
1139 + /* Check length */
1140 + if(len < IW_EV_LCP_LEN) {
1141 + printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
1146 + /* ReCheck length (len may have padding) */
1147 + if(request->len > len) {
1148 + printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
1149 + dev->name, request->len, len);
1153 + /* Only accept SET requests in here */
1154 + if(!IW_IS_SET(request->cmd))
1155 + return -EOPNOTSUPP;
1158 + if (!netif_device_present(dev))
1161 + /* New driver API : try to find the handler */
1162 + handler = get_handler(dev, request->cmd);
1163 + if(handler != NULL) {
1164 + /* Standard and private are not the same */
1165 + if(request->cmd < SIOCIWFIRSTPRIV)
1166 + return rtnetlink_standard_set(dev,
1171 + return rtnetlink_private_set(dev,
1177 + return -EOPNOTSUPP;
1179 +#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
1182 /************************* EVENT PROCESSING *************************/
1184 * Process events generated by the wireless layer or the driver.
1185 * Most often, the event will be propagated through rtnetlink
1188 -#ifdef WE_EVENT_NETLINK
1189 -/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
1190 - * It is declared in <linux/rtnetlink.h> */
1192 +#ifdef WE_EVENT_RTNETLINK
1193 /* ---------------------------------------------------------------- */
1195 * Fill a rtnetlink message with our event data.
1196 @@ -1121,12 +1857,11 @@ static inline int rtnetlink_fill_iwinfo(
1198 r->ifi_type = dev->type;
1199 r->ifi_index = dev->ifindex;
1200 - r->ifi_flags = dev->flags;
1201 + r->ifi_flags = dev_get_flags(dev);
1202 r->ifi_change = 0; /* Wireless changes don't affect those flags */
1204 /* Add the wireless events in the netlink packet */
1205 - RTA_PUT(skb, IFLA_WIRELESS,
1206 - event_len, event);
1207 + RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
1209 nlh->nlmsg_len = skb->tail - b;
1211 @@ -1163,7 +1898,7 @@ static inline void rtmsg_iwinfo(struct n
1212 NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
1213 netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC);
1215 -#endif /* WE_EVENT_NETLINK */
1216 +#endif /* WE_EVENT_RTNETLINK */
1218 /* ---------------------------------------------------------------- */
1220 @@ -1255,10 +1990,10 @@ void wireless_send_event(struct net_devi
1222 memcpy(((char *) event) + hdr_len, extra, extra_len);
1224 -#ifdef WE_EVENT_NETLINK
1225 - /* rtnetlink event channel */
1226 +#ifdef WE_EVENT_RTNETLINK
1227 + /* Send via the RtNetlink event channel */
1228 rtmsg_iwinfo(dev, (char *) event, event_len);
1229 -#endif /* WE_EVENT_NETLINK */
1230 +#endif /* WE_EVENT_RTNETLINK */