OSDN Git Service

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