OSDN Git Service

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