OSDN Git Service

v27
[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   fprintf(stderr, "              interface [roam {on|off}]\n");
245   fprintf(stderr, "              interface [port {ad-hoc|managed|N}]\n");
246 }
247
248 /************************* SETTING ROUTINES **************************/
249
250 /*------------------------------------------------------------------*/
251 /*
252  * Execute a private command on the interface
253  */
254 static int
255 set_private_cmd(int             skfd,           /* Socket */
256                 char *          args[],         /* Command line args */
257                 int             count,          /* Args count */
258                 char *          ifname,         /* Dev name */
259                 char *          cmdname,        /* Command name */
260                 iwprivargs *    priv,           /* Private ioctl description */
261                 int             priv_num)       /* Number of descriptions */
262 {
263   struct iwreq  wrq;
264   u_char        buffer[4096];   /* Only that big in v25 and later */
265   int           i = 0;          /* Start with first command arg */
266   int           k;              /* Index in private description table */
267   int           temp;
268   int           subcmd = 0;     /* sub-ioctl index */
269   int           offset = 0;     /* Space for sub-ioctl index */
270
271   /* Check if we have a token index.
272    * Do it now so that sub-ioctl takes precendence, and so that we
273    * don't have to bother with it later on... */
274   if((count >= 1) && (sscanf(args[0], "[%i]", &temp) == 1))
275     {
276       subcmd = temp;
277       args++;
278       count--;
279     }
280
281   /* Search the correct ioctl */
282   k = -1;
283   while((++k < priv_num) && strcmp(priv[k].name, cmdname));
284
285   /* If not found... */
286   if(k == priv_num)
287     {
288       fprintf(stderr, "Invalid command : %s\n", cmdname);
289       return(-1);
290     }
291           
292   /* Watch out for sub-ioctls ! */
293   if(priv[k].cmd < SIOCDEVPRIVATE)
294     {
295       int       j = -1;
296
297       /* Find the matching *real* ioctl */
298       while((++j < priv_num) && ((priv[j].name[0] != '\0') ||
299                                  (priv[j].set_args != priv[k].set_args) ||
300                                  (priv[j].get_args != priv[k].get_args)));
301
302       /* If not found... */
303       if(j == priv_num)
304         {
305           fprintf(stderr, "Invalid private ioctl definition for : %s\n",
306                   cmdname);
307           return(-1);
308         }
309
310       /* Save sub-ioctl number */
311       subcmd = priv[k].cmd;
312       /* Reserve one int (simplify alignment issues) */
313       offset = sizeof(__u32);
314       /* Use real ioctl definition from now on */
315       k = j;
316
317 #if 0
318       printf("<mapping sub-ioctl %s to cmd 0x%X-%d>\n", cmdname,
319              priv[k].cmd, subcmd);
320 #endif
321     }
322
323   /* If we have to set some data */
324   if((priv[k].set_args & IW_PRIV_TYPE_MASK) &&
325      (priv[k].set_args & IW_PRIV_SIZE_MASK))
326     {
327       switch(priv[k].set_args & IW_PRIV_TYPE_MASK)
328         {
329         case IW_PRIV_TYPE_BYTE:
330           /* Number of args to fetch */
331           wrq.u.data.length = count;
332           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
333             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
334
335           /* Fetch args */
336           for(; i < wrq.u.data.length; i++) {
337             sscanf(args[i], "%i", &temp);
338             buffer[i] = (char) temp;
339           }
340           break;
341
342         case IW_PRIV_TYPE_INT:
343           /* Number of args to fetch */
344           wrq.u.data.length = count;
345           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
346             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
347
348           /* Fetch args */
349           for(; i < wrq.u.data.length; i++) {
350             sscanf(args[i], "%i", &temp);
351             ((__s32 *) buffer)[i] = (__s32) temp;
352           }
353           break;
354
355         case IW_PRIV_TYPE_CHAR:
356           if(i < count)
357             {
358               /* Size of the string to fetch */
359               wrq.u.data.length = strlen(args[i]) + 1;
360               if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
361                 wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
362
363               /* Fetch string */
364               memcpy(buffer, args[i], wrq.u.data.length);
365               buffer[sizeof(buffer) - 1] = '\0';
366               i++;
367             }
368           else
369             {
370               wrq.u.data.length = 1;
371               buffer[0] = '\0';
372             }
373           break;
374
375         case IW_PRIV_TYPE_FLOAT:
376           /* Number of args to fetch */
377           wrq.u.data.length = count;
378           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
379             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
380
381           /* Fetch args */
382           for(; i < wrq.u.data.length; i++) {
383             double              freq;
384             if(sscanf(args[i], "%lg", &(freq)) != 1)
385               {
386                 printf("Invalid float [%s]...\n", args[i]);
387                 return(-1);
388               }    
389             if(index(args[i], 'G')) freq *= GIGA;
390             if(index(args[i], 'M')) freq *= MEGA;
391             if(index(args[i], 'k')) freq *= KILO;
392             sscanf(args[i], "%i", &temp);
393             iw_float2freq(freq, ((struct iw_freq *) buffer) + i);
394           }
395           break;
396
397         case IW_PRIV_TYPE_ADDR:
398           /* Number of args to fetch */
399           wrq.u.data.length = count;
400           if(wrq.u.data.length > (priv[k].set_args & IW_PRIV_SIZE_MASK))
401             wrq.u.data.length = priv[k].set_args & IW_PRIV_SIZE_MASK;
402
403           /* Fetch args */
404           for(; i < wrq.u.data.length; i++) {
405             if(iw_in_addr(skfd, ifname, args[i],
406                           ((struct sockaddr *) buffer) + i) < 0)
407               {
408                 printf("Invalid address [%s]...\n", args[i]);
409                 return(-1);
410               }
411           }
412           break;
413
414         default:
415           fprintf(stderr, "Not yet implemented...\n");
416           return(-1);
417         }
418           
419       if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
420          (wrq.u.data.length != (priv[k].set_args & IW_PRIV_SIZE_MASK)))
421         {
422           printf("The command %s need exactly %d argument...\n",
423                  cmdname, priv[k].set_args & IW_PRIV_SIZE_MASK);
424           return(-1);
425         }
426     }   /* if args to set */
427   else
428     {
429       wrq.u.data.length = 0L;
430     }
431
432   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
433
434   /* Those two tests are important. They define how the driver
435    * will have to handle the data */
436   if((priv[k].set_args & IW_PRIV_SIZE_FIXED) &&
437       ((iw_get_priv_size(priv[k].set_args) + offset) <= IFNAMSIZ))
438     {
439       /* First case : all SET args fit within wrq */
440       if(offset)
441         wrq.u.mode = subcmd;
442       memcpy(wrq.u.name + offset, buffer, IFNAMSIZ - offset);
443     }
444   else
445     {
446       if((priv[k].set_args == 0) &&
447          (priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
448          (iw_get_priv_size(priv[k].get_args) <= IFNAMSIZ))
449         {
450           /* Second case : no SET args, GET args fit within wrq */
451           if(offset)
452             wrq.u.mode = subcmd;
453         }
454       else
455         {
456           /* Thirst case : args won't fit in wrq, or variable number of args */
457           wrq.u.data.pointer = (caddr_t) buffer;
458           wrq.u.data.flags = subcmd;
459         }
460     }
461
462   /* Perform the private ioctl */
463   if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
464     {
465       fprintf(stderr, "Interface doesn't accept private ioctl...\n");
466       fprintf(stderr, "%s (%X): %s\n", cmdname, priv[k].cmd, strerror(errno));
467       return(-1);
468     }
469
470   /* If we have to get some data */
471   if((priv[k].get_args & IW_PRIV_TYPE_MASK) &&
472      (priv[k].get_args & IW_PRIV_SIZE_MASK))
473     {
474       int       j;
475       int       n = 0;          /* number of args */
476
477       printf("%-8.16s  %s:", ifname, cmdname);
478
479       /* Check where is the returned data */
480       if((priv[k].get_args & IW_PRIV_SIZE_FIXED) &&
481          (iw_get_priv_size(priv[k].get_args) <= IFNAMSIZ))
482         {
483           memcpy(buffer, wrq.u.name, IFNAMSIZ);
484           n = priv[k].get_args & IW_PRIV_SIZE_MASK;
485         }
486       else
487         n = wrq.u.data.length;
488
489       switch(priv[k].get_args & IW_PRIV_TYPE_MASK)
490         {
491         case IW_PRIV_TYPE_BYTE:
492           /* Display args */
493           for(j = 0; j < n; j++)
494             printf("%d  ", buffer[j]);
495           printf("\n");
496           break;
497
498         case IW_PRIV_TYPE_INT:
499           /* Display args */
500           for(j = 0; j < n; j++)
501             printf("%d  ", ((__s32 *) buffer)[j]);
502           printf("\n");
503           break;
504
505         case IW_PRIV_TYPE_CHAR:
506           /* Display args */
507           buffer[n] = '\0';
508           printf("%s\n", buffer);
509           break;
510
511         case IW_PRIV_TYPE_FLOAT:
512           {
513             double              freq;
514             /* Display args */
515             for(j = 0; j < n; j++)
516               {
517                 freq = iw_freq2float(((struct iw_freq *) buffer) + j);
518                 if(freq >= GIGA)
519                   printf("%gG  ", freq / GIGA);
520                 else
521                   if(freq >= MEGA)
522                   printf("%gM  ", freq / MEGA);
523                 else
524                   printf("%gk  ", freq / KILO);
525               }
526             printf("\n");
527           }
528           break;
529
530         case IW_PRIV_TYPE_ADDR:
531           {
532             char                scratch[128];
533             struct sockaddr *   hwa;
534             /* Display args */
535             for(j = 0; j < n; j++)
536               {
537                 hwa = ((struct sockaddr *) buffer) + j;
538                 if(j)
539                   printf("           %.*s", 
540                          (int) strlen(cmdname), "                ");
541                 printf("%s\n", iw_pr_ether(scratch, hwa->sa_data));
542               }
543           }
544           break;
545
546         default:
547           fprintf(stderr, "Not yet implemented...\n");
548           return(-1);
549         }
550     }   /* if args to set */
551
552   return(0);
553 }
554
555 /*------------------------------------------------------------------*/
556 /*
557  * Execute a private command on the interface
558  */
559 static inline int
560 set_private(int         skfd,           /* Socket */
561             char *      args[],         /* Command line args */
562             int         count,          /* Args count */
563             char *      ifname)         /* Dev name */
564 {
565   iwprivargs *  priv;
566   int           number;         /* Max of private ioctl */
567   int           ret;
568
569   /* Read the private ioctls */
570   number = iw_get_priv_info(skfd, ifname, &priv);
571
572   /* Is there any ? */
573   if(number <= 0)
574     {
575       /* Should I skip this message ? */
576       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
577               ifname);
578       if(priv)
579         free(priv);
580       return(-1);
581     }
582
583   /* Do it */
584   ret = set_private_cmd(skfd, args + 1, count - 1, ifname, args[0],
585                         priv, number);
586
587   free(priv);
588   return(ret);
589 }
590
591 /************************ CATALOG FUNCTIONS ************************/
592
593 /*------------------------------------------------------------------*/
594 /*
595  * Print on the screen in a neat fashion the list of private ioctls
596  * for the device.
597  */
598 static int
599 print_priv_info(int             skfd,
600                 char *          ifname,
601                 char *          args[],
602                 int             count)
603 {
604   int           k;
605   iwprivargs *  priv;
606   int           n;
607
608   /* Avoid "Unused parameter" warning */
609   args = args; count = count;
610
611   /* Read the private ioctls */
612   n = iw_get_priv_info(skfd, ifname, &priv);
613
614   /* Is there any ? */
615   if(n <= 0)
616     {
617       /* Should I skip this message ? */
618       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
619               ifname);
620     }
621   else
622     {
623       printf("%-8.16s  Available private ioctl :\n", ifname);
624       /* Print them all */
625       for(k = 0; k < n; k++)
626         if(priv[k].name[0] != '\0')
627           printf("          %-16.16s (%.4X) : set %3d %s & get %3d %s\n",
628                  priv[k].name, priv[k].cmd,
629                  priv[k].set_args & IW_PRIV_SIZE_MASK,
630                  argtype[(priv[k].set_args & IW_PRIV_TYPE_MASK) >> 12],
631                  priv[k].get_args & IW_PRIV_SIZE_MASK,
632                  argtype[(priv[k].get_args & IW_PRIV_TYPE_MASK) >> 12]);
633       printf("\n");
634     }
635
636   /* Cleanup */
637   if(priv)
638     free(priv);
639   return(0);
640 }
641
642 /*------------------------------------------------------------------*/
643 /*
644  * Print on the screen in a neat fashion the list of private GET ioctl
645  * data for the device and data returned by those.
646  */
647 static int
648 print_priv_all(int              skfd,
649                char *           ifname,
650                char *           args[],
651                int              count)
652 {
653   int           k;
654   iwprivargs *  priv;
655   int           n;
656
657   /* Avoid "Unused parameter" warning */
658   args = args; count = count;
659
660   /* Read the private ioctls */
661   n = iw_get_priv_info(skfd, ifname, &priv);
662
663   /* Is there any ? */
664   if(n <= 0)
665     {
666       /* Should I skip this message ? */
667       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
668               ifname);
669     }
670   else
671     {
672       printf("%-8.16s  Available read-only private ioctl :\n", ifname);
673       /* Print them all */
674       for(k = 0; k < n; k++)
675         /* We call all ioctls that don't have a null name, don't require
676          * args and return some (avoid triggering "reset" commands) */
677         if((priv[k].name[0] != '\0') && (priv[k].set_args == 0) &&
678            (priv[k].get_args != 0))
679           set_private_cmd(skfd, NULL, 0, ifname, priv[k].name,
680                           priv, n);
681       printf("\n");
682     }
683
684   /* Cleanup */
685   if(priv)
686     free(priv);
687   return(0);
688 }
689
690 /********************** PRIVATE IOCTLS MANIPS ***********************/
691 /*
692  * Convenient access to some private ioctls of some devices
693  */
694
695 /*------------------------------------------------------------------*/
696 /*
697  * Set roaming mode on and off
698  * Found in wavelan_cs driver
699  * Note : this is obsolete, most 802.11 devices should use the
700  * SIOCSIWAP request.
701  */
702 static int
703 set_roaming(int         skfd,           /* Socket */
704             char *      args[],         /* Command line args */
705             int         count,          /* Args count */
706             char *      ifname)         /* Dev name */
707 {
708   u_char        buffer[1024];
709   struct iwreq          wrq;
710   int           i = 0;          /* Start with first arg */
711   int           k;
712   iwprivargs *  priv;
713   int           number;
714   int           roamcmd;
715   char          RoamState;              /* buffer to hold new roam state */
716   char          ChangeRoamState=0;      /* whether or not we are going to
717                                            change roam states */
718
719   /* Read the private ioctls */
720   number = iw_get_priv_info(skfd, ifname, &priv);
721
722   /* Is there any ? */
723   if(number <= 0)
724     {
725       /* Should I skip this message ? */
726       fprintf(stderr, "%-8.16s  no private ioctls.\n\n",
727               ifname);
728       if(priv)
729         free(priv);
730       return(-1);
731     }
732
733   /* Get the ioctl number */
734   k = -1;
735   while((++k < number) && strcmp(priv[k].name, "setroam"));
736   if(k == number)
737     {
738       fprintf(stderr, "This device doesn't support roaming\n");
739       free(priv);
740       return(-1);
741     }
742   roamcmd = priv[k].cmd;
743
744   /* Cleanup */
745   free(priv);
746
747   if(count != 1)
748     {
749       iw_usage();
750       return(-1);
751     }
752
753   if(!strcasecmp(args[i], "on"))
754     {
755       printf("%-8.16s  enable roaming\n", ifname);
756       if(!number)
757         {
758           fprintf(stderr, "This device doesn't support roaming\n");
759           return(-1);
760         }
761       ChangeRoamState=1;
762       RoamState=1;
763     }
764   else
765     if(!strcasecmp(args[i], "off"))
766       {
767         i++;
768         printf("%-8.16s  disable roaming\n",  ifname);
769         if(!number)
770           {
771             fprintf(stderr, "This device doesn't support roaming\n");
772             return(-1);
773           }
774         ChangeRoamState=1;
775         RoamState=0;
776       }
777     else
778       {
779         iw_usage();
780         return(-1);
781       }
782
783   if(ChangeRoamState)
784     {
785       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
786
787       buffer[0]=RoamState;
788
789       memcpy(wrq.u.name, &buffer, IFNAMSIZ);
790
791       if(ioctl(skfd, roamcmd, &wrq) < 0)
792         {
793           fprintf(stderr, "Roaming support is broken.\n");
794           return(-1);
795         }
796     }
797
798   return(0);
799 }
800
801 /*------------------------------------------------------------------*/
802 /*
803  * Get and set the port type
804  * Found in wavelan2_cs and wvlan_cs drivers
805  * TODO : Add support for HostAP ?
806  */
807 static int
808 port_type(int           skfd,           /* Socket */
809           char *        args[],         /* Command line args */
810           int           count,          /* Args count */
811           char *        ifname)         /* Dev name */
812 {
813   struct iwreq  wrq;
814   int           i = 0;          /* Start with first arg */
815   int           k;
816   iwprivargs *  priv;
817   int           number;
818   char          ptype = 0;
819   char *        modes[] = { "invalid", "managed (BSS)", "reserved", "ad-hoc" };
820
821   /* Read the private ioctls */
822   number = iw_get_priv_info(skfd, ifname, &priv);
823
824   /* Is there any ? */
825   if(number <= 0)
826     {
827       /* Should I skip this message ? */
828       fprintf(stderr, "%-8.16s  no private ioctls.\n\n", ifname);
829       if(priv)
830         free(priv);
831       return(-1);
832     }
833
834   /* Arguments ? */
835   if(count == 0)
836     {
837       /* So, we just want to see the current value... */
838       k = -1;
839       while((++k < number) && strcmp(priv[k].name, "gport_type") &&
840              strcmp(priv[k].name, "get_port"));
841       if(k == number)
842         {
843           fprintf(stderr, "This device doesn't support getting port type\n");
844           goto err;
845         }
846       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
847
848       /* Get it */
849       if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
850         {
851           fprintf(stderr, "Port type support is broken.\n");
852           goto err;
853         }
854       ptype = *wrq.u.name;
855
856       /* Display it */
857       printf("%-8.16s  Current port mode is %s <port type is %d>.\n\n",
858              ifname, modes[(int) ptype], ptype);
859
860       free(priv);
861       return(0);
862     }
863
864   if(count != 1)
865     {
866       iw_usage();
867       goto err;
868     }
869
870   /* Read it */
871   /* As a string... */
872   k = 0;
873   while((k < 4) && strncasecmp(args[i], modes[k], 2))
874     k++;
875   if(k < 4)
876     ptype = k;
877   else
878     /* ...or as an integer */
879     if(sscanf(args[i], "%i", (int *) &ptype) != 1)
880       {
881         iw_usage();
882         goto err;
883       }
884   
885   k = -1;
886   while((++k < number) && strcmp(priv[k].name, "sport_type") &&
887         strcmp(priv[k].name, "set_port"));
888   if(k == number)
889     {
890       fprintf(stderr, "This device doesn't support setting port type\n");
891       goto err;
892     }
893   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
894
895   *(wrq.u.name) = ptype;
896
897   if(ioctl(skfd, priv[k].cmd, &wrq) < 0)
898     {
899       fprintf(stderr, "Invalid port type (or setting not allowed)\n");
900       goto err;
901     }
902
903   free(priv);
904   return(0);
905
906  err:
907   free(priv);
908   return(-1);
909 }
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               /* Roaming */
960               if(!strncmp(argv[2], "roam", 4))
961                 goterr = set_roaming(skfd, argv + 3, argc - 3, argv[1]);
962               else
963                 /* Port type */
964                 if(!strncmp(argv[2], "port", 4))
965                   goterr = port_type(skfd, argv + 3, argc - 3, argv[1]);
966                 else
967                   /*-------------*/
968                   /* Otherwise, it's a private ioctl */
969                   goterr = set_private(skfd, argv + 2, argc - 2, argv[1]);
970
971   /* Close the socket. */
972   iw_sockets_close(skfd);
973
974   return(goterr);
975 }