OSDN Git Service

Update README.md
[android-x86/external-wireless-tools.git] / wireless_tools / iwconfig.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.h"              /* Header */
15
16 /**************************** CONSTANTS ****************************/
17
18 /*
19  * Error codes defined for setting args
20  */
21 #define IWERR_ARG_NUM           -2
22 #define IWERR_ARG_TYPE          -3
23 #define IWERR_ARG_SIZE          -4
24 #define IWERR_ARG_CONFLICT      -5
25 #define IWERR_SET_EXT           -6
26 #define IWERR_GET_EXT           -7
27
28 /**************************** VARIABLES ****************************/
29
30 /*
31  * Ugly, but deal with errors in set_info() efficiently...
32  */
33 static int      errarg;
34 static int      errmax;
35
36 /************************* DISPLAY ROUTINES **************************/
37
38 /*------------------------------------------------------------------*/
39 /*
40  * Get wireless informations & config from the device driver
41  * We will call all the classical wireless ioctl on the driver through
42  * the socket to know what is supported and to get the settings...
43  */
44 static int
45 get_info(int                    skfd,
46          char *                 ifname,
47          struct wireless_info * info)
48 {
49   struct iwreq          wrq;
50
51   memset((char *) info, 0, sizeof(struct wireless_info));
52
53   /* Get basic information */
54   if(iw_get_basic_config(skfd, ifname, &(info->b)) < 0)
55     {
56       /* If no wireless name : no wireless extensions */
57       /* But let's check if the interface exists at all */
58       struct ifreq ifr;
59
60       strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
61       if(ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
62         return(-ENODEV);
63       else
64         return(-ENOTSUP);
65     }
66
67   /* Get ranges */
68   if(iw_get_range_info(skfd, ifname, &(info->range)) >= 0)
69     info->has_range = 1;
70
71   /* Get AP address */
72   if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) >= 0)
73     {
74       info->has_ap_addr = 1;
75       memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
76     }
77
78   /* Get bit rate */
79   if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
80     {
81       info->has_bitrate = 1;
82       memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
83     }
84
85   /* Get Power Management settings */
86   wrq.u.power.flags = 0;
87   if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
88     {
89       info->has_power = 1;
90       memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
91     }
92
93   /* Get stats */
94   if(iw_get_stats(skfd, ifname, &(info->stats),
95                   &info->range, info->has_range) >= 0)
96     {
97       info->has_stats = 1;
98     }
99
100 #ifndef WE_ESSENTIAL
101   /* Get NickName */
102   wrq.u.essid.pointer = (caddr_t) info->nickname;
103   wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
104   wrq.u.essid.flags = 0;
105   if(iw_get_ext(skfd, ifname, SIOCGIWNICKN, &wrq) >= 0)
106     if(wrq.u.data.length > 1)
107       info->has_nickname = 1;
108
109   if((info->has_range) && (info->range.we_version_compiled > 9))
110     {
111       /* Get Transmit Power */
112       if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
113         {
114           info->has_txpower = 1;
115           memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
116         }
117     }
118
119   /* Get sensitivity */
120   if(iw_get_ext(skfd, ifname, SIOCGIWSENS, &wrq) >= 0)
121     {
122       info->has_sens = 1;
123       memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
124     }
125
126   if((info->has_range) && (info->range.we_version_compiled > 10))
127     {
128       /* Get retry limit/lifetime */
129       if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
130         {
131           info->has_retry = 1;
132           memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
133         }
134     }
135
136   /* Get RTS threshold */
137   if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) >= 0)
138     {
139       info->has_rts = 1;
140       memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
141     }
142
143   /* Get fragmentation threshold */
144   if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) >= 0)
145     {
146       info->has_frag = 1;
147       memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
148     }
149 #endif  /* WE_ESSENTIAL */
150
151   return(0);
152 }
153
154 /*------------------------------------------------------------------*/
155 /*
156  * Print on the screen in a neat fashion all the info we have collected
157  * on a device.
158  */
159 static void
160 display_info(struct wireless_info *     info,
161              char *                     ifname)
162 {
163   char          buffer[128];    /* Temporary buffer */
164
165   /* One token is more of less 5 characters, 14 tokens per line */
166   int   tokens = 3;     /* For name */
167
168   /* Display device name and wireless name (name of the protocol used) */
169   printf("%-8.16s  %s  ", ifname, info->b.name);
170
171   /* Display ESSID (extended network), if any */
172   if(info->b.has_essid)
173     {
174       if(info->b.essid_on)
175         {
176           /* Does it have an ESSID index ? */
177           if((info->b.essid_on & IW_ENCODE_INDEX) > 1)
178             printf("ESSID:\"%s\" [%d]  ", info->b.essid,
179                    (info->b.essid_on & IW_ENCODE_INDEX));
180           else
181             printf("ESSID:\"%s\"  ", info->b.essid);
182         }
183       else
184         printf("ESSID:off/any  ");
185     }
186
187 #ifndef WE_ESSENTIAL
188   /* Display NickName (station name), if any */
189   if(info->has_nickname)
190     printf("Nickname:\"%s\"", info->nickname);
191 #endif  /* WE_ESSENTIAL */
192
193   /* Formatting */
194   if(info->b.has_essid || info->has_nickname)
195     {
196       printf("\n          ");
197       tokens = 0;
198     }
199
200 #ifndef WE_ESSENTIAL
201   /* Display Network ID */
202   if(info->b.has_nwid)
203     {
204       /* Note : should display proper number of digits according to info
205        * in range structure */
206       if(info->b.nwid.disabled)
207         printf("NWID:off/any  ");
208       else
209         printf("NWID:%X  ", info->b.nwid.value);
210       tokens +=2;
211     }
212 #endif  /* WE_ESSENTIAL */
213
214   /* Display the current mode of operation */
215   if(info->b.has_mode)
216     {
217       printf("Mode:%s  ", iw_operation_mode[info->b.mode]);
218       tokens +=3;
219     }
220
221   /* Display frequency / channel */
222   if(info->b.has_freq)
223     {
224       double            freq = info->b.freq;    /* Frequency/channel */
225       int               channel = -1;           /* Converted to channel */
226       /* Some drivers insist of returning channel instead of frequency.
227        * This fixes them up. Note that, driver should still return
228        * frequency, because other tools depend on it. */
229       if(info->has_range && (freq < KILO))
230         channel = iw_channel_to_freq((int) freq, &freq, &info->range);
231       /* Display */
232       iw_print_freq(buffer, sizeof(buffer), freq, -1, info->b.freq_flags);
233       printf("%s  ", buffer);
234       tokens +=4;
235     }
236
237   /* Display the address of the current Access Point */
238   if(info->has_ap_addr)
239     {
240       /* A bit of clever formatting */
241       if(tokens > 8)
242         {
243           printf("\n          ");
244           tokens = 0;
245         }
246       tokens +=6;
247
248       /* Oups ! No Access Point in Ad-Hoc mode */
249       if((info->b.has_mode) && (info->b.mode == IW_MODE_ADHOC))
250         printf("Cell:");
251       else
252         printf("Access Point:");
253       printf(" %s   ", iw_sawap_ntop(&info->ap_addr, buffer));
254     }
255
256   /* Display the currently used/set bit-rate */
257   if(info->has_bitrate)
258     {
259       /* A bit of clever formatting */
260       if(tokens > 11)
261         {
262           printf("\n          ");
263           tokens = 0;
264         }
265       tokens +=3;
266
267       /* Display it */
268       iw_print_bitrate(buffer, sizeof(buffer), info->bitrate.value);
269       printf("Bit Rate%c%s   ", (info->bitrate.fixed ? '=' : ':'), buffer);
270     }
271
272 #ifndef WE_ESSENTIAL
273   /* Display the Transmit Power */
274   if(info->has_txpower)
275     {
276       /* A bit of clever formatting */
277       if(tokens > 11)
278         {
279           printf("\n          ");
280           tokens = 0;
281         }
282       tokens +=3;
283
284       /* Display it */
285       iw_print_txpower(buffer, sizeof(buffer), &info->txpower);
286       printf("Tx-Power%c%s   ", (info->txpower.fixed ? '=' : ':'), buffer);
287     }
288
289   /* Display sensitivity */
290   if(info->has_sens)
291     {
292       /* A bit of clever formatting */
293       if(tokens > 10)
294         {
295           printf("\n          ");
296           tokens = 0;
297         }
298       tokens +=4;
299
300       /* Fixed ? */
301       printf("Sensitivity%c", info->sens.fixed ? '=' : ':');
302
303       if(info->has_range)
304         /* Display in dBm ? */
305         if(info->sens.value < 0)
306           printf("%d dBm  ", info->sens.value);
307         else
308           printf("%d/%d  ", info->sens.value, info->range.sensitivity);
309       else
310         printf("%d  ", info->sens.value);
311     }
312 #endif  /* WE_ESSENTIAL */
313
314   printf("\n          ");
315   tokens = 0;
316
317 #ifndef WE_ESSENTIAL
318   /* Display retry limit/lifetime information */
319   if(info->has_retry)
320     { 
321       printf("Retry");
322       /* Disabled ? */
323       if(info->retry.disabled)
324         printf(":off");
325       else
326         {
327           /* Let's check the value and its type */
328           if(info->retry.flags & IW_RETRY_TYPE)
329             {
330               iw_print_retry_value(buffer, sizeof(buffer),
331                                    info->retry.value, info->retry.flags,
332                                    info->range.we_version_compiled);
333               printf("%s", buffer);
334             }
335
336           /* Let's check if nothing (simply on) */
337           if(info->retry.flags == IW_RETRY_ON)
338             printf(":on");
339         }
340       printf("   ");
341       tokens += 5;      /* Between 3 and 5, depend on flags */
342     }
343
344   /* Display the RTS threshold */
345   if(info->has_rts)
346     {
347       /* Disabled ? */
348       if(info->rts.disabled)
349         printf("RTS thr:off   ");
350       else
351         {
352           /* Fixed ? */
353           printf("RTS thr%c%d B   ",
354                  info->rts.fixed ? '=' : ':',
355                  info->rts.value);
356         }
357       tokens += 3;
358     }
359
360   /* Display the fragmentation threshold */
361   if(info->has_frag)
362     {
363       /* A bit of clever formatting */
364       if(tokens > 10)
365         {
366           printf("\n          ");
367           tokens = 0;
368         }
369       tokens +=4;
370
371       /* Disabled ? */
372       if(info->frag.disabled)
373         printf("Fragment thr:off");
374       else
375         {
376           /* Fixed ? */
377           printf("Fragment thr%c%d B   ",
378                  info->frag.fixed ? '=' : ':',
379                  info->frag.value);
380         }
381     }
382
383   /* Formating */
384   if(tokens > 0)
385     printf("\n          ");
386 #endif  /* WE_ESSENTIAL */
387
388   /* Display encryption information */
389   /* Note : we display only the "current" key, use iwlist to list all keys */
390   if(info->b.has_key)
391     {
392       printf("Encryption key:");
393       if((info->b.key_flags & IW_ENCODE_DISABLED) || (info->b.key_size == 0))
394         printf("off");
395       else
396         {
397           /* Display the key */
398           iw_print_key(buffer, sizeof(buffer),
399                        info->b.key, info->b.key_size, info->b.key_flags);
400           printf("%s", buffer);
401
402           /* Other info... */
403           if((info->b.key_flags & IW_ENCODE_INDEX) > 1)
404             printf(" [%d]", info->b.key_flags & IW_ENCODE_INDEX);
405           if(info->b.key_flags & IW_ENCODE_RESTRICTED)
406             printf("   Security mode:restricted");
407           if(info->b.key_flags & IW_ENCODE_OPEN)
408             printf("   Security mode:open");
409         }
410       printf("\n          ");
411     }
412
413   /* Display Power Management information */
414   /* Note : we display only one parameter, period or timeout. If a device
415    * (such as HiperLan) has both, the user need to use iwlist... */
416   if(info->has_power)   /* I hope the device has power ;-) */
417     { 
418       printf("Power Management");
419       /* Disabled ? */
420       if(info->power.disabled)
421         printf(":off");
422       else
423         {
424           /* Let's check the value and its type */
425           if(info->power.flags & IW_POWER_TYPE)
426             {
427               iw_print_pm_value(buffer, sizeof(buffer),
428                                 info->power.value, info->power.flags,
429                                 info->range.we_version_compiled);
430               printf("%s  ", buffer);
431             }
432
433           /* Let's check the mode */
434           iw_print_pm_mode(buffer, sizeof(buffer), info->power.flags);
435           printf("%s", buffer);
436
437           /* Let's check if nothing (simply on) */
438           if(info->power.flags == IW_POWER_ON)
439             printf(":on");
440         }
441       printf("\n          ");
442     }
443
444   /* Display statistics */
445   if(info->has_stats)
446     {
447       iw_print_stats(buffer, sizeof(buffer),
448                      &info->stats.qual, &info->range, info->has_range);
449       printf("Link %s\n", buffer);
450
451       if(info->range.we_version_compiled > 11)
452         printf("          Rx invalid nwid:%d  Rx invalid crypt:%d  Rx invalid frag:%d\n          Tx excessive retries:%d  Invalid misc:%d   Missed beacon:%d\n",
453                info->stats.discard.nwid,
454                info->stats.discard.code,
455                info->stats.discard.fragment,
456                info->stats.discard.retries,
457                info->stats.discard.misc,
458                info->stats.miss.beacon);
459       else
460         printf("          Rx invalid nwid:%d  invalid crypt:%d  invalid misc:%d\n",
461                info->stats.discard.nwid,
462                info->stats.discard.code,
463                info->stats.discard.misc);
464     }
465
466   printf("\n");
467 }
468
469 /*------------------------------------------------------------------*/
470 /*
471  * Print on the screen in a neat fashion all the info we have collected
472  * on a device.
473  */
474 static int
475 print_info(int          skfd,
476            char *       ifname,
477            char *       args[],
478            int          count)
479 {
480   struct wireless_info  info;
481   int                   rc;
482
483   /* Avoid "Unused parameter" warning */
484   args = args; count = count;
485
486   rc = get_info(skfd, ifname, &info);
487   switch(rc)
488     {
489     case 0:     /* Success */
490       /* Display it ! */
491       display_info(&info, ifname);
492       break;
493
494     case -ENOTSUP:
495       fprintf(stderr, "%-8.16s  no wireless extensions.\n\n",
496               ifname);
497       break;
498
499     default:
500       fprintf(stderr, "%-8.16s  %s\n\n", ifname, strerror(-rc));
501     }
502   return(rc);
503 }
504
505 /****************** COMMAND LINE MODIFIERS PARSING ******************/
506 /*
507  * Factor out the parsing of command line modifiers.
508  */
509
510 /*------------------------------------------------------------------*/
511 /*
512  * Map command line modifiers to the proper flags...
513  */
514 typedef struct iwconfig_modifier {
515   const char *          cmd;            /* Command line shorthand */
516   __u16                 flag;           /* Flags to add */
517   __u16                 exclude;        /* Modifiers to exclude */
518 } iwconfig_modifier;
519
520 /*------------------------------------------------------------------*/
521 /*
522  * Modifiers for Power
523  */
524 static const struct iwconfig_modifier   iwmod_power[] = {
525   { "min",      IW_POWER_MIN,           IW_POWER_MAX },
526   { "max",      IW_POWER_MAX,           IW_POWER_MIN },
527   { "period",   IW_POWER_PERIOD,        IW_POWER_TIMEOUT | IW_POWER_SAVING },
528   { "timeout",  IW_POWER_TIMEOUT,       IW_POWER_PERIOD | IW_POWER_SAVING },
529   { "saving",   IW_POWER_SAVING,        IW_POWER_TIMEOUT | IW_POWER_PERIOD },
530 };
531 #define IWMOD_POWER_NUM (sizeof(iwmod_power)/sizeof(iwmod_power[0]))
532
533 /*------------------------------------------------------------------*/
534 /*
535  * Modifiers for Retry
536  */
537 #ifndef WE_ESSENTIAL
538 static const struct iwconfig_modifier   iwmod_retry[] = {
539   { "min",      IW_RETRY_MIN,           IW_RETRY_MAX },
540   { "max",      IW_RETRY_MAX,           IW_RETRY_MIN },
541   { "short",    IW_RETRY_SHORT,         IW_RETRY_LONG },
542   { "long",     IW_RETRY_LONG,          IW_RETRY_SHORT },
543   { "limit",    IW_RETRY_LIMIT,         IW_RETRY_LIFETIME },
544   { "lifetime", IW_RETRY_LIFETIME,      IW_RETRY_LIMIT },
545 };
546 #define IWMOD_RETRY_NUM (sizeof(iwmod_retry)/sizeof(iwmod_retry[0]))
547 #endif  /* WE_ESSENTIAL */
548
549 /*------------------------------------------------------------------*/
550 /*
551  * Parse command line modifiers.
552  * Return error or number arg parsed.
553  * Modifiers must be at the beggining of command line.
554  */
555 static int
556 parse_modifiers(char *          args[],         /* Command line args */
557                 int             count,          /* Args count */
558                 __u16 *         pout,           /* Flags to write */
559                 const struct iwconfig_modifier  modifier[],
560                 int             modnum)
561 {
562   int           i = 0;
563   int           k = 0;
564   __u16         result = 0;     /* Default : no flag set */
565
566   /* Get all modifiers and value types on the command line */
567   do
568     {
569       for(k = 0; k < modnum; k++)
570         {
571           /* Check if matches */
572           if(!strcasecmp(args[i], modifier[k].cmd))
573             {
574               /* Check for conflicting flags */
575               if(result & modifier[k].exclude)
576                 {
577                   errarg = i;
578                   return(IWERR_ARG_CONFLICT);
579                 }
580               /* Just add it */
581               result |= modifier[k].flag;
582               ++i;
583               break;
584             }
585         }
586     }
587   /* For as long as current arg matched and not out of args */
588   while((i < count) && (k < modnum));
589
590   /* Check there remains one arg for value */
591   if(i >= count)
592     return(IWERR_ARG_NUM);
593
594   /* Return result */
595   *pout = result;
596   return(i);
597 }
598
599
600 /*********************** SETTING SUB-ROUTINES ***********************/
601 /*
602  * The following functions are use to set some wireless parameters and
603  * are called by the set dispatcher set_info().
604  * They take as arguments the remaining of the command line, with
605  * arguments processed already removed.
606  * An error is indicated by a negative return value.
607  * 0 and positive return values indicate the number of args consumed.
608  */
609
610 /*------------------------------------------------------------------*/
611 /*
612  * Set ESSID
613  */
614 static int
615 set_essid_info(int              skfd,
616                char *           ifname,
617                char *           args[],         /* Command line args */
618                int              count)          /* Args count */
619 {
620   struct iwreq          wrq;
621   int                   i = 1;
622   char                  essid[IW_ESSID_MAX_SIZE + 1];
623   int                   we_kernel_version;
624
625   if((!strcasecmp(args[0], "off")) ||
626      (!strcasecmp(args[0], "any")))
627     {
628       wrq.u.essid.flags = 0;
629       essid[0] = '\0';
630     }
631   else
632     if(!strcasecmp(args[0], "on"))
633       {
634         /* Get old essid */
635         memset(essid, '\0', sizeof(essid));
636         wrq.u.essid.pointer = (caddr_t) essid;
637         wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
638         wrq.u.essid.flags = 0;
639         if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) < 0)
640           return(IWERR_GET_EXT);
641         wrq.u.essid.flags = 1;
642       }
643     else
644       {
645         i = 0;
646
647         /* '-' or '--' allow to escape the ESSID string, allowing
648          * to set it to the string "any" or "off".
649          * This is a big ugly, but it will do for now */
650         if((!strcmp(args[0], "-")) || (!strcmp(args[0], "--")))
651           {
652             if(++i >= count)
653               return(IWERR_ARG_NUM);
654           }
655
656         /* Check the size of what the user passed us to avoid
657          * buffer overflows */
658         if(strlen(args[i]) > IW_ESSID_MAX_SIZE)
659           {
660             errmax = IW_ESSID_MAX_SIZE;
661             return(IWERR_ARG_SIZE);
662           }
663         else
664           {
665             int         temp;
666
667             wrq.u.essid.flags = 1;
668             strcpy(essid, args[i]);     /* Size checked, all clear */
669             i++;
670
671             /* Check for ESSID index */
672             if((i < count) &&
673                (sscanf(args[i], "[%i]", &temp) == 1) &&
674                (temp > 0) && (temp < IW_ENCODE_INDEX))
675               {
676                 wrq.u.essid.flags = temp;
677                 ++i;
678               }
679           }
680       }
681
682   /* Get version from kernel, device may not have range... */
683   we_kernel_version = iw_get_kernel_we_version();
684
685   /* Finally set the ESSID value */
686   wrq.u.essid.pointer = (caddr_t) essid;
687   wrq.u.essid.length = strlen(essid);
688   if(we_kernel_version < 21)
689     wrq.u.essid.length++;
690
691   if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
692     return(IWERR_SET_EXT);
693
694   /* Var args */
695   return(i);
696 }
697
698 /*------------------------------------------------------------------*/
699 /*
700  * Set Mode
701  */
702 static int
703 set_mode_info(int               skfd,
704               char *            ifname,
705               char *            args[],         /* Command line args */
706               int               count)          /* Args count */
707 {
708   struct iwreq          wrq;
709   unsigned int          k;              /* Must be unsigned */
710
711   /* Avoid "Unused parameter" warning */
712   count = count;
713
714   /* Check if it is a uint, otherwise get is as a string */
715   if(sscanf(args[0], "%i", &k) != 1)
716     {
717       k = 0;
718       while((k < IW_NUM_OPER_MODE) &&
719             strncasecmp(args[0], iw_operation_mode[k], 3))
720         k++;
721     }
722   if(k >= IW_NUM_OPER_MODE)
723     {
724       errarg = 0;
725       return(IWERR_ARG_TYPE);
726     }
727
728   wrq.u.mode = k;
729   if(iw_set_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
730     return(IWERR_SET_EXT);
731
732   /* 1 arg */
733   return(1);
734 }
735
736 /*------------------------------------------------------------------*/
737 /*
738  * Set frequency/channel
739  */
740 static int
741 set_freq_info(int               skfd,
742               char *            ifname,
743               char *            args[],         /* Command line args */
744               int               count)          /* Args count */
745 {
746   struct iwreq          wrq;
747   int                   i = 1;
748
749   if(!strcasecmp(args[0], "auto"))
750     {
751       wrq.u.freq.m = -1;
752       wrq.u.freq.e = 0;
753       wrq.u.freq.flags = 0;
754     }
755   else
756     {
757       if(!strcasecmp(args[0], "fixed"))
758         {
759           /* Get old frequency */
760           if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
761             return(IWERR_GET_EXT);
762           wrq.u.freq.flags = IW_FREQ_FIXED;
763         }
764       else                      /* Should be a numeric value */
765         {
766           double                freq;
767           char *                unit;
768
769           freq = strtod(args[0], &unit);
770           if(unit == args[0])
771             {
772               errarg = 0;
773               return(IWERR_ARG_TYPE);
774             }
775           if(unit != NULL)
776             {
777               if(unit[0] == 'G') freq *= GIGA;
778               if(unit[0] == 'M') freq *= MEGA;
779               if(unit[0] == 'k') freq *= KILO;
780             }
781
782           iw_float2freq(freq, &(wrq.u.freq));
783
784           wrq.u.freq.flags = IW_FREQ_FIXED;
785
786           /* Check for an additional argument */
787           if((i < count) && (!strcasecmp(args[i], "auto")))
788             {
789               wrq.u.freq.flags = 0;
790               ++i;
791             }
792           if((i < count) && (!strcasecmp(args[i], "fixed")))
793             {
794               wrq.u.freq.flags = IW_FREQ_FIXED;
795               ++i;
796             }
797         }
798     }
799
800   if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
801     return(IWERR_SET_EXT);
802
803   /* Var args */
804   return(i);
805 }
806
807 /*------------------------------------------------------------------*/
808 /*
809  * Set Bit Rate
810  */
811 static int
812 set_bitrate_info(int            skfd,
813                  char *         ifname,
814                  char *         args[],         /* Command line args */
815                  int            count)          /* Args count */
816 {
817   struct iwreq          wrq;
818   int                   i = 1;
819
820   wrq.u.bitrate.flags = 0;
821   if(!strcasecmp(args[0], "auto"))
822     {
823       wrq.u.bitrate.value = -1;
824       wrq.u.bitrate.fixed = 0;
825     }
826   else
827     {
828       if(!strcasecmp(args[0], "fixed"))
829         {
830           /* Get old bitrate */
831           if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) < 0)
832             return(IWERR_GET_EXT);
833           wrq.u.bitrate.fixed = 1;
834         }
835       else                      /* Should be a numeric value */
836         {
837           double                brate;
838           char *                unit;
839
840           brate = strtod(args[0], &unit);
841           if(unit == args[0])
842             {
843               errarg = 0;
844               return(IWERR_ARG_TYPE);
845             }
846           if(unit != NULL)
847             {
848               if(unit[0] == 'G') brate *= GIGA;
849               if(unit[0] == 'M') brate *= MEGA;
850               if(unit[0] == 'k') brate *= KILO;
851             }
852           wrq.u.bitrate.value = (long) brate;
853           wrq.u.bitrate.fixed = 1;
854
855           /* Check for an additional argument */
856           if((i < count) && (!strcasecmp(args[i], "auto")))
857             {
858               wrq.u.bitrate.fixed = 0;
859               ++i;
860             }
861           if((i < count) && (!strcasecmp(args[i], "fixed")))
862             {
863               wrq.u.bitrate.fixed = 1;
864               ++i;
865             }
866           if((i < count) && (!strcasecmp(args[i], "unicast")))
867             {
868               wrq.u.bitrate.flags |= IW_BITRATE_UNICAST;
869               ++i;
870             }
871           if((i < count) && (!strcasecmp(args[i], "broadcast")))
872             {
873               wrq.u.bitrate.flags |= IW_BITRATE_BROADCAST;
874               ++i;
875             }
876         }
877     }
878
879   if(iw_set_ext(skfd, ifname, SIOCSIWRATE, &wrq) < 0)
880     return(IWERR_SET_EXT);
881
882   /* Var args */
883   return(i);
884 }
885
886 /*------------------------------------------------------------------*/
887 /*
888  * Set encryption
889  */
890 static int
891 set_enc_info(int                skfd,
892              char *             ifname,
893              char *             args[],         /* Command line args */
894              int                count)          /* Args count */
895 {
896   struct iwreq          wrq;
897   int                   i = 1;
898   unsigned char         key[IW_ENCODING_TOKEN_MAX];
899
900   if(!strcasecmp(args[0], "on"))
901     {
902       /* Get old encryption information */
903       wrq.u.data.pointer = (caddr_t) key;
904       wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
905       wrq.u.data.flags = 0;
906       if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
907         return(IWERR_GET_EXT);
908       wrq.u.data.flags &= ~IW_ENCODE_DISABLED;  /* Enable */
909     }
910   else
911     {
912       int       gotone = 0;
913       int       oldone;
914       int       keylen;
915       int       temp;
916
917       wrq.u.data.pointer = (caddr_t) NULL;
918       wrq.u.data.flags = 0;
919       wrq.u.data.length = 0;
920       i = 0;
921
922       /* Allow arguments in any order (it's safe) */
923       do
924         {
925           oldone = gotone;
926
927           /* -- Check for the key -- */
928           if(i < count)
929             {
930               keylen = iw_in_key_full(skfd, ifname,
931                                       args[i], key, &wrq.u.data.flags);
932               if(keylen > 0)
933                 {
934                   wrq.u.data.length = keylen;
935                   wrq.u.data.pointer = (caddr_t) key;
936                   ++i;
937                   gotone++;
938                 }
939             }
940
941           /* -- Check for token index -- */
942           if((i < count) &&
943              (sscanf(args[i], "[%i]", &temp) == 1) &&
944              (temp > 0) && (temp < IW_ENCODE_INDEX))
945             {
946               wrq.u.encoding.flags |= temp;
947               ++i;
948               gotone++;
949             }
950
951           /* -- Check the various flags -- */
952           if((i < count) && (!strcasecmp(args[i], "off")))
953             {
954               wrq.u.data.flags |= IW_ENCODE_DISABLED;
955               ++i;
956               gotone++;
957             }
958           if((i < count) && (!strcasecmp(args[i], "open")))
959             {
960               wrq.u.data.flags |= IW_ENCODE_OPEN;
961               ++i;
962               gotone++;
963             }
964           if((i < count) && (!strncasecmp(args[i], "restricted", 5)))
965             {
966               wrq.u.data.flags |= IW_ENCODE_RESTRICTED;
967               ++i;
968               gotone++;
969             }
970           if((i < count) && (!strncasecmp(args[i], "temporary", 4)))
971             {
972               wrq.u.data.flags |= IW_ENCODE_TEMP;
973               ++i;
974               gotone++;
975             }
976         }
977       while(gotone != oldone);
978
979       /* Pointer is absent in new API */
980       if(wrq.u.data.pointer == NULL)
981         wrq.u.data.flags |= IW_ENCODE_NOKEY;
982
983       /* Check if we have any invalid argument */
984       if(!gotone)
985         {
986           errarg = 0;
987           return(IWERR_ARG_TYPE);
988         }
989     }
990
991   if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
992     return(IWERR_SET_EXT);
993
994   /* Var arg */
995   return(i);
996 }
997
998 /*------------------------------------------------------------------*/
999 /*
1000  * Set Power Management
1001  */
1002 static int
1003 set_power_info(int              skfd,
1004                char *           ifname,
1005                char *           args[],         /* Command line args */
1006                int              count)          /* Args count */
1007 {
1008   struct iwreq          wrq;
1009   int                   i = 1;
1010
1011   if(!strcasecmp(args[0], "off"))
1012     wrq.u.power.disabled = 1;   /* i.e. max size */
1013   else
1014     if(!strcasecmp(args[0], "on"))
1015       {
1016         /* Get old Power info */
1017         wrq.u.power.flags = 0;
1018         if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) < 0)
1019           return(IWERR_GET_EXT);
1020         wrq.u.power.disabled = 0;
1021       }
1022     else
1023       {
1024         double          value;
1025         char *          unit;
1026         int             gotone = 0;
1027
1028         /* Parse modifiers */
1029         i = parse_modifiers(args, count, &wrq.u.power.flags,
1030                             iwmod_power, IWMOD_POWER_NUM);
1031         if(i < 0)
1032           return(i);
1033
1034         wrq.u.power.disabled = 0;
1035
1036         /* Is there any value to grab ? */
1037         value = strtod(args[0], &unit);
1038         if(unit != args[0])
1039           {
1040             struct iw_range     range;
1041             int                 flags;
1042             /* Extract range info to handle properly 'relative' */
1043             if(iw_get_range_info(skfd, ifname, &range) < 0)
1044               memset(&range, 0, sizeof(range));
1045
1046             /* Get the flags to be able to do the proper conversion */
1047             switch(wrq.u.power.flags & IW_POWER_TYPE)
1048               {
1049               case IW_POWER_SAVING:
1050                 flags = range.pms_flags;
1051                 break;
1052               case IW_POWER_TIMEOUT:
1053                 flags = range.pmt_flags;
1054                 break;
1055               default:
1056                 flags = range.pmp_flags;
1057                 break;
1058               }
1059             /* Check if time or relative */
1060             if(flags & IW_POWER_RELATIVE)
1061               {
1062                 if(range.we_version_compiled < 21)
1063                   value *= MEGA;
1064                 else
1065                   wrq.u.power.flags |= IW_POWER_RELATIVE;
1066               }
1067             else
1068               {
1069                 value *= MEGA;  /* default = s */
1070                 if(unit[0] == 'u') value /= MEGA;
1071                 if(unit[0] == 'm') value /= KILO;
1072               }
1073             wrq.u.power.value = (long) value;
1074             /* Set some default type if none */
1075             if((wrq.u.power.flags & IW_POWER_TYPE) == 0)
1076               wrq.u.power.flags |= IW_POWER_PERIOD;
1077             ++i;
1078             gotone = 1;
1079           }
1080
1081         /* Now, check the mode */
1082         if(i < count)
1083           {
1084             if(!strcasecmp(args[i], "all"))
1085               wrq.u.power.flags |= IW_POWER_ALL_R;
1086             if(!strncasecmp(args[i], "unicast", 4))
1087               wrq.u.power.flags |= IW_POWER_UNICAST_R;
1088             if(!strncasecmp(args[i], "multicast", 5))
1089               wrq.u.power.flags |= IW_POWER_MULTICAST_R;
1090             if(!strncasecmp(args[i], "force", 5))
1091               wrq.u.power.flags |= IW_POWER_FORCE_S;
1092             if(!strcasecmp(args[i], "repeat"))
1093               wrq.u.power.flags |= IW_POWER_REPEATER;
1094             if(wrq.u.power.flags & IW_POWER_MODE)
1095               {
1096                 ++i;
1097                 gotone = 1;
1098               }
1099           }
1100         if(!gotone)
1101           {
1102             errarg = i;
1103             return(IWERR_ARG_TYPE);
1104           }
1105       }
1106
1107   if(iw_set_ext(skfd, ifname, SIOCSIWPOWER, &wrq) < 0)
1108     return(IWERR_SET_EXT);
1109
1110   /* Var args */
1111   return(i);
1112 }
1113
1114 #ifndef WE_ESSENTIAL
1115 /*------------------------------------------------------------------*/
1116 /*
1117  * Set Nickname
1118  */
1119 static int
1120 set_nick_info(int               skfd,
1121               char *            ifname,
1122               char *            args[],         /* Command line args */
1123               int               count)          /* Args count */
1124 {
1125   struct iwreq          wrq;
1126   int                   we_kernel_version;
1127
1128   /* Avoid "Unused parameter" warning */
1129   count = count;
1130
1131   if(strlen(args[0]) > IW_ESSID_MAX_SIZE)
1132     {
1133       errmax = IW_ESSID_MAX_SIZE;
1134       return(IWERR_ARG_SIZE);
1135     }
1136
1137   we_kernel_version = iw_get_kernel_we_version();
1138
1139   wrq.u.essid.pointer = (caddr_t) args[0];
1140   wrq.u.essid.length = strlen(args[0]);
1141   if(we_kernel_version < 21)
1142     wrq.u.essid.length++;
1143
1144   if(iw_set_ext(skfd, ifname, SIOCSIWNICKN, &wrq) < 0)
1145     return(IWERR_SET_EXT);
1146
1147   /* 1 args */
1148   return(1);
1149 }
1150
1151 /*------------------------------------------------------------------*/
1152 /*
1153  * Set commit
1154  */
1155 static int
1156 set_nwid_info(int               skfd,
1157               char *            ifname,
1158               char *            args[],         /* Command line args */
1159               int               count)          /* Args count */
1160 {
1161   struct iwreq          wrq;
1162   unsigned long         temp;
1163
1164   /* Avoid "Unused parameter" warning */
1165   count = count;
1166
1167   if((!strcasecmp(args[0], "off")) ||
1168      (!strcasecmp(args[0], "any")))
1169     wrq.u.nwid.disabled = 1;
1170   else
1171     if(!strcasecmp(args[0], "on"))
1172       {
1173         /* Get old nwid */
1174         if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) < 0)
1175           return(IWERR_GET_EXT);
1176         wrq.u.nwid.disabled = 0;
1177       }
1178     else
1179       if(sscanf(args[0], "%lX", &(temp)) != 1)
1180         {
1181           errarg = 0;
1182           return(IWERR_ARG_TYPE);
1183         }
1184       else
1185         {
1186           wrq.u.nwid.value = temp;
1187           wrq.u.nwid.disabled = 0;
1188         }
1189
1190   wrq.u.nwid.fixed = 1;
1191
1192   /* Set new nwid */
1193   if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
1194     return(IWERR_SET_EXT);
1195
1196   /* 1 arg */
1197   return(1);
1198 }
1199
1200 /*------------------------------------------------------------------*/
1201 /*
1202  * Set AP Address
1203  */
1204 static int
1205 set_apaddr_info(int             skfd,
1206                 char *          ifname,
1207                 char *          args[],         /* Command line args */
1208                 int             count)          /* Args count */
1209 {
1210   struct iwreq          wrq;
1211
1212   /* Avoid "Unused parameter" warning */
1213   count = count;
1214
1215   if((!strcasecmp(args[0], "auto")) ||
1216      (!strcasecmp(args[0], "any")))
1217     {
1218       /* Send a broadcast address */
1219       iw_broad_ether(&(wrq.u.ap_addr));
1220     }
1221   else
1222     {
1223       if(!strcasecmp(args[0], "off"))
1224         {
1225           /* Send a NULL address */
1226           iw_null_ether(&(wrq.u.ap_addr));
1227         }
1228       else
1229         {
1230           /* Get the address and check if the interface supports it */
1231           if(iw_in_addr(skfd, ifname, args[0], &(wrq.u.ap_addr)) < 0)
1232             {
1233               errarg = 0;
1234               return(IWERR_ARG_TYPE);
1235             }
1236         }
1237     }
1238
1239   if(iw_set_ext(skfd, ifname, SIOCSIWAP, &wrq) < 0)
1240     return(IWERR_SET_EXT);
1241
1242   /* 1 args */
1243   return(1);
1244 }
1245
1246 /*------------------------------------------------------------------*/
1247 /*
1248  * Set Tx Power
1249  */
1250 static int
1251 set_txpower_info(int            skfd,
1252                 char *          ifname,
1253                 char *          args[],         /* Command line args */
1254                 int             count)          /* Args count */
1255 {
1256   struct iwreq          wrq;
1257   int                   i = 1;
1258
1259   /* Avoid "Unused parameter" warning */
1260   args = args; count = count;
1261
1262   /* Prepare the request */
1263   wrq.u.txpower.value = -1;
1264   wrq.u.txpower.fixed = 1;
1265   wrq.u.txpower.disabled = 0;
1266   wrq.u.txpower.flags = IW_TXPOW_DBM;
1267
1268   if(!strcasecmp(args[0], "off"))
1269     wrq.u.txpower.disabled = 1; /* i.e. turn radio off */
1270   else
1271     if(!strcasecmp(args[0], "auto"))
1272       wrq.u.txpower.fixed = 0;  /* i.e. use power control */
1273     else
1274       {
1275         if(!strcasecmp(args[0], "on"))
1276           {
1277             /* Get old tx-power */
1278             if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) < 0)
1279               return(IWERR_GET_EXT);
1280             wrq.u.txpower.disabled = 0;
1281           }
1282         else
1283           {
1284             if(!strcasecmp(args[0], "fixed"))
1285               {
1286                 /* Get old tx-power */
1287                 if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) < 0)
1288                   return(IWERR_GET_EXT);
1289                 wrq.u.txpower.fixed = 1;
1290                 wrq.u.txpower.disabled = 0;
1291               }
1292             else                        /* Should be a numeric value */
1293               {
1294                 int             power;
1295                 int             ismwatt = 0;
1296                 struct iw_range range;
1297
1298                 /* Extract range info to do proper conversion */
1299                 if(iw_get_range_info(skfd, ifname, &range) < 0)
1300                   memset(&range, 0, sizeof(range));
1301
1302                 /* Get the value */
1303                 if(sscanf(args[0], "%i", &(power)) != 1)
1304                   {
1305                     errarg = 0;
1306                     return(IWERR_ARG_TYPE);
1307                   }
1308
1309                 /* Check if milliWatt
1310                  * We authorise a single 'm' as a shorthand for 'mW',
1311                  * on the other hand a 'd' probably means 'dBm'... */
1312                 ismwatt = ((strchr(args[0], 'm') != NULL)
1313                            && (strchr(args[0], 'd') == NULL));
1314
1315                 /* We could check 'W' alone... Another time... */
1316
1317                 /* Convert */
1318                 if(range.txpower_capa & IW_TXPOW_RELATIVE)
1319                   {
1320                     /* Can't convert */
1321                     if(ismwatt)
1322                       {
1323                         errarg = 0;
1324                         return(IWERR_ARG_TYPE);
1325                       }
1326                     wrq.u.txpower.flags = IW_TXPOW_RELATIVE;
1327                   }
1328                 else
1329                   if(range.txpower_capa & IW_TXPOW_MWATT)
1330                     {
1331                       if(!ismwatt)
1332                         power = iw_dbm2mwatt(power);
1333                       wrq.u.txpower.flags = IW_TXPOW_MWATT;
1334                     }
1335                   else
1336                     {
1337                       if(ismwatt)
1338                         power = iw_mwatt2dbm(power);
1339                       wrq.u.txpower.flags = IW_TXPOW_DBM;
1340                     }
1341                 wrq.u.txpower.value = power;
1342
1343                 /* Check for an additional argument */
1344                 if((i < count) && (!strcasecmp(args[i], "auto")))
1345                   {
1346                     wrq.u.txpower.fixed = 0;
1347                     ++i;
1348                   }
1349                 if((i < count) && (!strcasecmp(args[i], "fixed")))
1350                   {
1351                     wrq.u.txpower.fixed = 1;
1352                     ++i;
1353                   }
1354               }
1355           }
1356       }
1357
1358   if(iw_set_ext(skfd, ifname, SIOCSIWTXPOW, &wrq) < 0)
1359     return(IWERR_SET_EXT);
1360
1361   /* Var args */
1362   return(i);
1363 }
1364
1365 /*------------------------------------------------------------------*/
1366 /*
1367  * Set Sensitivity
1368  */
1369 static int
1370 set_sens_info(int               skfd,
1371               char *            ifname,
1372               char *            args[],         /* Command line args */
1373               int               count)          /* Args count */
1374 {
1375   struct iwreq          wrq;
1376   int                   temp;
1377
1378   /* Avoid "Unused parameter" warning */
1379   count = count;
1380
1381   if(sscanf(args[0], "%i", &(temp)) != 1)
1382     {
1383       errarg = 0;
1384       return(IWERR_ARG_TYPE);
1385     }
1386   wrq.u.sens.value = temp;
1387
1388   if(iw_set_ext(skfd, ifname, SIOCSIWSENS, &wrq) < 0)
1389     return(IWERR_SET_EXT);
1390
1391   /* 1 arg */
1392   return(1);
1393 }
1394
1395 /*------------------------------------------------------------------*/
1396 /*
1397  * Set Retry Limit
1398  */
1399 static int
1400 set_retry_info(int              skfd,
1401                char *           ifname,
1402                char *           args[],         /* Command line args */
1403                int              count)          /* Args count */
1404 {
1405   struct iwreq          wrq;
1406   int                   i = 0;
1407   double                value;
1408   char *                unit;
1409
1410   /* Parse modifiers */
1411   i = parse_modifiers(args, count, &wrq.u.retry.flags,
1412                       iwmod_retry, IWMOD_RETRY_NUM);
1413   if(i < 0)
1414     return(i);
1415
1416   /* Add default type if none */
1417   if((wrq.u.retry.flags & IW_RETRY_TYPE) == 0)
1418     wrq.u.retry.flags |= IW_RETRY_LIMIT;
1419
1420   wrq.u.retry.disabled = 0;
1421
1422   /* Is there any value to grab ? */
1423   value = strtod(args[0], &unit);
1424   if(unit == args[0])
1425     {
1426       errarg = i;
1427       return(IWERR_ARG_TYPE);
1428     }
1429
1430   /* Limit is absolute, on the other hand lifetime is seconds */
1431   if(wrq.u.retry.flags & IW_RETRY_LIFETIME)
1432     {
1433       struct iw_range   range;
1434       /* Extract range info to handle properly 'relative' */
1435       if(iw_get_range_info(skfd, ifname, &range) < 0)
1436         memset(&range, 0, sizeof(range));
1437
1438       if(range.r_time_flags & IW_RETRY_RELATIVE)
1439         {
1440           if(range.we_version_compiled < 21)
1441             value *= MEGA;
1442           else
1443             wrq.u.retry.flags |= IW_RETRY_RELATIVE;
1444         }
1445       else
1446         {
1447           /* Normalise lifetime */
1448           value *= MEGA;        /* default = s */
1449           if(unit[0] == 'u') value /= MEGA;
1450           if(unit[0] == 'm') value /= KILO;
1451         }
1452     }
1453   wrq.u.retry.value = (long) value;
1454   ++i;
1455
1456   if(iw_set_ext(skfd, ifname, SIOCSIWRETRY, &wrq) < 0)
1457     return(IWERR_SET_EXT);
1458
1459   /* Var args */
1460   return(i);
1461 }
1462
1463 /*------------------------------------------------------------------*/
1464 /*
1465  * Set RTS Threshold
1466  */
1467 static int
1468 set_rts_info(int                skfd,
1469              char *             ifname,
1470              char *             args[],         /* Command line args */
1471              int                count)          /* Args count */
1472 {
1473   struct iwreq          wrq;
1474
1475   /* Avoid "Unused parameter" warning */
1476   count = count;
1477
1478   wrq.u.rts.value = -1;
1479   wrq.u.rts.fixed = 1;
1480   wrq.u.rts.disabled = 0;
1481
1482   if(!strcasecmp(args[0], "off"))
1483     wrq.u.rts.disabled = 1;     /* i.e. max size */
1484   else
1485     if(!strcasecmp(args[0], "auto"))
1486       wrq.u.rts.fixed = 0;
1487     else
1488       {
1489         if(!strcasecmp(args[0], "fixed"))
1490           {
1491             /* Get old RTS threshold */
1492             if(iw_get_ext(skfd, ifname, SIOCGIWRTS, &wrq) < 0)
1493               return(IWERR_GET_EXT);
1494             wrq.u.rts.fixed = 1;
1495           }
1496         else
1497           {     /* Should be a numeric value */
1498             long        temp;
1499             if(sscanf(args[0], "%li", (unsigned long *) &(temp)) != 1)
1500               {
1501                 errarg = 0;
1502                 return(IWERR_ARG_TYPE);
1503               }
1504             wrq.u.rts.value = temp;
1505           }
1506       }
1507
1508   if(iw_set_ext(skfd, ifname, SIOCSIWRTS, &wrq) < 0)
1509     return(IWERR_SET_EXT);
1510
1511   /* 1 arg */
1512   return(1);
1513 }
1514
1515 /*------------------------------------------------------------------*/
1516 /*
1517  * Set Fragmentation Threshold
1518  */
1519 static int
1520 set_frag_info(int               skfd,
1521               char *            ifname,
1522               char *            args[],         /* Command line args */
1523               int               count)          /* Args count */
1524 {
1525   struct iwreq          wrq;
1526
1527   /* Avoid "Unused parameter" warning */
1528   count = count;
1529
1530   wrq.u.frag.value = -1;
1531   wrq.u.frag.fixed = 1;
1532   wrq.u.frag.disabled = 0;
1533
1534   if(!strcasecmp(args[0], "off"))
1535     wrq.u.frag.disabled = 1;    /* i.e. max size */
1536   else
1537     if(!strcasecmp(args[0], "auto"))
1538       wrq.u.frag.fixed = 0;
1539     else
1540       {
1541         if(!strcasecmp(args[0], "fixed"))
1542           {
1543             /* Get old fragmentation threshold */
1544             if(iw_get_ext(skfd, ifname, SIOCGIWFRAG, &wrq) < 0)
1545               return(IWERR_GET_EXT);
1546             wrq.u.frag.fixed = 1;
1547           }
1548         else
1549           {     /* Should be a numeric value */
1550             long        temp;
1551             if(sscanf(args[0], "%li", &(temp))
1552                != 1)
1553               {
1554                 errarg = 0;
1555                 return(IWERR_ARG_TYPE);
1556               }
1557             wrq.u.frag.value = temp;
1558           }
1559       }
1560
1561   if(iw_set_ext(skfd, ifname, SIOCSIWFRAG, &wrq) < 0)
1562     return(IWERR_SET_EXT);
1563
1564   /* 1 arg */
1565   return(1);
1566 }
1567
1568 /*------------------------------------------------------------------*/
1569 /*
1570  * Set Modulation
1571  */
1572 static int
1573 set_modulation_info(int         skfd,
1574                     char *      ifname,
1575                     char *      args[],         /* Command line args */
1576                     int         count)          /* Args count */
1577 {
1578   struct iwreq          wrq;
1579   int                   i = 1;
1580
1581   /* Avoid "Unused parameter" warning */
1582   args = args; count = count;
1583
1584   if(!strcasecmp(args[0], "auto"))
1585     wrq.u.param.fixed = 0;      /* i.e. use any modulation */
1586   else
1587     {
1588       if(!strcasecmp(args[0], "fixed"))
1589         {
1590           /* Get old modulation */
1591           if(iw_get_ext(skfd, ifname, SIOCGIWMODUL, &wrq) < 0)
1592             return(IWERR_GET_EXT);
1593           wrq.u.param.fixed = 1;
1594         }
1595       else
1596         {
1597           int           k;
1598
1599           /* Allow multiple modulations, combine them together */
1600           wrq.u.param.value = 0x0;
1601           i = 0;
1602           do
1603             {
1604               for(k = 0; k < IW_SIZE_MODUL_LIST; k++)
1605                 {
1606                   if(!strcasecmp(args[i], iw_modul_list[k].cmd))
1607                     {
1608                       wrq.u.param.value |= iw_modul_list[k].mask;
1609                       ++i;
1610                       break;
1611                     }
1612                 }
1613             }
1614           /* For as long as current arg matched and not out of args */
1615           while((i < count) && (k < IW_SIZE_MODUL_LIST));
1616
1617           /* Check we got something */
1618           if(i == 0)
1619             {
1620               errarg = 0;
1621               return(IWERR_ARG_TYPE);
1622             }
1623
1624           /* Check for an additional argument */
1625           if((i < count) && (!strcasecmp(args[i], "auto")))
1626             {
1627               wrq.u.param.fixed = 0;
1628               ++i;
1629             }
1630           if((i < count) && (!strcasecmp(args[i], "fixed")))
1631             {
1632               wrq.u.param.fixed = 1;
1633               ++i;
1634             }
1635         }
1636     }
1637
1638   if(iw_set_ext(skfd, ifname, SIOCSIWMODUL, &wrq) < 0)
1639     return(IWERR_SET_EXT);
1640
1641   /* Var args */
1642   return(i);
1643 }
1644 #endif  /* WE_ESSENTIAL */
1645
1646 /*------------------------------------------------------------------*/
1647 /*
1648  * Set commit
1649  */
1650 static int
1651 set_commit_info(int             skfd,
1652                 char *          ifname,
1653                 char *          args[],         /* Command line args */
1654                 int             count)          /* Args count */
1655 {
1656   struct iwreq          wrq;
1657
1658   /* Avoid "Unused parameter" warning */
1659   args = args; count = count;
1660
1661   if(iw_set_ext(skfd, ifname, SIOCSIWCOMMIT, &wrq) < 0)
1662     return(IWERR_SET_EXT);
1663
1664   /* No args */
1665   return(0);
1666 }
1667
1668 /************************** SET DISPATCHER **************************/
1669 /*
1670  * This is a modified version of the dispatcher in iwlist.
1671  * The main difference is that here we may have multiple commands per
1672  * line. Also, most commands here do take arguments, and most often
1673  * a variable number of them.
1674  * Therefore, the handler *must* return how many args were consumed...
1675  *
1676  * Note that the use of multiple commands per line is not advised
1677  * in scripts, as it makes error management hard. All commands before
1678  * the error are executed, but commands after the error are not
1679  * processed.
1680  * We also try to give as much clue as possible via stderr to the caller
1681  * on which command did fail, but if there are two time the same command,
1682  * you don't know which one failed...
1683  */
1684
1685 /*------------------------------------------------------------------*/
1686 /*
1687  * Map command line arguments to the proper procedure...
1688  */
1689 typedef struct iwconfig_entry {
1690   const char *          cmd;            /* Command line shorthand */
1691   iw_enum_handler       fn;             /* Subroutine */
1692   int                   min_count;
1693   int                   request;        /* WE numerical ID */
1694   const char *          name;           /* Human readable string */
1695   const char *          argsname;       /* Args as human readable string */
1696 } iwconfig_cmd;
1697
1698 static const struct iwconfig_entry iwconfig_cmds[] = {
1699   { "essid",            set_essid_info,         1,      SIOCSIWESSID,
1700         "Set ESSID",                    "{NNN|any|on|off}" },
1701   { "mode",             set_mode_info,          1,      SIOCSIWMODE,
1702         "Set Mode",                     "{managed|ad-hoc|master|...}" },
1703   { "freq",             set_freq_info,          1,      SIOCSIWFREQ,
1704         "Set Frequency",                "N.NNN[k|M|G]" },
1705   { "channel",          set_freq_info,          1,      SIOCSIWFREQ,
1706         "Set Frequency",                "N" },
1707   { "bit",              set_bitrate_info,       1,      SIOCSIWRATE,
1708         "Set Bit Rate",                 "{N[k|M|G]|auto|fixed}" },
1709   { "rate",             set_bitrate_info,       1,      SIOCSIWRATE,
1710         "Set Bit Rate",                 "{N[k|M|G]|auto|fixed}" },
1711   { "enc",              set_enc_info,           1,      SIOCSIWENCODE,
1712         "Set Encode",                   "{NNNN-NNNN|off}" },
1713   { "key",              set_enc_info,           1,      SIOCSIWENCODE,
1714         "Set Encode",                   "{NNNN-NNNN|off}"  },
1715   { "power",            set_power_info,         1,      SIOCSIWPOWER,
1716         "Set Power Management",         "{period N|timeout N|saving N|off}" },
1717 #ifndef WE_ESSENTIAL
1718   { "nickname",         set_nick_info,          1,      SIOCSIWNICKN,
1719         "Set Nickname",                 "NNN" },
1720   { "nwid",             set_nwid_info,          1,      SIOCSIWNWID,
1721         "Set NWID",                     "{NN|on|off}" },
1722   { "ap",               set_apaddr_info,        1,      SIOCSIWAP,
1723         "Set AP Address",               "{N|off|auto}" },
1724   { "txpower",          set_txpower_info,       1,      SIOCSIWTXPOW,
1725         "Set Tx Power",                 "{NmW|NdBm|off|auto}" },
1726   { "sens",             set_sens_info,          1,      SIOCSIWSENS,
1727         "Set Sensitivity",              "N" },
1728   { "retry",            set_retry_info,         1,      SIOCSIWRETRY,
1729         "Set Retry Limit",              "{limit N|lifetime N}" },
1730   { "rts",              set_rts_info,           1,      SIOCSIWRTS,
1731         "Set RTS Threshold",            "{N|auto|fixed|off}" },
1732   { "frag",             set_frag_info,          1,      SIOCSIWFRAG,
1733         "Set Fragmentation Threshold",  "{N|auto|fixed|off}" },
1734   { "modulation",       set_modulation_info,    1,      SIOCGIWMODUL,
1735         "Set Modulation",               "{11g|11a|CCK|OFDMg|...}" },
1736 #endif  /* WE_ESSENTIAL */
1737   { "commit",           set_commit_info,        0,      SIOCSIWCOMMIT,
1738         "Commit changes",               "" },
1739   { NULL, NULL, 0, 0, NULL, NULL },
1740 };
1741
1742 /*------------------------------------------------------------------*/
1743 /*
1744  * Find the most appropriate command matching the command line
1745  */
1746 static inline const iwconfig_cmd *
1747 find_command(const char *       cmd)
1748 {
1749   const iwconfig_cmd *  found = NULL;
1750   int                   ambig = 0;
1751   unsigned int          len = strlen(cmd);
1752   int                   i;
1753
1754   /* Go through all commands */
1755   for(i = 0; iwconfig_cmds[i].cmd != NULL; ++i)
1756     {
1757       /* No match -> next one */
1758       if(strncasecmp(iwconfig_cmds[i].cmd, cmd, len) != 0)
1759         continue;
1760
1761       /* Exact match -> perfect */
1762       if(len == strlen(iwconfig_cmds[i].cmd))
1763         return &iwconfig_cmds[i];
1764
1765       /* Partial match */
1766       if(found == NULL)
1767         /* First time */
1768         found = &iwconfig_cmds[i];
1769       else
1770         /* Another time */
1771         if (iwconfig_cmds[i].fn != found->fn)
1772           ambig = 1;
1773     }
1774
1775   if(found == NULL)
1776     {
1777       fprintf(stderr, "iwconfig: unknown command \"%s\"\n", cmd);
1778       return NULL;
1779     }
1780
1781   if(ambig)
1782     {
1783       fprintf(stderr, "iwconfig: command \"%s\" is ambiguous\n", cmd);
1784       return NULL;
1785     }
1786
1787   return found;
1788 }
1789
1790 /*------------------------------------------------------------------*/
1791 /*
1792  * Set the wireless options requested on command line
1793  * Find the individual commands and call the appropriate subroutine
1794  */
1795 static int
1796 set_info(int            skfd,           /* The socket */
1797          char *         args[],         /* Command line args */
1798          int            count,          /* Args count */
1799          char *         ifname)         /* Dev name */
1800 {
1801   const iwconfig_cmd *  iwcmd;
1802   int                   ret;
1803
1804   /* Loop until we run out of args... */
1805   while(count > 0)
1806     {
1807       /* find the command matching the keyword */
1808       iwcmd = find_command(args[0]);
1809       if(iwcmd == NULL)
1810         {
1811           /* Here we have an unrecognised arg... Error already printed out. */
1812           return(-1);
1813         }
1814
1815       /* One arg is consumed (the command name) */
1816       args++;
1817       count--;
1818
1819       /* Check arg numbers */
1820       if(count < iwcmd->min_count)
1821         ret = IWERR_ARG_NUM;
1822       else
1823         ret = 0;
1824
1825       /* Call the command */
1826       if(!ret)
1827         ret = (*iwcmd->fn)(skfd, ifname, args, count);
1828
1829       /* Deal with various errors */
1830       if(ret < 0)
1831         {
1832           int   request = iwcmd->request;
1833           if(ret == IWERR_GET_EXT)
1834             request++;  /* Transform the SET into GET */
1835
1836           fprintf(stderr, "Error for wireless request \"%s\" (%X) :\n",
1837                   iwcmd->name, request);
1838           switch(ret)
1839             {
1840             case IWERR_ARG_NUM:
1841               fprintf(stderr, "    too few arguments.\n");
1842               break;
1843             case IWERR_ARG_TYPE:
1844               if(errarg < 0)
1845                 errarg = 0;
1846               if(errarg >= count)
1847                 errarg = count - 1;
1848               fprintf(stderr, "    invalid argument \"%s\".\n", args[errarg]);
1849               break;
1850             case IWERR_ARG_SIZE:
1851               fprintf(stderr, "    argument too big (max %d)\n", errmax);
1852               break;
1853             case IWERR_ARG_CONFLICT:
1854               if(errarg < 0)
1855                 errarg = 0;
1856               if(errarg >= count)
1857                 errarg = count - 1;
1858               fprintf(stderr, "    conflicting argument \"%s\".\n", args[errarg]);
1859               break;
1860             case IWERR_SET_EXT:
1861               fprintf(stderr, "    SET failed on device %-1.16s ; %s.\n",
1862                       ifname, strerror(errno));
1863               break;
1864             case IWERR_GET_EXT:
1865               fprintf(stderr, "    GET failed on device %-1.16s ; %s.\n",
1866                       ifname, strerror(errno));
1867               break;
1868             }
1869           /* Stop processing, we don't know if we are in a consistent state
1870            * in reading the command line */
1871           return(ret);
1872         }
1873
1874       /* Substract consumed args from command line */
1875       args += ret;
1876       count -= ret;
1877
1878       /* Loop back */
1879     }
1880
1881   /* Done, all done */
1882   return(0);
1883 }
1884
1885 /*------------------------------------------------------------------*/
1886 /*
1887  * Display help
1888  */
1889 static inline void
1890 iw_usage(void)
1891 {
1892   int i;
1893
1894   fprintf(stderr,   "Usage: iwconfig [interface]\n");
1895   for(i = 0; iwconfig_cmds[i].cmd != NULL; ++i)
1896     fprintf(stderr, "                interface %s %s\n",
1897             iwconfig_cmds[i].cmd, iwconfig_cmds[i].argsname);
1898   fprintf(stderr,   "       Check man pages for more details.\n");
1899 }
1900
1901
1902 /******************************* MAIN ********************************/
1903
1904 /*------------------------------------------------------------------*/
1905 /*
1906  * The main !
1907  */
1908 int
1909 main(int        argc,
1910      char **    argv)
1911 {
1912   int skfd;             /* generic raw socket desc.     */
1913   int goterr = 0;
1914
1915   /* Create a channel to the NET kernel. */
1916   if((skfd = iw_sockets_open()) < 0)
1917     {
1918       perror("socket");
1919       exit(-1);
1920     }
1921
1922   /* No argument : show the list of all device + info */
1923   if(argc == 1)
1924     iw_enum_devices(skfd, &print_info, NULL, 0);
1925   else
1926     /* Special case for help... */
1927     if((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help")))
1928       iw_usage();
1929     else
1930       /* Special case for version... */
1931       if(!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
1932         goterr = iw_print_version_info("iwconfig");
1933       else
1934         {
1935           /* '--' escape device name */
1936           if((argc > 2) && !strcmp(argv[1], "--"))
1937             {
1938               argv++;
1939               argc--;
1940             }
1941
1942           /* The device name must be the first argument */
1943           if(argc == 2)
1944             print_info(skfd, argv[1], NULL, 0);
1945           else
1946             /* The other args on the line specify options to be set... */
1947             goterr = set_info(skfd, argv + 2, argc - 2, argv[1]);
1948         }
1949
1950   /* Close the socket. */
1951   iw_sockets_close(skfd);
1952
1953   return(goterr);
1954 }