OSDN Git Service

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