OSDN Git Service

v24
[android-x86/external-wireless-tools.git] / wireless_tools / iwlib.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB 97->99 - HPL 99->01
5  *
6  * Common subroutines to all the wireless tools...
7  *
8  * This file is released under the GPL license.
9  *     Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
10  */
11
12 #include "iwlib.h"              /* Header */
13
14 /**************************** VARIABLES ****************************/
15
16 const char * const iw_operation_mode[] = { "Auto",
17                                         "Ad-Hoc",
18                                         "Managed",
19                                         "Master",
20                                         "Repeater",
21                                         "Secondary" };
22
23 /************************ SOCKET SUBROUTINES *************************/
24
25 /*------------------------------------------------------------------*/
26 /*
27  * Open a socket.
28  * Depending on the protocol present, open the right socket. The socket
29  * will allow us to talk to the driver.
30  */
31 int
32 iw_sockets_open(void)
33 {
34   static const int families[] = {
35     AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
36   };
37   unsigned int  i;
38   int           sock;
39
40   /*
41    * Now pick any (exisiting) useful socket family for generic queries
42    * Note : don't open all the socket, only returns when one matches,
43    * all protocols might not be valid.
44    * Workaround by Jim Kaba <jkaba@sarnoff.com>
45    * Note : in 99% of the case, we will just open the inet_sock.
46    * The remaining 1% case are not fully correct...
47    */
48
49   /* Try all families we support */
50   for(i = 0; i < sizeof(families)/sizeof(int); ++i)
51     {
52       /* Try to open the socket, if success returns it */
53       sock = socket(families[i], SOCK_DGRAM, 0);
54       if(sock >= 0)
55         return sock;
56   }
57
58   return -1;
59 }
60
61 /*------------------------------------------------------------------*/
62 /*
63  * Extract the interface name out of /proc/net/wireless
64  * Important note : this procedure will work only with /proc/net/wireless
65  * and not /proc/net/dev, because it doesn't guarantee a ' ' after the ':'.
66  */
67 static inline char *
68 iw_get_ifname(char *    name,   /* Where to store the name */
69               int       nsize,  /* Size of name buffer */
70               char *    buf)    /* Current position in buffer */
71 {
72   char *        end;
73
74   /* Skip leading spaces */
75   while(isspace(*buf))
76     buf++;
77
78   /* Get name up to ": "
79    * Note : we compare to ": " to make sure to process aliased interfaces
80    * properly. */
81   end = strstr(buf, ": ");
82
83   /* Not found ??? To big ??? */
84   if((end == NULL) || (((end - buf) + 1) > nsize))
85     return(NULL);
86
87   /* Copy */
88   memcpy(name, buf, (end - buf));
89   name[end - buf] = '\0';
90
91   return(end + 2);
92 }
93
94 /*------------------------------------------------------------------*/
95 /*
96  * Enumerate devices and call specified routine
97  * The new way just use /proc/net/wireless, so get all wireless interfaces,
98  * whether configured or not. This is the default if available.
99  * The old way use SIOCGIFCONF, so get only configured interfaces (wireless
100  * or not).
101  */
102 void
103 iw_enum_devices(int             skfd,
104                 iw_enum_handler fn,
105                 char *          args[],
106                 int             count)
107 {
108   char          buff[1024];
109   FILE *        fh;
110   struct ifconf ifc;
111   struct ifreq *ifr;
112   int           i;
113
114   /* Check if /proc/net/wireless is available */
115   fh = fopen(PROC_NET_WIRELESS, "r");
116
117   if(fh != NULL)
118     {
119       /* Success : use data from /proc/net/wireless */
120
121       /* Eat 2 lines of header */
122       fgets(buff, sizeof(buff), fh);
123       fgets(buff, sizeof(buff), fh);
124
125       /* Read each device line */
126       while(fgets(buff, sizeof(buff), fh))
127         {
128           char  name[IFNAMSIZ + 1];
129           char *s;
130
131           /* Extract interface name */
132           s = iw_get_ifname(name, sizeof(name), buff);
133
134           if(!s)
135             /* Failed to parse, complain and continue */
136             fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
137           else
138             /* Got it, print info about this interface */
139             (*fn)(skfd, name, args, count);
140         }
141
142       fclose(fh);
143     }
144   else
145     {
146       /* Get list of configured devices using "traditional" way */
147       ifc.ifc_len = sizeof(buff);
148       ifc.ifc_buf = buff;
149       if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
150         {
151           fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
152           return;
153         }
154       ifr = ifc.ifc_req;
155
156       /* Print them */
157       for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
158         (*fn)(skfd, ifr->ifr_name, args, count);
159     }
160 }
161
162 /*********************** WIRELESS SUBROUTINES ************************/
163
164 /*------------------------------------------------------------------*/
165 /*
166  * Get the range information out of the driver
167  */
168 int
169 iw_get_range_info(int           skfd,
170                   char *        ifname,
171                   iwrange *     range)
172 {
173   struct iwreq          wrq;
174   char                  buffer[sizeof(iwrange) * 2];    /* Large enough */
175
176   /* Cleanup */
177   memset(buffer, 0, sizeof(buffer));
178
179   wrq.u.data.pointer = (caddr_t) buffer;
180   wrq.u.data.length = sizeof(buffer);
181   wrq.u.data.flags = 0;
182   if(iw_get_ext(skfd, ifname, SIOCGIWRANGE, &wrq) < 0)
183     return(-1);
184
185   /* Copy stuff at the right place, ignore extra */
186   memcpy((char *) range, buffer, sizeof(iwrange));
187
188   /* Lots of people have driver and tools out of sync as far as Wireless
189    * Extensions are concerned. It's because /usr/include/linux/wireless.h
190    * and /usr/src/linux/include/linux/wireless.h are different.
191    * We try to catch this stuff here... */
192
193   /* For new versions, we can check the version directly, for old versions
194    * we use magic. 300 bytes is a also magic number, don't touch... */
195   if((WIRELESS_EXT > 10) && (wrq.u.data.length >= 300))
196     {
197 #if WIRELESS_EXT > 10
198       /* Version verification - for new versions */
199       if(range->we_version_compiled != WIRELESS_EXT)
200         {
201           fprintf(stderr, "Warning : Device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
202           fprintf(stderr, "of Wireless Extension, while we are using version %d.\n", WIRELESS_EXT);
203           fprintf(stderr, "Some things may be broken...\n\n");
204         }
205 #endif /* WIRELESS_EXT > 10 */
206     }
207   else
208     {
209       /* Version verification - for old versions */
210       if(wrq.u.data.length != sizeof(iwrange))
211         {
212           fprintf(stderr, "Warning : Device %s has been compiled with a different version\n", ifname);
213           fprintf(stderr, "of Wireless Extension than ours (we are using version %d).\n", WIRELESS_EXT);
214           fprintf(stderr, "Some things may be broken...\n\n");
215         }
216     }
217
218   /* Note : we are only trying to catch compile difference, not source.
219    * If the driver source has not been updated to the latest, it doesn't
220    * matter because the new fields are set to zero */
221
222   return(0);
223 }
224
225 /*------------------------------------------------------------------*/
226 /*
227  * Get information about what private ioctls are supported by the driver
228  */
229 int
230 iw_get_priv_info(int            skfd,
231                  char *         ifname,
232                  iwprivargs *   priv)
233 {
234   struct iwreq          wrq;
235
236   /* Ask the driver */
237   wrq.u.data.pointer = (caddr_t) priv;
238   wrq.u.data.length = 32;
239   wrq.u.data.flags = 0;
240   if(iw_get_ext(skfd, ifname, SIOCGIWPRIV, &wrq) < 0)
241     return(-1);
242
243   /* Return the number of ioctls */
244   return(wrq.u.data.length);
245 }
246
247 /*------------------------------------------------------------------*/
248 /*
249  * Get essential wireless config from the device driver
250  * We will call all the classical wireless ioctl on the driver through
251  * the socket to know what is supported and to get the settings...
252  * Note : compare to the version in iwconfig, we extract only
253  * what's *really* needed to configure a device...
254  */
255 int
256 iw_get_basic_config(int                 skfd,
257                     char *              ifname,
258                     wireless_config *   info)
259 {
260   struct iwreq          wrq;
261
262   memset((char *) info, 0, sizeof(struct wireless_config));
263
264   /* Get wireless name */
265   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
266     /* If no wireless name : no wireless extensions */
267     return(-1);
268   else
269     strcpy(info->name, wrq.u.name);
270
271   /* Get network ID */
272   if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) >= 0)
273     {
274       info->has_nwid = 1;
275       memcpy(&(info->nwid), &(wrq.u.nwid), sizeof(iwparam));
276     }
277
278   /* Get frequency / channel */
279   if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
280     {
281       info->has_freq = 1;
282       info->freq = iw_freq2float(&(wrq.u.freq));
283     }
284
285   /* Get encryption information */
286   wrq.u.data.pointer = (caddr_t) info->key;
287   wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
288   wrq.u.data.flags = 0;
289   if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
290     {
291       info->has_key = 1;
292       info->key_size = wrq.u.data.length;
293       info->key_flags = wrq.u.data.flags;
294     }
295
296   /* Get ESSID */
297   wrq.u.essid.pointer = (caddr_t) info->essid;
298   wrq.u.essid.length = IW_ESSID_MAX_SIZE;
299   wrq.u.essid.flags = 0;
300   if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) >= 0)
301     {
302       info->has_essid = 1;
303       info->essid_on = wrq.u.data.flags;
304     }
305
306   /* Get operation mode */
307   if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) >= 0)
308     {
309       info->mode = wrq.u.mode;
310       if((info->mode < 6) && (info->mode >= 0))
311         info->has_mode = 1;
312     }
313
314   return(0);
315 }
316
317 /*------------------------------------------------------------------*/
318 /*
319  * Set essential wireless config in the device driver
320  * We will call all the classical wireless ioctl on the driver through
321  * the socket to know what is supported and to set the settings...
322  * We support only the restricted set as above...
323  */
324 int
325 iw_set_basic_config(int                 skfd,
326                     char *              ifname,
327                     wireless_config *   info)
328 {
329   struct iwreq          wrq;
330   int                   ret = 0;
331
332   /* Get wireless name (check if interface is valid) */
333   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
334     /* If no wireless name : no wireless extensions */
335     return(-2);
336
337   /* Set Network ID, if available (this is for non-802.11 cards) */
338   if(info->has_nwid)
339     {
340       memcpy(&(wrq.u.nwid), &(info->nwid), sizeof(iwparam));
341       wrq.u.nwid.fixed = 1;     /* Hum... When in Rome... */
342
343       if(iw_set_ext(skfd, ifname, SIOCSIWNWID, &wrq) < 0)
344         {
345           fprintf(stderr, "SIOCSIWNWID: %s\n", strerror(errno));
346           ret = -1;
347         }
348     }
349
350   /* Set frequency / channel */
351   if(info->has_freq)
352     {
353       iw_float2freq(info->freq, &(wrq.u.freq));
354
355       if(iw_set_ext(skfd, ifname, SIOCSIWFREQ, &wrq) < 0)
356         {
357           fprintf(stderr, "SIOCSIWFREQ: %s\n", strerror(errno));
358           ret = -1;
359         }
360     }
361
362   /* Set encryption information */
363   if(info->has_key)
364     {
365       int               flags = info->key_flags;
366
367       /* Check if there is a key index */
368       if((flags & IW_ENCODE_INDEX) > 0)
369         {
370           /* Set the index */
371           wrq.u.data.pointer = (caddr_t) NULL;
372           wrq.u.data.flags = (flags & (IW_ENCODE_INDEX)) | IW_ENCODE_NOKEY;
373           wrq.u.data.length = 0;
374
375           if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
376             {
377               fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
378                       errno, strerror(errno));
379               ret = -1;
380             }
381         }
382
383       /* Mask out index to minimise probability of reject when setting key */
384       flags = flags & (~IW_ENCODE_INDEX);
385
386       /* Set the key itself (set current key in this case) */
387       wrq.u.data.pointer = (caddr_t) info->key;
388       wrq.u.data.length = info->key_size;
389       wrq.u.data.flags = flags;
390
391       if(iw_set_ext(skfd, ifname, SIOCSIWENCODE, &wrq) < 0)
392         {
393           fprintf(stderr, "SIOCSIWENCODE(%d): %s\n",
394                   errno, strerror(errno));
395           ret = -1;
396         }
397     }
398
399   /* Set ESSID (extended network), if available */
400   if(info->has_essid)
401     {
402       wrq.u.essid.pointer = (caddr_t) info->essid;
403       wrq.u.essid.length = strlen(info->essid) + 1;
404       wrq.u.data.flags = info->essid_on;
405
406       if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
407         {
408           fprintf(stderr, "SIOCSIWESSID: %s\n", strerror(errno));
409           ret = -1;
410         }
411     }
412
413   /* Set the current mode of operation */
414   if(info->has_mode)
415     {
416       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
417       wrq.u.mode = info->mode;
418
419       if(iw_get_ext(skfd, ifname, SIOCSIWMODE, &wrq) < 0)
420         {
421           fprintf(stderr, "SIOCSIWMODE: %s\n", strerror(errno));
422           ret = -1;
423         }
424     }
425
426   return(ret);
427 }
428
429 /********************** FREQUENCY SUBROUTINES ***********************/
430
431 /*------------------------------------------------------------------*/
432 /*
433  * Convert a floating point the our internal representation of
434  * frequencies.
435  * The kernel doesn't want to hear about floating point, so we use
436  * this custom format instead.
437  */
438 void
439 iw_float2freq(double    in,
440               iwfreq *  out)
441 {
442   out->e = (short) (floor(log10(in)));
443   if(out->e > 8)
444     {
445       out->m = ((long) (floor(in / pow(10,out->e - 6)))) * 100;
446       out->e -= 8;
447     }
448   else
449     {
450       out->m = in;
451       out->e = 0;
452     }
453 }
454
455 /*------------------------------------------------------------------*/
456 /*
457  * Convert our internal representation of frequencies to a floating point.
458  */
459 double
460 iw_freq2float(iwfreq *  in)
461 {
462   return ((double) in->m) * pow(10,in->e);
463 }
464
465 /*------------------------------------------------------------------*/
466 /*
467  * Output a frequency with proper scaling
468  */
469 void
470 iw_print_freq(char *    buffer,
471               float     freq)
472 {
473   if(freq < KILO)
474     sprintf(buffer, "Channel:%g", freq);
475   else
476     {
477       if(freq >= GIGA)
478         sprintf(buffer, "Frequency:%gGHz", freq / GIGA);
479       else
480         {
481           if(freq >= MEGA)
482             sprintf(buffer, "Frequency:%gMHz", freq / MEGA);
483           else
484             sprintf(buffer, "Frequency:%gkHz", freq / KILO);
485         }
486     }
487 }
488
489 /*********************** BITRATE SUBROUTINES ***********************/
490
491 /*------------------------------------------------------------------*/
492 /*
493  * Output a bitrate with proper scaling
494  */
495 void
496 iw_print_bitrate(char * buffer,
497                  int    bitrate)
498 {
499   double        rate = bitrate;
500
501   if(rate >= GIGA)
502     sprintf(buffer, "%gGb/s", rate / GIGA);
503   else
504     if(rate >= MEGA)
505       sprintf(buffer, "%gMb/s", rate / MEGA);
506     else
507       sprintf(buffer, "%gkb/s", rate / KILO);
508 }
509
510 /************************ POWER SUBROUTINES *************************/
511
512 /*------------------------------------------------------------------*/
513 /*
514  * Convert a value in dBm to a value in milliWatt.
515  */
516 int
517 iw_dbm2mwatt(int        in)
518 {
519   return((int) (floor(pow(10.0, (((double) in) / 10.0)))));
520 }
521
522 /*------------------------------------------------------------------*/
523 /*
524  * Convert a value in milliWatt to a value in dBm.
525  */
526 int
527 iw_mwatt2dbm(int        in)
528 {
529   return((int) (ceil(10.0 * log10((double) in))));
530 }
531
532 /********************** STATISTICS SUBROUTINES **********************/
533
534 /*------------------------------------------------------------------*/
535 /*
536  * Read /proc/net/wireless to get the latest statistics
537  */
538 int
539 iw_get_stats(int        skfd,
540              char *     ifname,
541              iwstats *  stats)
542 {
543 #if WIRELESS_EXT > 11
544   struct iwreq          wrq;
545   wrq.u.data.pointer = (caddr_t) stats;
546   wrq.u.data.length = 0;
547   wrq.u.data.flags = 1;         /* Clear updated flag */
548   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
549   if(iw_get_ext(skfd, ifname, SIOCGIWSTATS, &wrq) < 0)
550     return(-1);
551
552   return(0);
553 #else /* WIRELESS_EXT > 11 */
554   FILE *        f = fopen(PROC_NET_WIRELESS, "r");
555   char          buf[256];
556   char *        bp;
557   int           t;
558   if(f==NULL)
559     return -1;
560   /* Loop on all devices */
561   while(fgets(buf,255,f))
562     {
563       bp=buf;
564       while(*bp&&isspace(*bp))
565         bp++;
566       /* Is it the good device ? */
567       if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
568         {
569           /* Skip ethX: */
570           bp=strchr(bp,':');
571           bp++;
572           /* -- status -- */
573           bp = strtok(bp, " ");
574           sscanf(bp, "%X", &t);
575           stats->status = (unsigned short) t;
576           /* -- link quality -- */
577           bp = strtok(NULL, " ");
578           if(strchr(bp,'.') != NULL)
579             stats->qual.updated |= 1;
580           sscanf(bp, "%d", &t);
581           stats->qual.qual = (unsigned char) t;
582           /* -- signal level -- */
583           bp = strtok(NULL, " ");
584           if(strchr(bp,'.') != NULL)
585             stats->qual.updated |= 2;
586           sscanf(bp, "%d", &t);
587           stats->qual.level = (unsigned char) t;
588           /* -- noise level -- */
589           bp = strtok(NULL, " ");
590           if(strchr(bp,'.') != NULL)
591             stats->qual.updated += 4;
592           sscanf(bp, "%d", &t);
593           stats->qual.noise = (unsigned char) t;
594           /* -- discarded packets -- */
595           bp = strtok(NULL, " ");
596           sscanf(bp, "%d", &stats->discard.nwid);
597           bp = strtok(NULL, " ");
598           sscanf(bp, "%d", &stats->discard.code);
599           bp = strtok(NULL, " ");
600           sscanf(bp, "%d", &stats->discard.misc);
601           fclose(f);
602           return 0;
603         }
604     }
605   fclose(f);
606   return -1;
607 #endif /* WIRELESS_EXT > 11 */
608 }
609
610 /*------------------------------------------------------------------*/
611 /*
612  * Output the link statistics, taking care of formating
613  */
614 void
615 iw_print_stats(char *           buffer,
616                iwqual *         qual,
617                iwrange *        range,
618                int              has_range)
619 {
620   /* Just do it */
621   if(has_range && (qual->level != 0))
622     {
623       /* If the statistics are in dBm */
624       if(qual->level > range->max_qual.level)
625         {
626           /* Statistics are in dBm (absolute power measurement) */
627           sprintf(buffer,
628                   "Quality:%d/%d  Signal level:%d dBm  Noise level:%d dBm%s",
629                   qual->qual, range->max_qual.qual,
630                   qual->level - 0x100, qual->noise - 0x100,
631                   (qual->updated & 0x7) ? " (updated)" : "");
632         }
633       else
634         {
635           /* Statistics are relative values (0 -> max) */
636           sprintf(buffer,
637                   "Quality:%d/%d  Signal level:%d/%d  Noise level:%d/%d%s",
638                   qual->qual, range->max_qual.qual,
639                   qual->level, range->max_qual.level,
640                   qual->noise, range->max_qual.noise,
641                   (qual->updated & 0x7) ? " (updated)" : "");
642         }
643     }
644   else
645     {
646       /* We can't read the range, so we don't know... */
647       sprintf(buffer, "Quality:%d  Signal level:%d  Noise level:%d%s",
648               qual->qual, qual->level, qual->noise,
649               (qual->updated & 0x7) ? " (updated)" : "");
650     }
651 }
652
653 /*********************** ENCODING SUBROUTINES ***********************/
654
655 /*------------------------------------------------------------------*/
656 /*
657  * Output the encoding key, with a nice formating
658  */
659 void
660 iw_print_key(char *             buffer,
661              unsigned char *    key,
662              int                key_size,
663              int                key_flags)
664 {
665   int   i;
666
667   /* Is the key present ??? */
668   if(key_flags & IW_ENCODE_NOKEY)
669     {
670       /* Nope : print on or dummy */
671       if(key_size <= 0)
672         strcpy(buffer, "on");
673       else
674         {
675           strcpy(buffer, "**");
676           buffer +=2;
677           for(i = 1; i < key_size; i++)
678             {
679               if((i & 0x1) == 0)
680                 strcpy(buffer++, "-");
681               strcpy(buffer, "**");
682               buffer +=2;
683             }
684         }
685     }
686   else
687     {
688       /* Yes : print the key */
689       sprintf(buffer, "%.2X", key[0]);
690       buffer +=2;
691       for(i = 1; i < key_size; i++)
692         {
693           if((i & 0x1) == 0)
694             strcpy(buffer++, "-");
695           sprintf(buffer, "%.2X", key[i]);
696           buffer +=2;
697         }
698     }
699 }
700
701 /*------------------------------------------------------------------*/
702 /*
703  * Parse a key from the command line.
704  * Return size of the key, or 0 (no key) or -1 (error)
705  */
706 int
707 iw_in_key(char *                input,
708           unsigned char *       key)
709 {
710   int           keylen = 0;
711   char *        buff;
712   char *        p;
713   int           temp;
714
715   /* Check the type of key */
716   if(!strncmp(input, "s:", 2))
717     {
718       /* First case : as an ASCII string */
719       keylen = strlen(input + 2);               /* skip "s:" */
720       if(keylen > IW_ENCODING_TOKEN_MAX)
721         keylen = IW_ENCODING_TOKEN_MAX;
722       strncpy(key, input + 2, keylen);
723     }
724   else
725     {
726       /* Second case : as hexadecimal digits */
727       buff = malloc(strlen(input) + 1);
728       if(buff == NULL)
729         {
730           fprintf(stderr, "Malloc failed (string too long ?)\n");
731           return(-1);
732         }
733       /* Preserve original buffer */
734       strcpy(buff, input);
735
736       /* Parse */
737       p = strtok(buff, "-:;.,");
738       while((p != (char *) NULL) && (keylen < IW_ENCODING_TOKEN_MAX))
739         {
740           if(sscanf(p, "%2X", &temp) != 1)
741             return(-1);         /* Error */
742           key[keylen++] = (unsigned char) (temp & 0xFF);
743           if(strlen(p) > 2)     /* Token not finished yet */
744             p += 2;
745           else
746             p = strtok((char *) NULL, "-:;.,");
747         }
748       free(buff);
749     }
750
751   return(keylen);
752 }
753
754 /******************* POWER MANAGEMENT SUBROUTINES *******************/
755
756 /*------------------------------------------------------------------*/
757 /*
758  * Output a power management value with all attributes...
759  */
760 void
761 iw_print_pm_value(char *        buffer,
762                   int           value,
763                   int           flags)
764 {
765   /* Modifiers */
766   if(flags & IW_POWER_MIN)
767     {
768       strcpy(buffer, " min");
769       buffer += 4;
770     }
771   if(flags & IW_POWER_MAX)
772     {
773       strcpy(buffer, " max");
774       buffer += 4;
775     }
776
777   /* Type */
778   if(flags & IW_POWER_TIMEOUT)
779     {
780       strcpy(buffer, " timeout:");
781       buffer += 9;
782     }
783   else
784     {
785       strcpy(buffer, " period:");
786       buffer += 8;
787     }
788
789   /* Display value without units */
790   if(flags & IW_POWER_RELATIVE)
791     sprintf(buffer, "%g", ((double) value) / MEGA);
792   else
793     {
794       /* Display value with units */
795       if(value >= (int) MEGA)
796         sprintf(buffer, "%gs", ((double) value) / MEGA);
797       else
798         if(value >= (int) KILO)
799           sprintf(buffer, "%gms", ((double) value) / KILO);
800         else
801           sprintf(buffer, "%dus", value);
802     }
803 }
804
805 /*------------------------------------------------------------------*/
806 /*
807  * Output a power management mode
808  */
809 void
810 iw_print_pm_mode(char * buffer,
811                  int    flags)
812 {
813   /* Print the proper mode... */
814   switch(flags & IW_POWER_MODE)
815     {
816     case IW_POWER_UNICAST_R:
817       strcpy(buffer, "mode:Unicast only received");
818       break;
819     case IW_POWER_MULTICAST_R:
820       strcpy(buffer, "mode:Multicast only received");
821       break;
822     case IW_POWER_ALL_R:
823       strcpy(buffer, "mode:All packets received");
824       break;
825     case IW_POWER_FORCE_S:
826       strcpy(buffer, "mode:Force sending");
827       break;
828     case IW_POWER_REPEATER:
829       strcpy(buffer, "mode:Repeat multicasts");
830       break;
831     default:
832     }
833 }
834
835 /***************** RETRY LIMIT/LIFETIME SUBROUTINES *****************/
836
837 #if WIRELESS_EXT > 10
838 /*------------------------------------------------------------------*/
839 /*
840  * Output a retry value with all attributes...
841  */
842 void
843 iw_print_retry_value(char *     buffer,
844                      int        value,
845                      int        flags)
846 {
847   /* Modifiers */
848   if(flags & IW_RETRY_MIN)
849     {
850       strcpy(buffer, " min");
851       buffer += 4;
852     }
853   if(flags & IW_RETRY_MAX)
854     {
855       strcpy(buffer, " max");
856       buffer += 4;
857     }
858
859   /* Type lifetime of limit */
860   if(flags & IW_RETRY_LIFETIME)
861     {
862       strcpy(buffer, " lifetime:");
863       buffer += 10;
864
865       /* Display value without units */
866       if(flags & IW_POWER_RELATIVE)
867         sprintf(buffer, "%g", ((double) value) / MEGA);
868       else
869         {
870           /* Display value with units */
871           if(value >= (int) MEGA)
872             sprintf(buffer, "%gs", ((double) value) / MEGA);
873           else
874             if(value >= (int) KILO)
875               sprintf(buffer, "%gms", ((double) value) / KILO);
876             else
877               sprintf(buffer, "%dus", value);
878         }
879     }
880   else
881     sprintf(buffer, " limit:%d", value);
882 }
883 #endif  /* WIRELESS_EXT > 10 */
884
885 /************************* TIME SUBROUTINES *************************/
886
887 /*------------------------------------------------------------------*/
888 /*
889  * Print timestamps
890  * Inspired from irdadump...
891  */
892 void
893 iw_print_timeval(char *                 buffer,
894                  const struct timeval * time)
895 {
896         int s;
897
898         s = (time->tv_sec) % 86400;
899         sprintf(buffer, "%02d:%02d:%02d.%06u ", 
900                 s / 3600, (s % 3600) / 60, 
901                 s % 60, (u_int32_t) time->tv_usec);
902 }
903
904 /*********************** ADDRESS SUBROUTINES ************************/
905 /*
906  * This section is mostly a cut & past from net-tools-1.2.0
907  * manage address display and input...
908  */
909
910 /*------------------------------------------------------------------*/
911 /*
912  * Check if interface support the right MAC address type...
913  */
914 int
915 iw_check_mac_addr_type(int              skfd,
916                        char *           ifname)
917 {
918   struct ifreq          ifr;
919
920   /* Get the type of hardware address */
921   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
922   if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
923      (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
924     {
925       /* Deep trouble... */
926       fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
927              ifname);
928       return(-1);
929     }
930
931 #ifdef DEBUG
932   printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
933          iw_ether_ntoa((struct ether_addr *) ifr.ifr_hwaddr.sa_data));
934 #endif
935
936   return(0);
937 }
938
939
940 /*------------------------------------------------------------------*/
941 /*
942  * Check if interface support the right interface address type...
943  */
944 int
945 iw_check_if_addr_type(int               skfd,
946                       char *            ifname)
947 {
948   struct ifreq          ifr;
949
950   /* Get the type of interface address */
951   strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
952   if((ioctl(skfd, SIOCGIFADDR, &ifr) < 0) ||
953      (ifr.ifr_addr.sa_family !=  AF_INET))
954     {
955       /* Deep trouble... */
956       fprintf(stderr, "Interface %s doesn't support IP addresses\n", ifname);
957       return(-1);
958     }
959
960 #ifdef DEBUG
961   printf("Interface : %d - 0x%lX\n", ifr.ifr_addr.sa_family,
962          *((unsigned long *) ifr.ifr_addr.sa_data));
963 #endif
964
965   return(0);
966 }
967
968 #if 0
969 /*------------------------------------------------------------------*/
970 /*
971  * Check if interface support the right address types...
972  */
973 int
974 iw_check_addr_type(int          skfd,
975                    char *       ifname)
976 {
977   /* Check the interface address type */
978   if(iw_check_if_addr_type(skfd, ifname) < 0)
979     return(-1);
980
981   /* Check the interface address type */
982   if(iw_check_mac_addr_type(skfd, ifname) < 0)
983     return(-1);
984
985   return(0);
986 }
987 #endif
988
989 /*------------------------------------------------------------------*/
990 /*
991  * Display an Ethernet address in readable format.
992  */
993 void
994 iw_ether_ntop(const struct ether_addr* eth, char* buf)
995 {
996   sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
997           eth->ether_addr_octet[0], eth->ether_addr_octet[1],
998           eth->ether_addr_octet[2], eth->ether_addr_octet[3],
999           eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
1000 }
1001
1002 /*------------------------------------------------------------------*/
1003 /*
1004  * Display an Ethernet address in readable format.
1005  * Same with a static buffer
1006  */
1007 char *
1008 iw_ether_ntoa(const struct ether_addr* eth)
1009 {
1010   static char buf[20];
1011   iw_ether_ntop(eth, buf);
1012   return buf;
1013 }
1014
1015 /*------------------------------------------------------------------*/
1016 /*
1017  * Input an Ethernet address and convert to binary.
1018  */
1019 int
1020 iw_ether_aton(const char *orig, struct ether_addr *eth)
1021 {
1022   const char *bufp;
1023   int i;
1024
1025   i = 0;
1026   for(bufp = orig; *bufp != '\0'; ++bufp) {
1027         unsigned int val;
1028         unsigned char c = *bufp++;
1029         if (isdigit(c)) val = c - '0';
1030         else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
1031         else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
1032         else break;
1033
1034         val <<= 4;
1035         c = *bufp++;
1036         if (isdigit(c)) val |= c - '0';
1037         else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
1038         else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
1039         else break;
1040
1041         eth->ether_addr_octet[i] = (unsigned char) (val & 0377);
1042         if(++i == ETH_ALEN) {
1043                 /* That's it.  Any trailing junk? */
1044                 if (*bufp != '\0') {
1045 #ifdef DEBUG
1046                         fprintf(stderr, "iw_ether_aton(%s): trailing junk!\n", orig);
1047                         errno = EINVAL;
1048                         return(0);
1049 #endif
1050                 }
1051 #ifdef DEBUG
1052                 fprintf(stderr, "iw_ether_aton(%s): %s\n",
1053                         orig, ether_ntoa(eth));
1054 #endif
1055                 return(1);
1056         }
1057         if (*bufp != ':')
1058                 break;
1059   }
1060
1061 #ifdef DEBUG
1062   fprintf(stderr, "iw_ether_aton(%s): invalid ether address!\n", orig);
1063 #endif
1064   errno = EINVAL;
1065   return(0);
1066 }
1067
1068
1069 /*------------------------------------------------------------------*/
1070 /*
1071  * Input an Internet address and convert to binary.
1072  */
1073 int
1074 iw_in_inet(char *name, struct sockaddr *sap)
1075 {
1076   struct hostent *hp;
1077   struct netent *np;
1078   struct sockaddr_in *sin = (struct sockaddr_in *) sap;
1079
1080   /* Grmpf. -FvK */
1081   sin->sin_family = AF_INET;
1082   sin->sin_port = 0;
1083
1084   /* Default is special, meaning 0.0.0.0. */
1085   if (!strcmp(name, "default")) {
1086         sin->sin_addr.s_addr = INADDR_ANY;
1087         return(1);
1088   }
1089
1090   /* Try the NETWORKS database to see if this is a known network. */
1091   if ((np = getnetbyname(name)) != (struct netent *)NULL) {
1092         sin->sin_addr.s_addr = htonl(np->n_net);
1093         strcpy(name, np->n_name);
1094         return(1);
1095   }
1096
1097   if ((hp = gethostbyname(name)) == (struct hostent *)NULL) {
1098         errno = h_errno;
1099         return(-1);
1100   }
1101   memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], hp->h_length);
1102   strcpy(name, hp->h_name);
1103   return(0);
1104 }
1105
1106 /*------------------------------------------------------------------*/
1107 /*
1108  * Input an address and convert to binary.
1109  */
1110 int
1111 iw_in_addr(int          skfd,
1112            char *       ifname,
1113            char *       bufp,
1114            struct sockaddr *sap)
1115 {
1116   /* Check if it is a hardware or IP address */
1117   if(index(bufp, ':') == NULL)
1118     {
1119       struct sockaddr   if_address;
1120       struct arpreq     arp_query;
1121
1122       /* Check if we have valid interface address type */
1123       if(iw_check_if_addr_type(skfd, ifname) < 0)
1124         {
1125           fprintf(stderr, "%-8.8s  Interface doesn't support IP addresses\n", ifname);
1126           return(-1);
1127         }
1128
1129       /* Read interface address */
1130       if(iw_in_inet(bufp, &if_address) < 0)
1131         {
1132           fprintf(stderr, "Invalid interface address %s\n", bufp);
1133           return(-1);
1134         }
1135
1136       /* Translate IP addresses to MAC addresses */
1137       memcpy((char *) &(arp_query.arp_pa),
1138              (char *) &if_address,
1139              sizeof(struct sockaddr));
1140       arp_query.arp_ha.sa_family = 0;
1141       arp_query.arp_flags = 0;
1142       /* The following restrict the search to the interface only */
1143       /* For old kernels which complain, just comment it... */
1144       strncpy(arp_query.arp_dev, ifname, IFNAMSIZ);
1145       if((ioctl(skfd, SIOCGARP, &arp_query) < 0) ||
1146          !(arp_query.arp_flags & ATF_COM))
1147         {
1148           fprintf(stderr, "Arp failed for %s on %s... (%d)\nTry to ping the address before setting it.\n",
1149                   bufp, ifname, errno);
1150           return(-1);
1151         }
1152
1153       /* Store new MAC address */
1154       memcpy((char *) sap,
1155              (char *) &(arp_query.arp_ha),
1156              sizeof(struct sockaddr));
1157
1158 #ifdef DEBUG
1159       printf("IP Address %s => Hw Address = %s\n",
1160              bufp, iw_ether_ntoa((struct ether_addr *) sap->sa_data));
1161 #endif
1162     }
1163   else  /* If it's an hardware address */
1164     {
1165       /* Check if we have valid mac address type */
1166       if(iw_check_mac_addr_type(skfd, ifname) < 0)
1167         {
1168           fprintf(stderr, "%-8.8s  Interface doesn't support MAC addresses\n", ifname);
1169           return(-1);
1170         }
1171
1172       /* Get the hardware address */
1173       if(iw_in_ether(bufp, sap) < 0)
1174         {
1175           fprintf(stderr, "Invalid hardware address %s\n", bufp);
1176           return(-1);
1177         }
1178     }
1179
1180 #ifdef DEBUG
1181   printf("Hw Address = %s\n", iw_ether_ntoa((struct ether_addr *) sap->sa_data));
1182 #endif
1183
1184   return(0);
1185 }
1186
1187 /************************* MISC SUBROUTINES **************************/
1188
1189 /*------------------------------------------------------------------*/
1190 /*
1191  * Max size in bytes of an private argument.
1192  */
1193 int
1194 iw_byte_size(int        args)
1195 {
1196   int   ret = args & IW_PRIV_SIZE_MASK;
1197
1198   if(((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_INT) ||
1199      ((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_FLOAT))
1200     ret <<= 2;
1201
1202   if((args & IW_PRIV_TYPE_MASK) == IW_PRIV_TYPE_NONE)
1203     return 0;
1204
1205   return ret;
1206 }
1207
1208 /************************ EVENT SUBROUTINES ************************/
1209 /*
1210  * The Wireless Extension API 14 and greater define Wireless Events,
1211  * that are used for various events and scanning.
1212  * Those functions help the decoding of events, so are needed only in
1213  * this case.
1214  */
1215 #if WIRELESS_EXT > 13
1216
1217 /* Type of headers we know about (basically union iwreq_data) */
1218 #define IW_HEADER_TYPE_NULL     0       /* Not available */
1219 #define IW_HEADER_TYPE_CHAR     2       /* char [IFNAMSIZ] */
1220 #define IW_HEADER_TYPE_UINT     4       /* __u32 */
1221 #define IW_HEADER_TYPE_FREQ     5       /* struct iw_freq */
1222 #define IW_HEADER_TYPE_POINT    6       /* struct iw_point */
1223 #define IW_HEADER_TYPE_PARAM    7       /* struct iw_param */
1224 #define IW_HEADER_TYPE_ADDR     8       /* struct sockaddr */
1225 #define IW_HEADER_TYPE_QUAL     9       /* struct iw_quality */
1226
1227 /* Headers for the various requests */
1228 static const char standard_ioctl_hdr[] = {
1229         IW_HEADER_TYPE_NULL,    /* SIOCSIWCOMMIT */
1230         IW_HEADER_TYPE_CHAR,    /* SIOCGIWNAME */
1231         IW_HEADER_TYPE_PARAM,   /* SIOCSIWNWID */
1232         IW_HEADER_TYPE_PARAM,   /* SIOCGIWNWID */
1233         IW_HEADER_TYPE_FREQ,    /* SIOCSIWFREQ */
1234         IW_HEADER_TYPE_FREQ,    /* SIOCGIWFREQ */
1235         IW_HEADER_TYPE_UINT,    /* SIOCSIWMODE */
1236         IW_HEADER_TYPE_UINT,    /* SIOCGIWMODE */
1237         IW_HEADER_TYPE_PARAM,   /* SIOCSIWSENS */
1238         IW_HEADER_TYPE_PARAM,   /* SIOCGIWSENS */
1239         IW_HEADER_TYPE_NULL,    /* SIOCSIWRANGE */
1240         IW_HEADER_TYPE_POINT,   /* SIOCGIWRANGE */
1241         IW_HEADER_TYPE_NULL,    /* SIOCSIWPRIV */
1242         IW_HEADER_TYPE_POINT,   /* SIOCGIWPRIV */
1243         IW_HEADER_TYPE_NULL,    /* SIOCSIWSTATS */
1244         IW_HEADER_TYPE_POINT,   /* SIOCGIWSTATS */
1245         IW_HEADER_TYPE_POINT,   /* SIOCSIWSPY */
1246         IW_HEADER_TYPE_POINT,   /* SIOCGIWSPY */
1247         IW_HEADER_TYPE_NULL,    /* -- hole -- */
1248         IW_HEADER_TYPE_NULL,    /* -- hole -- */
1249         IW_HEADER_TYPE_ADDR,    /* SIOCSIWAP */
1250         IW_HEADER_TYPE_ADDR,    /* SIOCGIWAP */
1251         IW_HEADER_TYPE_NULL,    /* -- hole -- */
1252         IW_HEADER_TYPE_POINT,   /* SIOCGIWAPLIST */
1253         IW_HEADER_TYPE_PARAM,   /* SIOCSIWSCAN */
1254         IW_HEADER_TYPE_POINT,   /* SIOCGIWSCAN */
1255         IW_HEADER_TYPE_POINT,   /* SIOCSIWESSID */
1256         IW_HEADER_TYPE_POINT,   /* SIOCGIWESSID */
1257         IW_HEADER_TYPE_POINT,   /* SIOCSIWNICKN */
1258         IW_HEADER_TYPE_POINT,   /* SIOCGIWNICKN */
1259         IW_HEADER_TYPE_NULL,    /* -- hole -- */
1260         IW_HEADER_TYPE_NULL,    /* -- hole -- */
1261         IW_HEADER_TYPE_PARAM,   /* SIOCSIWRATE */
1262         IW_HEADER_TYPE_PARAM,   /* SIOCGIWRATE */
1263         IW_HEADER_TYPE_PARAM,   /* SIOCSIWRTS */
1264         IW_HEADER_TYPE_PARAM,   /* SIOCGIWRTS */
1265         IW_HEADER_TYPE_PARAM,   /* SIOCSIWFRAG */
1266         IW_HEADER_TYPE_PARAM,   /* SIOCGIWFRAG */
1267         IW_HEADER_TYPE_PARAM,   /* SIOCSIWTXPOW */
1268         IW_HEADER_TYPE_PARAM,   /* SIOCGIWTXPOW */
1269         IW_HEADER_TYPE_PARAM,   /* SIOCSIWRETRY */
1270         IW_HEADER_TYPE_PARAM,   /* SIOCGIWRETRY */
1271         IW_HEADER_TYPE_POINT,   /* SIOCSIWENCODE */
1272         IW_HEADER_TYPE_POINT,   /* SIOCGIWENCODE */
1273         IW_HEADER_TYPE_PARAM,   /* SIOCSIWPOWER */
1274         IW_HEADER_TYPE_PARAM,   /* SIOCGIWPOWER */
1275 };
1276 static const unsigned int standard_ioctl_num = sizeof(standard_ioctl_hdr);
1277
1278 /*
1279  * Meta-data about all the additional standard Wireless Extension events
1280  * we know about.
1281  */
1282 static const char       standard_event_hdr[] = {
1283         IW_HEADER_TYPE_ADDR,    /* IWEVTXDROP */
1284         IW_HEADER_TYPE_QUAL,    /* IWEVQUAL */
1285 };
1286 static const unsigned int standard_event_num = sizeof(standard_event_hdr);
1287
1288 /* Size (in bytes) of various events */
1289 static const int event_type_size[] = {
1290         IW_EV_LCP_LEN,
1291         0,
1292         IW_EV_CHAR_LEN,
1293         0,
1294         IW_EV_UINT_LEN,
1295         IW_EV_FREQ_LEN,
1296         IW_EV_POINT_LEN,                /* Without variable payload */
1297         IW_EV_PARAM_LEN,
1298         IW_EV_ADDR_LEN,
1299         IW_EV_QUAL_LEN,
1300 };
1301
1302 /*------------------------------------------------------------------*/
1303 /*
1304  * Initialise the struct stream_descr so that we can extract
1305  * individual events from the event stream.
1306  */
1307 void
1308 iw_init_event_stream(struct stream_descr *      stream, /* Stream of events */
1309                      char *                     data,
1310                      int                        len)
1311 {
1312   /* Cleanup */
1313   memset((char *) stream, '\0', sizeof(struct stream_descr));
1314
1315   /* Set things up */
1316   stream->current = data;
1317   stream->end = data + len;
1318 }
1319
1320 /*------------------------------------------------------------------*/
1321 /*
1322  * Extract the next event from the event stream.
1323  */
1324 int
1325 iw_extract_event_stream(struct stream_descr *   stream, /* Stream of events */
1326                         struct iw_event *       iwe)    /* Extracted event */
1327 {
1328   int           event_type = 0;
1329   int           event_len = 1;          /* Invalid */
1330   char *        pointer;
1331   /* Don't "optimise" the following variable, it will crash */
1332   unsigned      cmd_index;              /* *MUST* be unsigned */
1333
1334   /* Check for end of stream */
1335   if((stream->current + IW_EV_LCP_LEN) > stream->end)
1336     return(0);
1337
1338 #if 0
1339   printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
1340          stream->current, stream->value, stream->end);
1341 #endif
1342
1343   /* Extract the event header (to get the event id).
1344    * Note : the event may be unaligned, therefore copy... */
1345   memcpy((char *) iwe, stream->current, IW_EV_LCP_LEN);
1346
1347 #if 0
1348   printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
1349          iwe->cmd, iwe->len);
1350 #endif
1351
1352    /* Get the type and length of that event */
1353   if(iwe->cmd <= SIOCIWLAST)
1354     {
1355       cmd_index = iwe->cmd - SIOCIWFIRST;
1356       if(cmd_index < standard_ioctl_num)
1357         event_type = standard_ioctl_hdr[cmd_index];
1358     }
1359   else
1360     {
1361       cmd_index = iwe->cmd - IWEVFIRST;
1362       if(cmd_index < standard_event_num)
1363         event_type = standard_event_hdr[cmd_index];
1364     }
1365   event_len = event_type_size[event_type];
1366
1367   /* Check if we know about this event */
1368   if((event_len == 0) || (iwe->len == 0))
1369     return(-1);
1370   event_len -= IW_EV_LCP_LEN;
1371
1372   /* Set pointer on data */
1373   if(stream->value != NULL)
1374     pointer = stream->value;                    /* Next value in event */
1375   else
1376     pointer = stream->current + IW_EV_LCP_LEN;  /* First value in event */
1377
1378 #if 0
1379   printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
1380          event_type, event_len, pointer);
1381 #endif
1382
1383   /* Copy the rest of the event (at least, fixed part) */
1384   if((pointer + event_len) > stream->end)
1385     return(-2);
1386   memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
1387
1388   /* Skip event in the stream */
1389   pointer += event_len;
1390
1391   /* Special processing for iw_point events */
1392   if(event_type == IW_HEADER_TYPE_POINT)
1393     {
1394       /* Check the length of the payload */
1395       if((iwe->len - (event_len + IW_EV_LCP_LEN)) > 0)
1396         /* Set pointer on variable part (warning : non aligned) */
1397         iwe->u.data.pointer = pointer;
1398       else
1399         /* No data */
1400         iwe->u.data.pointer = NULL;
1401
1402        /* Go to next event */
1403       stream->current += iwe->len;
1404     }
1405   else
1406     {
1407       /* Is there more value in the event ? */
1408       if((pointer + event_len) <= (stream->current + iwe->len))
1409         /* Go to next value */
1410         stream->value = pointer;
1411       else
1412         {
1413           /* Go to next event */
1414           stream->value = NULL;
1415           stream->current += iwe->len;
1416         }
1417     }
1418   return(1);
1419 }
1420
1421 #endif /* WIRELESS_EXT > 13 */