OSDN Git Service

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