OSDN Git Service

Add Android.mk
[android-x86/external-wireless-tools.git] / wireless_tools / iwlib.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB 97->99 - HPL 99->09
5  *
6  * Common subroutines to all the wireless tools...
7  *
8  * This file is released under the GPL license.
9  *     Copyright (c) 1997-2009 Jean Tourrilhes <jt@hpl.hp.com>
10  */
11
12 /***************************** INCLUDES *****************************/
13
14 #include <strings.h>
15 #include "iwlib-private.h"              /* Private header */
16
17 /************************ CONSTANTS & MACROS ************************/
18
19 /*
20  * Constants fof WE-9->15
21  */
22 #define IW15_MAX_FREQUENCIES    16
23 #define IW15_MAX_BITRATES       8
24 #define IW15_MAX_TXPOWER        8
25 #define IW15_MAX_ENCODING_SIZES 8
26 #define IW15_MAX_SPY            8
27 #define IW15_MAX_AP             8
28
29 /****************************** TYPES ******************************/
30
31 /*
32  *      Struct iw_range up to WE-15
33  */
34 struct  iw15_range
35 {
36         __u32           throughput;
37         __u32           min_nwid;
38         __u32           max_nwid;
39         __u16           num_channels;
40         __u8            num_frequency;
41         struct iw_freq  freq[IW15_MAX_FREQUENCIES];
42         __s32           sensitivity;
43         struct iw_quality       max_qual;
44         __u8            num_bitrates;
45         __s32           bitrate[IW15_MAX_BITRATES];
46         __s32           min_rts;
47         __s32           max_rts;
48         __s32           min_frag;
49         __s32           max_frag;
50         __s32           min_pmp;
51         __s32           max_pmp;
52         __s32           min_pmt;
53         __s32           max_pmt;
54         __u16           pmp_flags;
55         __u16           pmt_flags;
56         __u16           pm_capa;
57         __u16           encoding_size[IW15_MAX_ENCODING_SIZES];
58         __u8            num_encoding_sizes;
59         __u8            max_encoding_tokens;
60         __u16           txpower_capa;
61         __u8            num_txpower;
62         __s32           txpower[IW15_MAX_TXPOWER];
63         __u8            we_version_compiled;
64         __u8            we_version_source;
65         __u16           retry_capa;
66         __u16           retry_flags;
67         __u16           r_time_flags;
68         __s32           min_retry;
69         __s32           max_retry;
70         __s32           min_r_time;
71         __s32           max_r_time;
72         struct iw_quality       avg_qual;
73 };
74
75 /*
76  * Union for all the versions of iwrange.
77  * Fortunately, I mostly only add fields at the end, and big-bang
78  * reorganisations are few.
79  */
80 union   iw_range_raw
81 {
82         struct iw15_range       range15;        /* WE 9->15 */
83         struct iw_range         range;          /* WE 16->current */
84 };
85
86 /*
87  * Offsets in iw_range struct
88  */
89 #define iwr15_off(f)    ( ((char *) &(((struct iw15_range *) NULL)->f)) - \
90                           (char *) NULL)
91 #define iwr_off(f)      ( ((char *) &(((struct iw_range *) NULL)->f)) - \
92                           (char *) NULL)
93
94 /*
95  * Union to perform unaligned access when working around alignement issues
96  */
97 union   iw_align_u16
98 {
99         __u16           value;
100         unsigned char   byte[2];
101 };
102
103 /**************************** VARIABLES ****************************/
104
105 /* Modes as human readable strings */
106 const char * const iw_operation_mode[] = { "Auto",
107                                         "Ad-Hoc",
108                                         "Managed",
109                                         "Master",
110                                         "Repeater",
111                                         "Secondary",
112                                         "Monitor",
113                                         "Unknown/bug" };
114
115 /* Modulations as human readable strings */
116 const struct iw_modul_descr     iw_modul_list[] = {
117   /* Start with aggregate types, so that they display first */
118   { IW_MODUL_11AG, "11ag",
119     "IEEE 802.11a + 802.11g (2.4 & 5 GHz, up to 54 Mb/s)" },
120   { IW_MODUL_11AB, "11ab",
121     "IEEE 802.11a + 802.11b (2.4 & 5 GHz, up to 54 Mb/s)" },
122   { IW_MODUL_11G, "11g", "IEEE 802.11g (2.4 GHz, up to 54 Mb/s)" },
123   { IW_MODUL_11A, "11a", "IEEE 802.11a (5 GHz, up to 54 Mb/s)" },
124   { IW_MODUL_11B, "11b", "IEEE 802.11b (2.4 GHz, up to 11 Mb/s)" },
125
126   /* Proprietary aggregates */
127   { IW_MODUL_TURBO | IW_MODUL_11A, "turboa",
128     "Atheros turbo mode at 5 GHz (up to 108 Mb/s)" },
129   { IW_MODUL_TURBO | IW_MODUL_11G, "turbog",
130     "Atheros turbo mode at 2.4 GHz (up to 108 Mb/s)" },
131   { IW_MODUL_PBCC | IW_MODUL_11B, "11+",
132     "TI 802.11+ (2.4 GHz, up to 22 Mb/s)" },
133
134   /* Individual modulations */
135   { IW_MODUL_OFDM_G, "OFDMg",
136     "802.11g higher rates, OFDM at 2.4 GHz (up to 54 Mb/s)" },
137   { IW_MODUL_OFDM_A, "OFDMa", "802.11a, OFDM at 5 GHz (up to 54 Mb/s)" },
138   { IW_MODUL_CCK, "CCK", "802.11b higher rates (2.4 GHz, up to 11 Mb/s)" },
139   { IW_MODUL_DS, "DS", "802.11 Direct Sequence (2.4 GHz, up to 2 Mb/s)" },
140   { IW_MODUL_FH, "FH", "802.11 Frequency Hopping (2,4 GHz, up to 2 Mb/s)" },
141
142   /* Proprietary modulations */
143   { IW_MODUL_TURBO, "turbo",
144     "Atheros turbo mode, channel bonding (up to 108 Mb/s)" },
145   { IW_MODUL_PBCC, "PBCC",
146     "TI 802.11+ higher rates (2.4 GHz, up to 22 Mb/s)" },
147   { IW_MODUL_CUSTOM, "custom",
148     "Driver specific modulation (check driver documentation)" },
149 };
150
151 /* Disable runtime version warning in iw_get_range_info() */
152 int     iw_ignore_version = 0;
153
154 /************************ SOCKET SUBROUTINES *************************/
155
156 /*------------------------------------------------------------------*/
157 /*
158  * Open a socket.
159  * Depending on the protocol present, open the right socket. The socket
160  * will allow us to talk to the driver.
161  */
162 int
163 iw_sockets_open(void)
164 {
165   static const int families[] = {
166     AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
167   };
168   unsigned int  i;
169   int           sock;
170
171   /*
172    * Now pick any (exisiting) useful socket family for generic queries
173    * Note : don't open all the socket, only returns when one matches,
174    * all protocols might not be valid.
175    * Workaround by Jim Kaba <jkaba@sarnoff.com>
176    * Note : in 99% of the case, we will just open the inet_sock.
177    * The remaining 1% case are not fully correct...
178    */
179
180   /* Try all families we support */
181   for(i = 0; i < sizeof(families)/sizeof(int); ++i)
182     {
183       /* Try to open the socket, if success returns it */
184       sock = socket(families[i], SOCK_DGRAM, 0);
185       if(sock >= 0)
186         return sock;
187   }
188
189   return -1;
190 }
191
192 /*------------------------------------------------------------------*/
193 /*
194  * Extract the interface name out of /proc/net/wireless or /proc/net/dev.
195  */
196 static inline char *
197 iw_get_ifname(char *    name,   /* Where to store the name */
198               int       nsize,  /* Size of name buffer */
199               char *    buf)    /* Current position in buffer */
200 {
201   char *        end;
202
203   /* Skip leading spaces */
204   while(isspace(*buf))
205     buf++;
206
207 #ifndef IW_RESTRIC_ENUM
208   /* Get name up to the last ':'. Aliases may contain ':' in them,
209    * but the last one should be the separator */
210   end = strrchr(buf, ':');
211 #else
212   /* Get name up to ": "
213    * Note : we compare to ": " to make sure to process aliased interfaces
214    * properly. Doesn't work on /proc/net/dev, because it doesn't guarantee
215    * a ' ' after the ':'*/
216   end = strstr(buf, ": ");
217 #endif
218
219   /* Not found ??? To big ??? */
220   if((end == NULL) || (((end - buf) + 1) > nsize))
221     return(NULL);
222
223   /* Copy */
224   memcpy(name, buf, (end - buf));
225   name[end - buf] = '\0';
226
227   /* Return value currently unused, just make sure it's non-NULL */
228   return(end);
229 }
230
231 /*------------------------------------------------------------------*/
232 /*
233  * Enumerate devices and call specified routine
234  * The new way just use /proc/net/wireless, so get all wireless interfaces,
235  * whether configured or not. This is the default if available.
236  * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
237  * or not).
238  */
239 void
240 iw_enum_devices(int             skfd,
241                 iw_enum_handler fn,
242                 char *          args[],
243                 int             count)
244 {
245   char          buff[1024];
246   FILE *        fh;
247   struct ifconf ifc;
248   struct ifreq *ifr;
249   int           i;
250
251 #ifndef IW_RESTRIC_ENUM
252   /* Check if /proc/net/dev is available */
253   fh = fopen(PROC_NET_DEV, "r");
254 #else
255   /* Check if /proc/net/wireless is available */
256   fh = fopen(PROC_NET_WIRELESS, "r");
257 #endif
258
259   if(fh != NULL)
260     {
261       /* Success : use data from /proc/net/wireless */
262
263       /* Eat 2 lines of header */
264       fgets(buff, sizeof(buff), fh);
265       fgets(buff, sizeof(buff), fh);
266
267       /* Read each device line */
268       while(fgets(buff, sizeof(buff), fh))
269         {
270           char  name[IFNAMSIZ + 1];
271           char *s;
272
273           /* Skip empty or almost empty lines. It seems that in some
274            * cases fgets return a line with only a newline. */
275           if((buff[0] == '\0') || (buff[1] == '\0'))
276             continue;
277
278           /* Extract interface name */
279           s = iw_get_ifname(name, sizeof(name), buff);
280
281           if(!s)
282             {
283               /* Failed to parse, complain and continue */
284 #ifndef IW_RESTRIC_ENUM
285               fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
286 #else
287               fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
288 #endif
289             }
290           else
291             /* Got it, print info about this interface */
292             (*fn)(skfd, name, args, count);
293         }
294
295       fclose(fh);
296     }
297   else
298     {
299       /* Get list of configured devices using "traditional" way */
300       ifc.ifc_len = sizeof(buff);
301       ifc.ifc_buf = buff;
302       if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
303         {
304           fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
305           return;
306         }
307       ifr = ifc.ifc_req;
308
309       /* Print them */
310       for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
311         (*fn)(skfd, ifr->ifr_name, args, count);
312     }
313 }
314
315 /*********************** WIRELESS SUBROUTINES ************************/
316
317 /*------------------------------------------------------------------*/
318 /*
319  * Extract WE version number from /proc/net/wireless
320  * In most cases, you really want to get version information from
321  * the range info (range->we_version_compiled), see below...
322  *
323  * If we have WE-16 and later, the WE version is available at the
324  * end of the header line of the file.
325  * For version prior to that, we can only detect the change from
326  * v11 to v12, so we do an approximate job. Fortunately, v12 to v15
327  * are highly binary compatible (on the struct level).
328  */
329 int
330 iw_get_kernel_we_version(void)
331 {
332   char          buff[1024];
333   FILE *        fh;
334   char *        p;
335   int           v;
336
337   /* Check if /proc/net/wireless is available */
338   fh = fopen(PROC_NET_WIRELESS, "r");
339
340   if(fh == NULL)
341     {
342       fprintf(stderr, "Cannot read " PROC_NET_WIRELESS "\n");
343       return(-1);
344     }
345
346   /* Read the first line of buffer */
347   fgets(buff, sizeof(buff), fh);
348
349   if(strstr(buff, "| WE") == NULL)
350     {
351       /* Prior to WE16, so explicit version not present */
352
353       /* Black magic */
354       if(strstr(buff, "| Missed") == NULL)
355         v = 11;
356       else
357         v = 15;
358       fclose(fh);
359       return(v);
360     }
361
362   /* Read the second line of buffer */
363   fgets(buff, sizeof(buff), fh);
364
365   /* Get to the last separator, to get the version */
366   p = strrchr(buff, '|');
367   if((p == NULL) || (sscanf(p + 1, "%d", &v) != 1))
368     {
369       fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
370       fclose(fh);
371       return(-1);
372     }
373
374   fclose(fh);
375   return(v);
376 }
377
378 /*------------------------------------------------------------------*/
379 /*
380  * Print the WE versions of the interface.
381  */
382 static int
383 print_iface_version_info(int    skfd,
384                          char * ifname,
385                          char * args[],         /* Command line args */
386                          int    count)          /* Args count */
387 {
388   struct iwreq          wrq;
389   char                  buffer[sizeof(iwrange) * 2];    /* Large enough */
390   struct iw_range *     range;
391
392   /* Avoid "Unused parameter" warning */
393   args = args; count = count;
394
395   /* If no wireless name : no wireless extensions.
396    * This enable us to treat the SIOCGIWRANGE failure below properly. */
397   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
398     return(-1);
399
400   /* Cleanup */
401   memset(buffer, 0, sizeof(buffer));
402
403   wrq.u.data.pointer = (caddr_t) buffer;
404   wrq.u.data.length = sizeof(buffer);
405   wrq.u.data.flags = 0;
406   if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
407     {
408       /* Interface support WE (see above), but not IWRANGE */
409       fprintf(stderr, "%-8.16s  Driver has no Wireless Extension version information.\n\n", ifname);
410       return(0);
411     }
412
413   /* Copy stuff at the right place, ignore extra */
414   range = (struct iw_range *) buffer;
415
416   /* For new versions, we can check the version directly, for old versions
417    * we use magic. 300 bytes is a also magic number, don't touch... */
418   if(wrq.u.data.length >= 300)
419     {
420       /* Version is always at the same offset, so it's ok */
421       printf("%-8.16s  Recommend Wireless Extension v%d or later,\n",
422              ifname, range->we_version_source);
423       printf("          Currently compiled with Wireless Extension v%d.\n\n",
424              range->we_version_compiled);
425     }
426   else
427     {
428       fprintf(stderr, "%-8.16s  Wireless Extension version too old.\n\n",
429                       ifname);
430     }
431
432
433   return(0);
434 }
435
436 /*------------------------------------------------------------------*/
437 /*
438  * Print the WE versions of the tools.
439  */
440 int
441 iw_print_version_info(const char *      toolname)
442 {
443   int           skfd;                   /* generic raw socket desc.     */
444   int           we_kernel_version;
445
446   /* Create a channel to the NET kernel. */
447   if((skfd = iw_sockets_open()) < 0)
448     {
449       perror("socket");
450       return -1;
451     }
452
453   /* Information about the tools themselves */
454   if(toolname != NULL)
455     printf("%-8.16s  Wireless-Tools version %d\n", toolname, WT_VERSION);
456   printf("          Compatible with Wireless Extension v11 to v%d.\n\n",
457          WE_MAX_VERSION);
458
459   /* Get version from kernel */
460   we_kernel_version = iw_get_kernel_we_version();
461   /* Only version >= 16 can be verified, other are guessed */
462   if(we_kernel_version > 15)
463     printf("Kernel    Currently compiled with Wireless Extension v%d.\n\n",
464            we_kernel_version);
465
466   /* Version for each device */
467   iw_enum_devices(skfd, &print_iface_version_info, NULL, 0);
468
469   iw_sockets_close(skfd);
470
471   return 0;
472 }
473
474 /*------------------------------------------------------------------*/
475 /*
476  * Get the range information out of the driver
477  */
478 int
479 iw_get_range_info(int           skfd,
480                   const char *  ifname,
481                   iwrange *     range)
482 {
483   struct iwreq          wrq;
484   char                  buffer[sizeof(iwrange) * 2];    /* Large enough */
485   union iw_range_raw *  range_raw;
486
487   /* Cleanup */
488   bzero(buffer, sizeof(buffer));
489
490   wrq.u.data.pointer = (caddr_t) buffer;
491   wrq.u.data.length = sizeof(buffer);
492   wrq.u.data.flags = 0;
493   if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
494     return(-1);
495
496   /* Point to the buffer */
497   range_raw = (union iw_range_raw *) buffer;
498
499   /* For new versions, we can check the version directly, for old versions
500    * we use magic. 300 bytes is a also magic number, don't touch... */
501   if(wrq.u.data.length < 300)
502     {
503       /* That's v10 or earlier. Ouch ! Let's make a guess...*/
504       range_raw->range.we_version_compiled = 9;
505     }
506
507   /* Check how it needs to be processed */
508   if(range_raw->range.we_version_compiled > 15)
509     {
510       /* This is our native format, that's easy... */
511       /* Copy stuff at the right place, ignore extra */
512       memcpy((char *) range, buffer, sizeof(iwrange));
513     }
514   else
515     {
516       /* Zero unknown fields */
517       bzero((char *) range, sizeof(struct iw_range));
518
519       /* Initial part unmoved */
520       memcpy((char *) range,
521              buffer,
522              iwr15_off(num_channels));
523       /* Frequencies pushed futher down towards the end */
524       memcpy((char *) range + iwr_off(num_channels),
525              buffer + iwr15_off(num_channels),
526              iwr15_off(sensitivity) - iwr15_off(num_channels));
527       /* This one moved up */
528       memcpy((char *) range + iwr_off(sensitivity),
529              buffer + iwr15_off(sensitivity),
530              iwr15_off(num_bitrates) - iwr15_off(sensitivity));
531       /* This one goes after avg_qual */
532       memcpy((char *) range + iwr_off(num_bitrates),
533              buffer + iwr15_off(num_bitrates),
534              iwr15_off(min_rts) - iwr15_off(num_bitrates));
535       /* Number of bitrates has changed, put it after */
536       memcpy((char *) range + iwr_off(min_rts),
537              buffer + iwr15_off(min_rts),
538              iwr15_off(txpower_capa) - iwr15_off(min_rts));
539       /* Added encoding_login_index, put it after */
540       memcpy((char *) range + iwr_off(txpower_capa),
541              buffer + iwr15_off(txpower_capa),
542              iwr15_off(txpower) - iwr15_off(txpower_capa));
543       /* Hum... That's an unexpected glitch. Bummer. */
544       memcpy((char *) range + iwr_off(txpower),
545              buffer + iwr15_off(txpower),
546              iwr15_off(avg_qual) - iwr15_off(txpower));
547       /* Avg qual moved up next to max_qual */
548       memcpy((char *) range + iwr_off(avg_qual),
549              buffer + iwr15_off(avg_qual),
550              sizeof(struct iw_quality));
551     }
552
553   /* We are now checking much less than we used to do, because we can
554    * accomodate more WE version. But, there are still cases where things
555    * will break... */
556   if(!iw_ignore_version)
557     {
558       /* We don't like very old version (unfortunately kernel 2.2.X) */
559       if(range->we_version_compiled <= 10)
560         {
561           fprintf(stderr, "Warning: Driver for device %s has been compiled with an ancient version\n", ifname);
562           fprintf(stderr, "of Wireless Extension, while this program support version 11 and later.\n");
563           fprintf(stderr, "Some things may be broken...\n\n");
564         }
565
566       /* We don't like future versions of WE, because we can't cope with
567        * the unknown */
568       if(range->we_version_compiled > WE_MAX_VERSION)
569         {
570           fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
571           fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_MAX_VERSION);
572           fprintf(stderr, "Some things may be broken...\n\n");
573         }
574
575       /* Driver version verification */
576       if((range->we_version_compiled > 10) &&
577          (range->we_version_compiled < range->we_version_source))
578         {
579           fprintf(stderr, "Warning: Driver for device %s recommend version %d of Wireless Extension,\n", ifname, range->we_version_source);
580           fprintf(stderr, "but has been compiled with version %d, therefore some driver features\n", range->we_version_compiled);
581           fprintf(stderr, "may not be available...\n\n");
582         }
583       /* Note : we are only trying to catch compile difference, not source.
584        * If the driver source has not been updated to the latest, it doesn't
585        * matter because the new fields are set to zero */
586     }
587
588   /* Don't complain twice.
589    * In theory, the test apply to each individual driver, but usually
590    * all drivers are compiled from the same kernel. */
591   iw_ignore_version = 1;
592
593   return(0);
594 }
595
596 /*------------------------------------------------------------------*/
597 /*
598  * Get information about what private ioctls are supported by the driver
599  *
600  * Note : there is one danger using this function. If it return 0, you
601  * still need to free() the buffer. Beware.
602  */
603 int
604 iw_get_priv_info(int            skfd,
605                  const char *   ifname,
606                  iwprivargs **  ppriv)
607 {
608   struct iwreq          wrq;
609   iwprivargs *          priv = NULL;    /* Not allocated yet */
610   int                   maxpriv = 16;   /* Minimum for compatibility WE<13 */
611   iwprivargs *          newpriv;
612
613   /* Some driver may return a very large number of ioctls. Some
614    * others a very small number. We now use a dynamic allocation
615    * of the array to satisfy everybody. Of course, as we don't know
616    * in advance the size of the array, we try various increasing
617    * sizes. Jean II */
618   do
619     {
620       /* (Re)allocate the buffer */
621       newpriv = realloc(priv, maxpriv * sizeof(priv[0]));
622       if(newpriv == NULL)
623         {
624           fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
625           break;
626         }
627       priv = newpriv;
628
629       /* Ask the driver if it's large enough */
630       wrq.u.data.pointer = (caddr_t) priv;
631       wrq.u.data.length = maxpriv;
632       wrq.u.data.flags = 0;
633       if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) >= 0)
634         {
635           /* Success. Pass the buffer by pointer */
636           *ppriv = priv;
637           /* Return the number of ioctls */
638           return(wrq.u.data.length);
639         }
640
641       /* Only E2BIG means the buffer was too small, abort on other errors */
642       if(errno != E2BIG)
643         {
644           /* Most likely "not supported". Don't barf. */
645           break;
646         }
647
648       /* Failed. We probably need a bigger buffer. Check if the kernel
649        * gave us any hints. */
650       if(wrq.u.data.length > maxpriv)
651         maxpriv = wrq.u.data.length;
652       else
653         maxpriv *= 2;
654     }
655   while(maxpriv < 1000);
656
657   /* Cleanup */
658   if(priv)
659     free(priv);
660   *ppriv = NULL;
661
662   return(-1);
663 }
664
665 /*------------------------------------------------------------------*/
666 /*
667  * Get essential wireless config from the device driver
668  * We will call all the classical wireless ioctl on the driver through
669  * the socket to know what is supported and to get the settings...
670  * Note : compare to the version in iwconfig, we extract only
671  * what's *really* needed to configure a device...
672  */
673 int
674 iw_get_basic_config(int                 skfd,
675                     const char *        ifname,
676                     wireless_config *   info)
677 {
678   struct iwreq          wrq;
679
680   memset((char *) info, 0, sizeof(struct wireless_config));
681
682   /* Get wireless name */
683   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
684     /* If no wireless name : no wireless extensions */
685     return(-1);
686   else
687     {
688       strncpy(info->name, wrq.u.name, IFNAMSIZ);
689       info->name[IFNAMSIZ] = '\0';
690     }
691
692   /* Get network ID */
693   if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
694     {
695       info->has_nwid = 1;
696       memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
697     }
698
699   /* Get frequency / channel */
700   if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
701     {
702       info->has_freq = 1;
703       info->freq = iw_freq2float(&(wrq.u.freq));
704       info->freq_flags = wrq.u.freq.flags;
705     }
706
707   /* Get encryption information */
708   wrq.u.data.pointer = (caddr_t) info->key;
709   wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
710   wrq.u.data.flags = 0;
711   if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
712     {
713       info->has_key = 1;
714       info->key_size = wrq.u.data.length;
715       info->key_flags = wrq.u.data.flags;
716     }
717
718   /* Get ESSID */
719   wrq.u.essid.pointer = (caddr_t) info->essid;
720   wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2;
721   wrq.u.essid.flags = 0;
722   if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
723     {
724       info->has_essid = 1;
725       info->essid_on = wrq.u.data.flags;
726       info->essid_len = wrq.u.essid.length;
727     }
728
729   /* Get operation mode */
730   if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
731     {
732       info->has_mode = 1;
733       /* Note : event->u.mode is unsigned, no need to check <= 0 */
734       if(wrq.u.mode < IW_NUM_OPER_MODE)
735         info->mode = wrq.u.mode;
736       else
737         info->mode = IW_NUM_OPER_MODE;  /* Unknown/bug */
738     }
739
740   return(0);
741 }
742
743 /*------------------------------------------------------------------*/
744 /*
745  * Set essential wireless config in the device driver
746  * We will call all the classical wireless ioctl on the driver through
747  * the socket to know what is supported and to set the settings...
748  * We support only the restricted set as above...
749  */
750 int
751 iw_set_basic_config(int                 skfd,
752                     const char *        ifname,
753                     wireless_config *   info)
754 {
755   struct iwreq          wrq;
756   int                   ret = 0;
757
758   /* Get wireless name (check if interface is valid) */
759   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
760     /* If no wireless name : no wireless extensions */
761     return(-2);
762
763   /* Set the current mode of operation
764    * Mode need to be first : some settings apply only in a specific mode
765    * (such as frequency).
766    */
767   if(info->has_mode)
768     {
769       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
770       wrq.u.mode = info->mode;
771
772       if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
773         {
774           fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
775           ret = -1;
776         }
777     }
778
779   /* Set frequency / channel */
780   if(info->has_freq)
781     {
782       iw_float2freq(info->freq, &(wrq.u.freq));
783
784       if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
785         {
786           fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
787           ret = -1;
788         }
789     }
790
791   /* Set encryption information */
792   if(info->has_key)
793     {
794       int               flags = info->key_flags;
795
796       /* Check if there is a key index */
797       if((flags & IW_ENCODE_INDEX) > 0)
798         {
799           /* Set the index */
800           wrq.u.data.pointer = (caddr_t) NULL;
801           wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
802           wrq.u.data.length = 0;
803
804           if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
805             {
806               fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
807                       errno, strerror(errno));
808               ret = -1;
809             }
810         }
811
812       /* Mask out index to minimise probability of reject when setting key */
813       flags = flags & (~IW_ENCODE_INDEX);
814
815       /* Set the key itself (set current key in this case) */
816       wrq.u.data.pointer = (caddr_t) info->key;
817       wrq.u.data.length = info->key_size;
818       wrq.u.data.flags = flags;
819
820       /* Compatibility with WE<13 */
821       if(flags & IW_ENCODE_NOKEY)
822         wrq.u.data.pointer = NULL;
823
824       if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
825         {
826           fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
827                   errno, strerror(errno));
828           ret = -1;
829         }
830     }
831
832   /* Set Network ID, if available (this is for non-802.11 cards) */
833   if(info->has_nwid)
834     {
835       memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
836       wrq.u.nwid.fixed = 1;     /* Hum... When in Rome... */
837
838       if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
839         {
840           fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
841           ret = -1;
842         }
843     }
844
845   /* Set ESSID (extended network), if available.
846    * ESSID need to be last : most device re-perform the scanning/discovery
847    * when this is set, and things like encryption keys are better be
848    * defined if we want to discover the right set of APs/nodes.
849    */
850   if(info->has_essid)
851     {
852       int               we_kernel_version;
853       we_kernel_version = iw_get_kernel_we_version();
854
855       wrq.u.essid.pointer = (caddr_t) info->essid;
856       wrq.u.essid.length = strlen(info->essid);
857       wrq.u.data.flags = info->essid_on;
858       if(we_kernel_version < 21)
859         wrq.u.essid.length++;
860
861       if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
862         {
863           fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
864           ret = -1;
865         }
866     }
867
868   return(ret);
869 }
870
871 /*********************** PROTOCOL SUBROUTINES ***********************/
872 /*
873  * Fun stuff with protocol identifiers (SIOCGIWNAME).
874  * We assume that drivers are returning sensible values in there,
875  * which is not always the case :-(
876  */
877
878 /*------------------------------------------------------------------*/
879 /*
880  * Compare protocol identifiers.
881  * We don't want to know if the two protocols are the exactly same,
882  * but if they interoperate at some level, and also if they accept the
883  * same type of config (ESSID vs NWID, freq...).
884  * This is supposed to work around the alphabet soup.
885  * Return 1 if protocols are compatible, 0 otherwise
886  */
887 int
888 iw_protocol_compare(const char *        protocol1,
889                     const char *        protocol2)
890 {
891   const char *  dot11 = "IEEE 802.11";
892   const char *  dot11_ds = "Dbg";
893   const char *  dot11_5g = "a";
894
895   /* If the strings are the same -> easy */
896   if(!strncmp(protocol1, protocol2, IFNAMSIZ))
897     return(1);
898
899   /* Are we dealing with one of the 802.11 variant ? */
900   if( (!strncmp(protocol1, dot11, strlen(dot11))) &&
901       (!strncmp(protocol2, dot11, strlen(dot11))) )
902     {
903       const char *      sub1 = protocol1 + strlen(dot11);
904       const char *      sub2 = protocol2 + strlen(dot11);
905       unsigned int      i;
906       int               isds1 = 0;
907       int               isds2 = 0;
908       int               is5g1 = 0;
909       int               is5g2 = 0;
910
911       /* Check if we find the magic letters telling it's DS compatible */
912       for(i = 0; i < strlen(dot11_ds); i++)
913         {
914           if(strchr(sub1, dot11_ds[i]) != NULL)
915             isds1 = 1;
916           if(strchr(sub2, dot11_ds[i]) != NULL)
917             isds2 = 1;
918         }
919       if(isds1 && isds2)
920         return(1);
921
922       /* Check if we find the magic letters telling it's 5GHz compatible */
923       for(i = 0; i < strlen(dot11_5g); i++)
924         {
925           if(strchr(sub1, dot11_5g[i]) != NULL)
926             is5g1 = 1;
927           if(strchr(sub2, dot11_5g[i]) != NULL)
928             is5g2 = 1;
929         }
930       if(is5g1 && is5g2)
931         return(1);
932     }
933   /* Not compatible */
934   return(0);
935 }
936
937 /************************ ESSID SUBROUTINES ************************/
938 /*
939  * The ESSID identify 802.11 networks, and is an array if 32 bytes.
940  * Most people use it as an ASCII string, and are happy with it.
941  * However, any byte is valid, including the NUL character. Characters
942  * beyond the ASCII range are interpreted according to the locale and
943  * the OS, which is somethign we don't control (network of other
944  * people).
945  * Routines in here try to deal with that in asafe way.
946  */
947
948 /*------------------------------------------------------------------*/
949 /*
950  * Escape non-ASCII characters from ESSID.
951  * This allow us to display those weirds characters to the user.
952  *
953  * Source is 32 bytes max.
954  * Destination buffer needs to be at least 129 bytes, will be NUL
955  * terminated.
956  */
957 void
958 iw_essid_escape(char *          dest,
959                 const char *    src,
960                 const int       slen)
961 {
962   const unsigned char * s = (const unsigned char *) src;
963   const unsigned char * e = s + slen;
964   char *                d = dest;
965
966   /* Look every character of the string */
967   while(s < e)
968     {
969       int       isescape;
970
971       /* Escape the escape to avoid ambiguity.
972        * We do a fast path test for performance reason. Compiler will
973        * optimise all that ;-) */
974       if(*s == '\\')
975         {
976           /* Check if we would confuse it with an escape sequence */
977           if((e-s) > 4 && (s[1] == 'x')
978              && (isxdigit(s[2])) && (isxdigit(s[3])))
979             {
980               isescape = 1;
981             }
982           else
983             isescape = 0;
984         }
985       else
986         isescape = 0;
987
988
989       /* Is it a non-ASCII character ??? */
990       if(isescape || !isascii(*s) || iscntrl(*s))
991         {
992           /* Escape */
993           sprintf(d, "\\x%02X", *s);
994           d += 4;
995         }
996       else
997         {
998           /* Plain ASCII, just copy */
999           *d = *s;
1000           d++;
1001         }
1002       s++;
1003     }
1004
1005   /* NUL terminate destination */
1006   *d = '\0';
1007 }
1008
1009 /* ---------------------------------------------------------------- */
1010 /*
1011  * Un-Escape non-ASCII characters from ESSID
1012  * This allow the user to specify weird characters in ESSID.
1013  *
1014  * The source is a NUL terminated string.
1015  * Destination buffer is at least the size of source (ESSID will shrink)
1016  * Destination may contains NUL, therefore we return the length.
1017  * This function still works is src and dest are the same ;-)
1018  */
1019 int
1020 iw_essid_unescape(char *        dest,
1021                   const char *  src)
1022 {
1023   const char *  s = src;
1024   char *        d = dest;
1025   char *        p;
1026   int           len;
1027
1028   /* Look-up the next '\' sequence, stop when no more */
1029   while((p = strchr(s, '\\')) != NULL)
1030     {
1031       /* Copy block of unescaped chars before the '\' */
1032       len = p - s;
1033       memcpy(d, s, len);
1034       d += len;
1035       s += len;         /* Identical to 's = p' */
1036
1037       /* Check if it is really an escape sequence. We do also check for NUL */
1038       if((s[1] == 'x') && (isxdigit(s[2])) && (isxdigit(s[3])))
1039         {
1040           unsigned int  temp;
1041           /* Valid Escape sequence, un-escape it */
1042           sscanf(s + 2, "%2X", &temp);
1043           *d = temp;
1044           d++;
1045           s+=4;
1046         }
1047       else
1048         {
1049           /* Not valid, don't un-escape it */
1050           *d = *s;
1051           d++;
1052           s++;
1053         }
1054     }
1055
1056   /* Copy remaining of the string */
1057   len = strlen(s);
1058   memcpy(d, s, len + 1);
1059   /* Return length */
1060   return((d - dest) + len);
1061 }
1062
1063 /********************** FREQUENCY SUBROUTINES ***********************/
1064 /*
1065  * Note : the two functions below are the cause of troubles on
1066  * various embeeded platforms, as they are the reason we require
1067  * libm (math library).
1068  * In this case, please use enable BUILD_NOLIBM in the makefile
1069  *
1070  * FIXME : check negative mantissa and exponent
1071  */
1072
1073 /*------------------------------------------------------------------*/
1074 /*
1075  * Convert a floating point the our internal representation of
1076  * frequencies.
1077  * The kernel doesn't want to hear about floating point, so we use
1078  * this custom format instead.
1079  */
1080 void
1081 iw_float2freq(double    in,
1082               iwfreq *  out)
1083 {
1084 #ifdef WE_NOLIBM
1085   /* Version without libm : slower */
1086   out->e = 0;
1087   while(in > 1e9)
1088     {
1089       in /= 10;
1090       out->e++;
1091     }
1092   out->m = (long) in;
1093 #else   /* WE_NOLIBM */
1094   /* Version with libm : faster */
1095   out->e = (short) (floor(log10(in)));
1096   if(out->e > 8)
1097     {
1098       out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
1099       out->e -= 8;
1100     }
1101   else
1102     {
1103       out->m = (long) in;
1104       out->e = 0;
1105     }
1106 #endif  /* WE_NOLIBM */
1107 }
1108
1109 /*------------------------------------------------------------------*/
1110 /*
1111  * Convert our internal representation of frequencies to a floating point.
1112  */
1113 double
1114 iw_freq2float(const iwfreq *    in)
1115 {
1116 #ifdef WE_NOLIBM
1117   /* Version without libm : slower */
1118   int           i;
1119   double        res = (double) in->m;
1120   for(i = 0; i < in->e; i++)
1121     res *= 10;
1122   return(res);
1123 #else   /* WE_NOLIBM */
1124   /* Version with libm : faster */
1125   return ((double) in->m) * pow(10,in->e);
1126 #endif  /* WE_NOLIBM */
1127 }
1128
1129 /*------------------------------------------------------------------*/
1130 /*
1131  * Output a frequency with proper scaling
1132  */
1133 void
1134 iw_print_freq_value(char *      buffer,
1135                     int         buflen,
1136                     double      freq)
1137 {
1138   if(freq < KILO)
1139     snprintf(buffer, buflen, "%g", freq);
1140   else
1141     {
1142       char      scale;
1143       int       divisor;
1144
1145       if(freq >= GIGA)
1146         {
1147           scale = 'G';
1148           divisor = GIGA;
1149         }
1150       else
1151         {
1152           if(freq >= MEGA)
1153             {
1154               scale = 'M';
1155               divisor = MEGA;
1156             }
1157           else
1158             {
1159               scale = 'k';
1160               divisor = KILO;
1161             }
1162         }
1163       snprintf(buffer, buflen, "%g %cHz", freq / divisor, scale);
1164     }
1165 }
1166
1167 /*------------------------------------------------------------------*/
1168 /*
1169  * Output a frequency with proper scaling
1170  */
1171 void
1172 iw_print_freq(char *    buffer,
1173               int       buflen,
1174               double    freq,
1175               int       channel,
1176               int       freq_flags)
1177 {
1178   char  sep = ((freq_flags & IW_FREQ_FIXED) ? '=' : ':');
1179   char  vbuf[16];
1180
1181   /* Print the frequency/channel value */
1182   iw_print_freq_value(vbuf, sizeof(vbuf), freq);
1183
1184   /* Check if channel only */
1185   if(freq < KILO)
1186     snprintf(buffer, buflen, "Channel%c%s", sep, vbuf);
1187   else
1188     {
1189       /* Frequency. Check if we have a channel as well */
1190       if(channel >= 0)
1191         snprintf(buffer, buflen, "Frequency%c%s (Channel %d)",
1192                  sep, vbuf, channel);
1193       else
1194         snprintf(buffer, buflen, "Frequency%c%s", sep, vbuf);
1195     }
1196 }
1197
1198 /*------------------------------------------------------------------*/
1199 /*
1200  * Convert a frequency to a channel (negative -> error)
1201  */
1202 int
1203 iw_freq_to_channel(double                       freq,
1204                    const struct iw_range *      range)
1205 {
1206   double        ref_freq;
1207   int           k;
1208
1209   /* Check if it's a frequency or not already a channel */
1210   if(freq < KILO)
1211     return(-1);
1212
1213   /* We compare the frequencies as double to ignore differences
1214    * in encoding. Slower, but safer... */
1215   for(k = 0; k < range->num_frequency; k++)
1216     {
1217       ref_freq = iw_freq2float(&(range->freq[k]));
1218       if(freq == ref_freq)
1219         return(range->freq[k].i);
1220     }
1221   /* Not found */
1222   return(-2);
1223 }
1224
1225 /*------------------------------------------------------------------*/
1226 /*
1227  * Convert a channel to a frequency (negative -> error)
1228  * Return the channel on success
1229  */
1230 int
1231 iw_channel_to_freq(int                          channel,
1232                    double *                     pfreq,
1233                    const struct iw_range *      range)
1234 {
1235   int           has_freq = 0;
1236   int           k;
1237
1238   /* Check if the driver support only channels or if it has frequencies */
1239   for(k = 0; k < range->num_frequency; k++)
1240     {
1241       if((range->freq[k].e != 0) || (range->freq[k].m > (int) KILO))
1242         has_freq = 1;
1243     }
1244   if(!has_freq)
1245     return(-1);
1246
1247   /* Find the correct frequency in the list */
1248   for(k = 0; k < range->num_frequency; k++)
1249     {
1250       if(range->freq[k].i == channel)
1251         {
1252           *pfreq = iw_freq2float(&(range->freq[k]));
1253           return(channel);
1254         }
1255     }
1256   /* Not found */
1257   return(-2);
1258 }
1259
1260 /*********************** BITRATE SUBROUTINES ***********************/
1261
1262 /*------------------------------------------------------------------*/
1263 /*
1264  * Output a bitrate with proper scaling
1265  */
1266 void
1267 iw_print_bitrate(char * buffer,
1268                  int    buflen,
1269                  int    bitrate)
1270 {
1271   double        rate = bitrate;
1272   char          scale;
1273   int           divisor;
1274
1275   if(rate >= GIGA)
1276     {
1277       scale = 'G';
1278       divisor = GIGA;
1279     }
1280   else
1281     {
1282       if(rate >= MEGA)
1283         {
1284           scale = 'M';
1285           divisor = MEGA;
1286         }
1287       else
1288         {
1289           scale = 'k';
1290           divisor = KILO;
1291         }
1292     }
1293   snprintf(buffer, buflen, "%g %cb/s", rate / divisor, scale);
1294 }
1295
1296 /************************ POWER SUBROUTINES *************************/
1297
1298 /*------------------------------------------------------------------*/
1299 /*
1300  * Convert a value in dBm to a value in milliWatt.
1301  */
1302 int
1303 iw_dbm2mwatt(int        in)
1304 {
1305 #ifdef WE_NOLIBM
1306   /* Version without libm : slower */
1307   int           ip = in / 10;
1308   int           fp = in % 10;
1309   int           k;
1310   double        res = 1.0;
1311
1312   /* Split integral and floating part to avoid accumulating rounding errors */
1313   for(k = 0; k < ip; k++)
1314     res *= 10;
1315   for(k = 0; k < fp; k++)
1316     res *= LOG10_MAGIC;
1317   return((int) res);
1318 #else   /* WE_NOLIBM */
1319   /* Version with libm : faster */
1320   return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
1321 #endif  /* WE_NOLIBM */
1322 }
1323
1324 /*------------------------------------------------------------------*/
1325 /*
1326  * Convert a value in milliWatt to a value in dBm.
1327  */
1328 int
1329 iw_mwatt2dbm(int        in)
1330 {
1331 #ifdef WE_NOLIBM
1332   /* Version without libm : slower */
1333   double        fin = (double) in;
1334   int           res = 0;
1335
1336   /* Split integral and floating part to avoid accumulating rounding errors */
1337   while(fin > 10.0)
1338     {
1339       res += 10;
1340       fin /= 10.0;
1341     }
1342   while(fin > 1.000001) /* Eliminate rounding errors, take ceil */
1343     {
1344       res += 1;
1345       fin /= LOG10_MAGIC;
1346     }
1347   return(res);
1348 #else   /* WE_NOLIBM */
1349   /* Version with libm : faster */
1350   return((int) (ceil(10.0 * log10((double) in))));
1351 #endif  /* WE_NOLIBM */
1352 }
1353
1354 /*------------------------------------------------------------------*/
1355 /*
1356  * Output a txpower with proper conversion
1357  */
1358 void
1359 iw_print_txpower(char *                 buffer,
1360                  int                    buflen,
1361                  struct iw_param *      txpower)
1362 {
1363   int           dbm;
1364
1365   /* Check if disabled */
1366   if(txpower->disabled)
1367     {
1368       snprintf(buffer, buflen, "off");
1369     }
1370   else
1371     {
1372       /* Check for relative values */
1373       if(txpower->flags & IW_TXPOW_RELATIVE)
1374         {
1375           snprintf(buffer, buflen, "%d", txpower->value);
1376         }
1377       else
1378         {
1379           /* Convert everything to dBm */
1380           if(txpower->flags & IW_TXPOW_MWATT)
1381             dbm = iw_mwatt2dbm(txpower->value);
1382           else
1383             dbm = txpower->value;
1384
1385           /* Display */
1386           snprintf(buffer, buflen, "%d dBm", dbm);
1387         }
1388     }
1389 }
1390
1391 /********************** STATISTICS SUBROUTINES **********************/
1392
1393 /*------------------------------------------------------------------*/
1394 /*
1395  * Read /proc/net/wireless to get the latest statistics
1396  * Note : strtok not thread safe, not used in WE-12 and later.
1397  */
1398 int
1399 iw_get_stats(int                skfd,
1400              const char *       ifname,
1401              iwstats *          stats,
1402              const iwrange *    range,
1403              int                has_range)
1404 {
1405   /* Fortunately, we can always detect this condition properly */
1406   if((has_range) && (range->we_version_compiled > 11))
1407     {
1408       struct iwreq              wrq;
1409       wrq.u.data.pointer = (caddr_t) stats;
1410       wrq.u.data.length = sizeof(struct iw_statistics);
1411       wrq.u.data.flags = 1;             /* Clear updated flag */
1412       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
1413       if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
1414         return(-1);
1415
1416       /* Format has not changed since WE-12, no conversion */
1417       return(0);
1418     }
1419   else
1420     {
1421       FILE *    f = fopen(PROC_NET_WIRELESS, "r");
1422       char      buf[256];
1423       char *    bp;
1424       int       t;
1425
1426       if(f==NULL)
1427         return -1;
1428       /* Loop on all devices */
1429       while(fgets(buf,255,f))
1430         {
1431           bp=buf;
1432           while(*bp&&isspace(*bp))
1433             bp++;
1434           /* Is it the good device ? */
1435           if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
1436             {
1437               /* Skip ethX: */
1438               bp=strchr(bp,':');
1439               bp++;
1440               /* -- status -- */
1441               bp = strtok(bp, " ");
1442               sscanf(bp, "%X", &t);
1443               stats->status = (unsigned short) t;
1444               /* -- link quality -- */
1445               bp = strtok(NULL, " ");
1446               if(strchr(bp,'.') != NULL)
1447                 stats->qual.updated |= 1;
1448               sscanf(bp, "%d", &t);
1449               stats->qual.qual = (unsigned char) t;
1450               /* -- signal level -- */
1451               bp = strtok(NULL, " ");
1452               if(strchr(bp,'.') != NULL)
1453                 stats->qual.updated |= 2;
1454               sscanf(bp, "%d", &t);
1455               stats->qual.level = (unsigned char) t;
1456               /* -- noise level -- */
1457               bp = strtok(NULL, " ");
1458               if(strchr(bp,'.') != NULL)
1459                 stats->qual.updated += 4;
1460               sscanf(bp, "%d", &t);
1461               stats->qual.noise = (unsigned char) t;
1462               /* -- discarded packets -- */
1463               bp = strtok(NULL, " ");
1464               sscanf(bp, "%d", &stats->discard.nwid);
1465               bp = strtok(NULL, " ");
1466               sscanf(bp, "%d", &stats->discard.code);
1467               bp = strtok(NULL, " ");
1468               sscanf(bp, "%d", &stats->discard.misc);
1469               fclose(f);
1470               /* No conversion needed */
1471               return 0;
1472             }
1473         }
1474       fclose(f);
1475       return -1;
1476     }
1477 }
1478
1479 /*------------------------------------------------------------------*/
1480 /*
1481  * Output the link statistics, taking care of formating
1482  */
1483 void
1484 iw_print_stats(char *           buffer,
1485                int              buflen,
1486                const iwqual *   qual,
1487                const iwrange *  range,
1488                int              has_range)
1489 {
1490   int           len;
1491
1492   /* People are very often confused by the 8 bit arithmetic happening
1493    * here.
1494    * All the values here are encoded in a 8 bit integer. 8 bit integers
1495    * are either unsigned [0 ; 255], signed [-128 ; +127] or
1496    * negative [-255 ; 0].
1497    * Further, on 8 bits, 0x100 == 256 == 0.
1498    *
1499    * Relative/percent values are always encoded unsigned, between 0 and 255.
1500    * Absolute/dBm values are always encoded between -192 and 63.
1501    * (Note that up to version 28 of Wireless Tools, dBm used to be
1502    *  encoded always negative, between -256 and -1).
1503    *
1504    * How do we separate relative from absolute values ?
1505    * The old way is to use the range to do that. As of WE-19, we have
1506    * an explicit IW_QUAL_DBM flag in updated...
1507    * The range allow to specify the real min/max of the value. As the
1508    * range struct only specify one bound of the value, we assume that
1509    * the other bound is 0 (zero).
1510    * For relative values, range is [0 ; range->max].
1511    * For absolute values, range is [range->max ; 63].
1512    *
1513    * Let's take two example :
1514    * 1) value is 75%. qual->value = 75 ; range->max_qual.value = 100
1515    * 2) value is -54dBm. noise floor of the radio is -104dBm.
1516    *    qual->value = -54 = 202 ; range->max_qual.value = -104 = 152
1517    *
1518    * Jean II
1519    */
1520
1521   /* Just do it...
1522    * The old way to detect dBm require both the range and a non-null
1523    * level (which confuse the test). The new way can deal with level of 0
1524    * because it does an explicit test on the flag. */
1525   if(has_range && ((qual->level != 0)
1526                    || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))))
1527     {
1528       /* Deal with quality : always a relative value */
1529       if(!(qual->updated & IW_QUAL_QUAL_INVALID))
1530         {
1531           len = snprintf(buffer, buflen, "Quality%c%d/%d  ",
1532                          qual->updated & IW_QUAL_QUAL_UPDATED ? '=' : ':',
1533                          qual->qual, range->max_qual.qual);
1534           buffer += len;
1535           buflen -= len;
1536         }
1537
1538       /* Check if the statistics are in RCPI (IEEE 802.11k) */
1539       if(qual->updated & IW_QUAL_RCPI)
1540         {
1541           /* Deal with signal level in RCPI */
1542           /* RCPI = int{(Power in dBm +110)*2} for 0dbm > Power > -110dBm */
1543           if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1544             {
1545               double    rcpilevel = (qual->level / 2.0) - 110.0;
1546               len = snprintf(buffer, buflen, "Signal level%c%g dBm  ",
1547                              qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1548                              rcpilevel);
1549               buffer += len;
1550               buflen -= len;
1551             }
1552
1553           /* Deal with noise level in dBm (absolute power measurement) */
1554           if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1555             {
1556               double    rcpinoise = (qual->noise / 2.0) - 110.0;
1557               len = snprintf(buffer, buflen, "Noise level%c%g dBm",
1558                              qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1559                              rcpinoise);
1560             }
1561         }
1562       else
1563         {
1564           /* Check if the statistics are in dBm */
1565           if((qual->updated & IW_QUAL_DBM)
1566              || (qual->level > range->max_qual.level))
1567             {
1568               /* Deal with signal level in dBm  (absolute power measurement) */
1569               if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1570                 {
1571                   int   dblevel = qual->level;
1572                   /* Implement a range for dBm [-192; 63] */
1573                   if(qual->level >= 64)
1574                     dblevel -= 0x100;
1575                   len = snprintf(buffer, buflen, "Signal level%c%d dBm  ",
1576                                  qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1577                                  dblevel);
1578                   buffer += len;
1579                   buflen -= len;
1580                 }
1581
1582               /* Deal with noise level in dBm (absolute power measurement) */
1583               if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1584                 {
1585                   int   dbnoise = qual->noise;
1586                   /* Implement a range for dBm [-192; 63] */
1587                   if(qual->noise >= 64)
1588                     dbnoise -= 0x100;
1589                   len = snprintf(buffer, buflen, "Noise level%c%d dBm",
1590                                  qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1591                                  dbnoise);
1592                 }
1593             }
1594           else
1595             {
1596               /* Deal with signal level as relative value (0 -> max) */
1597               if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
1598                 {
1599                   len = snprintf(buffer, buflen, "Signal level%c%d/%d  ",
1600                                  qual->updated & IW_QUAL_LEVEL_UPDATED ? '=' : ':',
1601                                  qual->level, range->max_qual.level);
1602                   buffer += len;
1603                   buflen -= len;
1604                 }
1605
1606               /* Deal with noise level as relative value (0 -> max) */
1607               if(!(qual->updated & IW_QUAL_NOISE_INVALID))
1608                 {
1609                   len = snprintf(buffer, buflen, "Noise level%c%d/%d",
1610                                  qual->updated & IW_QUAL_NOISE_UPDATED ? '=' : ':',
1611                                  qual->noise, range->max_qual.noise);
1612                 }
1613             }
1614         }
1615     }
1616   else
1617     {
1618       /* We can't read the range, so we don't know... */
1619       snprintf(buffer, buflen,
1620                "Quality:%d  Signal level:%d  Noise level:%d",
1621                qual->qual, qual->level, qual->noise);
1622     }
1623 }
1624
1625 /*********************** ENCODING SUBROUTINES ***********************/
1626
1627 /*------------------------------------------------------------------*/
1628 /*
1629  * Output the encoding key, with a nice formating
1630  */
1631 void
1632 iw_print_key(char *                     buffer,
1633              int                        buflen,
1634              const unsigned char *      key,            /* Must be unsigned */
1635              int                        key_size,
1636              int                        key_flags)
1637 {
1638   int   i;
1639
1640   /* Check buffer size -> 1 bytes => 2 digits + 1/2 separator */
1641   if((key_size * 3) > buflen)
1642     {
1643       snprintf(buffer, buflen, "<too big>");
1644       return;
1645     }
1646
1647   /* Is the key present ??? */
1648   if(key_flags & IW_ENCODE_NOKEY)
1649     {
1650       /* Nope : print on or dummy */
1651       if(key_size <= 0)
1652         strcpy(buffer, "on");                   /* Size checked */
1653       else
1654         {
1655           strcpy(buffer, "**");                 /* Size checked */
1656           buffer +=2;
1657           for(i = 1; i < key_size; i++)
1658             {
1659               if((i & 0x1) == 0)
1660                 strcpy(buffer++, "-");          /* Size checked */
1661               strcpy(buffer, "**");             /* Size checked */
1662               buffer +=2;
1663             }
1664         }
1665     }
1666   else
1667     {
1668       /* Yes : print the key */
1669       sprintf(buffer, "%.2X", key[0]);          /* Size checked */
1670       buffer +=2;
1671       for(i = 1; i < key_size; i++)
1672         {
1673           if((i & 0x1) == 0)
1674             strcpy(buffer++, "-");              /* Size checked */
1675           sprintf(buffer, "%.2X", key[i]);      /* Size checked */
1676           buffer +=2;
1677         }
1678     }
1679 }
1680
1681 /*------------------------------------------------------------------*/
1682 /*
1683  * Convert a passphrase into a key
1684  * ### NOT IMPLEMENTED ###
1685  * Return size of the key, or 0 (no key) or -1 (error)
1686  */
1687 static int
1688 iw_pass_key(const char *        input,
1689             unsigned char *     key)
1690 {
1691   input = input; key = key;
1692   fprintf(stderr, "Error: Passphrase not implemented\n");
1693   return(-1);
1694 }
1695
1696 /*------------------------------------------------------------------*/
1697 /*
1698  * Parse a key from the command line.
1699  * Return size of the key, or 0 (no key) or -1 (error)
1700  * If the key is too long, it's simply truncated...
1701  */
1702 int
1703 iw_in_key(const char *          input,
1704           unsigned char *       key)
1705 {
1706   int           keylen = 0;
1707
1708   /* Check the type of key */
1709   if(!strncmp(input, "s:", 2))
1710     {
1711       /* First case : as an ASCII string (Lucent/Agere cards) */
1712       keylen = strlen(input + 2);               /* skip "s:" */
1713       if(keylen > IW_ENCODING_TOKEN_MAX)
1714         keylen = IW_ENCODING_TOKEN_MAX;
1715       memcpy(key, input + 2, keylen);
1716     }
1717   else
1718     if(!strncmp(input, "p:", 2))
1719       {
1720         /* Second case : as a passphrase (PrismII cards) */
1721         return(iw_pass_key(input + 2, key));            /* skip "p:" */
1722       }
1723     else
1724       {
1725         const char *    p;
1726         int             dlen;   /* Digits sequence length */
1727         unsigned char   out[IW_ENCODING_TOKEN_MAX];
1728
1729         /* Third case : as hexadecimal digits */
1730         p = input;
1731         dlen = -1;
1732
1733         /* Loop until we run out of chars in input or overflow the output */
1734         while(*p != '\0')
1735           {
1736             int temph;
1737             int templ;
1738             int count;
1739             /* No more chars in this sequence */
1740             if(dlen <= 0)
1741               {
1742                 /* Skip separator */
1743                 if(dlen == 0)
1744                   p++;
1745                 /* Calculate num of char to next separator */
1746                 dlen = strcspn(p, "-:;.,");
1747               }
1748             /* Get each char separatly (and not by two) so that we don't
1749              * get confused by 'enc' (=> '0E'+'0C') and similar */
1750             count = sscanf(p, "%1X%1X", &temph, &templ);
1751             if(count < 1)
1752               return(-1);               /* Error -> non-hex char */
1753             /* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
1754             if(dlen % 2)
1755               count = 1;
1756             /* Put back two chars as one byte and output */
1757             if(count == 2)
1758               templ |= temph << 4;
1759             else
1760               templ = temph;
1761             out[keylen++] = (unsigned char) (templ & 0xFF);
1762             /* Check overflow in output */
1763             if(keylen >= IW_ENCODING_TOKEN_MAX)
1764               break;
1765             /* Move on to next chars */
1766             p += count;
1767             dlen -= count;
1768           }
1769         /* We use a temporary output buffer 'out' so that if there is
1770          * an error, we don't overwrite the original key buffer.
1771          * Because of the way iwconfig loop on multiple key/enc arguments
1772          * until it finds an error in here, this is necessary to avoid
1773          * silently corrupting the encryption key... */
1774         memcpy(key, out, keylen);
1775       }
1776
1777 #ifdef DEBUG
1778   {
1779     char buf[IW_ENCODING_TOKEN_MAX * 3];
1780     iw_print_key(buf, sizeof(buf), key, keylen, 0);
1781     printf("Got key : %d [%s]\n", keylen, buf);
1782   }
1783 #endif
1784
1785   return(keylen);
1786 }
1787
1788 /*------------------------------------------------------------------*/
1789 /*
1790  * Parse a key from the command line.
1791  * Return size of the key, or 0 (no key) or -1 (error)
1792  */
1793 int
1794 iw_in_key_full(int              skfd,
1795                const char *     ifname,
1796                const char *     input,
1797                unsigned char *  key,
1798                __u16 *          flags)
1799 {
1800   int           keylen = 0;
1801   char *        p;
1802
1803   if(!strncmp(input, "l:", 2))
1804     {
1805       struct iw_range   range;
1806
1807       /* Extra case : as a login (user:passwd - Cisco LEAP) */
1808       keylen = strlen(input + 2) + 1;           /* skip "l:", add '\0' */
1809       /* Most user/password is 8 char, so 18 char total, < 32 */
1810       if(keylen > IW_ENCODING_TOKEN_MAX)
1811         keylen = IW_ENCODING_TOKEN_MAX;
1812       memcpy(key, input + 2, keylen);
1813
1814       /* Separate the two strings */
1815       p = strchr((char *) key, ':');
1816       if(p == NULL)
1817         {
1818           fprintf(stderr, "Error: Invalid login format\n");
1819           return(-1);
1820         }
1821       *p = '\0';
1822
1823       /* Extract range info */
1824       if(iw_get_range_info(skfd, ifname, &range) < 0)
1825         /* Hum... Maybe we should return an error ??? */
1826         memset(&range, 0, sizeof(range));
1827
1828       if(range.we_version_compiled > 15)
1829         {
1830
1831           printf("flags = %X, index = %X\n",
1832                  *flags, range.encoding_login_index);
1833           if((*flags & IW_ENCODE_INDEX) == 0)
1834             {
1835               /* Extract range info */
1836               if(iw_get_range_info(skfd, ifname, &range) < 0)
1837                 memset(&range, 0, sizeof(range));
1838               printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1839               /* Set the index the driver expects */
1840               *flags |= range.encoding_login_index & IW_ENCODE_INDEX;
1841             }
1842           printf("flags = %X, index = %X\n", *flags, range.encoding_login_index);
1843         }
1844     }
1845   else
1846     /* Simpler routine above */
1847     keylen = iw_in_key(input, key);
1848
1849   return(keylen);
1850 }
1851
1852 /******************* POWER MANAGEMENT SUBROUTINES *******************/
1853
1854 /*------------------------------------------------------------------*/
1855 /*
1856  * Output a power management value with all attributes...
1857  */
1858 void
1859 iw_print_pm_value(char *        buffer,
1860                   int           buflen,
1861                   int           value,
1862                   int           flags,
1863                   int           we_version)
1864 {
1865   /* Check size */
1866   if(buflen < 25)
1867     {
1868       snprintf(buffer, buflen, "<too big>");
1869       return;
1870     }
1871   buflen -= 25;
1872
1873   /* Modifiers */
1874   if(flags & IW_POWER_MIN)
1875     {
1876       strcpy(buffer, " min");                           /* Size checked */
1877       buffer += 4;
1878     }
1879   if(flags & IW_POWER_MAX)
1880     {
1881       strcpy(buffer, " max");                           /* Size checked */
1882       buffer += 4;
1883     }
1884
1885   /* Type */
1886   if(flags & IW_POWER_TIMEOUT)
1887     {
1888       strcpy(buffer, " timeout:");                      /* Size checked */
1889       buffer += 9;
1890     }
1891   else
1892     {
1893       if(flags & IW_POWER_SAVING)
1894         {
1895           strcpy(buffer, " saving:");                   /* Size checked */
1896           buffer += 8;
1897         }
1898       else
1899         {
1900           strcpy(buffer, " period:");                   /* Size checked */
1901           buffer += 8;
1902         }
1903     }
1904
1905   /* Display value without units */
1906   if(flags & IW_POWER_RELATIVE)
1907     {
1908       if(we_version < 21)
1909         value /= MEGA;
1910       snprintf(buffer, buflen, "%d", value);
1911     }
1912   else
1913     {
1914       /* Display value with units */
1915       if(value >= (int) MEGA)
1916         snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
1917       else
1918         if(value >= (int) KILO)
1919           snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
1920         else
1921           snprintf(buffer, buflen, "%dus", value);
1922     }
1923 }
1924
1925 /*------------------------------------------------------------------*/
1926 /*
1927  * Output a power management mode
1928  */
1929 void
1930 iw_print_pm_mode(char * buffer,
1931                  int    buflen,
1932                  int    flags)
1933 {
1934   /* Check size */
1935   if(buflen < 28)
1936     {
1937       snprintf(buffer, buflen, "<too big>");
1938       return;
1939     }
1940
1941   /* Print the proper mode... */
1942   switch(flags & IW_POWER_MODE)
1943     {
1944     case IW_POWER_UNICAST_R:
1945       strcpy(buffer, "mode:Unicast only received");     /* Size checked */
1946       break;
1947     case IW_POWER_MULTICAST_R:
1948       strcpy(buffer, "mode:Multicast only received");   /* Size checked */
1949       break;
1950     case IW_POWER_ALL_R:
1951       strcpy(buffer, "mode:All packets received");      /* Size checked */
1952       break;
1953     case IW_POWER_FORCE_S:
1954       strcpy(buffer, "mode:Force sending");             /* Size checked */
1955       break;
1956     case IW_POWER_REPEATER:
1957       strcpy(buffer, "mode:Repeat multicasts");         /* Size checked */
1958       break;
1959     default:
1960       strcpy(buffer, "");                               /* Size checked */
1961       break;
1962     }
1963 }
1964
1965 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
1966
1967 /*------------------------------------------------------------------*/
1968 /*
1969  * Output a retry value with all attributes...
1970  */
1971 void
1972 iw_print_retry_value(char *     buffer,
1973                      int        buflen,
1974                      int        value,
1975                      int        flags,
1976                      int        we_version)
1977 {
1978   /* Check buffer size */
1979   if(buflen < 20)
1980     {
1981       snprintf(buffer, buflen, "<too big>");
1982       return;
1983     }
1984   buflen -= 20;
1985
1986   /* Modifiers */
1987   if(flags & IW_RETRY_MIN)
1988     {
1989       strcpy(buffer, " min");                           /* Size checked */
1990       buffer += 4;
1991     }
1992   if(flags & IW_RETRY_MAX)
1993     {
1994       strcpy(buffer, " max");                           /* Size checked */
1995       buffer += 4;
1996     }
1997   if(flags & IW_RETRY_SHORT)
1998     {
1999       strcpy(buffer, " short");                         /* Size checked */
2000       buffer += 6;
2001     }
2002   if(flags & IW_RETRY_LONG)
2003     {
2004       strcpy(buffer, "  long");                         /* Size checked */
2005       buffer += 6;
2006     }
2007
2008   /* Type lifetime of limit */
2009   if(flags & IW_RETRY_LIFETIME)
2010     {
2011       strcpy(buffer, " lifetime:");                     /* Size checked */
2012       buffer += 10;
2013
2014       /* Display value without units */
2015       if(flags & IW_RETRY_RELATIVE)
2016         {
2017           if(we_version < 21)
2018             value /= MEGA;
2019           snprintf(buffer, buflen, "%d", value);
2020         }
2021       else
2022         {
2023           /* Display value with units */
2024           if(value >= (int) MEGA)
2025             snprintf(buffer, buflen, "%gs", ((double) value) / MEGA);
2026           else
2027             if(value >= (int) KILO)
2028               snprintf(buffer, buflen, "%gms", ((double) value) / KILO);
2029             else
2030               snprintf(buffer, buflen, "%dus", value);
2031         }
2032     }
2033   else
2034     snprintf(buffer, buflen, " limit:%d", value);
2035 }
2036
2037 /************************* TIME SUBROUTINES *************************/
2038
2039 /*------------------------------------------------------------------*/
2040 /*
2041  * Print timestamps
2042  * Inspired from irdadump...
2043  */
2044 void
2045 iw_print_timeval(char *                         buffer,
2046                  int                            buflen,
2047                  const struct timeval *         timev,
2048                  const struct timezone *        tz)
2049 {
2050         int s;
2051
2052         s = (timev->tv_sec - tz->tz_minuteswest * 60) % 86400;
2053         snprintf(buffer, buflen, "%02d:%02d:%02d.%06u", 
2054                 s / 3600, (s % 3600) / 60, 
2055                 s % 60, (u_int32_t) timev->tv_usec);
2056 }
2057
2058 /*********************** ADDRESS SUBROUTINES ************************/
2059 /*
2060  * This section is mostly a cut & past from net-tools-1.2.0
2061  * (Well... This has evolved over the years)
2062  * manage address display and input...
2063  */
2064
2065 /*------------------------------------------------------------------*/
2066 /*
2067  * Check if interface support the right MAC address type...
2068  */
2069 int
2070 iw_check_mac_addr_type(int              skfd,
2071                        const char *     ifname)
2072 {
2073   struct ifreq          ifr;
2074
2075   /* Get the type of hardware address */
2076   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2077   if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
2078      ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
2079       && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211)))
2080     {
2081       /* Deep trouble... */
2082       fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
2083              ifname);
2084       return(-1);
2085     }
2086
2087 #ifdef DEBUG
2088   {
2089     char buf[20];
2090     printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
2091            iw_saether_ntop(&ifr.ifr_hwaddr, buf));
2092   }
2093 #endif
2094
2095   return(0);
2096 }
2097
2098
2099 /*------------------------------------------------------------------*/
2100 /*
2101  * Check if interface support the right interface address type...
2102  */
2103 int
2104 iw_check_if_addr_type(int               skfd,
2105                       const char *      ifname)
2106 {
2107   struct ifreq          ifr;
2108
2109   /* Get the type of interface address */
2110   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
2111   if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
2112      (ifr.ifr_addr.sa_family !=  AF_INET))
2113     {
2114       /* Deep trouble... */
2115       fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
2116       return(-1);
2117     }
2118
2119 #ifdef DEBUG
2120   printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
2121          *((unsigned long *) ifr.ifr_addr.sa_data));
2122 #endif
2123
2124   return(0);
2125 }
2126
2127 /*------------------------------------------------------------------*/
2128 /*
2129  * Display an arbitrary length MAC address in readable format.
2130  */
2131 char *
2132 iw_mac_ntop(const unsigned char *       mac,
2133             int                         maclen,
2134             char *                      buf,
2135             int                         buflen)
2136 {
2137   int   i;
2138
2139   /* Overflow check (don't forget '\0') */
2140   if(buflen < (maclen * 3 - 1 + 1))
2141     return(NULL);
2142
2143   /* First byte */
2144   sprintf(buf, "%02X", mac[0]);
2145
2146   /* Other bytes */
2147   for(i = 1; i < maclen; i++)
2148     sprintf(buf + (i * 3) - 1, ":%02X", mac[i]);
2149   return(buf);
2150 }
2151
2152 /*------------------------------------------------------------------*/
2153 /*
2154  * Display an Ethernet address in readable format.
2155  */
2156 void
2157 iw_ether_ntop(const struct ether_addr * eth,
2158               char *                    buf)
2159 {
2160   sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
2161           eth->ether_addr_octet[0], eth->ether_addr_octet[1],
2162           eth->ether_addr_octet[2], eth->ether_addr_octet[3],
2163           eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
2164 }
2165
2166 /*------------------------------------------------------------------*/
2167 /*
2168  * Display an Wireless Access Point Socket Address in readable format.
2169  * Note : 0x44 is an accident of history, that's what the Orinoco/PrismII
2170  * chipset report, and the driver doesn't filter it.
2171  */
2172 char *
2173 iw_sawap_ntop(const struct sockaddr *   sap,
2174               char *                    buf)
2175 {
2176   const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
2177   const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
2178   const struct ether_addr ether_hack = {{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }};
2179   const struct ether_addr * ether_wap = (const struct ether_addr *) sap->sa_data;
2180
2181   if(!iw_ether_cmp(ether_wap, &ether_zero))
2182     sprintf(buf, "Not-Associated");
2183   else
2184     if(!iw_ether_cmp(ether_wap, &ether_bcast))
2185       sprintf(buf, "Invalid");
2186     else
2187       if(!iw_ether_cmp(ether_wap, &ether_hack))
2188         sprintf(buf, "None");
2189       else
2190         iw_ether_ntop(ether_wap, buf);
2191   return(buf);
2192 }
2193
2194 /*------------------------------------------------------------------*/
2195 /*
2196  * Input an arbitrary length MAC address and convert to binary.
2197  * Return address size.
2198  */
2199 int
2200 iw_mac_aton(const char *        orig,
2201             unsigned char *     mac,
2202             int                 macmax)
2203 {
2204   const char *  p = orig;
2205   int           maclen = 0;
2206
2207   /* Loop on all bytes of the string */
2208   while(*p != '\0')
2209     {
2210       int       temph;
2211       int       templ;
2212       int       count;
2213       /* Extract one byte as two chars */
2214       count = sscanf(p, "%1X%1X", &temph, &templ);
2215       if(count != 2)
2216         break;                  /* Error -> non-hex chars */
2217       /* Output two chars as one byte */
2218       templ |= temph << 4;
2219       mac[maclen++] = (unsigned char) (templ & 0xFF);
2220
2221       /* Check end of string */
2222       p += 2;
2223       if(*p == '\0')
2224         {
2225 #ifdef DEBUG
2226           char buf[20];
2227           iw_ether_ntop((const struct ether_addr *) mac, buf);
2228           fprintf(stderr, "iw_mac_aton(%s): %s\n", orig, buf);
2229 #endif
2230           return(maclen);               /* Normal exit */
2231         }
2232
2233       /* Check overflow */
2234       if(maclen >= macmax)
2235         {
2236 #ifdef DEBUG
2237           fprintf(stderr, "iw_mac_aton(%s): trailing junk!\n", orig);
2238 #endif
2239           errno = E2BIG;
2240           return(0);                    /* Error -> overflow */
2241         }
2242
2243       /* Check separator */
2244       if(*p != ':')
2245         break;
2246       p++;
2247     }
2248
2249   /* Error... */
2250 #ifdef DEBUG
2251   fprintf(stderr, "iw_mac_aton(%s): invalid ether address!\n", orig);
2252 #endif
2253   errno = EINVAL;
2254   return(0);
2255 }
2256
2257 /*------------------------------------------------------------------*/
2258 /*
2259  * Input an Ethernet address and convert to binary.
2260  */
2261 int
2262 iw_ether_aton(const char *orig, struct ether_addr *eth)
2263 {
2264   int   maclen;
2265   maclen = iw_mac_aton(orig, (unsigned char *) eth, ETH_ALEN);
2266   if((maclen > 0) && (maclen < ETH_ALEN))
2267     {
2268       errno = EINVAL;
2269       maclen = 0;
2270     }
2271   return(maclen);
2272 }
2273
2274 /*------------------------------------------------------------------*/
2275 /*
2276  * Input an Internet address and convert to binary.
2277  */
2278 int
2279 iw_in_inet(char *name, struct sockaddr *sap)
2280 {
2281   struct hostent *hp;
2282   struct netent *np;
2283   struct sockaddr_in *sain = (struct sockaddr_in *) sap;
2284
2285   /* Grmpf. -FvK */
2286   sain->sin_family = AF_INET;
2287   sain->sin_port = 0;
2288
2289   /* Default is special, meaning 0.0.0.0. */
2290   if (!strcmp(name, "default")) {
2291         sain->sin_addr.s_addr = INADDR_ANY;
2292         return(1);
2293   }
2294
2295   /* Try the NETWORKS database to see if this is a known network. */
2296   if ((np = getnetbyname(name)) != (struct netent *)NULL) {
2297         sain->sin_addr.s_addr = htonl(np->n_net);
2298         strcpy(name, np->n_name);
2299         return(1);
2300   }
2301
2302   /* Always use the resolver (DNS name + IP addresses) */
2303   if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
2304         errno = h_errno;
2305         return(-1);
2306   }
2307   memcpy((char *) &sain->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
2308   strcpy(name, hp->h_name);
2309   return(0);
2310 }
2311
2312 /*------------------------------------------------------------------*/
2313 /*
2314  * Input an address and convert to binary.
2315  */
2316 int
2317 iw_in_addr(int          skfd,
2318            const char * ifname,
2319            char *       bufp,
2320            struct sockaddr *sap)
2321 {
2322   /* Check if it is a hardware or IP address */
2323   if(strchr(bufp, ':') == NULL)
2324     {
2325       struct sockaddr   if_address;
2326       struct arpreq     arp_query;
2327
2328       /* Check if we have valid interface address type */
2329       if(iw_check_if_addr_type(skfd, ifname) < 0)
2330         {
2331           fprintf(stderr, "%-8.16s  Interface doesn't support IP addresses\n", ifname);
2332           return(-1);
2333         }
2334
2335       /* Read interface address */
2336       if(iw_in_inet(bufp, &if_address) < 0)
2337         {
2338           fprintf(stderr, "Invalid interface address %s\n", bufp);
2339           return(-1);
2340         }
2341
2342       /* Translate IP addresses to MAC addresses */
2343       memcpy((char *) &(arp_query.arp_pa),
2344              (char *) &if_address,
2345              sizeof(struct sockaddr));
2346       arp_query.arp_ha.sa_family = 0;
2347       arp_query.arp_flags = 0;
2348       /* The following restrict the search to the interface only */
2349       /* For old kernels which complain, just comment it... */
2350       strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
2351       if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
2352          !(arp_query.arp_flags & ATF_COM))
2353         {
2354           fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
2355                   bufp, ifname, errno);
2356           return(-1);
2357         }
2358
2359       /* Store new MAC address */
2360       memcpy((char *) sap,
2361              (char *) &(arp_query.arp_ha),
2362              sizeof(struct sockaddr));
2363
2364 #ifdef DEBUG
2365       {
2366         char buf[20];
2367         printf("IP Address %s => Hw Address = %s\n",
2368                bufp, iw_saether_ntop(sap, buf));
2369       }
2370 #endif
2371     }
2372   else  /* If it's an hardware address */
2373     {
2374       /* Check if we have valid mac address type */
2375       if(iw_check_mac_addr_type(skfd, ifname) < 0)
2376         {
2377           fprintf(stderr, "%-8.16s  Interface doesn't support MAC addresses\n", ifname);
2378           return(-1);
2379         }
2380
2381       /* Get the hardware address */
2382       if(iw_saether_aton(bufp, sap) == 0)
2383         {
2384           fprintf(stderr, "Invalid hardware address %s\n", bufp);
2385           return(-1);
2386         }
2387     }
2388
2389 #ifdef DEBUG
2390   {
2391     char buf[20];
2392     printf("Hw Address = %s\n", iw_saether_ntop(sap, buf));
2393   }
2394 #endif
2395
2396   return(0);
2397 }
2398
2399 /************************* MISC SUBROUTINES **************************/
2400
2401 /* Size (in bytes) of various events */
2402 static const int priv_type_size[] = {
2403         0,                              /* IW_PRIV_TYPE_NONE */
2404         1,                              /* IW_PRIV_TYPE_BYTE */
2405         1,                              /* IW_PRIV_TYPE_CHAR */
2406         0,                              /* Not defined */
2407         sizeof(__u32),                  /* IW_PRIV_TYPE_INT */
2408         sizeof(struct iw_freq),         /* IW_PRIV_TYPE_FLOAT */
2409         sizeof(struct sockaddr),        /* IW_PRIV_TYPE_ADDR */
2410         0,                              /* Not defined */
2411 };
2412
2413 /*------------------------------------------------------------------*/
2414 /*
2415  * Max size in bytes of an private argument.
2416  */
2417 int
2418 iw_get_priv_size(int    args)
2419 {
2420   int   num = args & IW_PRIV_SIZE_MASK;
2421   int   type = (args & IW_PRIV_TYPE_MASK) >> 12;
2422
2423   return(num * priv_type_size[type]);
2424 }
2425
2426 /************************ EVENT SUBROUTINES ************************/
2427 /*
2428  * The Wireless Extension API 14 and greater define Wireless Events,
2429  * that are used for various events and scanning.
2430  * Those functions help the decoding of events, so are needed only in
2431  * this case.
2432  */
2433
2434 /* -------------------------- CONSTANTS -------------------------- */
2435
2436 /* Type of headers we know about (basically union iwreq_data) */
2437 #define IW_HEADER_TYPE_NULL     0       /* Not available */
2438 #define IW_HEADER_TYPE_CHAR     2       /* char [IFNAMSIZ] */
2439 #define IW_HEADER_TYPE_UINT     4       /* __u32 */
2440 #define IW_HEADER_TYPE_FREQ     5       /* struct iw_freq */
2441 #define IW_HEADER_TYPE_ADDR     6       /* struct sockaddr */
2442 #define IW_HEADER_TYPE_POINT    8       /* struct iw_point */
2443 #define IW_HEADER_TYPE_PARAM    9       /* struct iw_param */
2444 #define IW_HEADER_TYPE_QUAL     10      /* struct iw_quality */
2445
2446 /* Handling flags */
2447 /* Most are not implemented. I just use them as a reminder of some
2448  * cool features we might need one day ;-) */
2449 #define IW_DESCR_FLAG_NONE      0x0000  /* Obvious */
2450 /* Wrapper level flags */
2451 #define IW_DESCR_FLAG_DUMP      0x0001  /* Not part of the dump command */
2452 #define IW_DESCR_FLAG_EVENT     0x0002  /* Generate an event on SET */
2453 #define IW_DESCR_FLAG_RESTRICT  0x0004  /* GET : request is ROOT only */
2454                                 /* SET : Omit payload from generated iwevent */
2455 #define IW_DESCR_FLAG_NOMAX     0x0008  /* GET : no limit on request size */
2456 /* Driver level flags */
2457 #define IW_DESCR_FLAG_WAIT      0x0100  /* Wait for driver event */
2458
2459 /* ---------------------------- TYPES ---------------------------- */
2460
2461 /*
2462  * Describe how a standard IOCTL looks like.
2463  */
2464 struct iw_ioctl_description
2465 {
2466         __u8    header_type;            /* NULL, iw_point or other */
2467         __u8    token_type;             /* Future */
2468         __u16   token_size;             /* Granularity of payload */
2469         __u16   min_tokens;             /* Min acceptable token number */
2470         __u16   max_tokens;             /* Max acceptable token number */
2471         __u32   flags;                  /* Special handling of the request */
2472 };
2473
2474 /* -------------------------- VARIABLES -------------------------- */
2475
2476 /*
2477  * Meta-data about all the standard Wireless Extension request we
2478  * know about.
2479  */
2480 static const struct iw_ioctl_description standard_ioctl_descr[] = {
2481         [SIOCSIWCOMMIT  - SIOCIWFIRST] = {
2482                 .header_type    = IW_HEADER_TYPE_NULL,
2483         },
2484         [SIOCGIWNAME    - SIOCIWFIRST] = {
2485                 .header_type    = IW_HEADER_TYPE_CHAR,
2486                 .flags          = IW_DESCR_FLAG_DUMP,
2487         },
2488         [SIOCSIWNWID    - SIOCIWFIRST] = {
2489                 .header_type    = IW_HEADER_TYPE_PARAM,
2490                 .flags          = IW_DESCR_FLAG_EVENT,
2491         },
2492         [SIOCGIWNWID    - SIOCIWFIRST] = {
2493                 .header_type    = IW_HEADER_TYPE_PARAM,
2494                 .flags          = IW_DESCR_FLAG_DUMP,
2495         },
2496         [SIOCSIWFREQ    - SIOCIWFIRST] = {
2497                 .header_type    = IW_HEADER_TYPE_FREQ,
2498                 .flags          = IW_DESCR_FLAG_EVENT,
2499         },
2500         [SIOCGIWFREQ    - SIOCIWFIRST] = {
2501                 .header_type    = IW_HEADER_TYPE_FREQ,
2502                 .flags          = IW_DESCR_FLAG_DUMP,
2503         },
2504         [SIOCSIWMODE    - SIOCIWFIRST] = {
2505                 .header_type    = IW_HEADER_TYPE_UINT,
2506                 .flags          = IW_DESCR_FLAG_EVENT,
2507         },
2508         [SIOCGIWMODE    - SIOCIWFIRST] = {
2509                 .header_type    = IW_HEADER_TYPE_UINT,
2510                 .flags          = IW_DESCR_FLAG_DUMP,
2511         },
2512         [SIOCSIWSENS    - SIOCIWFIRST] = {
2513                 .header_type    = IW_HEADER_TYPE_PARAM,
2514         },
2515         [SIOCGIWSENS    - SIOCIWFIRST] = {
2516                 .header_type    = IW_HEADER_TYPE_PARAM,
2517         },
2518         [SIOCSIWRANGE   - SIOCIWFIRST] = {
2519                 .header_type    = IW_HEADER_TYPE_NULL,
2520         },
2521         [SIOCGIWRANGE   - SIOCIWFIRST] = {
2522                 .header_type    = IW_HEADER_TYPE_POINT,
2523                 .token_size     = 1,
2524                 .max_tokens     = sizeof(struct iw_range),
2525                 .flags          = IW_DESCR_FLAG_DUMP,
2526         },
2527         [SIOCSIWPRIV    - SIOCIWFIRST] = {
2528                 .header_type    = IW_HEADER_TYPE_NULL,
2529         },
2530         [SIOCGIWPRIV    - SIOCIWFIRST] = { /* (handled directly by us) */
2531                 .header_type    = IW_HEADER_TYPE_NULL,
2532         },
2533         [SIOCSIWSTATS   - SIOCIWFIRST] = {
2534                 .header_type    = IW_HEADER_TYPE_NULL,
2535         },
2536         [SIOCGIWSTATS   - SIOCIWFIRST] = { /* (handled directly by us) */
2537                 .header_type    = IW_HEADER_TYPE_NULL,
2538                 .flags          = IW_DESCR_FLAG_DUMP,
2539         },
2540         [SIOCSIWSPY     - SIOCIWFIRST] = {
2541                 .header_type    = IW_HEADER_TYPE_POINT,
2542                 .token_size     = sizeof(struct sockaddr),
2543                 .max_tokens     = IW_MAX_SPY,
2544         },
2545         [SIOCGIWSPY     - SIOCIWFIRST] = {
2546                 .header_type    = IW_HEADER_TYPE_POINT,
2547                 .token_size     = sizeof(struct sockaddr) +
2548                                   sizeof(struct iw_quality),
2549                 .max_tokens     = IW_MAX_SPY,
2550         },
2551         [SIOCSIWTHRSPY  - SIOCIWFIRST] = {
2552                 .header_type    = IW_HEADER_TYPE_POINT,
2553                 .token_size     = sizeof(struct iw_thrspy),
2554                 .min_tokens     = 1,
2555                 .max_tokens     = 1,
2556         },
2557         [SIOCGIWTHRSPY  - SIOCIWFIRST] = {
2558                 .header_type    = IW_HEADER_TYPE_POINT,
2559                 .token_size     = sizeof(struct iw_thrspy),
2560                 .min_tokens     = 1,
2561                 .max_tokens     = 1,
2562         },
2563         [SIOCSIWAP      - SIOCIWFIRST] = {
2564                 .header_type    = IW_HEADER_TYPE_ADDR,
2565         },
2566         [SIOCGIWAP      - SIOCIWFIRST] = {
2567                 .header_type    = IW_HEADER_TYPE_ADDR,
2568                 .flags          = IW_DESCR_FLAG_DUMP,
2569         },
2570         [SIOCSIWMLME    - SIOCIWFIRST] = {
2571                 .header_type    = IW_HEADER_TYPE_POINT,
2572                 .token_size     = 1,
2573                 .min_tokens     = sizeof(struct iw_mlme),
2574                 .max_tokens     = sizeof(struct iw_mlme),
2575         },
2576         [SIOCGIWAPLIST  - SIOCIWFIRST] = {
2577                 .header_type    = IW_HEADER_TYPE_POINT,
2578                 .token_size     = sizeof(struct sockaddr) +
2579                                   sizeof(struct iw_quality),
2580                 .max_tokens     = IW_MAX_AP,
2581                 .flags          = IW_DESCR_FLAG_NOMAX,
2582         },
2583         [SIOCSIWSCAN    - SIOCIWFIRST] = {
2584                 .header_type    = IW_HEADER_TYPE_POINT,
2585                 .token_size     = 1,
2586                 .min_tokens     = 0,
2587                 .max_tokens     = sizeof(struct iw_scan_req),
2588         },
2589         [SIOCGIWSCAN    - SIOCIWFIRST] = {
2590                 .header_type    = IW_HEADER_TYPE_POINT,
2591                 .token_size     = 1,
2592                 .max_tokens     = IW_SCAN_MAX_DATA,
2593                 .flags          = IW_DESCR_FLAG_NOMAX,
2594         },
2595         [SIOCSIWESSID   - SIOCIWFIRST] = {
2596                 .header_type    = IW_HEADER_TYPE_POINT,
2597                 .token_size     = 1,
2598                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
2599                 .flags          = IW_DESCR_FLAG_EVENT,
2600         },
2601         [SIOCGIWESSID   - SIOCIWFIRST] = {
2602                 .header_type    = IW_HEADER_TYPE_POINT,
2603                 .token_size     = 1,
2604                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
2605                 .flags          = IW_DESCR_FLAG_DUMP,
2606         },
2607         [SIOCSIWNICKN   - SIOCIWFIRST] = {
2608                 .header_type    = IW_HEADER_TYPE_POINT,
2609                 .token_size     = 1,
2610                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
2611         },
2612         [SIOCGIWNICKN   - SIOCIWFIRST] = {
2613                 .header_type    = IW_HEADER_TYPE_POINT,
2614                 .token_size     = 1,
2615                 .max_tokens     = IW_ESSID_MAX_SIZE + 1,
2616         },
2617         [SIOCSIWRATE    - SIOCIWFIRST] = {
2618                 .header_type    = IW_HEADER_TYPE_PARAM,
2619         },
2620         [SIOCGIWRATE    - SIOCIWFIRST] = {
2621                 .header_type    = IW_HEADER_TYPE_PARAM,
2622         },
2623         [SIOCSIWRTS     - SIOCIWFIRST] = {
2624                 .header_type    = IW_HEADER_TYPE_PARAM,
2625         },
2626         [SIOCGIWRTS     - SIOCIWFIRST] = {
2627                 .header_type    = IW_HEADER_TYPE_PARAM,
2628         },
2629         [SIOCSIWFRAG    - SIOCIWFIRST] = {
2630                 .header_type    = IW_HEADER_TYPE_PARAM,
2631         },
2632         [SIOCGIWFRAG    - SIOCIWFIRST] = {
2633                 .header_type    = IW_HEADER_TYPE_PARAM,
2634         },
2635         [SIOCSIWTXPOW   - SIOCIWFIRST] = {
2636                 .header_type    = IW_HEADER_TYPE_PARAM,
2637         },
2638         [SIOCGIWTXPOW   - SIOCIWFIRST] = {
2639                 .header_type    = IW_HEADER_TYPE_PARAM,
2640         },
2641         [SIOCSIWRETRY   - SIOCIWFIRST] = {
2642                 .header_type    = IW_HEADER_TYPE_PARAM,
2643         },
2644         [SIOCGIWRETRY   - SIOCIWFIRST] = {
2645                 .header_type    = IW_HEADER_TYPE_PARAM,
2646         },
2647         [SIOCSIWENCODE  - SIOCIWFIRST] = {
2648                 .header_type    = IW_HEADER_TYPE_POINT,
2649                 /* Hack : this never returns any payload in event.
2650                  * Fix the 64->32 bit hack... */
2651                 .token_size     = 0,
2652                 .max_tokens     = IW_ENCODING_TOKEN_MAX,
2653                 .flags          = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
2654         },
2655         [SIOCGIWENCODE  - SIOCIWFIRST] = {
2656                 .header_type    = IW_HEADER_TYPE_POINT,
2657                 /* Hack : this never returns any payload in event.
2658                  * Fix the 64->32 bit hack... */
2659                 .token_size     = 0,
2660                 .max_tokens     = IW_ENCODING_TOKEN_MAX,
2661                 .flags          = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
2662         },
2663         [SIOCSIWPOWER   - SIOCIWFIRST] = {
2664                 .header_type    = IW_HEADER_TYPE_PARAM,
2665         },
2666         [SIOCGIWPOWER   - SIOCIWFIRST] = {
2667                 .header_type    = IW_HEADER_TYPE_PARAM,
2668         },
2669         [SIOCSIWMODUL   - SIOCIWFIRST] = {
2670                 .header_type    = IW_HEADER_TYPE_PARAM,
2671         },
2672         [SIOCGIWMODUL   - SIOCIWFIRST] = {
2673                 .header_type    = IW_HEADER_TYPE_PARAM,
2674         },
2675         [SIOCSIWGENIE   - SIOCIWFIRST] = {
2676                 .header_type    = IW_HEADER_TYPE_POINT,
2677                 .token_size     = 1,
2678                 .max_tokens     = IW_GENERIC_IE_MAX,
2679         },
2680         [SIOCGIWGENIE   - SIOCIWFIRST] = {
2681                 .header_type    = IW_HEADER_TYPE_POINT,
2682                 .token_size     = 1,
2683                 .max_tokens     = IW_GENERIC_IE_MAX,
2684         },
2685         [SIOCSIWAUTH    - SIOCIWFIRST] = {
2686                 .header_type    = IW_HEADER_TYPE_PARAM,
2687         },
2688         [SIOCGIWAUTH    - SIOCIWFIRST] = {
2689                 .header_type    = IW_HEADER_TYPE_PARAM,
2690         },
2691         [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
2692                 .header_type    = IW_HEADER_TYPE_POINT,
2693                 .token_size     = 1,
2694                 .min_tokens     = sizeof(struct iw_encode_ext),
2695                 .max_tokens     = sizeof(struct iw_encode_ext) +
2696                                   IW_ENCODING_TOKEN_MAX,
2697         },
2698         [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
2699                 .header_type    = IW_HEADER_TYPE_POINT,
2700                 .token_size     = 1,
2701                 .min_tokens     = sizeof(struct iw_encode_ext),
2702                 .max_tokens     = sizeof(struct iw_encode_ext) +
2703                                   IW_ENCODING_TOKEN_MAX,
2704         },
2705         [SIOCSIWPMKSA - SIOCIWFIRST] = {
2706                 .header_type    = IW_HEADER_TYPE_POINT,
2707                 .token_size     = 1,
2708                 .min_tokens     = sizeof(struct iw_pmksa),
2709                 .max_tokens     = sizeof(struct iw_pmksa),
2710         },
2711 };
2712 static const unsigned int standard_ioctl_num = (sizeof(standard_ioctl_descr) /
2713                                                 sizeof(struct iw_ioctl_description));
2714
2715 /*
2716  * Meta-data about all the additional standard Wireless Extension events
2717  * we know about.
2718  */
2719 static const struct iw_ioctl_description standard_event_descr[] = {
2720         [IWEVTXDROP     - IWEVFIRST] = {
2721                 .header_type    = IW_HEADER_TYPE_ADDR,
2722         },
2723         [IWEVQUAL       - IWEVFIRST] = {
2724                 .header_type    = IW_HEADER_TYPE_QUAL,
2725         },
2726         [IWEVCUSTOM     - IWEVFIRST] = {
2727                 .header_type    = IW_HEADER_TYPE_POINT,
2728                 .token_size     = 1,
2729                 .max_tokens     = IW_CUSTOM_MAX,
2730         },
2731         [IWEVREGISTERED - IWEVFIRST] = {
2732                 .header_type    = IW_HEADER_TYPE_ADDR,
2733         },
2734         [IWEVEXPIRED    - IWEVFIRST] = {
2735                 .header_type    = IW_HEADER_TYPE_ADDR, 
2736         },
2737         [IWEVGENIE      - IWEVFIRST] = {
2738                 .header_type    = IW_HEADER_TYPE_POINT,
2739                 .token_size     = 1,
2740                 .max_tokens     = IW_GENERIC_IE_MAX,
2741         },
2742         [IWEVMICHAELMICFAILURE  - IWEVFIRST] = {
2743                 .header_type    = IW_HEADER_TYPE_POINT, 
2744                 .token_size     = 1,
2745                 .max_tokens     = sizeof(struct iw_michaelmicfailure),
2746         },
2747         [IWEVASSOCREQIE - IWEVFIRST] = {
2748                 .header_type    = IW_HEADER_TYPE_POINT,
2749                 .token_size     = 1,
2750                 .max_tokens     = IW_GENERIC_IE_MAX,
2751         },
2752         [IWEVASSOCRESPIE        - IWEVFIRST] = {
2753                 .header_type    = IW_HEADER_TYPE_POINT,
2754                 .token_size     = 1,
2755                 .max_tokens     = IW_GENERIC_IE_MAX,
2756         },
2757         [IWEVPMKIDCAND  - IWEVFIRST] = {
2758                 .header_type    = IW_HEADER_TYPE_POINT,
2759                 .token_size     = 1,
2760                 .max_tokens     = sizeof(struct iw_pmkid_cand),
2761         },
2762 };
2763 static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
2764                                                 sizeof(struct iw_ioctl_description));
2765
2766 /* Size (in bytes) of various events */
2767 static const int event_type_size[] = {
2768         IW_EV_LCP_PK_LEN,       /* IW_HEADER_TYPE_NULL */
2769         0,
2770         IW_EV_CHAR_PK_LEN,      /* IW_HEADER_TYPE_CHAR */
2771         0,
2772         IW_EV_UINT_PK_LEN,      /* IW_HEADER_TYPE_UINT */
2773         IW_EV_FREQ_PK_LEN,      /* IW_HEADER_TYPE_FREQ */
2774         IW_EV_ADDR_PK_LEN,      /* IW_HEADER_TYPE_ADDR */
2775         0,
2776         IW_EV_POINT_PK_LEN,     /* Without variable payload */
2777         IW_EV_PARAM_PK_LEN,     /* IW_HEADER_TYPE_PARAM */
2778         IW_EV_QUAL_PK_LEN,      /* IW_HEADER_TYPE_QUAL */
2779 };
2780
2781 /*------------------------------------------------------------------*/
2782 /*
2783  * Initialise the struct stream_descr so that we can extract
2784  * individual events from the event stream.
2785  */
2786 void
2787 iw_init_event_stream(struct stream_descr *      stream, /* Stream of events */
2788                      char *                     data,
2789                      int                        len)
2790 {
2791   /* Cleanup */
2792   memset((char *) stream, '\0', sizeof(struct stream_descr));
2793
2794   /* Set things up */
2795   stream->current = data;
2796   stream->end = data + len;
2797 }
2798
2799 /*------------------------------------------------------------------*/
2800 /*
2801  * Extract the next event from the event stream.
2802  */
2803 int
2804 iw_extract_event_stream(struct stream_descr *   stream, /* Stream of events */
2805                         struct iw_event *       iwe,    /* Extracted event */
2806                         int                     we_version)
2807 {
2808   const struct iw_ioctl_description *   descr = NULL;
2809   int           event_type = 0;
2810   unsigned int  event_len = 1;          /* Invalid */
2811   char *        pointer;
2812   /* Don't "optimise" the following variable, it will crash */
2813   unsigned      cmd_index;              /* *MUST* be unsigned */
2814
2815   /* Check for end of stream */
2816   if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
2817     return(0);
2818
2819 #ifdef DEBUG
2820   printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
2821          stream->current, stream->value, stream->end);
2822 #endif
2823
2824   /* Extract the event header (to get the event id).
2825    * Note : the event may be unaligned, therefore copy... */
2826   memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
2827
2828 #ifdef DEBUG
2829   printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
2830          iwe->cmd, iwe->len);
2831 #endif
2832
2833   /* Check invalid events */
2834   if(iwe->len <= IW_EV_LCP_PK_LEN)
2835     return(-1);
2836
2837   /* Get the type and length of that event */
2838   if(iwe->cmd <= SIOCIWLAST)
2839     {
2840       cmd_index = iwe->cmd - SIOCIWFIRST;
2841       if(cmd_index < standard_ioctl_num)
2842         descr = &(standard_ioctl_descr[cmd_index]);
2843     }
2844   else
2845     {
2846       cmd_index = iwe->cmd - IWEVFIRST;
2847       if(cmd_index < standard_event_num)
2848         descr = &(standard_event_descr[cmd_index]);
2849     }
2850   if(descr != NULL)
2851     event_type = descr->header_type;
2852   /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
2853   event_len = event_type_size[event_type];
2854   /* Fixup for earlier version of WE */
2855   if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
2856     event_len += IW_EV_POINT_OFF;
2857
2858   /* Check if we know about this event */
2859   if(event_len <= IW_EV_LCP_PK_LEN)
2860     {
2861       /* Skip to next event */
2862       stream->current += iwe->len;
2863       return(2);
2864     }
2865   event_len -= IW_EV_LCP_PK_LEN;
2866
2867   /* Set pointer on data */
2868   if(stream->value != NULL)
2869     pointer = stream->value;                    /* Next value in event */
2870   else
2871     pointer = stream->current + IW_EV_LCP_PK_LEN;       /* First value in event */
2872
2873 #ifdef DEBUG
2874   printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
2875          event_type, event_len, pointer);
2876 #endif
2877
2878   /* Copy the rest of the event (at least, fixed part) */
2879   if((pointer + event_len) > stream->end)
2880     {
2881       /* Go to next event */
2882       stream->current += iwe->len;
2883       return(-2);
2884     }
2885   /* Fixup for WE-19 and later : pointer no longer in the stream */
2886   /* Beware of alignement. Dest has local alignement, not packed */
2887   if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
2888     memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2889            pointer, event_len);
2890   else
2891     memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2892
2893   /* Skip event in the stream */
2894   pointer += event_len;
2895
2896   /* Special processing for iw_point events */
2897   if(event_type == IW_HEADER_TYPE_POINT)
2898     {
2899       /* Check the length of the payload */
2900       unsigned int      extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
2901       if(extra_len > 0)
2902         {
2903           /* Set pointer on variable part (warning : non aligned) */
2904           iwe->u.data.pointer = pointer;
2905
2906           /* Check that we have a descriptor for the command */
2907           if(descr == NULL)
2908             /* Can't check payload -> unsafe... */
2909             iwe->u.data.pointer = NULL; /* Discard paylod */
2910           else
2911             {
2912               /* Those checks are actually pretty hard to trigger,
2913                * because of the checks done in the kernel... */
2914
2915               unsigned int      token_len = iwe->u.data.length * descr->token_size;
2916
2917               /* Ugly fixup for alignement issues.
2918                * If the kernel is 64 bits and userspace 32 bits,
2919                * we have an extra 4+4 bytes.
2920                * Fixing that in the kernel would break 64 bits userspace. */
2921               if((token_len != extra_len) && (extra_len >= 4))
2922                 {
2923                   union iw_align_u16    alt_dlen;
2924                   unsigned int          alt_token_len;
2925                   /* Usespace seems to not always like unaligned access,
2926                    * so be careful and make sure to align value.
2927                    * I hope gcc won't play any of its aliasing tricks... */
2928                   alt_dlen.byte[0] = *(pointer);
2929                   alt_dlen.byte[1] = *(pointer + 1);
2930                   alt_token_len = alt_dlen.value * descr->token_size;
2931 #ifdef DEBUG
2932                   printf("DBG - alt_token_len = %d\n", alt_token_len);
2933 #endif
2934                   /* Verify that data is consistent if assuming 64 bit
2935                    * alignement... */
2936                   if((alt_token_len + 8) == extra_len)
2937                     {
2938                       /* Ok, let's redo everything */
2939                       pointer -= event_len;
2940                       pointer += 4;
2941                       /* Dest has local alignement, not packed */
2942                       memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
2943                              pointer, event_len);
2944                       pointer += event_len + 4;
2945                       token_len = alt_token_len;
2946                       /* We may have no payload */
2947                       if(alt_token_len)
2948                         iwe->u.data.pointer = pointer;
2949                       else
2950                         iwe->u.data.pointer = NULL;
2951                     }
2952                 }
2953
2954               /* Discard bogus events which advertise more tokens than
2955                * what they carry... */
2956               if(token_len > extra_len)
2957                 iwe->u.data.pointer = NULL;     /* Discard paylod */
2958               /* Check that the advertised token size is not going to
2959                * produce buffer overflow to our caller... */
2960               if((iwe->u.data.length > descr->max_tokens)
2961                  && !(descr->flags & IW_DESCR_FLAG_NOMAX))
2962                 iwe->u.data.pointer = NULL;     /* Discard paylod */
2963               /* Same for underflows... */
2964               if(iwe->u.data.length < descr->min_tokens)
2965                 iwe->u.data.pointer = NULL;     /* Discard paylod */
2966 #ifdef DEBUG
2967               printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
2968                      extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
2969 #endif
2970             }
2971         }
2972       else
2973         /* No data */
2974         iwe->u.data.pointer = NULL;
2975
2976       /* Go to next event */
2977       stream->current += iwe->len;
2978     }
2979   else
2980     {
2981       /* Ugly fixup for alignement issues.
2982        * If the kernel is 64 bits and userspace 32 bits,
2983        * we have an extra 4 bytes.
2984        * Fixing that in the kernel would break 64 bits userspace. */
2985       if((stream->value == NULL)
2986          && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
2987              || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
2988                                       (event_type == IW_HEADER_TYPE_QUAL))) ))
2989         {
2990 #ifdef DEBUG
2991           printf("DBG - alt iwe->len = %d\n", iwe->len - 4);
2992 #endif
2993           pointer -= event_len;
2994           pointer += 4;
2995           /* Beware of alignement. Dest has local alignement, not packed */
2996           memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
2997           pointer += event_len;
2998         }
2999
3000       /* Is there more value in the event ? */
3001       if((pointer + event_len) <= (stream->current + iwe->len))
3002         /* Go to next value */
3003         stream->value = pointer;
3004       else
3005         {
3006           /* Go to next event */
3007           stream->value = NULL;
3008           stream->current += iwe->len;
3009         }
3010     }
3011   return(1);
3012 }
3013
3014 /*********************** SCANNING SUBROUTINES ***********************/
3015 /*
3016  * The Wireless Extension API 14 and greater define Wireless Scanning.
3017  * The normal API is complex, this is an easy API that return
3018  * a subset of the scanning results. This should be enough for most
3019  * applications that want to use Scanning.
3020  * If you want to have use the full/normal API, check iwlist.c...
3021  *
3022  * Precaution when using scanning :
3023  * The scanning operation disable normal network traffic, and therefore
3024  * you should not abuse of scan.
3025  * The scan need to check the presence of network on other frequencies.
3026  * While you are checking those other frequencies, you can *NOT* be on
3027  * your normal frequency to listen to normal traffic in the cell.
3028  * You need typically in the order of one second to actively probe all
3029  * 802.11b channels (do the maths). Some cards may do that in background,
3030  * to reply to scan commands faster, but they still have to do it.
3031  * Leaving the cell for such an extended period of time is pretty bad.
3032  * Any kind of streaming/low latency traffic will be impacted, and the
3033  * user will perceive it (easily checked with telnet). People trying to
3034  * send traffic to you will retry packets and waste bandwidth. Some
3035  * applications may be sensitive to those packet losses in weird ways,
3036  * and tracing those weird behavior back to scanning may take time.
3037  * If you are in ad-hoc mode, if two nodes scan approx at the same
3038  * time, they won't see each other, which may create associations issues.
3039  * For those reasons, the scanning activity should be limited to
3040  * what's really needed, and continuous scanning is a bad idea.
3041  * Jean II
3042  */
3043
3044 /*------------------------------------------------------------------*/
3045 /*
3046  * Process/store one element from the scanning results in wireless_scan
3047  */
3048 static inline struct wireless_scan *
3049 iw_process_scanning_token(struct iw_event *             event,
3050                           struct wireless_scan *        wscan)
3051 {
3052   struct wireless_scan *        oldwscan;
3053
3054   /* Now, let's decode the event */
3055   switch(event->cmd)
3056     {
3057     case SIOCGIWAP:
3058       /* New cell description. Allocate new cell descriptor, zero it. */
3059       oldwscan = wscan;
3060       wscan = (struct wireless_scan *) malloc(sizeof(struct wireless_scan));
3061       if(wscan == NULL)
3062         return(wscan);
3063       /* Link at the end of the list */
3064       if(oldwscan != NULL)
3065         oldwscan->next = wscan;
3066
3067       /* Reset it */
3068       bzero(wscan, sizeof(struct wireless_scan));
3069
3070       /* Save cell identifier */
3071       wscan->has_ap_addr = 1;
3072       memcpy(&(wscan->ap_addr), &(event->u.ap_addr), sizeof (sockaddr));
3073       break;
3074     case SIOCGIWNWID:
3075       wscan->b.has_nwid = 1;
3076       memcpy(&(wscan->b.nwid), &(event->u.nwid), sizeof(iwparam));
3077       break;
3078     case SIOCGIWFREQ:
3079       wscan->b.has_freq = 1;
3080       wscan->b.freq = iw_freq2float(&(event->u.freq));
3081       wscan->b.freq_flags = event->u.freq.flags;
3082       break;
3083     case SIOCGIWMODE:
3084       wscan->b.mode = event->u.mode;
3085       if((wscan->b.mode < IW_NUM_OPER_MODE) && (wscan->b.mode >= 0))
3086         wscan->b.has_mode = 1;
3087       break;
3088     case SIOCGIWESSID:
3089       wscan->b.has_essid = 1;
3090       wscan->b.essid_on = event->u.data.flags;
3091       memset(wscan->b.essid, '\0', IW_ESSID_MAX_SIZE + 1);
3092       if((event->u.essid.pointer) && (event->u.essid.length))
3093         memcpy(wscan->b.essid, event->u.essid.pointer, event->u.essid.length);
3094       break;
3095     case SIOCGIWENCODE:
3096       wscan->b.has_key = 1;
3097       wscan->b.key_size = event->u.data.length;
3098       wscan->b.key_flags = event->u.data.flags;
3099       if(event->u.data.pointer)
3100         memcpy(wscan->b.key, event->u.essid.pointer, event->u.data.length);
3101       else
3102         wscan->b.key_flags |= IW_ENCODE_NOKEY;
3103       break;
3104     case IWEVQUAL:
3105       /* We don't get complete stats, only qual */
3106       wscan->has_stats = 1;
3107       memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
3108       break;
3109     case SIOCGIWRATE:
3110       /* Scan may return a list of bitrates. As we have space for only
3111        * a single bitrate, we only keep the largest one. */
3112       if((!wscan->has_maxbitrate) ||
3113          (event->u.bitrate.value > wscan->maxbitrate.value))
3114         {
3115           wscan->has_maxbitrate = 1;
3116           memcpy(&(wscan->maxbitrate), &(event->u.bitrate), sizeof(iwparam));
3117         }
3118     case IWEVCUSTOM:
3119       /* How can we deal with those sanely ? Jean II */
3120     default:
3121       break;
3122    }    /* switch(event->cmd) */
3123
3124   return(wscan);
3125 }
3126
3127 /*------------------------------------------------------------------*/
3128 /*
3129  * Initiate the scan procedure, and process results.
3130  * This is a non-blocking procedure and it will return each time
3131  * it would block, returning the amount of time the caller should wait
3132  * before calling again.
3133  * Return -1 for error, delay to wait for (in ms), or 0 for success.
3134  * Error code is in errno
3135  */
3136 int
3137 iw_process_scan(int                     skfd,
3138                 char *                  ifname,
3139                 int                     we_version,
3140                 wireless_scan_head *    context)
3141 {
3142   struct iwreq          wrq;
3143   unsigned char *       buffer = NULL;          /* Results */
3144   int                   buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
3145   unsigned char *       newbuf;
3146
3147   /* Don't waste too much time on interfaces (150 * 100 = 15s) */
3148   context->retry++;
3149   if(context->retry > 150)
3150     {
3151       errno = ETIME;
3152       return(-1);
3153     }
3154
3155   /* If we have not yet initiated scanning on the interface */
3156   if(context->retry == 1)
3157     {
3158       /* Initiate Scan */
3159       wrq.u.data.pointer = NULL;                /* Later */
3160       wrq.u.data.flags = 0;
3161       wrq.u.data.length = 0;
3162       /* Remember that as non-root, we will get an EPERM here */
3163       if((iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
3164          && (errno != EPERM))
3165         return(-1);
3166       /* Success : now, just wait for event or results */
3167       return(250);      /* Wait 250 ms */
3168     }
3169
3170  realloc:
3171   /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
3172   newbuf = realloc(buffer, buflen);
3173   if(newbuf == NULL)
3174     {
3175       /* man says : If realloc() fails the original block is left untouched */
3176       if(buffer)
3177         free(buffer);
3178       errno = ENOMEM;
3179       return(-1);
3180     }
3181   buffer = newbuf;
3182
3183   /* Try to read the results */
3184   wrq.u.data.pointer = buffer;
3185   wrq.u.data.flags = 0;
3186   wrq.u.data.length = buflen;
3187   if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
3188     {
3189       /* Check if buffer was too small (WE-17 only) */
3190       if((errno == E2BIG) && (we_version > 16) && (buflen < 0xFFFF))
3191         {
3192           /* Some driver may return very large scan results, either
3193            * because there are many cells, or because they have many
3194            * large elements in cells (like IWEVCUSTOM). Most will
3195            * only need the regular sized buffer. We now use a dynamic
3196            * allocation of the buffer to satisfy everybody. Of course,
3197            * as we don't know in advance the size of the array, we try
3198            * various increasing sizes. Jean II */
3199
3200           /* Check if the driver gave us any hints. */
3201           if(wrq.u.data.length > buflen)
3202             buflen = wrq.u.data.length;
3203           else
3204             buflen *= 2;
3205
3206           /* wrq.u.data.length is 16 bits so max size is 65535 */
3207           if(buflen > 0xFFFF)
3208             buflen = 0xFFFF;
3209
3210           /* Try again */
3211           goto realloc;
3212         }
3213
3214       /* Check if results not available yet */
3215       if(errno == EAGAIN)
3216         {
3217           free(buffer);
3218           /* Wait for only 100ms from now on */
3219           return(100);  /* Wait 100 ms */
3220         }
3221
3222       free(buffer);
3223       /* Bad error, please don't come back... */
3224       return(-1);
3225     }
3226
3227   /* We have the results, process them */
3228   if(wrq.u.data.length)
3229     {
3230       struct iw_event           iwe;
3231       struct stream_descr       stream;
3232       struct wireless_scan *    wscan = NULL;
3233       int                       ret;
3234 #ifdef DEBUG
3235       /* Debugging code. In theory useless, because it's debugged ;-) */
3236       int       i;
3237       printf("Scan result [%02X", buffer[0]);
3238       for(i = 1; i < wrq.u.data.length; i++)
3239         printf(":%02X", buffer[i]);
3240       printf("]\n");
3241 #endif
3242
3243       /* Init */
3244       iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
3245       /* This is dangerous, we may leak user data... */
3246       context->result = NULL;
3247
3248       /* Look every token */
3249       do
3250         {
3251           /* Extract an event and print it */
3252           ret = iw_extract_event_stream(&stream, &iwe, we_version);
3253           if(ret > 0)
3254             {
3255               /* Convert to wireless_scan struct */
3256               wscan = iw_process_scanning_token(&iwe, wscan);
3257               /* Check problems */
3258               if(wscan == NULL)
3259                 {
3260                   free(buffer);
3261                   errno = ENOMEM;
3262                   return(-1);
3263                 }
3264               /* Save head of list */
3265               if(context->result == NULL)
3266                 context->result = wscan;
3267             }
3268         }
3269       while(ret > 0);
3270     }
3271
3272   /* Done with this interface - return success */
3273   free(buffer);
3274   return(0);
3275 }
3276
3277 /*------------------------------------------------------------------*/
3278 /*
3279  * Perform a wireless scan on the specified interface.
3280  * This is a blocking procedure and it will when the scan is completed
3281  * or when an error occur.
3282  *
3283  * The scan results are given in a linked list of wireless_scan objects.
3284  * The caller *must* free the result himself (by walking the list).
3285  * If there is an error, -1 is returned and the error code is available
3286  * in errno.
3287  *
3288  * The parameter we_version can be extracted from the range structure
3289  * (range.we_version_compiled - see iw_get_range_info()), or using
3290  * iw_get_kernel_we_version(). For performance reason, you should
3291  * cache this parameter when possible rather than querying it every time.
3292  *
3293  * Return -1 for error and 0 for success.
3294  */
3295 int
3296 iw_scan(int                     skfd,
3297         char *                  ifname,
3298         int                     we_version,
3299         wireless_scan_head *    context)
3300 {
3301   int           delay;          /* in ms */
3302
3303   /* Clean up context. Potential memory leak if(context.result != NULL) */
3304   context->result = NULL;
3305   context->retry = 0;
3306
3307   /* Wait until we get results or error */
3308   while(1)
3309     {
3310       /* Try to get scan results */
3311       delay = iw_process_scan(skfd, ifname, we_version, context);
3312
3313       /* Check termination */
3314       if(delay <= 0)
3315         break;
3316
3317       /* Wait a bit */
3318       usleep(delay * 1000);
3319     }
3320
3321   /* End - return -1 or 0 */
3322   return(delay);
3323 }