]>
Commit | Line | Data |
---|---|---|
3bccf403 AM |
1 | diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h |
2 | --- linux/include/linux-w13/rtnetlink.h Thu Jun 6 14:44:08 2002 | |
3 | +++ linux/include/linux/rtnetlink.h Thu Jun 6 15:47:44 2002 | |
4 | @@ -440,12 +440,14 @@ enum | |
5 | #define IFLA_COST IFLA_COST | |
6 | IFLA_PRIORITY, | |
7 | #define IFLA_PRIORITY IFLA_PRIORITY | |
8 | - IFLA_MASTER | |
9 | + IFLA_MASTER, | |
10 | #define IFLA_MASTER IFLA_MASTER | |
11 | + IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ | |
12 | +#define IFLA_WIRELESS IFLA_WIRELESS | |
13 | }; | |
14 | ||
15 | ||
16 | -#define IFLA_MAX IFLA_MASTER | |
17 | +#define IFLA_MAX IFLA_WIRELESS | |
18 | ||
19 | #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) | |
20 | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) | |
21 | diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h | |
22 | --- linux/include/linux-w13/wireless.h Thu Jun 6 15:00:28 2002 | |
23 | +++ linux/include/linux/wireless.h Thu Jun 6 15:47:44 2002 | |
24 | @@ -1,10 +1,10 @@ | |
25 | /* | |
26 | * This file define a set of standard wireless extensions | |
27 | * | |
28 | - * Version : 13 6.12.01 | |
29 | + * Version : 14 25.1.02 | |
30 | * | |
31 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> | |
32 | - * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. | |
33 | + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. | |
34 | */ | |
35 | ||
36 | #ifndef _LINUX_WIRELESS_H | |
37 | @@ -40,7 +40,7 @@ | |
38 | * # include/linux/netdevice.h (one place) | |
39 | * # include/linux/proc_fs.h (one place) | |
40 | * | |
41 | - * New driver API (2001 -> onward) : | |
42 | + * New driver API (2002 -> onward) : | |
43 | * ------------------------------- | |
44 | * This file is only concerned with the user space API and common definitions. | |
45 | * The new driver API is defined and documented in : | |
46 | @@ -49,6 +49,11 @@ | |
47 | * Note as well that /proc/net/wireless implementation has now moved in : | |
48 | * # include/linux/wireless.c | |
49 | * | |
50 | + * Wireless Events (2002 -> onward) : | |
51 | + * -------------------------------- | |
52 | + * Events are defined at the end of this file, and implemented in : | |
53 | + * # include/linux/wireless.c | |
54 | + * | |
55 | * Other comments : | |
56 | * -------------- | |
57 | * Do not add here things that are redundant with other mechanisms | |
58 | @@ -75,7 +80,7 @@ | |
59 | * (there is some stuff that will be added in the future...) | |
60 | * I just plan to increment with each new version. | |
61 | */ | |
62 | -#define WIRELESS_EXT 13 | |
63 | +#define WIRELESS_EXT 14 | |
64 | ||
65 | /* | |
66 | * Changes : | |
67 | @@ -141,6 +146,13 @@ | |
68 | * - Document creation of new driver API. | |
69 | * - Extract union iwreq_data from struct iwreq (for new driver API). | |
70 | * - Rename SIOCSIWNAME as SIOCSIWCOMMIT | |
71 | + * | |
72 | + * V13 to V14 | |
73 | + * ---------- | |
74 | + * - Wireless Events support : define struct iw_event | |
75 | + * - Define additional specific event numbers | |
76 | + * - Add "addr" and "param" fields in union iwreq_data | |
77 | + * - AP scanning stuff (SIOCSIWSCAN and friends) | |
78 | */ | |
79 | ||
80 | /**************************** CONSTANTS ****************************/ | |
81 | @@ -175,6 +187,8 @@ | |
82 | #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ | |
83 | #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ | |
84 | #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ | |
85 | +#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ | |
86 | +#define SIOCGIWSCAN 0x8B19 /* get scanning results */ | |
87 | ||
88 | /* 802.11 specific support */ | |
89 | #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ | |
90 | @@ -238,6 +252,15 @@ | |
91 | #define IW_IS_SET(cmd) (!((cmd) & 0x1)) | |
92 | #define IW_IS_GET(cmd) ((cmd) & 0x1) | |
93 | ||
94 | +/* ----------------------- WIRELESS EVENTS ----------------------- */ | |
95 | +/* Those are *NOT* ioctls, do not issue request on them !!! */ | |
96 | +/* Most events use the same identifier as ioctl requests */ | |
97 | + | |
98 | +#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ | |
99 | +#define IWEVQUAL 0x8C01 /* Quality part of statistics */ | |
100 | + | |
101 | +#define IWEVFIRST 0x8C00 | |
102 | + | |
103 | /* ------------------------- PRIVATE INFO ------------------------- */ | |
104 | /* | |
105 | * The following is used with SIOCGIWPRIV. It allow a driver to define | |
106 | @@ -340,6 +363,19 @@ | |
107 | #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ | |
108 | #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ | |
109 | ||
110 | +/* Scanning request flags */ | |
111 | +#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ | |
112 | +#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ | |
113 | +#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ | |
114 | +#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ | |
115 | +#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ | |
116 | +#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ | |
117 | +#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ | |
118 | +#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ | |
119 | +#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ | |
120 | +/* Maximum size of returned data */ | |
121 | +#define IW_SCAN_MAX_DATA 4096 /* In bytes */ | |
122 | + | |
123 | /****************************** TYPES ******************************/ | |
124 | ||
125 | /* --------------------------- SUBTYPES --------------------------- */ | |
126 | @@ -466,9 +502,12 @@ union iwreq_data | |
127 | ||
128 | struct iw_point encoding; /* Encoding stuff : tokens */ | |
129 | struct iw_param power; /* PM duration/timeout */ | |
130 | + struct iw_quality qual; /* Quality part of statistics */ | |
131 | ||
132 | struct sockaddr ap_addr; /* Access point address */ | |
133 | + struct sockaddr addr; /* Destination address (hw) */ | |
134 | ||
135 | + struct iw_param param; /* Other small parameters */ | |
136 | struct iw_point data; /* Other large parameters */ | |
137 | }; | |
138 | ||
139 | @@ -595,5 +634,36 @@ struct iw_priv_args | |
140 | __u16 get_args; /* Type and number of args */ | |
141 | char name[IFNAMSIZ]; /* Name of the extension */ | |
142 | }; | |
143 | + | |
144 | +/* ----------------------- WIRELESS EVENTS ----------------------- */ | |
145 | +/* | |
146 | + * Wireless events are carried through the rtnetlink socket to user | |
147 | + * space. They are encapsulated in the IFLA_WIRELESS field of | |
148 | + * a RTM_NEWLINK message. | |
149 | + */ | |
150 | + | |
151 | +/* | |
152 | + * A Wireless Event. Contains basically the same data as the ioctl... | |
153 | + */ | |
154 | +struct iw_event | |
155 | +{ | |
156 | + __u16 len; /* Real lenght of this stuff */ | |
157 | + __u16 cmd; /* Wireless IOCTL */ | |
158 | + union iwreq_data u; /* IOCTL fixed payload */ | |
159 | +}; | |
160 | + | |
161 | +/* Size of the Event prefix (including padding and alignement junk) */ | |
162 | +#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) | |
163 | +/* Size of the various events */ | |
164 | +#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) | |
165 | +#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) | |
166 | +#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) | |
167 | +#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point)) | |
168 | +#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) | |
169 | +#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) | |
170 | +#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) | |
171 | + | |
172 | +/* Note : in the case of iw_point, the extra data will come at the | |
173 | + * end of the event */ | |
174 | ||
175 | #endif /* _LINUX_WIRELESS_H */ | |
176 | diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h | |
177 | --- linux/include/net-w13/iw_handler.h Thu Jun 6 15:06:16 2002 | |
178 | +++ linux/include/net/iw_handler.h Thu Jun 6 15:48:06 2002 | |
179 | @@ -1,10 +1,10 @@ | |
180 | /* | |
181 | * This file define the new driver API for Wireless Extensions | |
182 | * | |
183 | - * Version : 2 6.12.01 | |
184 | + * Version : 3 17.1.02 | |
185 | * | |
186 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> | |
187 | - * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. | |
188 | + * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. | |
189 | */ | |
190 | ||
191 | #ifndef _IW_HANDLER_H | |
192 | @@ -33,7 +33,7 @@ | |
193 | * o The user space interface is tied to ioctl because of the use | |
194 | * copy_to/from_user. | |
195 | * | |
196 | - * New driver API (2001 -> onward) : | |
197 | + * New driver API (2002 -> onward) : | |
198 | * ------------------------------- | |
199 | * The new driver API is just a bunch of standard functions (handlers), | |
200 | * each handling a specific Wireless Extension. The driver just export | |
201 | @@ -206,7 +206,18 @@ | |
202 | * will be needed... | |
203 | * I just plan to increment with each new version. | |
204 | */ | |
205 | -#define IW_HANDLER_VERSION 2 | |
206 | +#define IW_HANDLER_VERSION 3 | |
207 | + | |
208 | +/* | |
209 | + * Changes : | |
210 | + * | |
211 | + * V2 to V3 | |
212 | + * -------- | |
213 | + * - Move event definition in <linux/wireless.h> | |
214 | + * - Add Wireless Event support : | |
215 | + * o wireless_send_event() prototype | |
216 | + * o iwe_stream_add_event/point() inline functions | |
217 | + */ | |
218 | ||
219 | /**************************** CONSTANTS ****************************/ | |
220 | ||
221 | @@ -225,6 +236,7 @@ | |
222 | #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ | |
223 | #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ | |
224 | #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ | |
225 | +#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ | |
226 | ||
227 | /* Handling flags */ | |
228 | /* Most are not implemented. I just use them as a reminder of some | |
229 | @@ -233,7 +245,8 @@ | |
230 | /* Wrapper level flags */ | |
231 | #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ | |
232 | #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ | |
233 | -#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ | |
234 | +#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ | |
235 | + /* SET : Omit payload from generated iwevent */ | |
236 | /* Driver level flags */ | |
237 | #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ | |
238 | ||
239 | @@ -303,25 +316,6 @@ struct iw_handler_def | |
240 | * 'struct net_device' to here, to minimise bloat. */ | |
241 | }; | |
242 | ||
243 | -/* ----------------------- WIRELESS EVENTS ----------------------- */ | |
244 | -/* | |
245 | - * Currently we don't support events, so let's just plan for the | |
246 | - * future... | |
247 | - */ | |
248 | - | |
249 | -/* | |
250 | - * A Wireless Event. | |
251 | - */ | |
252 | -// How do we define short header ? We don't want a flag on length. | |
253 | -// Probably a flag on event ? Highest bit to zero... | |
254 | -struct iw_event | |
255 | -{ | |
256 | - __u16 length; /* Lenght of this stuff */ | |
257 | - __u16 event; /* Wireless IOCTL */ | |
258 | - union iwreq_data header; /* IOCTL fixed payload */ | |
259 | - char extra[0]; /* Optional IOCTL data */ | |
260 | -}; | |
261 | - | |
262 | /* ---------------------- IOCTL DESCRIPTION ---------------------- */ | |
263 | /* | |
264 | * One of the main goal of the new interface is to deal entirely with | |
265 | @@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * | |
266 | extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); | |
267 | ||
268 | /* Second : functions that may be called by driver modules */ | |
269 | -/* None yet */ | |
270 | ||
271 | -#endif /* _LINUX_WIRELESS_H */ | |
272 | +/* Send a single event to user space */ | |
273 | +extern void wireless_send_event(struct net_device * dev, | |
274 | + unsigned int cmd, | |
275 | + union iwreq_data * wrqu, | |
276 | + char * extra); | |
277 | + | |
278 | +/* We may need a function to send a stream of events to user space. | |
279 | + * More on that later... */ | |
280 | + | |
281 | +/************************* INLINE FUNTIONS *************************/ | |
282 | +/* | |
283 | + * Function that are so simple that it's more efficient inlining them | |
284 | + */ | |
285 | + | |
286 | +/*------------------------------------------------------------------*/ | |
287 | +/* | |
288 | + * Wrapper to add an Wireless Event to a stream of events. | |
289 | + */ | |
290 | +static inline char * | |
291 | +iwe_stream_add_event(char * stream, /* Stream of events */ | |
292 | + char * ends, /* End of stream */ | |
293 | + struct iw_event *iwe, /* Payload */ | |
294 | + int event_len) /* Real size of payload */ | |
295 | +{ | |
296 | + /* Check if it's possible */ | |
297 | + if((stream + event_len) < ends) { | |
298 | + iwe->len = event_len; | |
299 | + memcpy(stream, (char *) iwe, event_len); | |
300 | + stream += event_len; | |
301 | + } | |
302 | + return stream; | |
303 | +} | |
304 | + | |
305 | +/*------------------------------------------------------------------*/ | |
306 | +/* | |
307 | + * Wrapper to add an short Wireless Event containing a pointer to a | |
308 | + * stream of events. | |
309 | + */ | |
310 | +static inline char * | |
311 | +iwe_stream_add_point(char * stream, /* Stream of events */ | |
312 | + char * ends, /* End of stream */ | |
313 | + struct iw_event *iwe, /* Payload */ | |
314 | + char * extra) | |
315 | +{ | |
316 | + int event_len = IW_EV_POINT_LEN + iwe->u.data.length; | |
317 | + /* Check if it's possible */ | |
318 | + if((stream + event_len) < ends) { | |
319 | + iwe->len = event_len; | |
320 | + memcpy(stream, (char *) iwe, IW_EV_POINT_LEN); | |
321 | + memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); | |
322 | + stream += event_len; | |
323 | + } | |
324 | + return stream; | |
325 | +} | |
326 | + | |
327 | +/*------------------------------------------------------------------*/ | |
328 | +/* | |
329 | + * Wrapper to add a value to a Wireless Event in a stream of events. | |
330 | + * Be careful, this one is tricky to use properly : | |
331 | + * At the first run, you need to have (value = event + IW_EV_LCP_LEN). | |
332 | + */ | |
333 | +static inline char * | |
334 | +iwe_stream_add_value(char * event, /* Event in the stream */ | |
335 | + char * value, /* Value in event */ | |
336 | + char * ends, /* End of stream */ | |
337 | + struct iw_event *iwe, /* Payload */ | |
338 | + int event_len) /* Real size of payload */ | |
339 | +{ | |
340 | + /* Don't duplicate LCP */ | |
341 | + event_len -= IW_EV_LCP_LEN; | |
342 | + | |
343 | + /* Check if it's possible */ | |
344 | + if((value + event_len) < ends) { | |
345 | + /* Add new value */ | |
346 | + memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); | |
347 | + value += event_len; | |
348 | + /* Patch LCP */ | |
349 | + iwe->len = value - event; | |
350 | + memcpy(event, (char *) iwe, IW_EV_LCP_LEN); | |
351 | + } | |
352 | + return value; | |
353 | +} | |
354 | + | |
355 | +#endif /* _IW_HANDLER_H */ | |
356 | diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c | |
357 | --- linux/net/netsyms-w13.c Thu Jun 6 15:46:34 2002 | |
358 | +++ linux/net/netsyms.c Thu Jun 6 15:47:44 2002 | |
359 | @@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf); | |
360 | EXPORT_SYMBOL(net_call_rx_atomic); | |
361 | EXPORT_SYMBOL(softnet_data); | |
362 | ||
363 | +#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) | |
364 | +/* Don't include the whole header mess for a single function */ | |
365 | +extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); | |
366 | +EXPORT_SYMBOL(wireless_send_event); | |
367 | +#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ | |
368 | + | |
369 | #endif /* CONFIG_NET */ | |
370 | diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c | |
371 | --- linux/net/core/wireless-w13.c Thu Jun 6 15:46:45 2002 | |
372 | +++ linux/net/core/wireless.c Thu Jun 6 15:48:06 2002 | |
373 | @@ -2,7 +2,7 @@ | |
374 | * This file implement the Wireless Extensions APIs. | |
375 | * | |
376 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> | |
377 | - * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. | |
378 | + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. | |
379 | * | |
380 | * (As all part of the Linux kernel, this file is GPL) | |
381 | */ | |
382 | @@ -25,6 +25,16 @@ | |
383 | * o Added iw_handler handling ;-) | |
384 | * o Added standard ioctl description | |
385 | * o Initial dumb commit strategy based on orinoco.c | |
386 | + * | |
387 | + * v3 - 19.12.01 - Jean II | |
388 | + * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call | |
389 | + * o Add event dispatcher function | |
390 | + * o Add event description | |
391 | + * o Propagate events as rtnetlink IFLA_WIRELESS option | |
392 | + * o Generate event on selected SET requests | |
393 | + * | |
394 | + * v4 - 18.04.01 - Jean II | |
395 | + * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 | |
396 | */ | |
397 | ||
398 | /***************************** INCLUDES *****************************/ | |
399 | @@ -33,6 +43,7 @@ | |
400 | #include <linux/config.h> /* Not needed ??? */ | |
401 | #include <linux/types.h> /* off_t */ | |
402 | #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ | |
403 | +#include <linux/rtnetlink.h> /* rtnetlink stuff */ | |
404 | ||
405 | #include <linux/wireless.h> /* Pretty obvious */ | |
406 | #include <net/iw_handler.h> /* New driver API */ | |
407 | @@ -44,14 +55,23 @@ | |
408 | ||
409 | /* Debuging stuff */ | |
410 | #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ | |
411 | +#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ | |
412 | + | |
413 | +/* Options */ | |
414 | +#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ | |
415 | +#define WE_SET_EVENT /* Generate an event on some set commands */ | |
416 | ||
417 | /************************* GLOBAL VARIABLES *************************/ | |
418 | /* | |
419 | * You should not use global variables, because or re-entrancy. | |
420 | * On our case, it's only const, so it's OK... | |
421 | */ | |
422 | +/* | |
423 | + * Meta-data about all the standard Wireless Extension request we | |
424 | + * know about. | |
425 | + */ | |
426 | static const struct iw_ioctl_description standard_ioctl[] = { | |
427 | - /* SIOCSIWCOMMIT (internal) */ | |
428 | + /* SIOCSIWCOMMIT */ | |
429 | { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, | |
430 | /* SIOCGIWNAME */ | |
431 | { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, | |
432 | @@ -99,18 +119,18 @@ static const struct iw_ioctl_description | |
433 | { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, | |
434 | /* SIOCGIWAPLIST */ | |
435 | { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, | |
436 | - /* -- hole -- */ | |
437 | - { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, | |
438 | - /* -- hole -- */ | |
439 | - { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, | |
440 | + /* SIOCSIWSCAN */ | |
441 | + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, | |
442 | + /* SIOCGIWSCAN */ | |
443 | + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0}, | |
444 | /* SIOCSIWESSID */ | |
445 | - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, | |
446 | + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT}, | |
447 | /* SIOCGIWESSID */ | |
448 | - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, | |
449 | + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP}, | |
450 | /* SIOCSIWNICKN */ | |
451 | - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, | |
452 | + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, | |
453 | /* SIOCGIWNICKN */ | |
454 | - { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, | |
455 | + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, | |
456 | /* -- hole -- */ | |
457 | { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, | |
458 | /* -- hole -- */ | |
459 | @@ -136,7 +156,7 @@ static const struct iw_ioctl_description | |
460 | /* SIOCGIWRETRY */ | |
461 | { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, | |
462 | /* SIOCSIWENCODE */ | |
463 | - { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, | |
464 | + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, | |
465 | /* SIOCGIWENCODE */ | |
466 | { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, | |
467 | /* SIOCSIWPOWER */ | |
468 | @@ -144,9 +164,38 @@ static const struct iw_ioctl_description | |
469 | /* SIOCGIWPOWER */ | |
470 | { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, | |
471 | }; | |
472 | +static const int standard_ioctl_num = (sizeof(standard_ioctl) / | |
473 | + sizeof(struct iw_ioctl_description)); | |
474 | + | |
475 | +/* | |
476 | + * Meta-data about all the additional standard Wireless Extension events | |
477 | + * we know about. | |
478 | + */ | |
479 | +static const struct iw_ioctl_description standard_event[] = { | |
480 | + /* IWEVTXDROP */ | |
481 | + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, | |
482 | + /* IWEVQUAL */ | |
483 | + { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, | |
484 | +}; | |
485 | +static const int standard_event_num = (sizeof(standard_event) / | |
486 | + sizeof(struct iw_ioctl_description)); | |
487 | ||
488 | /* Size (in bytes) of the various private data types */ | |
489 | -char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; | |
490 | +static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; | |
491 | + | |
492 | +/* Size (in bytes) of various events */ | |
493 | +static const int event_type_size[] = { | |
494 | + IW_EV_LCP_LEN, | |
495 | + 0, | |
496 | + IW_EV_CHAR_LEN, | |
497 | + 0, | |
498 | + IW_EV_UINT_LEN, | |
499 | + IW_EV_FREQ_LEN, | |
500 | + IW_EV_POINT_LEN, /* Without variable payload */ | |
501 | + IW_EV_PARAM_LEN, | |
502 | + IW_EV_ADDR_LEN, | |
503 | + IW_EV_QUAL_LEN, | |
504 | +}; | |
505 | ||
506 | /************************ COMMON SUBROUTINES ************************/ | |
507 | /* | |
508 | @@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4, | |
509 | static inline iw_handler get_handler(struct net_device *dev, | |
510 | unsigned int cmd) | |
511 | { | |
512 | - unsigned int index; /* MUST be unsigned */ | |
513 | + /* Don't "optimise" the following variable, it will crash */ | |
514 | + unsigned int index; /* *MUST* be unsigned */ | |
515 | ||
516 | /* Check if we have some wireless handlers defined */ | |
517 | if(dev->wireless_handlers == NULL) | |
518 | @@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats | |
519 | stats->status, | |
520 | stats->qual.qual, | |
521 | stats->qual.updated & 1 ? '.' : ' ', | |
522 | - stats->qual.level, | |
523 | + ((__u8) stats->qual.level), | |
524 | stats->qual.updated & 2 ? '.' : ' ', | |
525 | - stats->qual.noise, | |
526 | + ((__u8) stats->qual.noise), | |
527 | stats->qual.updated & 4 ? '.' : ' ', | |
528 | stats->discard.nwid, | |
529 | stats->discard.code, | |
530 | @@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st | |
531 | int ret = -EINVAL; | |
532 | ||
533 | /* Get the description of the IOCTL */ | |
534 | + if((cmd - SIOCIWFIRST) >= standard_ioctl_num) | |
535 | + return -EOPNOTSUPP; | |
536 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); | |
537 | ||
538 | #ifdef WE_IOCTL_DEBUG | |
539 | - printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", | |
540 | + printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", | |
541 | ifr->ifr_name, cmd); | |
542 | - 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); | |
543 | + 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); | |
544 | #endif /* WE_IOCTL_DEBUG */ | |
545 | ||
546 | /* Prepare the call */ | |
547 | @@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st | |
548 | ||
549 | /* Check if we have a pointer to user space data or not */ | |
550 | if(descr->header_type != IW_HEADER_TYPE_POINT) { | |
551 | + | |
552 | /* No extra arguments. Trivial to handle */ | |
553 | ret = handler(dev, &info, &(iwr->u), NULL); | |
554 | + | |
555 | +#ifdef WE_SET_EVENT | |
556 | + /* Generate an event to notify listeners of the change */ | |
557 | + if((descr->flags & IW_DESCR_FLAG_EVENT) && | |
558 | + ((ret == 0) || (ret == -EIWCOMMIT))) | |
559 | + wireless_send_event(dev, cmd, &(iwr->u), NULL); | |
560 | +#endif /* WE_SET_EVENT */ | |
561 | } else { | |
562 | char * extra; | |
563 | int err; | |
564 | @@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st | |
565 | } | |
566 | ||
567 | #ifdef WE_IOCTL_DEBUG | |
568 | - printk(KERN_DEBUG "Malloc %d bytes\n", | |
569 | - descr->max_tokens * descr->token_size); | |
570 | + printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", | |
571 | + dev->name, descr->max_tokens * descr->token_size); | |
572 | #endif /* WE_IOCTL_DEBUG */ | |
573 | ||
574 | /* Always allocate for max space. Easier, and won't last | |
575 | @@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st | |
576 | return -EFAULT; | |
577 | } | |
578 | #ifdef WE_IOCTL_DEBUG | |
579 | - printk(KERN_DEBUG "Got %d bytes\n", | |
580 | + printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", | |
581 | + dev->name, | |
582 | iwr->u.data.length * descr->token_size); | |
583 | #endif /* WE_IOCTL_DEBUG */ | |
584 | } | |
585 | @@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st | |
586 | if (err) | |
587 | ret = -EFAULT; | |
588 | #ifdef WE_IOCTL_DEBUG | |
589 | - printk(KERN_DEBUG "Wrote %d bytes\n", | |
590 | + printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", | |
591 | + dev->name, | |
592 | iwr->u.data.length * descr->token_size); | |
593 | #endif /* WE_IOCTL_DEBUG */ | |
594 | } | |
595 | ||
596 | +#ifdef WE_SET_EVENT | |
597 | + /* Generate an event to notify listeners of the change */ | |
598 | + if((descr->flags & IW_DESCR_FLAG_EVENT) && | |
599 | + ((ret == 0) || (ret == -EIWCOMMIT))) { | |
600 | + if(descr->flags & IW_DESCR_FLAG_RESTRICT) | |
601 | + /* If the event is restricted, don't | |
602 | + * export the payload */ | |
603 | + wireless_send_event(dev, cmd, &(iwr->u), NULL); | |
604 | + else | |
605 | + wireless_send_event(dev, cmd, &(iwr->u), | |
606 | + extra); | |
607 | + } | |
608 | +#endif /* WE_SET_EVENT */ | |
609 | + | |
610 | /* Cleanup - I told you it wasn't that long ;-) */ | |
611 | kfree(extra); | |
612 | } | |
613 | @@ -558,11 +634,12 @@ static inline int ioctl_private_call(str | |
614 | } | |
615 | ||
616 | #ifdef WE_IOCTL_DEBUG | |
617 | - printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", | |
618 | + printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", | |
619 | ifr->ifr_name, cmd); | |
620 | if(descr) { | |
621 | - printk(KERN_DEBUG "Name %s, set %X, get %X\n", | |
622 | - descr->name, descr->set_args, descr->get_args); | |
623 | + printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", | |
624 | + dev->name, descr->name, | |
625 | + descr->set_args, descr->get_args); | |
626 | } | |
627 | #endif /* WE_IOCTL_DEBUG */ | |
628 | ||
629 | @@ -617,7 +694,8 @@ static inline int ioctl_private_call(str | |
630 | } | |
631 | ||
632 | #ifdef WE_IOCTL_DEBUG | |
633 | - printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); | |
634 | + printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", | |
635 | + dev->name, extra_size); | |
636 | #endif /* WE_IOCTL_DEBUG */ | |
637 | ||
638 | /* Always allocate for max space. Easier, and won't last | |
639 | @@ -636,7 +714,8 @@ static inline int ioctl_private_call(str | |
640 | return -EFAULT; | |
641 | } | |
642 | #ifdef WE_IOCTL_DEBUG | |
643 | - printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); | |
644 | + printk(KERN_DEBUG "%s (WE) : Got %d elem\n", | |
645 | + dev->name, iwr->u.data.length); | |
646 | #endif /* WE_IOCTL_DEBUG */ | |
647 | } | |
648 | ||
649 | @@ -650,8 +729,8 @@ static inline int ioctl_private_call(str | |
650 | if (err) | |
651 | ret = -EFAULT; | |
652 | #ifdef WE_IOCTL_DEBUG | |
653 | - printk(KERN_DEBUG "Wrote %d elem\n", | |
654 | - iwr->u.data.length); | |
655 | + printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", | |
656 | + dev->name, iwr->u.data.length); | |
657 | #endif /* WE_IOCTL_DEBUG */ | |
658 | } | |
659 | ||
660 | @@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq | |
661 | } | |
662 | /* Not reached */ | |
663 | return -EINVAL; | |
664 | +} | |
665 | + | |
666 | +/************************* EVENT PROCESSING *************************/ | |
667 | +/* | |
668 | + * Process events generated by the wireless layer or the driver. | |
669 | + * Most often, the event will be propagated through rtnetlink | |
670 | + */ | |
671 | + | |
672 | +#ifdef WE_EVENT_NETLINK | |
673 | +/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. | |
674 | + * It is declared in <linux/rtnetlink.h> */ | |
675 | + | |
676 | +/* ---------------------------------------------------------------- */ | |
677 | +/* | |
678 | + * Fill a rtnetlink message with our event data. | |
679 | + * Note that we propage only the specified event and don't dump the | |
680 | + * current wireless config. Dumping the wireless config is far too | |
681 | + * expensive (for each parameter, the driver need to query the hardware). | |
682 | + */ | |
683 | +static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, | |
684 | + struct net_device * dev, | |
685 | + int type, | |
686 | + char * event, | |
687 | + int event_len) | |
688 | +{ | |
689 | + struct ifinfomsg *r; | |
690 | + struct nlmsghdr *nlh; | |
691 | + unsigned char *b = skb->tail; | |
692 | + | |
693 | + nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); | |
694 | + r = NLMSG_DATA(nlh); | |
695 | + r->ifi_family = AF_UNSPEC; | |
696 | + r->ifi_type = dev->type; | |
697 | + r->ifi_index = dev->ifindex; | |
698 | + r->ifi_flags = dev->flags; | |
699 | + r->ifi_change = 0; /* Wireless changes don't affect those flags */ | |
700 | + | |
701 | + /* Add the wireless events in the netlink packet */ | |
702 | + RTA_PUT(skb, IFLA_WIRELESS, | |
703 | + event_len, event); | |
704 | + | |
705 | + nlh->nlmsg_len = skb->tail - b; | |
706 | + return skb->len; | |
707 | + | |
708 | +nlmsg_failure: | |
709 | +rtattr_failure: | |
710 | + skb_trim(skb, b - skb->data); | |
711 | + return -1; | |
712 | +} | |
713 | + | |
714 | +/* ---------------------------------------------------------------- */ | |
715 | +/* | |
716 | + * Create and broadcast and send it on the standard rtnetlink socket | |
717 | + * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c | |
718 | + * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field | |
719 | + * within a RTM_NEWLINK event. | |
720 | + */ | |
721 | +static inline void rtmsg_iwinfo(struct net_device * dev, | |
722 | + char * event, | |
723 | + int event_len) | |
724 | +{ | |
725 | + struct sk_buff *skb; | |
726 | + int size = NLMSG_GOODSIZE; | |
727 | + | |
728 | + skb = alloc_skb(size, GFP_ATOMIC); | |
729 | + if (!skb) | |
730 | + return; | |
731 | + | |
732 | + if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, | |
733 | + event, event_len) < 0) { | |
734 | + kfree_skb(skb); | |
735 | + return; | |
736 | + } | |
737 | + NETLINK_CB(skb).dst_groups = RTMGRP_LINK; | |
738 | + netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC); | |
739 | +} | |
740 | +#endif /* WE_EVENT_NETLINK */ | |
741 | + | |
742 | +/* ---------------------------------------------------------------- */ | |
743 | +/* | |
744 | + * Main event dispatcher. Called from other parts and drivers. | |
745 | + * Send the event on the apropriate channels. | |
746 | + * May be called from interrupt context. | |
747 | + */ | |
748 | +void wireless_send_event(struct net_device * dev, | |
749 | + unsigned int cmd, | |
750 | + union iwreq_data * wrqu, | |
751 | + char * extra) | |
752 | +{ | |
753 | + const struct iw_ioctl_description * descr = NULL; | |
754 | + int extra_len = 0; | |
755 | + struct iw_event *event; /* Mallocated whole event */ | |
756 | + int event_len; /* Its size */ | |
757 | + int hdr_len; /* Size of the event header */ | |
758 | + /* Don't "optimise" the following variable, it will crash */ | |
759 | + unsigned cmd_index; /* *MUST* be unsigned */ | |
760 | + | |
761 | + /* Get the description of the IOCTL */ | |
762 | + if(cmd <= SIOCIWLAST) { | |
763 | + cmd_index = cmd - SIOCIWFIRST; | |
764 | + if(cmd_index < standard_ioctl_num) | |
765 | + descr = &(standard_ioctl[cmd_index]); | |
766 | + } else { | |
767 | + cmd_index = cmd - IWEVFIRST; | |
768 | + if(cmd_index < standard_event_num) | |
769 | + descr = &(standard_event[cmd_index]); | |
770 | + } | |
771 | + /* Don't accept unknown events */ | |
772 | + if(descr == NULL) { | |
773 | + /* Note : we don't return an error to the driver, because | |
774 | + * the driver would not know what to do about it. It can't | |
775 | + * return an error to the user, because the event is not | |
776 | + * initiated by a user request. | |
777 | + * The best the driver could do is to log an error message. | |
778 | + * We will do it ourselves instead... | |
779 | + */ | |
780 | + printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", | |
781 | + dev->name, cmd); | |
782 | + return; | |
783 | + } | |
784 | +#ifdef WE_EVENT_DEBUG | |
785 | + printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", | |
786 | + dev->name, cmd); | |
787 | + 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); | |
788 | +#endif /* WE_EVENT_DEBUG */ | |
789 | + | |
790 | + /* Check extra parameters and set extra_len */ | |
791 | + if(descr->header_type == IW_HEADER_TYPE_POINT) { | |
792 | + /* Check if number of token fits within bounds */ | |
793 | + if(wrqu->data.length > descr->max_tokens) { | |
794 | + printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); | |
795 | + return; | |
796 | + } | |
797 | + if(wrqu->data.length < descr->min_tokens) { | |
798 | + printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); | |
799 | + return; | |
800 | + } | |
801 | + /* Calculate extra_len - extra is NULL for restricted events */ | |
802 | + if(extra != NULL) | |
803 | + extra_len = wrqu->data.length * descr->token_size; | |
804 | +#ifdef WE_EVENT_DEBUG | |
805 | + printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); | |
806 | +#endif /* WE_EVENT_DEBUG */ | |
807 | + } | |
808 | + | |
809 | + /* Total length of the event */ | |
810 | + hdr_len = event_type_size[descr->header_type]; | |
811 | + event_len = hdr_len + extra_len; | |
812 | + | |
813 | +#ifdef WE_EVENT_DEBUG | |
814 | + printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); | |
815 | +#endif /* WE_EVENT_DEBUG */ | |
816 | + | |
817 | + /* Create temporary buffer to hold the event */ | |
818 | + event = kmalloc(event_len, GFP_ATOMIC); | |
819 | + if(event == NULL) | |
820 | + return; | |
821 | + | |
822 | + /* Fill event */ | |
823 | + event->len = event_len; | |
824 | + event->cmd = cmd; | |
825 | + memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); | |
826 | + if(extra != NULL) | |
827 | + memcpy(((char *) event) + hdr_len, extra, extra_len); | |
828 | + | |
829 | +#ifdef WE_EVENT_NETLINK | |
830 | + /* rtnetlink event channel */ | |
831 | + rtmsg_iwinfo(dev, (char *) event, event_len); | |
832 | +#endif /* WE_EVENT_NETLINK */ | |
833 | + | |
834 | + /* Cleanup */ | |
835 | + kfree(event); | |
836 | + | |
837 | + return; /* Always success, I guess ;-) */ | |
838 | } |