OSDN Git Service

v28
[android-x86/external-wireless-tools.git] / wireless_tools / iwpriv.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB 97->99 - HPL 99->04
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-2004 Jean Tourrilhes <jt@hpl.hp.com>
12  */
13
14 #include "iwlib.h"              /* 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(index(args[i], 'G')) freq *= GIGA;
388             if(index(args[i], 'M')) freq *= MEGA;
389             if(index(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 /*------------------------------------------------------------------*/
694 /*
695  * Set roaming mode on and off
696  * Found in wavelan_cs driver
697  * Note : this is obsolete, most 802.11 devices should use the
698  * SIOCSIWAP request.
699  */
700 static int
701 set_roaming(int         skfd,           /* Socket */
702             char *      args[],         /* Command line args */
703             int         count,          /* Args count */
704             char *      ifname)         /* Dev name */
705 {
706   u_char        buffer[1024];
707   struct iwreq          wrq;
708   int           i = 0;          /* Start with first arg */
709   int           k;
710   iwprivargs *  priv;
711   int           number;
712   int           roamcmd;
713   char          RoamState;              /* buffer to hold new roam state */
714   char          ChangeRoamState=0;      /* whether or not we are going to
715                                            change roam states */
716
717   /* Read the private ioctls */
718   number = iw_get_priv_info(skfd, ifname, &priv);
719
720   /* Is there any ? */
721   if(number <= 0)
722     {
723       /* Should I skip this message ? */
724       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
725               ifname);
726       if(priv)
727         free(priv);
728       return(-1);
729     }
730
731   /* Get the ioctl number */
732   k = -1;
733   while((++k < number) && strcmp(priv[k].name, "setroam"));
734   if(k == number)
735     {
736       fprintf(stderr, "This device doesn't support roaming\n");
737       free(priv);
738       return(-1);
739     }
740   roamcmd = priv[k].cmd;
741
742   /* Cleanup */
743   free(priv);
744
745   if(count != 1)
746     {
747       iw_usage();
748       return(-1);
749     }
750
751   if(!strcasecmp(args[i], "on"))
752     {
753       printf("%-8.16s  enable roaming\n", ifname);
754       if(!number)
755         {
756           fprintf(stderr, "This device doesn't support roaming\n");
757           return(-1);
758         }
759       ChangeRoamState=1;
760       RoamState=1;
761     }
762   else
763     if(!strcasecmp(args[i], "off"))
764       {
765         i++;
766         printf("%-8.16s  disable roaming\n",  ifname);
767         if(!number)
768           {
769             fprintf(stderr, "This device doesn't support roaming\n");
770             return(-1);
771           }
772         ChangeRoamState=1;
773         RoamState=0;
774       }
775     else
776       {
777         iw_usage();
778         return(-1);
779       }
780
781   if(ChangeRoamState)
782     {
783       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
784
785       buffer[0]=RoamState;
786
787       memcpy(wrq.u.name, &buffer, IFNAMSIZ);
788
789       if(ioctl(skfd, roamcmd, &wrq) < 0)
790         {
791           fprintf(stderr, "Roaming support is broken.\n");
792           return(-1);
793         }
794     }
795
796   return(0);
797 }
798
799 /*------------------------------------------------------------------*/
800 /*
801  * Get and set the port type
802  * Found in wavelan2_cs and wvlan_cs drivers
803  * TODO : Add support for HostAP ?
804  */
805 static int
806 port_type(int           skfd,           /* Socket */
807           char *        args[],         /* Command line args */
808           int           count,          /* Args count */
809           char *        ifname)         /* Dev name */
810 {
811   struct iwreq  wrq;
812   int           i = 0;          /* Start with first arg */
813   int           k;
814   iwprivargs *  priv;
815   int           number;
816   char          ptype = 0;
817   char *        modes[] = { "invalid", "managed (BSS)", "reserved", "ad-hoc" };
818
819   /* Read the private ioctls */
820   number = iw_get_priv_info(skfd, ifname, &priv);
821
822   /* Is there any ? */
823   if(number <= 0)
824     {
825       /* Should I skip this message ? */
826       fprintf(stderr, "%-8.16s  no private ioctls.\n\n", ifname);
827       if(priv)
828         free(priv);
829       return(-1);
830     }
831
832   /* Arguments ? */
833   if(count == 0)
834     {
835       /* So, we just want to see the current value... */
836       k = -1;
837       while((++k < number) && strcmp(priv[k].name, "gport_type") &&
838              strcmp(priv[k].name, "get_port"));
839       if(k == number)
840         {
841           fprintf(stderr, "This device doesn't support getting port type\n");
842           goto err;
843         }
844       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
845
846       /* Get it */
847       if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
848         {
849           fprintf(stderr, "Port type support is broken.\n");
850           goto err;
851         }
852       ptype = *wrq.u.name;
853
854       /* Display it */
855       printf("%-8.16s  Current port mode is %s <port type is %d>.\n\n",
856              ifname, modes[(int) ptype], ptype);
857
858       free(priv);
859       return(0);
860     }
861
862   if(count != 1)
863     {
864       iw_usage();
865       goto err;
866     }
867
868   /* Read it */
869   /* As a string... */
870   k = 0;
871   while((k < 4) && strncasecmp(args[i], modes[k], 2))
872     k++;
873   if(k < 4)
874     ptype = k;
875   else
876     /* ...or as an integer */
877     if(sscanf(args[i], "%i", (int *) &ptype) != 1)
878       {
879         iw_usage();
880         goto err;
881       }
882   
883   k = -1;
884   while((++k < number) && strcmp(priv[k].name, "sport_type") &&
885         strcmp(priv[k].name, "set_port"));
886   if(k == number)
887     {
888       fprintf(stderr, "This device doesn't support setting port type\n");
889       goto err;
890     }
891   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
892
893   *(wrq.u.name) = ptype;
894
895   if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
896     {
897       fprintf(stderr, "Invalid port type (or setting not allowed)\n");
898       goto err;
899     }
900
901   free(priv);
902   return(0);
903
904  err:
905   free(priv);
906   return(-1);
907 }
908
909 /******************************* MAIN ********************************/
910
911 /*------------------------------------------------------------------*/
912 /*
913  * The main !
914  */
915 int
916 main(int        argc,
917      char **    argv)
918 {
919   int skfd;             /* generic raw socket desc.     */
920   int goterr = 0;
921
922   /* Create a channel to the NET kernel. */
923   if((skfd = iw_sockets_open()) < 0)
924     {
925       perror("socket");
926       return(-1);
927     }
928
929   /* No argument : show the list of all devices + ioctl list */
930   if(argc == 1)
931     iw_enum_devices(skfd, &print_priv_info, NULL, 0);
932   else
933     /* Special cases take one... */
934     /* All */
935     if((!strncmp(argv[1], "-a", 2)) || (!strcmp(argv[1], "--all")))
936       iw_enum_devices(skfd, &print_priv_all, NULL, 0);
937     else
938       /* Help */
939       if((!strncmp(argv[1], "-h", 2)) || (!strcmp(argv[1], "--help")))
940         iw_usage();
941       else
942         /* Version */
943         if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
944           goterr = iw_print_version_info("iwpriv");
945         else
946           /* The device name must be the first argument */
947           /* Name only : show for that device only */
948           if(argc == 2)
949             print_priv_info(skfd, argv[1], NULL, 0);
950           else
951             /* Special cases take two... */
952             /* All */
953             if((!strncmp(argv[2], "-a", 2)) ||
954                (!strcmp(argv[2], "--all")))
955               print_priv_all(skfd, argv[1], NULL, 0);
956             else
957               /* Roaming */
958               if(!strncmp(argv[2], "roam", 4))
959                 goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]);
960               else
961                 /* Port type */
962                 if(!strncmp(argv[2], "port", 4))
963                   goterr = port_type(skfd, argv + 3, argc - 3, argv[1]);
964                 else
965                   /*-------------*/
966                   /* Otherwise, it's a private ioctl */
967                   goterr = set_private(skfd, argv + 2, argc - 2, argv[1]);
968
969   /* Close the socket. */
970   iw_sockets_close(skfd);
971
972   return(goterr);
973 }