diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h --- linux/include/linux-w13/rtnetlink.h Thu Jun 6 14:44:08 2002 +++ linux/include/linux/rtnetlink.h Thu Jun 6 15:47:44 2002 @@ -440,12 +440,14 @@ enum #define IFLA_COST IFLA_COST IFLA_PRIORITY, #define IFLA_PRIORITY IFLA_PRIORITY - IFLA_MASTER + IFLA_MASTER, #define IFLA_MASTER IFLA_MASTER + IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ +#define IFLA_WIRELESS IFLA_WIRELESS }; -#define IFLA_MAX IFLA_MASTER +#define IFLA_MAX IFLA_WIRELESS #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h --- linux/include/linux-w13/wireless.h Thu Jun 6 15:00:28 2002 +++ linux/include/linux/wireless.h Thu Jun 6 15:47:44 2002 @@ -1,10 +1,10 @@ /* * This file define a set of standard wireless extensions * - * Version : 13 6.12.01 + * Version : 14 25.1.02 * * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. */ #ifndef _LINUX_WIRELESS_H @@ -40,7 +40,7 @@ * # include/linux/netdevice.h (one place) * # include/linux/proc_fs.h (one place) * - * New driver API (2001 -> onward) : + * New driver API (2002 -> onward) : * ------------------------------- * This file is only concerned with the user space API and common definitions. * The new driver API is defined and documented in : @@ -49,6 +49,11 @@ * Note as well that /proc/net/wireless implementation has now moved in : * # include/linux/wireless.c * + * Wireless Events (2002 -> onward) : + * -------------------------------- + * Events are defined at the end of this file, and implemented in : + * # include/linux/wireless.c + * * Other comments : * -------------- * Do not add here things that are redundant with other mechanisms @@ -75,7 +80,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 13 +#define WIRELESS_EXT 14 /* * Changes : @@ -141,6 +146,13 @@ * - Document creation of new driver API. * - Extract union iwreq_data from struct iwreq (for new driver API). * - Rename SIOCSIWNAME as SIOCSIWCOMMIT + * + * V13 to V14 + * ---------- + * - Wireless Events support : define struct iw_event + * - Define additional specific event numbers + * - Add "addr" and "param" fields in union iwreq_data + * - AP scanning stuff (SIOCSIWSCAN and friends) */ /**************************** CONSTANTS ****************************/ @@ -175,6 +187,8 @@ #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ +#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ +#define SIOCGIWSCAN 0x8B19 /* get scanning results */ /* 802.11 specific support */ #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ @@ -238,6 +252,15 @@ #define IW_IS_SET(cmd) (!((cmd) & 0x1)) #define IW_IS_GET(cmd) ((cmd) & 0x1) +/* ----------------------- WIRELESS EVENTS ----------------------- */ +/* Those are *NOT* ioctls, do not issue request on them !!! */ +/* Most events use the same identifier as ioctl requests */ + +#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ +#define IWEVQUAL 0x8C01 /* Quality part of statistics */ + +#define IWEVFIRST 0x8C00 + /* ------------------------- PRIVATE INFO ------------------------- */ /* * The following is used with SIOCGIWPRIV. It allow a driver to define @@ -340,6 +363,19 @@ #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ +/* Scanning request flags */ +#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ +#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ +#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ +#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ +#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ +#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ +#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ +#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ +#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ +/* Maximum size of returned data */ +#define IW_SCAN_MAX_DATA 4096 /* In bytes */ + /****************************** TYPES ******************************/ /* --------------------------- SUBTYPES --------------------------- */ @@ -466,9 +502,12 @@ union iwreq_data struct iw_point encoding; /* Encoding stuff : tokens */ struct iw_param power; /* PM duration/timeout */ + struct iw_quality qual; /* Quality part of statistics */ struct sockaddr ap_addr; /* Access point address */ + struct sockaddr addr; /* Destination address (hw) */ + struct iw_param param; /* Other small parameters */ struct iw_point data; /* Other large parameters */ }; @@ -595,5 +634,36 @@ struct iw_priv_args __u16 get_args; /* Type and number of args */ char name[IFNAMSIZ]; /* Name of the extension */ }; + +/* ----------------------- WIRELESS EVENTS ----------------------- */ +/* + * Wireless events are carried through the rtnetlink socket to user + * space. They are encapsulated in the IFLA_WIRELESS field of + * a RTM_NEWLINK message. + */ + +/* + * A Wireless Event. Contains basically the same data as the ioctl... + */ +struct iw_event +{ + __u16 len; /* Real lenght of this stuff */ + __u16 cmd; /* Wireless IOCTL */ + union iwreq_data u; /* IOCTL fixed payload */ +}; + +/* Size of the Event prefix (including padding and alignement junk) */ +#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) +/* Size of the various events */ +#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) +#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) +#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) +#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point)) +#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) +#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) +#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) + +/* Note : in the case of iw_point, the extra data will come at the + * end of the event */ #endif /* _LINUX_WIRELESS_H */ diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h --- linux/include/net-w13/iw_handler.h Thu Jun 6 15:06:16 2002 +++ linux/include/net/iw_handler.h Thu Jun 6 15:48:06 2002 @@ -1,10 +1,10 @@ /* * This file define the new driver API for Wireless Extensions * - * Version : 2 6.12.01 + * Version : 3 17.1.02 * * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. + * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. */ #ifndef _IW_HANDLER_H @@ -33,7 +33,7 @@ * o The user space interface is tied to ioctl because of the use * copy_to/from_user. * - * New driver API (2001 -> onward) : + * New driver API (2002 -> onward) : * ------------------------------- * The new driver API is just a bunch of standard functions (handlers), * each handling a specific Wireless Extension. The driver just export @@ -206,7 +206,18 @@ * will be needed... * I just plan to increment with each new version. */ -#define IW_HANDLER_VERSION 2 +#define IW_HANDLER_VERSION 3 + +/* + * Changes : + * + * V2 to V3 + * -------- + * - Move event definition in + * - Add Wireless Event support : + * o wireless_send_event() prototype + * o iwe_stream_add_event/point() inline functions + */ /**************************** CONSTANTS ****************************/ @@ -225,6 +236,7 @@ #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ +#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ /* Handling flags */ /* Most are not implemented. I just use them as a reminder of some @@ -233,7 +245,8 @@ /* Wrapper level flags */ #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ -#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ +#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ + /* SET : Omit payload from generated iwevent */ /* Driver level flags */ #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ @@ -303,25 +316,6 @@ struct iw_handler_def * 'struct net_device' to here, to minimise bloat. */ }; -/* ----------------------- WIRELESS EVENTS ----------------------- */ -/* - * Currently we don't support events, so let's just plan for the - * future... - */ - -/* - * A Wireless Event. - */ -// How do we define short header ? We don't want a flag on length. -// Probably a flag on event ? Highest bit to zero... -struct iw_event -{ - __u16 length; /* Lenght of this stuff */ - __u16 event; /* Wireless IOCTL */ - union iwreq_data header; /* IOCTL fixed payload */ - char extra[0]; /* Optional IOCTL data */ -}; - /* ---------------------- IOCTL DESCRIPTION ---------------------- */ /* * One of the main goal of the new interface is to deal entirely with @@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); /* Second : functions that may be called by driver modules */ -/* None yet */ -#endif /* _LINUX_WIRELESS_H */ +/* Send a single event to user space */ +extern void wireless_send_event(struct net_device * dev, + unsigned int cmd, + union iwreq_data * wrqu, + char * extra); + +/* We may need a function to send a stream of events to user space. + * More on that later... */ + +/************************* INLINE FUNTIONS *************************/ +/* + * Function that are so simple that it's more efficient inlining them + */ + +/*------------------------------------------------------------------*/ +/* + * Wrapper to add an Wireless Event to a stream of events. + */ +static inline char * +iwe_stream_add_event(char * stream, /* Stream of events */ + char * ends, /* End of stream */ + struct iw_event *iwe, /* Payload */ + int event_len) /* Real size of payload */ +{ + /* Check if it's possible */ + if((stream + event_len) < ends) { + iwe->len = event_len; + memcpy(stream, (char *) iwe, event_len); + stream += event_len; + } + return stream; +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper to add an short Wireless Event containing a pointer to a + * stream of events. + */ +static inline char * +iwe_stream_add_point(char * stream, /* Stream of events */ + char * ends, /* End of stream */ + struct iw_event *iwe, /* Payload */ + char * extra) +{ + int event_len = IW_EV_POINT_LEN + iwe->u.data.length; + /* Check if it's possible */ + if((stream + event_len) < ends) { + iwe->len = event_len; + memcpy(stream, (char *) iwe, IW_EV_POINT_LEN); + memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); + stream += event_len; + } + return stream; +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper to add a value to a Wireless Event in a stream of events. + * Be careful, this one is tricky to use properly : + * At the first run, you need to have (value = event + IW_EV_LCP_LEN). + */ +static inline char * +iwe_stream_add_value(char * event, /* Event in the stream */ + char * value, /* Value in event */ + char * ends, /* End of stream */ + struct iw_event *iwe, /* Payload */ + int event_len) /* Real size of payload */ +{ + /* Don't duplicate LCP */ + event_len -= IW_EV_LCP_LEN; + + /* Check if it's possible */ + if((value + event_len) < ends) { + /* Add new value */ + memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); + value += event_len; + /* Patch LCP */ + iwe->len = value - event; + memcpy(event, (char *) iwe, IW_EV_LCP_LEN); + } + return value; +} + +#endif /* _IW_HANDLER_H */ diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c --- linux/net/netsyms-w13.c Thu Jun 6 15:46:34 2002 +++ linux/net/netsyms.c Thu Jun 6 15:47:44 2002 @@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf); EXPORT_SYMBOL(net_call_rx_atomic); EXPORT_SYMBOL(softnet_data); +#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) +/* Don't include the whole header mess for a single function */ +extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); +EXPORT_SYMBOL(wireless_send_event); +#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + #endif /* CONFIG_NET */ diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c --- linux/net/core/wireless-w13.c Thu Jun 6 15:46:45 2002 +++ linux/net/core/wireless.c Thu Jun 6 15:48:06 2002 @@ -2,7 +2,7 @@ * This file implement the Wireless Extensions APIs. * * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. * * (As all part of the Linux kernel, this file is GPL) */ @@ -25,6 +25,16 @@ * o Added iw_handler handling ;-) * o Added standard ioctl description * o Initial dumb commit strategy based on orinoco.c + * + * v3 - 19.12.01 - Jean II + * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call + * o Add event dispatcher function + * o Add event description + * o Propagate events as rtnetlink IFLA_WIRELESS option + * o Generate event on selected SET requests + * + * v4 - 18.04.01 - Jean II + * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 */ /***************************** INCLUDES *****************************/ @@ -33,6 +43,7 @@ #include /* Not needed ??? */ #include /* off_t */ #include /* struct ifreq, dev_get_by_name() */ +#include /* rtnetlink stuff */ #include /* Pretty obvious */ #include /* New driver API */ @@ -44,14 +55,23 @@ /* Debuging stuff */ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ +#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ + +/* Options */ +#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ +#define WE_SET_EVENT /* Generate an event on some set commands */ /************************* GLOBAL VARIABLES *************************/ /* * You should not use global variables, because or re-entrancy. * On our case, it's only const, so it's OK... */ +/* + * Meta-data about all the standard Wireless Extension request we + * know about. + */ static const struct iw_ioctl_description standard_ioctl[] = { - /* SIOCSIWCOMMIT (internal) */ + /* SIOCSIWCOMMIT */ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, /* SIOCGIWNAME */ { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, @@ -99,18 +119,18 @@ static const struct iw_ioctl_description { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, /* SIOCGIWAPLIST */ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, - /* -- hole -- */ - { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, - /* -- hole -- */ - { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCSIWSCAN */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + /* SIOCGIWSCAN */ + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0}, /* SIOCSIWESSID */ - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT}, /* SIOCGIWESSID */ - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP}, /* SIOCSIWNICKN */ - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, /* SIOCGIWNICKN */ - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, /* -- hole -- */ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, /* -- hole -- */ @@ -136,7 +156,7 @@ static const struct iw_ioctl_description /* SIOCGIWRETRY */ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, /* SIOCSIWENCODE */ - { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, /* SIOCGIWENCODE */ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, /* SIOCSIWPOWER */ @@ -144,9 +164,38 @@ static const struct iw_ioctl_description /* SIOCGIWPOWER */ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, }; +static const int standard_ioctl_num = (sizeof(standard_ioctl) / + sizeof(struct iw_ioctl_description)); + +/* + * Meta-data about all the additional standard Wireless Extension events + * we know about. + */ +static const struct iw_ioctl_description standard_event[] = { + /* IWEVTXDROP */ + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + /* IWEVQUAL */ + { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, +}; +static const int standard_event_num = (sizeof(standard_event) / + sizeof(struct iw_ioctl_description)); /* Size (in bytes) of the various private data types */ -char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; +static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; + +/* Size (in bytes) of various events */ +static const int event_type_size[] = { + IW_EV_LCP_LEN, + 0, + IW_EV_CHAR_LEN, + 0, + IW_EV_UINT_LEN, + IW_EV_FREQ_LEN, + IW_EV_POINT_LEN, /* Without variable payload */ + IW_EV_PARAM_LEN, + IW_EV_ADDR_LEN, + IW_EV_QUAL_LEN, +}; /************************ COMMON SUBROUTINES ************************/ /* @@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4, static inline iw_handler get_handler(struct net_device *dev, unsigned int cmd) { - unsigned int index; /* MUST be unsigned */ + /* Don't "optimise" the following variable, it will crash */ + unsigned int index; /* *MUST* be unsigned */ /* Check if we have some wireless handlers defined */ if(dev->wireless_handlers == NULL) @@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats stats->status, stats->qual.qual, stats->qual.updated & 1 ? '.' : ' ', - stats->qual.level, + ((__u8) stats->qual.level), stats->qual.updated & 2 ? '.' : ' ', - stats->qual.noise, + ((__u8) stats->qual.noise), stats->qual.updated & 4 ? '.' : ' ', stats->discard.nwid, stats->discard.code, @@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st int ret = -EINVAL; /* Get the description of the IOCTL */ + if((cmd - SIOCIWFIRST) >= standard_ioctl_num) + return -EOPNOTSUPP; descr = &(standard_ioctl[cmd - SIOCIWFIRST]); #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", + printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", ifr->ifr_name, cmd); - printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); + 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); #endif /* WE_IOCTL_DEBUG */ /* Prepare the call */ @@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st /* Check if we have a pointer to user space data or not */ if(descr->header_type != IW_HEADER_TYPE_POINT) { + /* No extra arguments. Trivial to handle */ ret = handler(dev, &info, &(iwr->u), NULL); + +#ifdef WE_SET_EVENT + /* Generate an event to notify listeners of the change */ + if((descr->flags & IW_DESCR_FLAG_EVENT) && + ((ret == 0) || (ret == -EIWCOMMIT))) + wireless_send_event(dev, cmd, &(iwr->u), NULL); +#endif /* WE_SET_EVENT */ } else { char * extra; int err; @@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st } #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "Malloc %d bytes\n", - descr->max_tokens * descr->token_size); + printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", + dev->name, descr->max_tokens * descr->token_size); #endif /* WE_IOCTL_DEBUG */ /* Always allocate for max space. Easier, and won't last @@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st return -EFAULT; } #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "Got %d bytes\n", + printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", + dev->name, iwr->u.data.length * descr->token_size); #endif /* WE_IOCTL_DEBUG */ } @@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st if (err) ret = -EFAULT; #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "Wrote %d bytes\n", + printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", + dev->name, iwr->u.data.length * descr->token_size); #endif /* WE_IOCTL_DEBUG */ } +#ifdef WE_SET_EVENT + /* Generate an event to notify listeners of the change */ + if((descr->flags & IW_DESCR_FLAG_EVENT) && + ((ret == 0) || (ret == -EIWCOMMIT))) { + if(descr->flags & IW_DESCR_FLAG_RESTRICT) + /* If the event is restricted, don't + * export the payload */ + wireless_send_event(dev, cmd, &(iwr->u), NULL); + else + wireless_send_event(dev, cmd, &(iwr->u), + extra); + } +#endif /* WE_SET_EVENT */ + /* Cleanup - I told you it wasn't that long ;-) */ kfree(extra); } @@ -558,11 +634,12 @@ static inline int ioctl_private_call(str } #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", + printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", ifr->ifr_name, cmd); if(descr) { - printk(KERN_DEBUG "Name %s, set %X, get %X\n", - descr->name, descr->set_args, descr->get_args); + printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", + dev->name, descr->name, + descr->set_args, descr->get_args); } #endif /* WE_IOCTL_DEBUG */ @@ -617,7 +694,8 @@ static inline int ioctl_private_call(str } #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); + printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", + dev->name, extra_size); #endif /* WE_IOCTL_DEBUG */ /* Always allocate for max space. Easier, and won't last @@ -636,7 +714,8 @@ static inline int ioctl_private_call(str return -EFAULT; } #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); + printk(KERN_DEBUG "%s (WE) : Got %d elem\n", + dev->name, iwr->u.data.length); #endif /* WE_IOCTL_DEBUG */ } @@ -650,8 +729,8 @@ static inline int ioctl_private_call(str if (err) ret = -EFAULT; #ifdef WE_IOCTL_DEBUG - printk(KERN_DEBUG "Wrote %d elem\n", - iwr->u.data.length); + printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", + dev->name, iwr->u.data.length); #endif /* WE_IOCTL_DEBUG */ } @@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq } /* Not reached */ return -EINVAL; +} + +/************************* EVENT PROCESSING *************************/ +/* + * Process events generated by the wireless layer or the driver. + * Most often, the event will be propagated through rtnetlink + */ + +#ifdef WE_EVENT_NETLINK +/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. + * It is declared in */ + +/* ---------------------------------------------------------------- */ +/* + * Fill a rtnetlink message with our event data. + * Note that we propage only the specified event and don't dump the + * current wireless config. Dumping the wireless config is far too + * expensive (for each parameter, the driver need to query the hardware). + */ +static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, + struct net_device * dev, + int type, + char * event, + int event_len) +{ + struct ifinfomsg *r; + struct nlmsghdr *nlh; + unsigned char *b = skb->tail; + + nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); + r = NLMSG_DATA(nlh); + r->ifi_family = AF_UNSPEC; + r->ifi_type = dev->type; + r->ifi_index = dev->ifindex; + r->ifi_flags = dev->flags; + r->ifi_change = 0; /* Wireless changes don't affect those flags */ + + /* Add the wireless events in the netlink packet */ + RTA_PUT(skb, IFLA_WIRELESS, + event_len, event); + + nlh->nlmsg_len = skb->tail - b; + return skb->len; + +nlmsg_failure: +rtattr_failure: + skb_trim(skb, b - skb->data); + return -1; +} + +/* ---------------------------------------------------------------- */ +/* + * Create and broadcast and send it on the standard rtnetlink socket + * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c + * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field + * within a RTM_NEWLINK event. + */ +static inline void rtmsg_iwinfo(struct net_device * dev, + char * event, + int event_len) +{ + struct sk_buff *skb; + int size = NLMSG_GOODSIZE; + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) + return; + + if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, + event, event_len) < 0) { + kfree_skb(skb); + return; + } + NETLINK_CB(skb).dst_groups = RTMGRP_LINK; + netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC); +} +#endif /* WE_EVENT_NETLINK */ + +/* ---------------------------------------------------------------- */ +/* + * Main event dispatcher. Called from other parts and drivers. + * Send the event on the apropriate channels. + * May be called from interrupt context. + */ +void wireless_send_event(struct net_device * dev, + unsigned int cmd, + union iwreq_data * wrqu, + char * extra) +{ + const struct iw_ioctl_description * descr = NULL; + int extra_len = 0; + struct iw_event *event; /* Mallocated whole event */ + int event_len; /* Its size */ + int hdr_len; /* Size of the event header */ + /* Don't "optimise" the following variable, it will crash */ + unsigned cmd_index; /* *MUST* be unsigned */ + + /* Get the description of the IOCTL */ + if(cmd <= SIOCIWLAST) { + cmd_index = cmd - SIOCIWFIRST; + if(cmd_index < standard_ioctl_num) + descr = &(standard_ioctl[cmd_index]); + } else { + cmd_index = cmd - IWEVFIRST; + if(cmd_index < standard_event_num) + descr = &(standard_event[cmd_index]); + } + /* Don't accept unknown events */ + if(descr == NULL) { + /* Note : we don't return an error to the driver, because + * the driver would not know what to do about it. It can't + * return an error to the user, because the event is not + * initiated by a user request. + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ + printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", + dev->name, cmd); + return; + } +#ifdef WE_EVENT_DEBUG + printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", + dev->name, cmd); + 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); +#endif /* WE_EVENT_DEBUG */ + + /* Check extra parameters and set extra_len */ + if(descr->header_type == IW_HEADER_TYPE_POINT) { + /* Check if number of token fits within bounds */ + if(wrqu->data.length > descr->max_tokens) { + printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); + return; + } + if(wrqu->data.length < descr->min_tokens) { + printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); + return; + } + /* Calculate extra_len - extra is NULL for restricted events */ + if(extra != NULL) + extra_len = wrqu->data.length * descr->token_size; +#ifdef WE_EVENT_DEBUG + printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); +#endif /* WE_EVENT_DEBUG */ + } + + /* Total length of the event */ + hdr_len = event_type_size[descr->header_type]; + event_len = hdr_len + extra_len; + +#ifdef WE_EVENT_DEBUG + printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); +#endif /* WE_EVENT_DEBUG */ + + /* Create temporary buffer to hold the event */ + event = kmalloc(event_len, GFP_ATOMIC); + if(event == NULL) + return; + + /* Fill event */ + event->len = event_len; + event->cmd = cmd; + memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); + if(extra != NULL) + memcpy(((char *) event) + hdr_len, extra, extra_len); + +#ifdef WE_EVENT_NETLINK + /* rtnetlink event channel */ + rtmsg_iwinfo(dev, (char *) event, event_len); +#endif /* WE_EVENT_NETLINK */ + + /* Cleanup */ + kfree(event); + + return; /* Always success, I guess ;-) */ }