OSDN Git Service

Add Android.mk
[android-x86/external-wireless-tools.git] / wireless_tools / iwpriv.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB 97->99 - HPL 99->07
5  *
6  * Main code for "iwconfig". This is the generic tool for most
7  * manipulations...
8  * You need to link this code against "iwlib.c" and "-lm".
9  *
10  * This file is released under the GPL license.
11  *     Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
12  */
13
14 #include "iwlib-private.h"              /* Private header */
15
16 /************************** DOCUMENTATION **************************/
17
18 /*
19  * BASIC PRINCIPLE
20  * ---------------
21  *      Wireless Extension recognise that each wireless device has some
22  * specific features not covered by the standard wireless extensions.
23  * Private wireless ioctls/requests allow a device to export the control
24  * of those device specific features, and allow users to directly interact
25  * with your driver.
26  *      There are many other ways you can implement such functionality :
27  *              o module parameters
28  *              o netlink socket
29  *              o file system (/proc/ or /sysfs/)
30  *              o extra character device (/dev/)
31  *      Private wireless ioctls is one of the simplest implementation,
32  * however it is limited, so you may want to check the alternatives.
33  *
34  *      Like for standard Wireless Extensions, each private wireless
35  * request is identified by an IOCTL NUMBER and carry a certain number
36  * of arguments (SET or GET).
37  *      The driver exports a description of those requests (ioctl number,
38  * request name, set and get arguments). Then, iwpriv uses those request
39  * descriptions to call the appropriate request and handle the
40  * arguments.
41  *
42  * IOCTL RANGES :
43  * ------------
44  *      The initial implementation of iwpriv was using the SIOCDEVPRIVATE
45  * ioctl range (up to 16 ioctls - driver specific). However, this was
46  * causing some compatibility problems with other usages of those
47  * ioctls, and those ioctls are supposed to be removed.
48  *      Therefore, I created a new ioctl range, at SIOCIWFIRSTPRIV. Those
49  * ioctls are specific to Wireless Extensions, so you don't have to
50  * worry about collisions with other usages. On the other hand, in the
51  * new range, the SET convention is enforced (see below).
52  *      The differences are :           SIOCDEVPRIVATE  SIOCIWFIRSTPRIV
53  *              o availability          <= 2.5.X        WE > 11 (>= 2.4.13)
54  *              o collisions            yes             no
55  *              o SET convention        optional        enforced
56  *              o number                16              32
57  *
58  * NEW DRIVER API :
59  * --------------
60  *      Wireless Extension 13 introduces a new driver API. Wireless
61  * Extensions requests can be handled via a iw_handler table instead
62  * of through the regular ioctl handler.
63  *      The new driver API can be handled only with the new ioctl range
64  * and enforces the GET convention (see below).
65  *      The differences are :           old API         new API
66  *              o handler               do_ioctl()      struct iw_handler_def
67  *              o SIOCIWFIRSTPRIV       WE > 11         yes
68  *              o SIOCDEVPRIVATE        yes             no
69  *              o GET convention        optional        enforced
70  *      Note that the new API before Wireless Extension 15 contains bugs
71  * when handling sub-ioctls and addr/float data types.
72  *
73  * INLINING vs. POINTER :
74  * --------------------
75  *      One of the tricky aspect of the old driver API is how the data
76  * is handled, which is how the driver is supposed to extract the data
77  * passed to it by iwpriv.
78  *      1) If the data has a fixed size (private ioctl definition
79  * has the flag IW_PRIV_SIZE_FIXED) and the byte size of the data is
80  * lower than 16 bytes, the data will be inlined. The driver can extract
81  * data in the field 'u.name' of the struct iwreq.
82  *      2) If the if the data doesn't have a fixed size or is larger than
83  * 16 bytes, the data is passed by pointer. struct iwreq contains a
84  * struct iwpoint with a user space pointer to the data. Appropriate
85  * copy_from/to_user() function should be used.
86  *      
87  *      With the new API, this is handled transparently, the data is
88  * always available as the fourth argument of the request handler
89  * (usually called 'extra').
90  *
91  * SET/GET CONVENTION :
92  * ------------------
93  *      Simplistic summary :
94  *      o even numbered ioctls are SET, restricted to root, and should not
95  * return arguments (get_args = 0).
96  *      o odd numbered ioctls are GET, authorised to anybody, and should
97  * not expect any arguments (set_args = 0).
98  *
99  *      The regular Wireless Extensions use the SET/GET convention, where
100  * the low order bit identify a SET (0) or a GET (1) request. The private
101  * Wireless Extension is not as restrictive, but still has some
102  * limitations.
103  *      The new ioctl range enforces the SET convention : SET request will
104  * be available to root only and can't return any arguments. If you don't
105  * like that, just use every other two ioctl.
106  *      The new driver API enforce the GET convention : GET request won't
107  * be able to accept any arguments (except if its fits within (union
108  * iwreq_data)). If you don't like that, you can either use the Token Index
109  * support or the old API (aka the ioctl handler).
110  *      In any case, it's a good idea to not have ioctl with both SET
111  * and GET arguments. If the GET arguments doesn't fit within
112  * (union iwreq_data) and SET do, or vice versa, the current code in iwpriv
113  * won't work. One exception is if both SET and GET arguments fit within
114  * (union iwreq_data), this case should be handled safely in a GET
115  * request.
116  *      If you don't fully understand those limitations, just follow the
117  * rules of the simplistic summary ;-)
118  *
119  * SUB-IOCTLS :
120  * ----------
121  *      Wireless Extension 15 introduces sub-ioctls. For some applications,
122  * 32 ioctls is not enough, and this simple mechanism allows to increase
123  * the number of ioctls by adding a sub-ioctl index to some of the ioctls
124  * (so basically it's a two level addressing).
125  *      One might argue that at the point, some other mechanisms might be
126  * better, like using a real filesystem abstraction (/proc, driverfs, ...),
127  * but sub-ioctls are simple enough and don't have much drawbacks (which
128  * means that it's a quick and dirty hack ;-).
129  *
130  *      There are two slightly different variations of the sub-ioctl scheme :
131  *      1) If the payload fits within (union iwreq_data), the first int
132  * (4 bytes) is reserved as the sub-ioctl number and the regular payload
133  * shifted by 4 bytes. The handler must extract the sub-ioctl number,
134  * increment the data pointer and then use it in the usual way.
135  *      2) If the ioctl uses (struct iw_point), the sub-ioctl number is
136  * set in the flags member of the structure. In this case, the handler
137  * should simply get the sub-ioctl number from the flags and process the
138  * data in the usual way.
139  *
140  *      Sub-ioctls are declared normally in the private definition table,
141  * with cmd (first arg) being the sub-ioctl number. Then, you should
142  * declare the real ioctl, which will process the sub-ioctls, with
143  * the SAME ARGUMENTS and a EMPTY NAME.
144  *      Here's an example of how it could look like :
145  * --------------------------------------------
146         // --- sub-ioctls handlers ---
147         { 0x8BE0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
148         { 0x8BE1, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
149         // --- sub-ioctls definitions ---
150         { 1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_param1" },
151         { 1, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param1" },
152         { 2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_param2" },
153         { 2, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param2" },
154         // --- Raw access to sub-ioctl handlers ---
155         { 0x8BE0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_paramN" },
156         { 0x8BE1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
157           IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_paramN" },
158  * --------------------------------------------
159  *      And iwpriv should do the rest for you ;-)
160  *
161  *      Note that versions of iwpriv up to v24 (included) expect at most
162  * 16 ioctls definitions and will likely crash when given more.
163  *      There is no fix that I can see, apart from recommending your users
164  * to upgrade their Wireless Tools. Wireless Extensions 15 will check this
165  * condition, so another workaround is restricting those extra definitions
166  * to WE-15.
167  *
168  *      Another problem is that the new API before Wireless Extension 15
169  * has a bug when passing fixed arguments of 12-15 bytes. It will
170  * try to get them inline instead of by pointer. You can fool the new API
171  * to do the right thing using fake ioctl definitions (but remember that
172  * you will be more likely to hit the limit of 16 ioctl definitions).
173  *      To play safe, use the old-style ioctl handler before v15.
174  *
175  * NEW DATA TYPES (ADDR/FLOAT) :
176  * ---------------------------
177  *      Wireless Tools 25 introduce two new data types, addr and float,
178  * corresponding to struct sockaddr and struct iwfreq.
179  *      Those types are properly handled with Wireless Extensions 15.
180  * However, the new API before v15 won't handle them properly.
181  *
182  *      The first problem is that the new API won't know their size, so
183  * it won't copy them. This can be workaround with a fake ioctl definition.
184  *      The second problem is that a fixed single addr won't be inlined
185  * in struct iwreq and will be passed as a pointer. This is due to an
186  * off-by-one error, where all fixed data of 16 bytes is considered too
187  * big to fit in struct iwreq.
188  *
189  *      For those reasons, I would recommend to use the ioctl handler
190  * before v15 when manipulating those data.
191  *
192  * TOKEN INDEX :
193  * -----------
194  *      Token index is very similar to sub-ioctl. It allows the user
195  * to specify an integer index in front of a bunch of other arguments
196  * (addresses, strings, ...). It's specified in square brackets on the
197  * iwpriv command line before other arguments.
198  *              > iwpriv eth0 [index] args...
199  *      Token index works only when the data is passed as pointer, and
200  * is otherwise ignored. If your data would fit within struct iwreq, you
201  * should declare the command *without* IW_PRIV_SIZE_FIXED to force
202  * this to happen (and check arg number yourself).
203  * --------------------------------------------
204         // --- Commands that would fit in struct iwreq ---
205         { 0x8BE0, IW_PRIV_TYPE_ADDR | 1, 0, "set_param_with_token" },
206         // --- No problem here (bigger than struct iwreq) ---
207         { 0x8BE1, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 2, 0, "again" },
208  * --------------------------------------------
209  *      The token index feature is pretty transparent, the token index
210  * will just be in the flags member of (struct iw_point). Default value
211  * (if the user doesn't specify it) will be 0. Token index itself will
212  * work with any version of Wireless Extensions.
213  *      Token index is not compatible with sub-ioctl (both use the same
214  * field of struct iw_point). However, the token index can be used to offer
215  * raw access to the sub-ioctl handlers (if it uses struct iw_point) :
216  * --------------------------------------------
217         // --- sub-ioctls handler ---
218         { 0x8BE0, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "" },
219         // --- sub-ioctls definitions ---
220         { 0, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "setaddr" },
221         { 1, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "deladdr" },
222         // --- raw access with token index (+ iwreq workaround) ---
223         { 0x8BE0, IW_PRIV_TYPE_ADDR | 1, 0, "rawaddr" },
224  * --------------------------------------------
225  *
226  * Jean II
227  */
228
229 /**************************** CONSTANTS ****************************/
230
231 static const char *     argtype[] = {
232   "     ", "byte ", "char ", "", "int  ", "float", "addr " };
233
234 /************************* MISC SUBROUTINES **************************/
235
236 /*------------------------------------------------------------------*/
237 /*
238  * Print usage string
239  */
240 static void
241 iw_usage(void)
242 {
243   fprintf(stderr, "Usage: iwpriv interface [private-command [private-arguments]]\n");
244 }
245
246 /************************* SETTING ROUTINES **************************/
247
248 /*------------------------------------------------------------------*/
249 /*
250  * Execute a private command on the interface
251  */
252 static int
253 set_private_cmd(int             skfd,           /* Socket */
254                 char *          args[],         /* Command line args */
255                 int             count,          /* Args count */
256                 char *          ifname,         /* Dev name */
257                 char *          cmdname,        /* Command name */
258                 iwprivargs *    priv,           /* Private ioctl description */
259                 int             priv_num)       /* Number of descriptions */
260 {
261   struct iwreq  wrq;
262   u_char        buffer[4096];   /* Only that big in v25 and later */
263   int           i = 0;          /* Start with first command arg */
264   int           k;              /* Index in private description table */
265   int           temp;
266   int           subcmd = 0;     /* sub-ioctl index */
267   int           offset = 0;     /* Space for sub-ioctl index */
268
269   /* Check if we have a token index.
270    * Do it now so that sub-ioctl takes precedence, and so that we
271    * don't have to bother with it later on... */
272   if((count >= 1) && (sscanf(args[0], "[%i]", &temp) == 1))
273     {
274       subcmd = temp;
275       args++;
276       count--;
277     }
278
279   /* Search the correct ioctl */
280   k = -1;
281   while((++k < priv_num) && strcmp(priv[k].name, cmdname));
282
283   /* If not found... */
284   if(k == priv_num)
285     {
286       fprintf(stderr, "Invalid command : %s\n", cmdname);
287       return(-1);
288     }
289           
290   /* Watch out for sub-ioctls ! */
291   if(priv[k].cmd < SIOCDEVPRIVATE)
292     {
293       int       j = -1;
294
295       /* Find the matching *real* ioctl */
296       while((++j < priv_num) && ((priv[j].name[0] != '\0') ||
297                                  (priv[j].set_args != priv[k].set_args) ||
298                                  (priv[j].get_args != priv[k].get_args)));
299
300       /* If not found... */
301       if(j == priv_num)
302         {
303           fprintf(stderr, "Invalid private ioctl definition for : %s\n",
304                   cmdname);
305           return(-1);
306         }
307
308       /* Save sub-ioctl number */
309       subcmd = priv[k].cmd;
310       /* Reserve one int (simplify alignment issues) */
311       offset = sizeof(__u32);
312       /* Use real ioctl definition from now on */
313       k = j;
314
315 #if 0
316       printf("<mapping sub-ioctl %s to cmd 0x%X-%d>\n", cmdname,
317              priv[k].cmd, subcmd);
318 #endif
319     }
320
321   /* If we have to set some data */
322   if((priv[k].set_args & IW_PRIV_TYPE_MASK) &&
323      (priv[k].set_args & IW_PRIV_SIZE_MASK))
324     {
325       switch(priv[k].set_args & IW_PRIV_TYPE_MASK)
326         {
327         case IW_PRIV_TYPE_BYTE:
328           /* Number of args to fetch */
329           wrq.u.data.length = count;
330           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
331             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
332
333           /* Fetch args */
334           for(; i < wrq.u.data.length; i++) {
335             sscanf(args[i], "%i", &temp);
336             buffer[i] = (char) temp;
337           }
338           break;
339
340         case IW_PRIV_TYPE_INT:
341           /* Number of args to fetch */
342           wrq.u.data.length = count;
343           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
344             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
345
346           /* Fetch args */
347           for(; i < wrq.u.data.length; i++) {
348             sscanf(args[i], "%i", &temp);
349             ((__s32 *) buffer)[i] = (__s32) temp;
350           }
351           break;
352
353         case IW_PRIV_TYPE_CHAR:
354           if(i < count)
355             {
356               /* Size of the string to fetch */
357               wrq.u.data.length = strlen(args[i]) + 1;
358               if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
359                 wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
360
361               /* Fetch string */
362               memcpy(buffer, args[i], wrq.u.data.length);
363               buffer[sizeof(buffer) - 1] = '\0';
364               i++;
365             }
366           else
367             {
368               wrq.u.data.length = 1;
369               buffer[0] = '\0';
370             }
371           break;
372
373         case IW_PRIV_TYPE_FLOAT:
374           /* Number of args to fetch */
375           wrq.u.data.length = count;
376           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
377             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
378
379           /* Fetch args */
380           for(; i < wrq.u.data.length; i++) {
381             double              freq;
382             if(sscanf(args[i], "%lg", &(freq)) != 1)
383               {
384                 printf("Invalid float [%s]...\n", args[i]);
385                 return(-1);
386               }    
387             if(strchr(args[i], 'G')) freq *= GIGA;
388             if(strchr(args[i], 'M')) freq *= MEGA;
389             if(strchr(args[i], 'k')) freq *= KILO;
390             sscanf(args[i], "%i", &temp);
391             iw_float2freq(freq, ((struct iw_freq *) buffer) + i);
392           }
393           break;
394
395         case IW_PRIV_TYPE_ADDR:
396           /* Number of args to fetch */
397           wrq.u.data.length = count;
398           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
399             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
400
401           /* Fetch args */
402           for(; i < wrq.u.data.length; i++) {
403             if(iw_in_addr(skfd, ifname, args[i],
404                           ((struct sockaddr *) buffer) + i) < 0)
405               {
406                 printf("Invalid address [%s]...\n", args[i]);
407                 return(-1);
408               }
409           }
410           break;
411
412         default:
413           fprintf(stderr, "Not implemented...\n");
414           return(-1);
415         }
416           
417       if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
418          (wrq.u.data.length != (priv[k].set_args & IW_PRIV_SIZE_MASK)))
419         {
420           printf("The command %s needs exactly %d argument(s)...\n",
421                  cmdname, priv[k].set_args & IW_PRIV_SIZE_MASK);
422           return(-1);
423         }
424     }   /* if args to set */
425   else
426     {
427       wrq.u.data.length = 0L;
428     }
429
430   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
431
432   /* Those two tests are important. They define how the driver
433    * will have to handle the data */
434   if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
435       ((iw_get_priv_size(priv[k].set_args) + offset) <= IFNAMSIZ))
436     {
437       /* First case : all SET args fit within wrq */
438       if(offset)
439         wrq.u.mode = subcmd;
440       memcpy(wrq.u.name + offset, buffer, IFNAMSIZ - offset);
441     }
442   else
443     {
444       if((priv[k].set_args == 0) &&
445          (priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
446          (iw_get_priv_size(priv[k].get_args) <= IFNAMSIZ))
447         {
448           /* Second case : no SET args, GET args fit within wrq */
449           if(offset)
450             wrq.u.mode = subcmd;
451         }
452       else
453         {
454           /* Third case : args won't fit in wrq, or variable number of args */
455           wrq.u.data.pointer = (caddr_t) buffer;
456           wrq.u.data.flags = subcmd;
457         }
458     }
459
460   /* Perform the private ioctl */
461   if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
462     {
463       fprintf(stderr, "Interface doesn't accept private ioctl...\n");
464       fprintf(stderr, "%s (%X): %s\n", cmdname, priv[k].cmd, strerror(errno));
465       return(-1);
466     }
467
468   /* If we have to get some data */
469   if((priv[k].get_args & IW_PRIV_TYPE_MASK) &&
470      (priv[k].get_args & IW_PRIV_SIZE_MASK))
471     {
472       int       j;
473       int       n = 0;          /* number of args */
474
475       printf("%-8.16s  %s:", ifname, cmdname);
476
477       /* Check where is the returned data */
478       if((priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
479          (iw_get_priv_size(priv[k].get_args) <= IFNAMSIZ))
480         {
481           memcpy(buffer, wrq.u.name, IFNAMSIZ);
482           n = priv[k].get_args & IW_PRIV_SIZE_MASK;
483         }
484       else
485         n = wrq.u.data.length;
486
487       switch(priv[k].get_args & IW_PRIV_TYPE_MASK)
488         {
489         case IW_PRIV_TYPE_BYTE:
490           /* Display args */
491           for(j = 0; j < n; j++)
492             printf("%d  ", buffer[j]);
493           printf("\n");
494           break;
495
496         case IW_PRIV_TYPE_INT:
497           /* Display args */
498           for(j = 0; j < n; j++)
499             printf("%d  ", ((__s32 *) buffer)[j]);
500           printf("\n");
501           break;
502
503         case IW_PRIV_TYPE_CHAR:
504           /* Display args */
505           buffer[n] = '\0';
506           printf("%s\n", buffer);
507           break;
508
509         case IW_PRIV_TYPE_FLOAT:
510           {
511             double              freq;
512             /* Display args */
513             for(j = 0; j < n; j++)
514               {
515                 freq = iw_freq2float(((struct iw_freq *) buffer) + j);
516                 if(freq >= GIGA)
517                   printf("%gG  ", freq / GIGA);
518                 else
519                   if(freq >= MEGA)
520                   printf("%gM  ", freq / MEGA);
521                 else
522                   printf("%gk  ", freq / KILO);
523               }
524             printf("\n");
525           }
526           break;
527
528         case IW_PRIV_TYPE_ADDR:
529           {
530             char                scratch[128];
531             struct sockaddr *   hwa;
532             /* Display args */
533             for(j = 0; j < n; j++)
534               {
535                 hwa = ((struct sockaddr *) buffer) + j;
536                 if(j)
537                   printf("           %.*s", 
538                          (int) strlen(cmdname), "                ");
539                 printf("%s\n", iw_saether_ntop(hwa, scratch));
540               }
541           }
542           break;
543
544         default:
545           fprintf(stderr, "Not yet implemented...\n");
546           return(-1);
547         }
548     }   /* if args to set */
549
550   return(0);
551 }
552
553 /*------------------------------------------------------------------*/
554 /*
555  * Execute a private command on the interface
556  */
557 static inline int
558 set_private(int         skfd,           /* Socket */
559             char *      args[],         /* Command line args */
560             int         count,          /* Args count */
561             char *      ifname)         /* Dev name */
562 {
563   iwprivargs *  priv;
564   int           number;         /* Max of private ioctl */
565   int           ret;
566
567   /* Read the private ioctls */
568   number = iw_get_priv_info(skfd, ifname, &priv);
569
570   /* Is there any ? */
571   if(number <= 0)
572     {
573       /* Should I skip this message ? */
574       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
575               ifname);
576       if(priv)
577         free(priv);
578       return(-1);
579     }
580
581   /* Do it */
582   ret = set_private_cmd(skfd, args + 1, count - 1, ifname, args[0],
583                         priv, number);
584
585   free(priv);
586   return(ret);
587 }
588
589 /************************ CATALOG FUNCTIONS ************************/
590
591 /*------------------------------------------------------------------*/
592 /*
593  * Print on the screen in a neat fashion the list of private ioctls
594  * for the device.
595  */
596 static int
597 print_priv_info(int             skfd,
598                 char *          ifname,
599                 char *          args[],
600                 int             count)
601 {
602   int           k;
603   iwprivargs *  priv;
604   int           n;
605
606   /* Avoid "Unused parameter" warning */
607   args = args; count = count;
608
609   /* Read the private ioctls */
610   n = iw_get_priv_info(skfd, ifname, &priv);
611
612   /* Is there any ? */
613   if(n <= 0)
614     {
615       /* Should I skip this message ? */
616       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
617               ifname);
618     }
619   else
620     {
621       printf("%-8.16s  Available private ioctls :\n", ifname);
622       /* Print them all */
623       for(k = 0; k < n; k++)
624         if(priv[k].name[0] != '\0')
625           printf("          %-16.16s (%.4X) : set %3d %s & get %3d %s\n",
626                  priv[k].name, priv[k].cmd,
627                  priv[k].set_args & IW_PRIV_SIZE_MASK,
628                  argtype[(priv[k].set_args & IW_PRIV_TYPE_MASK) >> 12],
629                  priv[k].get_args & IW_PRIV_SIZE_MASK,
630                  argtype[(priv[k].get_args & IW_PRIV_TYPE_MASK) >> 12]);
631       printf("\n");
632     }
633
634   /* Cleanup */
635   if(priv)
636     free(priv);
637   return(0);
638 }
639
640 /*------------------------------------------------------------------*/
641 /*
642  * Print on the screen in a neat fashion the list of private GET ioctl
643  * data for the device and data returned by those.
644  */
645 static int
646 print_priv_all(int              skfd,
647                char *           ifname,
648                char *           args[],
649                int              count)
650 {
651   int           k;
652   iwprivargs *  priv;
653   int           n;
654
655   /* Avoid "Unused parameter" warning */
656   args = args; count = count;
657
658   /* Read the private ioctls */
659   n = iw_get_priv_info(skfd, ifname, &priv);
660
661   /* Is there any ? */
662   if(n <= 0)
663     {
664       /* Should I skip this message ? */
665       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
666               ifname);
667     }
668   else
669     {
670       printf("%-8.16s  Available read-only private ioctl :\n", ifname);
671       /* Print them all */
672       for(k = 0; k < n; k++)
673         /* We call all ioctls that don't have a null name, don't require
674          * args and return some (avoid triggering "reset" commands) */
675         if((priv[k].name[0] != '\0') && (priv[k].set_args == 0) &&
676            (priv[k].get_args != 0))
677           set_private_cmd(skfd, NULL, 0, ifname, priv[k].name,
678                           priv, n);
679       printf("\n");
680     }
681
682   /* Cleanup */
683   if(priv)
684     free(priv);
685   return(0);
686 }
687
688 /********************** PRIVATE IOCTLS MANIPS ***********************/
689 /*
690  * Convenient access to some private ioctls of some devices
691  */
692
693 #if 0
694 /*------------------------------------------------------------------*/
695 /*
696  * Set roaming mode on and off
697  * Found in wavelan_cs driver
698  * Note : this is obsolete, most 802.11 devices should use the
699  * SIOCSIWAP request.
700  */
701 static int
702 set_roaming(int         skfd,           /* Socket */
703             char *      args[],         /* Command line args */
704             int         count,          /* Args count */
705             char *      ifname)         /* Dev name */
706 {
707   u_char        buffer[1024];
708   struct iwreq          wrq;
709   int           i = 0;          /* Start with first arg */
710   int           k;
711   iwprivargs *  priv;
712   int           number;
713   int           roamcmd;
714   char          RoamState;              /* buffer to hold new roam state */
715   char          ChangeRoamState=0;      /* whether or not we are going to
716                                            change roam states */
717
718   /* Read the private ioctls */
719   number = iw_get_priv_info(skfd, ifname, &priv);
720
721   /* Is there any ? */
722   if(number <= 0)
723     {
724       /* Should I skip this message ? */
725       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
726               ifname);
727       if(priv)
728         free(priv);
729       return(-1);
730     }
731
732   /* Get the ioctl number */
733   k = -1;
734   while((++k < number) && strcmp(priv[k].name, "setroam"));
735   if(k == number)
736     {
737       fprintf(stderr, "This device doesn't support roaming\n");
738       free(priv);
739       return(-1);
740     }
741   roamcmd = priv[k].cmd;
742
743   /* Cleanup */
744   free(priv);
745
746   if(count != 1)
747     {
748       iw_usage();
749       return(-1);
750     }
751
752   if(!strcasecmp(args[i], "on"))
753     {
754       printf("%-8.16s  enable roaming\n", ifname);
755       if(!number)
756         {
757           fprintf(stderr, "This device doesn't support roaming\n");
758           return(-1);
759         }
760       ChangeRoamState=1;
761       RoamState=1;
762     }
763   else
764     if(!strcasecmp(args[i], "off"))
765       {
766         i++;
767         printf("%-8.16s  disable roaming\n",  ifname);
768         if(!number)
769           {
770             fprintf(stderr, "This device doesn't support roaming\n");
771             return(-1);
772           }
773         ChangeRoamState=1;
774         RoamState=0;
775       }
776     else
777       {
778         iw_usage();
779         return(-1);
780       }
781
782   if(ChangeRoamState)
783     {
784       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
785
786       buffer[0]=RoamState;
787
788       memcpy(wrq.u.name, &buffer, IFNAMSIZ);
789
790       if(ioctl(skfd, roamcmd, &wrq) < 0)
791         {
792           fprintf(stderr, "Roaming support is broken.\n");
793           return(-1);
794         }
795     }
796
797   return(0);
798 }
799
800 /*------------------------------------------------------------------*/
801 /*
802  * Get and set the port type
803  * Found in wavelan2_cs and wvlan_cs drivers
804  * TODO : Add support for HostAP ?
805  */
806 static int
807 port_type(int           skfd,           /* Socket */
808           char *        args[],         /* Command line args */
809           int           count,          /* Args count */
810           char *        ifname)         /* Dev name */
811 {
812   struct iwreq  wrq;
813   int           i = 0;          /* Start with first arg */
814   int           k;
815   iwprivargs *  priv;
816   int           number;
817   char          ptype = 0;
818   char *        modes[] = { "invalid", "managed (BSS)", "reserved", "ad-hoc" };
819
820   /* Read the private ioctls */
821   number = iw_get_priv_info(skfd, ifname, &priv);
822
823   /* Is there any ? */
824   if(number <= 0)
825     {
826       /* Should I skip this message ? */
827       fprintf(stderr, "%-8.16s  no private ioctls.\n\n", ifname);
828       if(priv)
829         free(priv);
830       return(-1);
831     }
832
833   /* Arguments ? */
834   if(count == 0)
835     {
836       /* So, we just want to see the current value... */
837       k = -1;
838       while((++k < number) && strcmp(priv[k].name, "gport_type") &&
839              strcmp(priv[k].name, "get_port"));
840       if(k == number)
841         {
842           fprintf(stderr, "This device doesn't support getting port type\n");
843           goto err;
844         }
845       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
846
847       /* Get it */
848       if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
849         {
850           fprintf(stderr, "Port type support is broken.\n");
851           goto err;
852         }
853       ptype = *wrq.u.name;
854
855       /* Display it */
856       printf("%-8.16s  Current port mode is %s <port type is %d>.\n\n",
857              ifname, modes[(int) ptype], ptype);
858
859       free(priv);
860       return(0);
861     }
862
863   if(count != 1)
864     {
865       iw_usage();
866       goto err;
867     }
868
869   /* Read it */
870   /* As a string... */
871   k = 0;
872   while((k < 4) && strncasecmp(args[i], modes[k], 2))
873     k++;
874   if(k < 4)
875     ptype = k;
876   else
877     /* ...or as an integer */
878     if(sscanf(args[i], "%i", (int *) &ptype) != 1)
879       {
880         iw_usage();
881         goto err;
882       }
883   
884   k = -1;
885   while((++k < number) && strcmp(priv[k].name, "sport_type") &&
886         strcmp(priv[k].name, "set_port"));
887   if(k == number)
888     {
889       fprintf(stderr, "This device doesn't support setting port type\n");
890       goto err;
891     }
892   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
893
894   *(wrq.u.name) = ptype;
895
896   if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
897     {
898       fprintf(stderr, "Invalid port type (or setting not allowed)\n");
899       goto err;
900     }
901
902   free(priv);
903   return(0);
904
905  err:
906   free(priv);
907   return(-1);
908 }
909 #endif
910
911 /******************************* MAIN ********************************/
912
913 /*------------------------------------------------------------------*/
914 /*
915  * The main !
916  */
917 int
918 main(int        argc,
919      char **    argv)
920 {
921   int skfd;             /* generic raw socket desc.     */
922   int goterr = 0;
923
924   /* Create a channel to the NET kernel. */
925   if((skfd = iw_sockets_open()) < 0)
926     {
927       perror("socket");
928       return(-1);
929     }
930
931   /* No argument : show the list of all devices + ioctl list */
932   if(argc == 1)
933     iw_enum_devices(skfd, &print_priv_info, NULL, 0);
934   else
935     /* Special cases take one... */
936     /* All */
937     if((!strncmp(argv[1], "-a", 2)) || (!strcmp(argv[1], "--all")))
938       iw_enum_devices(skfd, &print_priv_all, NULL, 0);
939     else
940       /* Help */
941       if((!strncmp(argv[1], "-h", 2)) || (!strcmp(argv[1], "--help")))
942         iw_usage();
943       else
944         /* Version */
945         if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
946           goterr = iw_print_version_info("iwpriv");
947         else
948           /* The device name must be the first argument */
949           /* Name only : show for that device only */
950           if(argc == 2)
951             print_priv_info(skfd, argv[1], NULL, 0);
952           else
953             /* Special cases take two... */
954             /* All */
955             if((!strncmp(argv[2], "-a", 2)) ||
956                (!strcmp(argv[2], "--all")))
957               print_priv_all(skfd, argv[1], NULL, 0);
958             else
959 #if 0
960               /* Roaming */
961               if(!strncmp(argv[2], "roam", 4))
962                 goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]);
963               else
964                 /* Port type */
965                 if(!strncmp(argv[2], "port", 4))
966                   goterr = port_type(skfd, argv + 3, argc - 3, argv[1]);
967                 else
968 #endif
969                   /*-------------*/
970                   /* Otherwise, it's a private ioctl */
971                   goterr = set_private(skfd, argv + 2, argc - 2, argv[1]);
972
973   /* Close the socket. */
974   iw_sockets_close(skfd);
975
976   return(goterr);
977 }