OSDN Git Service

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