OSDN Git Service

v27
[android-x86/external-wireless-tools.git] / wireless_tools / iwlist.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB '99 - HPL 99->04
5  *
6  * This tool can access various piece of information on the card
7  * not part of iwconfig...
8  * You need to link this code against "iwlist.c" and "-lm".
9  *
10  * This file is released under the GPL license.
11  *     Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
12  */
13
14 #include "iwlib.h"              /* Header */
15 #include <sys/time.h>
16
17 /*********************** FREQUENCIES/CHANNELS ***********************/
18
19 /*------------------------------------------------------------------*/
20 /*
21  * Print the number of channels and available frequency for the device
22  */
23 static int
24 print_freq_info(int             skfd,
25                 char *          ifname,
26                 char *          args[],         /* Command line args */
27                 int             count)          /* Args count */
28 {
29   struct iwreq          wrq;
30   struct iw_range       range;
31   double                freq;
32   int                   k;
33   int                   channel;
34   char                  buffer[128];    /* Temporary buffer */
35
36   /* Avoid "Unused parameter" warning */
37   args = args; count = count;
38
39   /* Get list of frequencies / channels */
40   if(iw_get_range_info(skfd, ifname, &range) < 0)
41       fprintf(stderr, "%-8.16s  no frequency information.\n\n",
42                       ifname);
43   else
44     {
45       if(range.num_frequency > 0)
46         {
47           printf("%-8.16s  %d channels in total; available frequencies :\n",
48                  ifname, range.num_channels);
49           /* Print them all */
50           for(k = 0; k < range.num_frequency; k++)
51             {
52               freq = iw_freq2float(&(range.freq[k]));
53               iw_print_freq_value(buffer, sizeof(buffer), freq);
54               printf("          Channel %.2d : %s\n",
55                      range.freq[k].i, buffer);
56             }
57         }
58       else
59         printf("%-8.16s  %d channels\n",
60                ifname, range.num_channels);
61
62       /* Get current frequency / channel and display it */
63       if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
64         {
65           freq = iw_freq2float(&(wrq.u.freq));
66           channel = iw_freq_to_channel(freq, &range);
67           iw_print_freq(buffer, sizeof(buffer),
68                         freq, channel, wrq.u.freq.flags);
69           printf("          Current %s\n\n", buffer);
70         }
71     }
72   return(0);
73 }
74
75 /************************ ACCESS POINT LIST ************************/
76 /*
77  * Note : now that we have scanning support, this is depracted and
78  * won't survive long. Actually, next version it's out !
79  */
80
81 /*------------------------------------------------------------------*/
82 /*
83  * Display the list of ap addresses and the associated stats
84  * Exacly the same as the spy list, only with different IOCTL and messages
85  */
86 static int
87 print_ap_info(int       skfd,
88               char *    ifname,
89               char *    args[],         /* Command line args */
90               int       count)          /* Args count */
91 {
92   struct iwreq          wrq;
93   char          buffer[(sizeof(struct iw_quality) +
94                         sizeof(struct sockaddr)) * IW_MAX_AP];
95   char          temp[128];
96   struct sockaddr *     hwa;
97   struct iw_quality *   qual;
98   iwrange       range;
99   int           has_range = 0;
100   int           has_qual = 0;
101   int           n;
102   int           i;
103
104   /* Avoid "Unused parameter" warning */
105   args = args; count = count;
106
107   /* Collect stats */
108   wrq.u.data.pointer = (caddr_t) buffer;
109   wrq.u.data.length = IW_MAX_AP;
110   wrq.u.data.flags = 0;
111   if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
112     {
113       fprintf(stderr, "%-8.16s  Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
114       return(-1);
115     }
116
117   /* Number of addresses */
118   n = wrq.u.data.length;
119   has_qual = wrq.u.data.flags;
120
121   /* The two lists */
122   hwa = (struct sockaddr *) buffer;
123   qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
124
125   /* Check if we have valid mac address type */
126   if(iw_check_mac_addr_type(skfd, ifname) < 0)
127     {
128       fprintf(stderr, "%-8.16s  Interface doesn't support MAC addresses\n\n", ifname);
129       return(-2);
130     }
131
132   /* Get range info if we can */
133   if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
134     has_range = 1;
135
136   /* Display it */
137   if(n == 0)
138     printf("%-8.16s  No Peers/Access-Point in range\n", ifname);
139   else
140     printf("%-8.16s  Peers/Access-Points in range:\n", ifname);
141   for(i = 0; i < n; i++)
142     {
143       if(has_qual)
144         {
145           /* Print stats for this address */
146           printf("    %s : ", iw_pr_ether(temp, hwa[i].sa_data));
147           iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
148           printf("%s\n", temp);
149         }
150       else
151         /* Only print the address */
152         printf("    %s\n", iw_pr_ether(temp, hwa[i].sa_data));
153     }
154   printf("\n");
155   return(0);
156 }
157
158 /***************************** BITRATES *****************************/
159
160 /*------------------------------------------------------------------*/
161 /*
162  * Print the number of available bitrates for the device
163  */
164 static int
165 print_bitrate_info(int          skfd,
166                    char *       ifname,
167                    char *       args[],         /* Command line args */
168                    int          count)          /* Args count */
169 {
170   struct iwreq          wrq;
171   struct iw_range       range;
172   int                   k;
173   char                  buffer[128];
174
175   /* Avoid "Unused parameter" warning */
176   args = args; count = count;
177
178   /* Extract range info */
179   if(iw_get_range_info(skfd, ifname, &range) < 0)
180       fprintf(stderr, "%-8.16s  no bit-rate information.\n\n",
181                       ifname);
182   else
183     {
184       if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
185         {
186           printf("%-8.16s  %d available bit-rates :\n",
187                  ifname, range.num_bitrates);
188           /* Print them all */
189           for(k = 0; k < range.num_bitrates; k++)
190             {
191               iw_print_bitrate(buffer, sizeof(buffer), range.bitrate[k]);
192               /* Maybe this should be %10s */
193               printf("\t  %s\n", buffer);
194             }
195         }
196       else
197         printf("%-8.16s  unknown bit-rate information.\n", ifname);
198
199       /* Get current bit rate */
200       if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
201         {
202           iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
203           printf("          Current Bit Rate%c%s\n\n",
204                  (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
205         }
206     }
207   return(0);
208 }
209
210 /************************* ENCRYPTION KEYS *************************/
211
212 /*------------------------------------------------------------------*/
213 /*
214  * Print the number of available encryption key for the device
215  */
216 static int
217 print_keys_info(int             skfd,
218                 char *          ifname,
219                 char *          args[],         /* Command line args */
220                 int             count)          /* Args count */
221 {
222   struct iwreq          wrq;
223   struct iw_range       range;
224   unsigned char         key[IW_ENCODING_TOKEN_MAX];
225   int                   k;
226   char                  buffer[128];
227
228   /* Avoid "Unused parameter" warning */
229   args = args; count = count;
230
231   /* Extract range info */
232   if(iw_get_range_info(skfd, ifname, &range) < 0)
233       fprintf(stderr, "%-8.16s  no encryption keys information.\n\n",
234                       ifname);
235   else
236     {
237       printf("%-8.16s  ", ifname);
238       /* Print key sizes */
239       if((range.num_encoding_sizes > 0) &&
240          (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
241         {
242           printf("%d key sizes : %d", range.num_encoding_sizes,
243                  range.encoding_size[0] * 8);
244           /* Print them all */
245           for(k = 1; k < range.num_encoding_sizes; k++)
246             printf(", %d", range.encoding_size[k] * 8);
247           printf("bits\n          ");
248         }
249       /* Print the keys and associate mode */
250       printf("%d keys available :\n", range.max_encoding_tokens);
251       for(k = 1; k <= range.max_encoding_tokens; k++)
252         {
253           wrq.u.data.pointer = (caddr_t) key;
254           wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
255           wrq.u.data.flags = k;
256           if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
257             {
258               fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
259               break;
260             }
261           if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
262              (wrq.u.data.length == 0))
263             printf("\t\t[%d]: off\n", k);
264           else
265             {
266               /* Display the key */
267               iw_print_key(buffer, sizeof(buffer),
268                            key, wrq.u.data.length, wrq.u.data.flags);
269               printf("\t\t[%d]: %s", k, buffer);
270
271               /* Other info... */
272               printf(" (%d bits)", wrq.u.data.length * 8);
273               printf("\n");
274             }
275         }
276       /* Print current key and mode */
277       wrq.u.data.pointer = (caddr_t) key;
278       wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
279       wrq.u.data.flags = 0;     /* Set index to zero to get current */
280       if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
281         {
282           fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
283           return(-1);
284         }
285       printf("          Current Transmit Key: [%d]\n",
286              wrq.u.data.flags & IW_ENCODE_INDEX);
287       if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
288         printf("          Security mode:restricted\n");
289       if(wrq.u.data.flags & IW_ENCODE_OPEN)
290         printf("          Security mode:open\n");
291
292       printf("\n\n");
293     }
294   return(0);
295 }
296
297 /************************* POWER MANAGEMENT *************************/
298
299 /*------------------------------------------------------------------*/
300 /*
301  * Print Power Management info for each device
302  */
303 static inline int
304 get_pm_value(int                skfd,
305              char *             ifname,
306              struct iwreq *     pwrq,
307              int                flags,
308              char *             buffer)
309 {
310   /* Get Another Power Management value */
311   pwrq->u.power.flags = flags;
312   if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, pwrq) >= 0)
313     {
314       /* Let's check the value and its type */
315       if(pwrq->u.power.flags & IW_POWER_TYPE)
316         {
317           iw_print_pm_value(buffer, sizeof(buffer),
318                             pwrq->u.power.value, pwrq->u.power.flags);
319           printf("\n                 %s", buffer);
320         }
321     }
322   return(pwrq->u.power.flags);
323 }
324
325 /*------------------------------------------------------------------*/
326 /*
327  * Print Power Management info for each device
328  */
329 static int
330 print_pm_info(int               skfd,
331               char *            ifname,
332               char *            args[],         /* Command line args */
333               int               count)          /* Args count */
334 {
335   struct iwreq          wrq;
336   struct iw_range       range;
337   char                  buffer[128];
338
339   /* Avoid "Unused parameter" warning */
340   args = args; count = count;
341
342   /* Extract range info */
343   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
344      (range.we_version_compiled < 10))
345       fprintf(stderr, "%-8.16s  no power management information.\n\n",
346                       ifname);
347   else
348     {
349       printf("%-8.16s  ", ifname);
350
351       /* Display modes availables */
352       if(range.pm_capa & IW_POWER_MODE)
353         {
354           printf("Supported modes :\n          ");
355           if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
356             printf("\t\to Receive all packets (unicast & multicast)\n          ");
357           if(range.pm_capa & IW_POWER_UNICAST_R)
358             printf("\t\to Receive Unicast only (discard multicast)\n          ");
359           if(range.pm_capa & IW_POWER_MULTICAST_R)
360             printf("\t\to Receive Multicast only (discard unicast)\n          ");
361           if(range.pm_capa & IW_POWER_FORCE_S)
362             printf("\t\to Force sending using Power Management\n          ");
363           if(range.pm_capa & IW_POWER_REPEATER)
364             printf("\t\to Repeat multicast\n          ");
365         }
366       /* Display min/max period availables */
367       if(range.pmp_flags & IW_POWER_PERIOD)
368         {
369           int   flags = (range.pmp_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
370           /* Display if auto or fixed */
371           if(range.pmp_flags & IW_POWER_MIN)
372             printf("Auto  period  ; ");
373           else
374             printf("Fixed period  ; ");
375           /* Print the range */
376           iw_print_pm_value(buffer, sizeof(buffer),
377                             range.min_pmp, flags | IW_POWER_MIN);
378           printf("%s\n                          ", buffer);
379           iw_print_pm_value(buffer, sizeof(buffer),
380                             range.max_pmp, flags | IW_POWER_MAX);
381           printf("%s\n          ", buffer);
382         }
383       /* Display min/max timeout availables */
384       if(range.pmt_flags & IW_POWER_TIMEOUT)
385         {
386           int   flags = (range.pmt_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
387           /* Display if auto or fixed */
388           if(range.pmt_flags & IW_POWER_MIN)
389             printf("Auto  timeout ; ");
390           else
391             printf("Fixed timeout ; ");
392           /* Print the range */
393           iw_print_pm_value(buffer, sizeof(buffer),
394                             range.min_pmt, flags | IW_POWER_MIN);
395           printf("%s\n                          ", buffer);
396           iw_print_pm_value(buffer, sizeof(buffer),
397                             range.max_pmt, flags | IW_POWER_MAX);
398           printf("%s\n          ", buffer);
399         }
400
401       /* Get current Power Management settings */
402       wrq.u.power.flags = 0;
403       if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
404         {
405           int   flags = wrq.u.power.flags;
406
407           /* Is it disabled ? */
408           if(wrq.u.power.disabled)
409             printf("Current mode:off\n          ");
410           else
411             {
412               int       pm_mask = 0;
413
414               /* Let's check the mode */
415               iw_print_pm_mode(buffer, sizeof(buffer), flags);
416               printf("Current %s", buffer);
417
418               /* Let's check if nothing (simply on) */
419               if((flags & IW_POWER_MODE) == IW_POWER_ON)
420                 printf("mode:on");
421               printf("\n                 ");
422
423               /* Let's check the value and its type */
424               if(wrq.u.power.flags & IW_POWER_TYPE)
425                 {
426                   iw_print_pm_value(buffer, sizeof(buffer),
427                                     wrq.u.power.value, wrq.u.power.flags);
428                   printf("%s", buffer);
429                 }
430
431               /* If we have been returned a MIN value, ask for the MAX */
432               if(flags & IW_POWER_MIN)
433                 pm_mask = IW_POWER_MAX;
434               /* If we have been returned a MAX value, ask for the MIN */
435               if(flags & IW_POWER_MAX)
436                 pm_mask = IW_POWER_MIN;
437               /* If we have something to ask for... */
438               if(pm_mask)
439                 get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
440
441               /* And if we have both a period and a timeout, ask the other */
442               pm_mask = (range.pm_capa & (~(wrq.u.power.flags) &
443                                           IW_POWER_TYPE));
444               if(pm_mask)
445                 {
446                   int   base_mask = pm_mask;
447                   flags = get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
448                   pm_mask = 0;
449
450                   /* If we have been returned a MIN value, ask for the MAX */
451                   if(flags & IW_POWER_MIN)
452                     pm_mask = IW_POWER_MAX | base_mask;
453                   /* If we have been returned a MAX value, ask for the MIN */
454                   if(flags & IW_POWER_MAX)
455                     pm_mask = IW_POWER_MIN | base_mask;
456                   /* If we have something to ask for... */
457                   if(pm_mask)
458                     get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
459                 }
460             }
461         }
462       printf("\n");
463     }
464   return(0);
465 }
466
467 /************************** TRANSMIT POWER **************************/
468
469 /*------------------------------------------------------------------*/
470 /*
471  * Print the number of available transmit powers for the device
472  */
473 static int
474 print_txpower_info(int          skfd,
475                    char *       ifname,
476                    char *       args[],         /* Command line args */
477                    int          count)          /* Args count */
478 {
479   struct iwreq          wrq;
480   struct iw_range       range;
481   int                   dbm;
482   int                   mwatt;
483   int                   k;
484
485   /* Avoid "Unused parameter" warning */
486   args = args; count = count;
487
488   /* Extract range info */
489   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
490      (range.we_version_compiled < 10))
491       fprintf(stderr, "%-8.16s  no transmit-power information.\n\n",
492                       ifname);
493   else
494     {
495       if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
496         printf("%-8.16s  unknown transmit-power information.\n\n", ifname);
497       else
498         {
499           printf("%-8.16s  %d available transmit-powers :\n",
500                  ifname, range.num_txpower);
501           /* Print them all */
502           for(k = 0; k < range.num_txpower; k++)
503             {
504               /* Check for relative values */
505               if(range.txpower_capa & IW_TXPOW_RELATIVE)
506                 {
507                   printf("\t  %d (no units)\n", range.txpower[k]);
508                 }
509               else
510                 {
511                   if(range.txpower_capa & IW_TXPOW_MWATT)
512                     {
513                       dbm = iw_mwatt2dbm(range.txpower[k]);
514                       mwatt = range.txpower[k];
515                     }
516                   else
517                     {
518                       dbm = range.txpower[k];
519                       mwatt = iw_dbm2mwatt(range.txpower[k]);
520                     }
521                   printf("\t  %d dBm  \t(%d mW)\n", dbm, mwatt);
522                 }
523             }
524         }
525
526       /* Get current Transmit Power */
527       if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
528         {
529           printf("          Current Tx-Power");
530           /* Disabled ? */
531           if(wrq.u.txpower.disabled)
532             printf(":off\n\n");
533           else
534             {
535               /* Fixed ? */
536               if(wrq.u.txpower.fixed)
537                 printf("=");
538               else
539                 printf(":");
540               /* Check for relative values */
541               if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
542                 {
543                   /* I just hate relative value, because they are
544                    * driver specific, so not very meaningfull to apps.
545                    * But, we have to support that, because
546                    * this is the way hardware is... */
547                   printf("\t  %d (no units)\n", wrq.u.txpower.value);
548                 }
549               else
550                 {
551                   if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
552                     {
553                       dbm = iw_mwatt2dbm(wrq.u.txpower.value);
554                       mwatt = wrq.u.txpower.value;
555                     }
556                   else
557                     {
558                       dbm = wrq.u.txpower.value;
559                       mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
560                     }
561                   printf("%d dBm  \t(%d mW)\n\n", dbm, mwatt);
562                 }
563             }
564         }
565     }
566   return(0);
567 }
568
569 /*********************** RETRY LIMIT/LIFETIME ***********************/
570
571 /*------------------------------------------------------------------*/
572 /*
573  * Print one retry value
574  */
575 static inline int
576 get_retry_value(int             skfd,
577                 char *          ifname,
578                 struct iwreq *  pwrq,
579                 int             flags,
580                 char *          buffer,
581                 int             buflen)
582 {
583   /* Get Another retry value */
584   pwrq->u.retry.flags = flags;
585   if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, pwrq) >= 0)
586     {
587       /* Let's check the value and its type */
588       if(pwrq->u.retry.flags & IW_RETRY_TYPE)
589         {
590           iw_print_retry_value(buffer, buflen,
591                                pwrq->u.retry.value, pwrq->u.retry.flags);
592           printf("%s\n                 ", buffer);
593         }
594     }
595   return(pwrq->u.retry.flags);
596 }
597
598 /*------------------------------------------------------------------*/
599 /*
600  * Print Retry info for each device
601  */
602 static int
603 print_retry_info(int            skfd,
604                  char *         ifname,
605                  char *         args[],         /* Command line args */
606                  int            count)          /* Args count */
607 {
608   struct iwreq          wrq;
609   struct iw_range       range;
610   char                  buffer[128];
611
612   /* Avoid "Unused parameter" warning */
613   args = args; count = count;
614
615   /* Extract range info */
616   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
617      (range.we_version_compiled < 11))
618     fprintf(stderr, "%-8.16s  no retry limit/lifetime information.\n\n",
619             ifname);
620   else
621     {
622       printf("%-8.16s  ", ifname);
623
624       /* Display min/max limit availables */
625       if(range.retry_flags & IW_RETRY_LIMIT)
626         {
627           int   flags = (range.retry_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
628           /* Display if auto or fixed */
629           if(range.retry_flags & IW_RETRY_MIN)
630             printf("Auto  limit    ; ");
631           else
632             printf("Fixed limit    ; ");
633           /* Print the range */
634           iw_print_retry_value(buffer, sizeof(buffer),
635                                range.min_retry, flags | IW_RETRY_MIN);
636           printf("%s\n                           ", buffer);
637           iw_print_retry_value(buffer, sizeof(buffer),
638                                range.max_retry, flags | IW_RETRY_MAX);
639           printf("%s\n          ", buffer);
640           
641         }
642       /* Display min/max lifetime availables */
643       if(range.r_time_flags & IW_RETRY_LIFETIME)
644         {
645           int   flags = (range.r_time_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
646           /* Display if auto or fixed */
647           if(range.r_time_flags & IW_RETRY_MIN)
648             printf("Auto  lifetime ; ");
649           else
650             printf("Fixed lifetime ; ");
651           /* Print the range */
652           iw_print_retry_value(buffer, sizeof(buffer),
653                                range.min_r_time, flags | IW_RETRY_MIN);
654           printf("%s\n                           ", buffer);
655           iw_print_retry_value(buffer, sizeof(buffer),
656                                range.max_r_time, flags | IW_RETRY_MAX);
657           printf("%s\n          ", buffer);
658           
659         }
660
661       /* Get current retry settings */
662       wrq.u.retry.flags = 0;
663       if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
664         {
665           int   flags = wrq.u.retry.flags;
666
667           /* Is it disabled ? */
668           if(wrq.u.retry.disabled)
669             printf("Current mode:off\n          ");
670           else
671             {
672               int       retry_mask = 0;
673
674               /* Let's check the mode */
675               printf("Current mode:on\n                 ");
676
677               /* Let's check the value and its type */
678               if(wrq.u.retry.flags & IW_RETRY_TYPE)
679                 {
680                   iw_print_retry_value(buffer, sizeof(buffer),
681                                        wrq.u.retry.value, wrq.u.retry.flags);
682                   printf("%s\n                 ", buffer);
683                 }
684
685               /* If we have been returned a MIN value, ask for the MAX */
686               if(flags & IW_RETRY_MIN)
687                 retry_mask = IW_RETRY_MAX;
688               /* If we have been returned a MAX value, ask for the MIN */
689               if(flags & IW_RETRY_MAX)
690                 retry_mask = IW_RETRY_MIN;
691               /* If we have something to ask for... */
692               if(retry_mask)
693                 get_retry_value(skfd, ifname, &wrq, retry_mask,
694                                 buffer, sizeof(buffer));
695
696               /* And if we have both a period and a timeout, ask the other */
697               retry_mask = (range.retry_capa & (~(wrq.u.retry.flags) &
698                                           IW_RETRY_TYPE));
699               if(retry_mask)
700                 {
701                   int   base_mask = retry_mask;
702                   flags = get_retry_value(skfd, ifname, &wrq, retry_mask,
703                                           buffer, sizeof(buffer));
704                   retry_mask = 0;
705
706                   /* If we have been returned a MIN value, ask for the MAX */
707                   if(flags & IW_RETRY_MIN)
708                     retry_mask = IW_RETRY_MAX | base_mask;
709                   /* If we have been returned a MAX value, ask for the MIN */
710                   if(flags & IW_RETRY_MAX)
711                     retry_mask = IW_RETRY_MIN | base_mask;
712                   /* If we have something to ask for... */
713                   if(retry_mask)
714                     get_retry_value(skfd, ifname, &wrq, retry_mask,
715                                     buffer, sizeof(buffer));
716                 }
717             }
718         }
719       printf("\n");
720     }
721   return(0);
722 }
723
724 /***************************** SCANNING *****************************/
725 /*
726  * This one behave quite differently from the others
727  *
728  * Note that we don't use the scanning capability of iwlib (functions
729  * iw_process_scan() and iw_scan()). The main reason is that
730  * iw_process_scan() return only a subset of the scan data to the caller,
731  * for example custom elements and bitrates are ommited. Here, we
732  * do the complete job...
733  */
734
735 /*------------------------------------------------------------------*/
736 /*
737  * Print one element from the scanning results
738  */
739 static inline int
740 print_scanning_token(struct iw_event *  event,  /* Extracted token */
741                      int                ap_num, /* AP number */
742                      struct iw_range *  iw_range,       /* Range info */
743                      int                has_range)
744 {
745   char          buffer[128];    /* Temporary buffer */
746
747   /* Now, let's decode the event */
748   switch(event->cmd)
749     {
750     case SIOCGIWAP:
751       printf("          Cell %02d - Address: %s\n", ap_num,
752              iw_pr_ether(buffer, event->u.ap_addr.sa_data));
753       ap_num++;
754       break;
755     case SIOCGIWNWID:
756       if(event->u.nwid.disabled)
757         printf("                    NWID:off/any\n");
758       else
759         printf("                    NWID:%X\n", event->u.nwid.value);
760       break;
761     case SIOCGIWFREQ:
762       {
763         double          freq;                   /* Frequency/channel */
764         int             channel = -1;           /* Converted to channel */
765         freq = iw_freq2float(&(event->u.freq));
766         /* Convert to channel if possible */
767         if(has_range)
768           channel = iw_freq_to_channel(freq, iw_range);
769         iw_print_freq(buffer, sizeof(buffer),
770                       freq, channel, event->u.freq.flags);
771         printf("                    %s\n", buffer);
772       }
773       break;
774     case SIOCGIWMODE:
775       printf("                    Mode:%s\n",
776              iw_operation_mode[event->u.mode]);
777       break;
778     case SIOCGIWNAME:
779       printf("                    Protocol:%-1.16s\n", event->u.name);
780       break;
781     case SIOCGIWESSID:
782       {
783         char essid[IW_ESSID_MAX_SIZE+1];
784         if((event->u.essid.pointer) && (event->u.essid.length))
785           memcpy(essid, event->u.essid.pointer, event->u.essid.length);
786         essid[event->u.essid.length] = '\0';
787         if(event->u.essid.flags)
788           {
789             /* Does it have an ESSID index ? */
790             if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
791               printf("                    ESSID:\"%s\" [%d]\n", essid,
792                      (event->u.essid.flags & IW_ENCODE_INDEX));
793             else
794               printf("                    ESSID:\"%s\"\n", essid);
795           }
796         else
797           printf("                    ESSID:off/any\n");
798       }
799       break;
800     case SIOCGIWENCODE:
801       {
802         unsigned char   key[IW_ENCODING_TOKEN_MAX];
803         if(event->u.data.pointer)
804           memcpy(key, event->u.essid.pointer, event->u.data.length);
805         else
806           event->u.data.flags |= IW_ENCODE_NOKEY;
807         printf("                    Encryption key:");
808         if(event->u.data.flags & IW_ENCODE_DISABLED)
809           printf("off\n");
810         else
811           {
812             /* Display the key */
813             iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
814                          event->u.data.flags);
815             printf("%s", buffer);
816
817             /* Other info... */
818             if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
819               printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
820             if(event->u.data.flags & IW_ENCODE_RESTRICTED)
821               printf("   Security mode:restricted");
822             if(event->u.data.flags & IW_ENCODE_OPEN)
823               printf("   Security mode:open");
824             printf("\n");
825           }
826       }
827       break;
828     case SIOCGIWRATE:
829       iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
830       printf("                    Bit Rate:%s\n", buffer);
831       break;
832     case IWEVQUAL:
833       {
834         iw_print_stats(buffer, sizeof(buffer),
835                        &event->u.qual, iw_range, has_range);
836         printf("                    %s\n", buffer);
837         break;
838       }
839     case IWEVCUSTOM:
840       {
841         char custom[IW_CUSTOM_MAX+1];
842         if((event->u.data.pointer) && (event->u.data.length))
843           memcpy(custom, event->u.data.pointer, event->u.data.length);
844         custom[event->u.data.length] = '\0';
845         printf("                    Extra:%s\n", custom);
846       }
847       break;
848     default:
849       printf("                    (Unknown Wireless Token 0x%04X)\n",
850              event->cmd);
851    }    /* switch(event->cmd) */
852
853   /* May have changed */
854   return(ap_num);
855 }
856
857 /*------------------------------------------------------------------*/
858 /*
859  * Perform a scanning on one device
860  */
861 static int
862 print_scanning_info(int         skfd,
863                     char *      ifname,
864                     char *      args[],         /* Command line args */
865                     int         count)          /* Args count */
866 {
867   struct iwreq          wrq;
868   unsigned char *       buffer = NULL;          /* Results */
869   int                   buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
870   struct iw_range       range;
871   int                   has_range;
872   struct timeval        tv;                             /* Select timeout */
873   int                   timeout = 5000000;              /* 5s */
874
875   /* Avoid "Unused parameter" warning */
876   args = args; count = count;
877
878   /* Get range stuff */
879   has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
880
881   /* Check if the interface could support scanning. */
882   if((!has_range) || (range.we_version_compiled < 14))
883     {
884       fprintf(stderr, "%-8.16s  Interface doesn't support scanning.\n\n",
885               ifname);
886       return(-1);
887     }
888
889   /* Init timeout value -> 250ms*/
890   tv.tv_sec = 0;
891   tv.tv_usec = 250000;
892
893   /*
894    * Here we should look at the command line args and set the IW_SCAN_ flags
895    * properly
896    */
897   wrq.u.data.pointer = NULL;            /* Later */
898   wrq.u.data.flags = 0;
899   wrq.u.data.length = 0;
900
901   /* Initiate Scanning */
902   if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
903     {
904       if(errno != EPERM)
905         {
906           fprintf(stderr, "%-8.16s  Interface doesn't support scanning : %s\n\n",
907                   ifname, strerror(errno));
908           return(-1);
909         }
910       /* If we don't have the permission to initiate the scan, we may
911        * still have permission to read left-over results.
912        * But, don't wait !!! */
913 #if 0
914       /* Not cool, it display for non wireless interfaces... */
915       fprintf(stderr, "%-8.16s  (Could not trigger scanning, just reading left-over results)\n", ifname);
916 #endif
917       tv.tv_usec = 0;
918     }
919   timeout -= tv.tv_usec;
920
921   /* Forever */
922   while(1)
923     {
924       fd_set            rfds;           /* File descriptors for select */
925       int               last_fd;        /* Last fd */
926       int               ret;
927
928       /* Guess what ? We must re-generate rfds each time */
929       FD_ZERO(&rfds);
930       last_fd = -1;
931
932       /* In here, add the rtnetlink fd in the list */
933
934       /* Wait until something happens */
935       ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
936
937       /* Check if there was an error */
938       if(ret < 0)
939         {
940           if(errno == EAGAIN || errno == EINTR)
941             continue;
942           fprintf(stderr, "Unhandled signal - exiting...\n");
943           return(-1);
944         }
945
946       /* Check if there was a timeout */
947       if(ret == 0)
948         {
949           unsigned char *       newbuf;
950
951         realloc:
952           /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
953           newbuf = realloc(buffer, buflen);
954           if(newbuf == NULL)
955             {
956               if(buffer)
957                 free(buffer);
958               fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
959               return(-1);
960             }
961           buffer = newbuf;
962
963           /* Try to read the results */
964           wrq.u.data.pointer = buffer;
965           wrq.u.data.flags = 0;
966           wrq.u.data.length = buflen;
967           if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
968             {
969               /* Check if buffer was too small (WE-17 only) */
970               if((errno == E2BIG) && (range.we_version_compiled > 16))
971                 {
972                   /* Some driver may return very large scan results, either
973                    * because there are many cells, or because they have many
974                    * large elements in cells (like IWEVCUSTOM). Most will
975                    * only need the regular sized buffer. We now use a dynamic
976                    * allocation of the buffer to satisfy everybody. Of course,
977                    * as we don't know in advance the size of the array, we try
978                    * various increasing sizes. Jean II */
979
980                   /* Check if the driver gave us any hints. */
981                   if(wrq.u.data.length > buflen)
982                     buflen = wrq.u.data.length;
983                   else
984                     buflen *= 2;
985
986                   /* Try again */
987                   goto realloc;
988                 }
989
990               /* Check if results not available yet */
991               if(errno == EAGAIN)
992                 {
993                   /* Restart timer for only 100ms*/
994                   tv.tv_sec = 0;
995                   tv.tv_usec = 100000;
996                   timeout -= tv.tv_usec;
997                   if(timeout > 0)
998                     continue;   /* Try again later */
999                 }
1000
1001               /* Bad error */
1002               free(buffer);
1003               fprintf(stderr, "%-8.16s  Failed to read scan data : %s\n\n",
1004                       ifname, strerror(errno));
1005               return(-2);
1006             }
1007           else
1008             /* We have the results, go to process them */
1009             break;
1010         }
1011
1012       /* In here, check if event and event type
1013        * if scan event, read results. All errors bad & no reset timeout */
1014     }
1015
1016   if(wrq.u.data.length)
1017     {
1018       struct iw_event           iwe;
1019       struct stream_descr       stream;
1020       int                       ap_num = 1;
1021       int                       ret;
1022 #if 0
1023       /* Debugging code. In theory useless, because it's debugged ;-) */
1024       int       i;
1025       printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
1026       for(i = 1; i < wrq.u.data.length; i++)
1027         printf(":%02X", buffer[i]);
1028       printf("]\n");
1029 #endif
1030       printf("%-8.16s  Scan completed :\n", ifname);
1031       iw_init_event_stream(&stream, buffer, wrq.u.data.length);
1032       do
1033         {
1034           /* Extract an event and print it */
1035           ret = iw_extract_event_stream(&stream, &iwe,
1036                                         range.we_version_compiled);
1037           if(ret > 0)
1038             ap_num = print_scanning_token(&iwe, ap_num, &range, has_range);
1039         }
1040       while(ret > 0);
1041       printf("\n");
1042     }
1043   else
1044     printf("%-8.16s  No scan results\n", ifname);
1045
1046   free(buffer);
1047   return(0);
1048 }
1049
1050 /******************** WIRELESS EVENT CAPABILITY ********************/
1051
1052 static const char *     event_capa_req[] =
1053 {
1054   [SIOCSIWNWID  - SIOCIWFIRST] = "Set NWID (kernel generated)",
1055   [SIOCSIWFREQ  - SIOCIWFIRST] = "Set Frequency/Channel (kernel generated)",
1056   [SIOCGIWFREQ  - SIOCIWFIRST] = "New Frequency/Channel",
1057   [SIOCSIWMODE  - SIOCIWFIRST] = "Set Mode (kernel generated)",
1058   [SIOCGIWTHRSPY - SIOCIWFIRST] = "Spy threshold crossed",
1059   [SIOCGIWAP    - SIOCIWFIRST] = "New Access Point/Cell address - roaming",
1060   [SIOCGIWSCAN  - SIOCIWFIRST] = "Scan request completed",
1061   [SIOCSIWESSID - SIOCIWFIRST] = "Set ESSID (kernel generated)",
1062   [SIOCGIWESSID - SIOCIWFIRST] = "New ESSID",
1063   [SIOCGIWRATE  - SIOCIWFIRST] = "New bit-rate",
1064   [SIOCSIWENCODE - SIOCIWFIRST] = "Set Encoding (kernel generated)",
1065   [SIOCGIWPOWER - SIOCIWFIRST] = NULL,
1066 };
1067
1068 static const char *     event_capa_evt[] =
1069 {
1070   [IWEVTXDROP   - IWEVFIRST] = "Tx packet dropped - retry exceeded",
1071   [IWEVCUSTOM   - IWEVFIRST] = "Custom driver event",
1072   [IWEVREGISTERED - IWEVFIRST] = "Registered node",
1073   [IWEVEXPIRED  - IWEVFIRST] = "Expired node",
1074 };
1075
1076 /*------------------------------------------------------------------*/
1077 /*
1078  * Print the number of available transmit powers for the device
1079  */
1080 static int
1081 print_event_capa_info(int               skfd,
1082                       char *            ifname,
1083                       char *            args[],         /* Command line args */
1084                       int               count)          /* Args count */
1085 {
1086   struct iw_range       range;
1087   int                   cmd;
1088
1089   /* Avoid "Unused parameter" warning */
1090   args = args; count = count;
1091
1092   /* Extract range info */
1093   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1094      (range.we_version_compiled < 10))
1095       fprintf(stderr, "%-8.16s  no wireless event capability information.\n\n",
1096                       ifname);
1097   else
1098     {
1099 #if 0
1100       /* Debugging ;-) */
1101       for(cmd = 0x8B00; cmd < 0x8C0F; cmd++)
1102         {
1103           int idx = IW_EVENT_CAPA_INDEX(cmd);
1104           int mask = IW_EVENT_CAPA_MASK(cmd);
1105           printf("0x%X - %d - %X\n", cmd, idx, mask);
1106         }
1107 #endif
1108
1109       printf("%-8.16s  Wireless Events supported :\n", ifname);
1110
1111       for(cmd = SIOCIWFIRST; cmd <= SIOCGIWPOWER; cmd++)
1112         {
1113           int idx = IW_EVENT_CAPA_INDEX(cmd);
1114           int mask = IW_EVENT_CAPA_MASK(cmd);
1115           if(range.event_capa[idx] & mask)
1116             printf("          0x%04X : %s\n",
1117                    cmd, event_capa_req[cmd - SIOCIWFIRST]);
1118         }
1119       for(cmd = IWEVFIRST; cmd <= IWEVEXPIRED; cmd++)
1120         {
1121           int idx = IW_EVENT_CAPA_INDEX(cmd);
1122           int mask = IW_EVENT_CAPA_MASK(cmd);
1123           if(range.event_capa[idx] & mask)
1124             printf("          0x%04X : %s\n",
1125                    cmd, event_capa_evt[cmd - IWEVFIRST]);
1126         }
1127       printf("\n");
1128     }
1129   return(0);
1130 }
1131
1132 /************************* COMMON UTILITIES *************************/
1133 /*
1134  * This section was written by Michael Tokarev <mjt@tls.msk.ru>
1135  * But modified by me ;-)
1136  */
1137
1138 /* command list */
1139 typedef struct iwlist_entry {
1140   const char *cmd;
1141   iw_enum_handler fn;
1142   int min_count;
1143   int max_count;
1144 } iwlist_cmd;
1145
1146 static const struct iwlist_entry iwlist_cmds[] = {
1147   { "scanning",         print_scanning_info,    0, 5 },
1148   { "frequency",        print_freq_info,        0, 0 },
1149   { "channel",          print_freq_info,        0, 0 },
1150   { "bitrate",          print_bitrate_info,     0, 0 },
1151   { "rate",             print_bitrate_info,     0, 0 },
1152   { "encryption",       print_keys_info,        0, 0 },
1153   { "key",              print_keys_info,        0, 0 },
1154   { "power",            print_pm_info,          0, 0 },
1155   { "txpower",          print_txpower_info,     0, 0 },
1156   { "retry",            print_retry_info,       0, 0 },
1157   { "ap",               print_ap_info,          0, 0 },
1158   { "accesspoints",     print_ap_info,          0, 0 },
1159   { "peers",            print_ap_info,          0, 0 },
1160   { "event",            print_event_capa_info,  0, 0 },
1161   { NULL, NULL, 0, 0 },
1162 };
1163
1164 /*------------------------------------------------------------------*/
1165 /*
1166  * Find the most appropriate command matching the command line
1167  */
1168 static inline const iwlist_cmd *
1169 find_command(const char *       cmd)
1170 {
1171   const iwlist_cmd *    found = NULL;
1172   int                   ambig = 0;
1173   unsigned int          len = strlen(cmd);
1174   int                   i;
1175
1176   /* Go through all commands */
1177   for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
1178     {
1179       /* No match -> next one */
1180       if(strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0)
1181         continue;
1182
1183       /* Exact match -> perfect */
1184       if(len == strlen(iwlist_cmds[i].cmd))
1185         return &iwlist_cmds[i];
1186
1187       /* Partial match */
1188       if(found == NULL)
1189         /* First time */
1190         found = &iwlist_cmds[i];
1191       else
1192         /* Another time */
1193         if (iwlist_cmds[i].fn != found->fn)
1194           ambig = 1;
1195     }
1196
1197   if(found == NULL)
1198     {
1199       fprintf(stderr, "iwlist: unknown command `%s'\n", cmd);
1200       return NULL;
1201     }
1202
1203   if(ambig)
1204     {
1205       fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd);
1206       return NULL;
1207     }
1208
1209   return found;
1210 }
1211
1212 /*------------------------------------------------------------------*/
1213 /*
1214  * Display help
1215  */
1216 static void iw_usage(int status)
1217 {
1218   FILE* f = status ? stderr : stdout;
1219   int i;
1220
1221   fprintf(f,   "Usage: iwlist [interface] %s\n", iwlist_cmds[0].cmd);
1222   for(i = 1; iwlist_cmds[i].cmd != NULL; ++i)
1223     fprintf(f, "              [interface] %s\n", iwlist_cmds[i].cmd);
1224   exit(status);
1225 }
1226
1227 /******************************* MAIN ********************************/
1228
1229 /*------------------------------------------------------------------*/
1230 /*
1231  * The main !
1232  */
1233 int
1234 main(int        argc,
1235      char **    argv)
1236 {
1237   int skfd;                     /* generic raw socket desc.     */
1238   char *dev;                    /* device name                  */
1239   char *cmd;                    /* command                      */
1240   char **args;                  /* Command arguments */
1241   int count;                    /* Number of arguments */
1242   const iwlist_cmd *iwcmd;
1243
1244   if(argc == 1 || argc > 3)
1245     iw_usage(1);
1246
1247   if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
1248     iw_usage(0);
1249
1250   /* This is also handled slightly differently */
1251   if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
1252     return(iw_print_version_info("iwlist"));
1253
1254   if (argc == 2)
1255     {
1256       cmd = argv[1];
1257       dev = NULL;
1258       args = NULL;
1259       count = 0;
1260     }
1261   else
1262     {
1263       cmd = argv[2];
1264       dev = argv[1];
1265       args = argv + 3;
1266       count = argc - 3;
1267     }
1268
1269   /* find a command */
1270   iwcmd = find_command(cmd);
1271   if(iwcmd == NULL)
1272     return 1;
1273
1274   /* Check arg numbers */
1275   if(count < iwcmd->min_count)
1276     {
1277       fprintf(stderr, "iwlist: command `%s' needs more arguments\n", cmd);
1278       return 1;
1279     }
1280   if(count > iwcmd->max_count)
1281     {
1282       fprintf(stderr, "iwlist: command `%s' needs fewer arguments\n", cmd);
1283       return 1;
1284     }
1285
1286   /* Create a channel to the NET kernel. */
1287   if((skfd = iw_sockets_open()) < 0)
1288     {
1289       perror("socket");
1290       return -1;
1291     }
1292
1293   /* do the actual work */
1294   if (dev)
1295     (*iwcmd->fn)(skfd, dev, args, count);
1296   else
1297     iw_enum_devices(skfd, iwcmd->fn, args, count);
1298
1299   /* Close the socket. */
1300   iw_sockets_close(skfd);
1301
1302   return 0;
1303 }