OSDN Git Service

f59ab1e7045747218bb8bdecb53c4cdd62100f8c
[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 /****************************** TYPES ******************************/
18
19 /*
20  * Scan state and meta-information, used to decode events...
21  */
22 typedef struct iwscan_state
23 {
24   /* State */
25   int                   ap_num;         /* Access Point number 1->N */
26   int                   val_index;      /* Value in table 0->(N-1) */
27 } iwscan_state;
28
29
30 /*********************** FREQUENCIES/CHANNELS ***********************/
31
32 /*------------------------------------------------------------------*/
33 /*
34  * Print the number of channels and available frequency for the device
35  */
36 static int
37 print_freq_info(int             skfd,
38                 char *          ifname,
39                 char *          args[],         /* Command line args */
40                 int             count)          /* Args count */
41 {
42   struct iwreq          wrq;
43   struct iw_range       range;
44   double                freq;
45   int                   k;
46   int                   channel;
47   char                  buffer[128];    /* Temporary buffer */
48
49   /* Avoid "Unused parameter" warning */
50   args = args; count = count;
51
52   /* Get list of frequencies / channels */
53   if(iw_get_range_info(skfd, ifname, &range) < 0)
54       fprintf(stderr, "%-8.16s  no frequency information.\n\n",
55                       ifname);
56   else
57     {
58       if(range.num_frequency > 0)
59         {
60           printf("%-8.16s  %d channels in total; available frequencies :\n",
61                  ifname, range.num_channels);
62           /* Print them all */
63           for(k = 0; k < range.num_frequency; k++)
64             {
65               freq = iw_freq2float(&(range.freq[k]));
66               iw_print_freq_value(buffer, sizeof(buffer), freq);
67               printf("          Channel %.2d : %s\n",
68                      range.freq[k].i, buffer);
69             }
70         }
71       else
72         printf("%-8.16s  %d channels\n",
73                ifname, range.num_channels);
74
75       /* Get current frequency / channel and display it */
76       if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
77         {
78           freq = iw_freq2float(&(wrq.u.freq));
79           channel = iw_freq_to_channel(freq, &range);
80           iw_print_freq(buffer, sizeof(buffer),
81                         freq, channel, wrq.u.freq.flags);
82           printf("          Current %s\n\n", buffer);
83         }
84     }
85   return(0);
86 }
87
88 /************************ ACCESS POINT LIST ************************/
89 /*
90  * Note : now that we have scanning support, this is depracted and
91  * won't survive long. Actually, next version it's out !
92  */
93
94 /*------------------------------------------------------------------*/
95 /*
96  * Display the list of ap addresses and the associated stats
97  * Exacly the same as the spy list, only with different IOCTL and messages
98  */
99 static int
100 print_ap_info(int       skfd,
101               char *    ifname,
102               char *    args[],         /* Command line args */
103               int       count)          /* Args count */
104 {
105   struct iwreq          wrq;
106   char          buffer[(sizeof(struct iw_quality) +
107                         sizeof(struct sockaddr)) * IW_MAX_AP];
108   char          temp[128];
109   struct sockaddr *     hwa;
110   struct iw_quality *   qual;
111   iwrange       range;
112   int           has_range = 0;
113   int           has_qual = 0;
114   int           n;
115   int           i;
116
117   /* Avoid "Unused parameter" warning */
118   args = args; count = count;
119
120   /* Collect stats */
121   wrq.u.data.pointer = (caddr_t) buffer;
122   wrq.u.data.length = IW_MAX_AP;
123   wrq.u.data.flags = 0;
124   if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
125     {
126       fprintf(stderr, "%-8.16s  Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
127       return(-1);
128     }
129
130   /* Number of addresses */
131   n = wrq.u.data.length;
132   has_qual = wrq.u.data.flags;
133
134   /* The two lists */
135   hwa = (struct sockaddr *) buffer;
136   qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
137
138   /* Check if we have valid mac address type */
139   if(iw_check_mac_addr_type(skfd, ifname) < 0)
140     {
141       fprintf(stderr, "%-8.16s  Interface doesn't support MAC addresses\n\n", ifname);
142       return(-2);
143     }
144
145   /* Get range info if we can */
146   if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
147     has_range = 1;
148
149   /* Display it */
150   if(n == 0)
151     printf("%-8.16s  No Peers/Access-Point in range\n", ifname);
152   else
153     printf("%-8.16s  Peers/Access-Points in range:\n", ifname);
154   for(i = 0; i < n; i++)
155     {
156       if(has_qual)
157         {
158           /* Print stats for this address */
159           printf("    %s : ", iw_saether_ntop(&hwa[i], temp));
160           iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
161           printf("%s\n", temp);
162         }
163       else
164         /* Only print the address */
165         printf("    %s\n", iw_saether_ntop(&hwa[i], temp));
166     }
167   printf("\n");
168   return(0);
169 }
170
171 /***************************** BITRATES *****************************/
172
173 /*------------------------------------------------------------------*/
174 /*
175  * Print the number of available bitrates for the device
176  */
177 static int
178 print_bitrate_info(int          skfd,
179                    char *       ifname,
180                    char *       args[],         /* Command line args */
181                    int          count)          /* Args count */
182 {
183   struct iwreq          wrq;
184   struct iw_range       range;
185   int                   k;
186   char                  buffer[128];
187
188   /* Avoid "Unused parameter" warning */
189   args = args; count = count;
190
191   /* Extract range info */
192   if(iw_get_range_info(skfd, ifname, &range) < 0)
193       fprintf(stderr, "%-8.16s  no bit-rate information.\n\n",
194                       ifname);
195   else
196     {
197       if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
198         {
199           printf("%-8.16s  %d available bit-rates :\n",
200                  ifname, range.num_bitrates);
201           /* Print them all */
202           for(k = 0; k < range.num_bitrates; k++)
203             {
204               iw_print_bitrate(buffer, sizeof(buffer), range.bitrate[k]);
205               /* Maybe this should be %10s */
206               printf("\t  %s\n", buffer);
207             }
208         }
209       else
210         printf("%-8.16s  unknown bit-rate information.\n", ifname);
211
212       /* Get current bit rate */
213       if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
214         {
215           iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
216           printf("          Current Bit Rate%c%s\n\n",
217                  (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
218         }
219     }
220   return(0);
221 }
222
223 /************************* ENCRYPTION KEYS *************************/
224
225 /*------------------------------------------------------------------*/
226 /*
227  * Print the number of available encryption key for the device
228  */
229 static int
230 print_keys_info(int             skfd,
231                 char *          ifname,
232                 char *          args[],         /* Command line args */
233                 int             count)          /* Args count */
234 {
235   struct iwreq          wrq;
236   struct iw_range       range;
237   unsigned char         key[IW_ENCODING_TOKEN_MAX];
238   int                   k;
239   char                  buffer[128];
240
241   /* Avoid "Unused parameter" warning */
242   args = args; count = count;
243
244   /* Extract range info */
245   if(iw_get_range_info(skfd, ifname, &range) < 0)
246       fprintf(stderr, "%-8.16s  no encryption keys information.\n\n",
247                       ifname);
248   else
249     {
250       printf("%-8.16s  ", ifname);
251       /* Print key sizes */
252       if((range.num_encoding_sizes > 0) &&
253          (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
254         {
255           printf("%d key sizes : %d", range.num_encoding_sizes,
256                  range.encoding_size[0] * 8);
257           /* Print them all */
258           for(k = 1; k < range.num_encoding_sizes; k++)
259             printf(", %d", range.encoding_size[k] * 8);
260           printf("bits\n          ");
261         }
262       /* Print the keys and associate mode */
263       printf("%d keys available :\n", range.max_encoding_tokens);
264       for(k = 1; k <= range.max_encoding_tokens; k++)
265         {
266           wrq.u.data.pointer = (caddr_t) key;
267           wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
268           wrq.u.data.flags = k;
269           if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
270             {
271               fprintf(stderr, "Error reading wireless keys (SIOCGIWENCODE): %s\n", strerror(errno));
272               break;
273             }
274           if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
275              (wrq.u.data.length == 0))
276             printf("\t\t[%d]: off\n", k);
277           else
278             {
279               /* Display the key */
280               iw_print_key(buffer, sizeof(buffer),
281                            key, wrq.u.data.length, wrq.u.data.flags);
282               printf("\t\t[%d]: %s", k, buffer);
283
284               /* Other info... */
285               printf(" (%d bits)", wrq.u.data.length * 8);
286               printf("\n");
287             }
288         }
289       /* Print current key and mode */
290       wrq.u.data.pointer = (caddr_t) key;
291       wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
292       wrq.u.data.flags = 0;     /* Set index to zero to get current */
293       if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
294         {
295           /* Note : if above fails, we have already printed an error
296            * message int the loop above */
297           printf("          Current Transmit Key: [%d]\n",
298                  wrq.u.data.flags & IW_ENCODE_INDEX);
299           if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
300             printf("          Security mode:restricted\n");
301           if(wrq.u.data.flags & IW_ENCODE_OPEN)
302             printf("          Security mode:open\n");
303         }
304
305       /* Print WPA/802.1x/802.11i security parameters */
306       if(range.we_version_compiled > 17)
307         {
308           /* Display advance encryption capabilities */
309           if(range.enc_capa)
310             {
311               const char *      auth_string[] = { "WPA",
312                                                   "WPA2",
313                                                   "CIPHER TKIP",
314                                                   "CIPHER CCMP" };
315               const int         auth_num = (sizeof(auth_string) /
316                                             sizeof(auth_string[1]));
317               int               i;
318               int               mask = 0x1;
319
320               printf("          Authentication capabilities :\n");
321               for(i = 0; i < auth_num; i++)
322                 {
323                   if(range.enc_capa & mask)
324                     printf("\t\t%s\n", auth_string[i]);
325                   mask <<= 1;
326                 }
327             }
328
329           /* Current values for authentication */
330           wrq.u.param.flags = IW_AUTH_KEY_MGMT;
331           if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
332               printf("          Current key_mgmt:0x%X\n",
333                      wrq.u.param.value);
334
335           wrq.u.param.flags = IW_AUTH_CIPHER_PAIRWISE;
336           if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
337               printf("          Current cipher_pairwise:0x%X\n",
338                      wrq.u.param.value);
339
340           wrq.u.param.flags = IW_AUTH_CIPHER_GROUP;
341           if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
342             printf("          Current cipher_group:0x%X\n",
343                    wrq.u.param.value);
344         }
345
346      printf("\n\n");
347     }
348   return(0);
349 }
350
351 /************************* POWER MANAGEMENT *************************/
352
353 /*------------------------------------------------------------------*/
354 /*
355  * Print Power Management info for each device
356  */
357 static inline int
358 get_pm_value(int                skfd,
359              char *             ifname,
360              struct iwreq *     pwrq,
361              int                flags,
362              char *             buffer,
363              int                buflen)
364 {
365   /* Get Another Power Management value */
366   pwrq->u.power.flags = flags;
367   if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, pwrq) >= 0)
368     {
369       /* Let's check the value and its type */
370       if(pwrq->u.power.flags & IW_POWER_TYPE)
371         {
372           iw_print_pm_value(buffer, buflen,
373                             pwrq->u.power.value, pwrq->u.power.flags);
374           printf("\n                 %s", buffer);
375         }
376     }
377   return(pwrq->u.power.flags);
378 }
379
380 /*------------------------------------------------------------------*/
381 /*
382  * Print Power Management info for each device
383  */
384 static int
385 print_pm_info(int               skfd,
386               char *            ifname,
387               char *            args[],         /* Command line args */
388               int               count)          /* Args count */
389 {
390   struct iwreq          wrq;
391   struct iw_range       range;
392   char                  buffer[128];
393
394   /* Avoid "Unused parameter" warning */
395   args = args; count = count;
396
397   /* Extract range info */
398   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
399      (range.we_version_compiled < 10))
400       fprintf(stderr, "%-8.16s  no power management information.\n\n",
401                       ifname);
402   else
403     {
404       printf("%-8.16s  ", ifname);
405
406       /* Display modes availables */
407       if(range.pm_capa & IW_POWER_MODE)
408         {
409           printf("Supported modes :\n          ");
410           if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
411             printf("\t\to Receive all packets (unicast & multicast)\n          ");
412           if(range.pm_capa & IW_POWER_UNICAST_R)
413             printf("\t\to Receive Unicast only (discard multicast)\n          ");
414           if(range.pm_capa & IW_POWER_MULTICAST_R)
415             printf("\t\to Receive Multicast only (discard unicast)\n          ");
416           if(range.pm_capa & IW_POWER_FORCE_S)
417             printf("\t\to Force sending using Power Management\n          ");
418           if(range.pm_capa & IW_POWER_REPEATER)
419             printf("\t\to Repeat multicast\n          ");
420         }
421       /* Display min/max period availables */
422       if(range.pmp_flags & IW_POWER_PERIOD)
423         {
424           int   flags = (range.pmp_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
425           /* Display if auto or fixed */
426           if(range.pmp_flags & IW_POWER_MIN)
427             printf("Auto  period  ; ");
428           else
429             printf("Fixed period  ; ");
430           /* Print the range */
431           iw_print_pm_value(buffer, sizeof(buffer),
432                             range.min_pmp, flags | IW_POWER_MIN);
433           printf("%s\n                          ", buffer);
434           iw_print_pm_value(buffer, sizeof(buffer),
435                             range.max_pmp, flags | IW_POWER_MAX);
436           printf("%s\n          ", buffer);
437         }
438       /* Display min/max timeout availables */
439       if(range.pmt_flags & IW_POWER_TIMEOUT)
440         {
441           int   flags = (range.pmt_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
442           /* Display if auto or fixed */
443           if(range.pmt_flags & IW_POWER_MIN)
444             printf("Auto  timeout ; ");
445           else
446             printf("Fixed timeout ; ");
447           /* Print the range */
448           iw_print_pm_value(buffer, sizeof(buffer),
449                             range.min_pmt, flags | IW_POWER_MIN);
450           printf("%s\n                          ", buffer);
451           iw_print_pm_value(buffer, sizeof(buffer),
452                             range.max_pmt, flags | IW_POWER_MAX);
453           printf("%s\n          ", buffer);
454         }
455
456       /* Get current Power Management settings */
457       wrq.u.power.flags = 0;
458       if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
459         {
460           int   flags = wrq.u.power.flags;
461
462           /* Is it disabled ? */
463           if(wrq.u.power.disabled)
464             printf("Current mode:off\n          ");
465           else
466             {
467               int       pm_mask = 0;
468
469               /* Let's check the mode */
470               iw_print_pm_mode(buffer, sizeof(buffer), flags);
471               printf("Current %s", buffer);
472
473               /* Let's check if nothing (simply on) */
474               if((flags & IW_POWER_MODE) == IW_POWER_ON)
475                 printf("mode:on");
476               printf("\n                 ");
477
478               /* Let's check the value and its type */
479               if(wrq.u.power.flags & IW_POWER_TYPE)
480                 {
481                   iw_print_pm_value(buffer, sizeof(buffer),
482                                     wrq.u.power.value, wrq.u.power.flags);
483                   printf("%s", buffer);
484                 }
485
486               /* If we have been returned a MIN value, ask for the MAX */
487               if(flags & IW_POWER_MIN)
488                 pm_mask = IW_POWER_MAX;
489               /* If we have been returned a MAX value, ask for the MIN */
490               if(flags & IW_POWER_MAX)
491                 pm_mask = IW_POWER_MIN;
492               /* If we have something to ask for... */
493               if(pm_mask)
494                 get_pm_value(skfd, ifname, &wrq, pm_mask,
495                              buffer, sizeof(buffer));
496
497               /* And if we have both a period and a timeout, ask the other */
498               pm_mask = (range.pm_capa & (~(wrq.u.power.flags) &
499                                           IW_POWER_TYPE));
500               if(pm_mask)
501                 {
502                   int   base_mask = pm_mask;
503                   flags = get_pm_value(skfd, ifname, &wrq, pm_mask,
504                                        buffer, sizeof(buffer));
505                   pm_mask = 0;
506
507                   /* If we have been returned a MIN value, ask for the MAX */
508                   if(flags & IW_POWER_MIN)
509                     pm_mask = IW_POWER_MAX | base_mask;
510                   /* If we have been returned a MAX value, ask for the MIN */
511                   if(flags & IW_POWER_MAX)
512                     pm_mask = IW_POWER_MIN | base_mask;
513                   /* If we have something to ask for... */
514                   if(pm_mask)
515                     get_pm_value(skfd, ifname, &wrq, pm_mask,
516                                  buffer, sizeof(buffer));
517                 }
518             }
519         }
520       printf("\n");
521     }
522   return(0);
523 }
524
525 /************************** TRANSMIT POWER **************************/
526
527 /*------------------------------------------------------------------*/
528 /*
529  * Print the number of available transmit powers for the device
530  */
531 static int
532 print_txpower_info(int          skfd,
533                    char *       ifname,
534                    char *       args[],         /* Command line args */
535                    int          count)          /* Args count */
536 {
537   struct iwreq          wrq;
538   struct iw_range       range;
539   int                   dbm;
540   int                   mwatt;
541   int                   k;
542
543   /* Avoid "Unused parameter" warning */
544   args = args; count = count;
545
546   /* Extract range info */
547   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
548      (range.we_version_compiled < 10))
549       fprintf(stderr, "%-8.16s  no transmit-power information.\n\n",
550                       ifname);
551   else
552     {
553       if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
554         printf("%-8.16s  unknown transmit-power information.\n\n", ifname);
555       else
556         {
557           printf("%-8.16s  %d available transmit-powers :\n",
558                  ifname, range.num_txpower);
559           /* Print them all */
560           for(k = 0; k < range.num_txpower; k++)
561             {
562               /* Check for relative values */
563               if(range.txpower_capa & IW_TXPOW_RELATIVE)
564                 {
565                   printf("\t  %d (no units)\n", range.txpower[k]);
566                 }
567               else
568                 {
569                   if(range.txpower_capa & IW_TXPOW_MWATT)
570                     {
571                       dbm = iw_mwatt2dbm(range.txpower[k]);
572                       mwatt = range.txpower[k];
573                     }
574                   else
575                     {
576                       dbm = range.txpower[k];
577                       mwatt = iw_dbm2mwatt(range.txpower[k]);
578                     }
579                   printf("\t  %d dBm  \t(%d mW)\n", dbm, mwatt);
580                 }
581             }
582         }
583
584       /* Get current Transmit Power */
585       if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
586         {
587           printf("          Current Tx-Power");
588           /* Disabled ? */
589           if(wrq.u.txpower.disabled)
590             printf(":off\n\n");
591           else
592             {
593               /* Fixed ? */
594               if(wrq.u.txpower.fixed)
595                 printf("=");
596               else
597                 printf(":");
598               /* Check for relative values */
599               if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
600                 {
601                   /* I just hate relative value, because they are
602                    * driver specific, so not very meaningfull to apps.
603                    * But, we have to support that, because
604                    * this is the way hardware is... */
605                   printf("\t  %d (no units)\n", wrq.u.txpower.value);
606                 }
607               else
608                 {
609                   if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
610                     {
611                       dbm = iw_mwatt2dbm(wrq.u.txpower.value);
612                       mwatt = wrq.u.txpower.value;
613                     }
614                   else
615                     {
616                       dbm = wrq.u.txpower.value;
617                       mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
618                     }
619                   printf("%d dBm  \t(%d mW)\n\n", dbm, mwatt);
620                 }
621             }
622         }
623     }
624   return(0);
625 }
626
627 /*********************** RETRY LIMIT/LIFETIME ***********************/
628
629 /*------------------------------------------------------------------*/
630 /*
631  * Print one retry value
632  */
633 static inline int
634 get_retry_value(int             skfd,
635                 char *          ifname,
636                 struct iwreq *  pwrq,
637                 int             flags,
638                 char *          buffer,
639                 int             buflen)
640 {
641   /* Get Another retry value */
642   pwrq->u.retry.flags = flags;
643   if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, pwrq) >= 0)
644     {
645       /* Let's check the value and its type */
646       if(pwrq->u.retry.flags & IW_RETRY_TYPE)
647         {
648           iw_print_retry_value(buffer, buflen,
649                                pwrq->u.retry.value, pwrq->u.retry.flags);
650           printf("%s\n                 ", buffer);
651         }
652     }
653   return(pwrq->u.retry.flags);
654 }
655
656 /*------------------------------------------------------------------*/
657 /*
658  * Print Retry info for each device
659  */
660 static int
661 print_retry_info(int            skfd,
662                  char *         ifname,
663                  char *         args[],         /* Command line args */
664                  int            count)          /* Args count */
665 {
666   struct iwreq          wrq;
667   struct iw_range       range;
668   char                  buffer[128];
669
670   /* Avoid "Unused parameter" warning */
671   args = args; count = count;
672
673   /* Extract range info */
674   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
675      (range.we_version_compiled < 11))
676     fprintf(stderr, "%-8.16s  no retry limit/lifetime information.\n\n",
677             ifname);
678   else
679     {
680       printf("%-8.16s  ", ifname);
681
682       /* Display min/max limit availables */
683       if(range.retry_flags & IW_RETRY_LIMIT)
684         {
685           int   flags = (range.retry_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
686           /* Display if auto or fixed */
687           if(range.retry_flags & IW_RETRY_MIN)
688             printf("Auto  limit    ; ");
689           else
690             printf("Fixed limit    ; ");
691           /* Print the range */
692           iw_print_retry_value(buffer, sizeof(buffer),
693                                range.min_retry, flags | IW_RETRY_MIN);
694           printf("%s\n                           ", buffer);
695           iw_print_retry_value(buffer, sizeof(buffer),
696                                range.max_retry, flags | IW_RETRY_MAX);
697           printf("%s\n          ", buffer);
698           
699         }
700       /* Display min/max lifetime availables */
701       if(range.r_time_flags & IW_RETRY_LIFETIME)
702         {
703           int   flags = (range.r_time_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
704           /* Display if auto or fixed */
705           if(range.r_time_flags & IW_RETRY_MIN)
706             printf("Auto  lifetime ; ");
707           else
708             printf("Fixed lifetime ; ");
709           /* Print the range */
710           iw_print_retry_value(buffer, sizeof(buffer),
711                                range.min_r_time, flags | IW_RETRY_MIN);
712           printf("%s\n                           ", buffer);
713           iw_print_retry_value(buffer, sizeof(buffer),
714                                range.max_r_time, flags | IW_RETRY_MAX);
715           printf("%s\n          ", buffer);
716           
717         }
718
719       /* Get current retry settings */
720       wrq.u.retry.flags = 0;
721       if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
722         {
723           int   flags = wrq.u.retry.flags;
724
725           /* Is it disabled ? */
726           if(wrq.u.retry.disabled)
727             printf("Current mode:off\n          ");
728           else
729             {
730               int       retry_mask = 0;
731
732               /* Let's check the mode */
733               printf("Current mode:on\n                 ");
734
735               /* Let's check the value and its type */
736               if(wrq.u.retry.flags & IW_RETRY_TYPE)
737                 {
738                   iw_print_retry_value(buffer, sizeof(buffer),
739                                        wrq.u.retry.value, wrq.u.retry.flags);
740                   printf("%s\n                 ", buffer);
741                 }
742
743               /* If we have been returned a MIN value, ask for the MAX */
744               if(flags & IW_RETRY_MIN)
745                 retry_mask = IW_RETRY_MAX;
746               /* If we have been returned a MAX value, ask for the MIN */
747               if(flags & IW_RETRY_MAX)
748                 retry_mask = IW_RETRY_MIN;
749               /* If we have something to ask for... */
750               if(retry_mask)
751                 get_retry_value(skfd, ifname, &wrq, retry_mask,
752                                 buffer, sizeof(buffer));
753
754               /* And if we have both a period and a timeout, ask the other */
755               retry_mask = (range.retry_capa & (~(wrq.u.retry.flags) &
756                                           IW_RETRY_TYPE));
757               if(retry_mask)
758                 {
759                   int   base_mask = retry_mask;
760                   flags = get_retry_value(skfd, ifname, &wrq, retry_mask,
761                                           buffer, sizeof(buffer));
762                   retry_mask = 0;
763
764                   /* If we have been returned a MIN value, ask for the MAX */
765                   if(flags & IW_RETRY_MIN)
766                     retry_mask = IW_RETRY_MAX | base_mask;
767                   /* If we have been returned a MAX value, ask for the MIN */
768                   if(flags & IW_RETRY_MAX)
769                     retry_mask = IW_RETRY_MIN | base_mask;
770                   /* If we have something to ask for... */
771                   if(retry_mask)
772                     get_retry_value(skfd, ifname, &wrq, retry_mask,
773                                     buffer, sizeof(buffer));
774                 }
775             }
776         }
777       printf("\n");
778     }
779   return(0);
780 }
781
782 /***************************** SCANNING *****************************/
783 /*
784  * This one behave quite differently from the others
785  *
786  * Note that we don't use the scanning capability of iwlib (functions
787  * iw_process_scan() and iw_scan()). The main reason is that
788  * iw_process_scan() return only a subset of the scan data to the caller,
789  * for example custom elements and bitrates are ommited. Here, we
790  * do the complete job...
791  */
792
793 /*------------------------------------------------------------------*/
794 /*
795  * Parse, and display the results of a WPA or WPA2 IE.
796  *
797  */
798 static void 
799 iw_print_ie_unknown(unsigned char *     iebuf,
800                     int                 buflen)
801 {
802   int   ielen = iebuf[1] + 2;
803   int   i;
804
805   if(ielen > buflen)
806     ielen = buflen;
807
808   printf("Unknown: ");
809   for(i = 0; i < ielen; i++)
810     printf("%02X", iebuf[i]);
811   printf("\n");
812 }
813
814 /*-----------------------------------------------------------------*/
815 /*
816  * Display the cipher type for the value passed in.
817  *
818  */
819 static inline void 
820 iw_print_ie_cipher(unsigned char        csuite)
821 {
822   switch (csuite)
823     {
824     case 0x00:
825       printf("None or same as Group ");
826       break;
827  
828     case 0x01:
829       printf("WEP-40 ");
830       break;
831  
832     case 0x02:
833       printf("TKIP ");
834       break;
835  
836     case 0x03:
837       printf("WRAP ");
838       break;
839  
840     case 0x04:
841       printf("CCMP ");
842       break;
843  
844     case 0x05:
845       printf("WEP-104 ");
846       break;
847  
848     default:
849       printf("Unknown ");
850       break;
851     }
852  }
853  
854 /*------------------------------------------------------------------*/
855 /*
856  * Parse, and display the results of a WPA or WPA2 IE.
857  *
858  */
859 static inline void 
860 iw_print_ie_wpa(unsigned char * iebuf,
861                 int             buflen)
862 {
863   int                   ielen = iebuf[1] + 2;
864   int                   offset = 2;     /* Skip the IE id, and the length. */
865   unsigned char         wpa1_oui[3] = {0x00, 0x50, 0xf2};
866   unsigned char         wpa2_oui[3] = {0x00, 0x0f, 0xac};
867   unsigned char *       wpa_oui;
868   int                   i;
869   uint16_t              ver = 0;
870   uint16_t              cnt = 0;
871
872   if(ielen > buflen)
873     ielen = buflen;
874
875   switch(iebuf[0])
876     {
877     case 0x30:          /* WPA2 */
878       /* Check if we have enough data */
879       if(ielen < 4)
880         {
881           iw_print_ie_unknown(iebuf, buflen);
882           return;
883         }
884
885       wpa_oui = wpa2_oui;
886       break;
887
888     case 0xdd:          /* WPA or else */
889       wpa_oui = wpa1_oui;
890  
891       /* Not all IEs that start with 0xdd are WPA. 
892        * So check that the OUI is valid. */
893       if((ielen < 8)
894          || ((memcmp(&iebuf[offset], wpa_oui, 3) != 0)
895              && (iebuf[offset+3] == 0x01)))
896         {
897           iw_print_ie_unknown(iebuf, buflen);
898           return;
899         }
900
901        offset += 4;
902        break;
903
904     default:
905       return;
906     }
907   
908   /* Pick version number (little endian) */
909   ver = iebuf[offset] | (iebuf[offset + 1] << 8);
910   offset += 2;
911
912   if(iebuf[0] == 0xdd)
913     printf("WPA Version %d\n", ver);
914   if(iebuf[0] == 0x30)
915     printf("IEEE 802.11i/WPA2 Version %d\n", ver);
916
917   /* From here, everything is technically optional. */
918
919   /* Check if we are done */
920   if(ielen < (offset + 4))
921     {
922       /* We have a short IE.  So we should assume TKIP/TKIP. */
923       printf("                        Group Cipher : TKIP\n");
924       printf("                        Pairwise Cipher : TKIP\n");
925       return;
926     }
927  
928   /* Next we have our group cipher. */
929   if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
930     {
931       printf("                        Group Cipher : Proprietary\n");
932     }
933   else
934     {
935       printf("                        Group Cipher : ");
936       iw_print_ie_cipher(iebuf[offset+3]);
937       printf("\n");
938     }
939   offset += 4;
940
941   /* Check if we are done */
942   if(ielen < (offset + 2))
943     {
944       /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
945       printf("                        Pairwise Ciphers (1) : TKIP\n");
946       return;
947     }
948
949   /* Otherwise, we have some number of pairwise ciphers. */
950   cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
951   offset += 2;
952   printf("                        Pairwise Ciphers (%d) : ", cnt);
953
954   if(ielen < (offset + 4*cnt))
955     return;
956
957   for(i = 0; i < cnt; i++)
958     {
959       if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
960         {
961           printf("Proprietary  ");
962         }
963       else
964         {
965           iw_print_ie_cipher(iebuf[offset+3]);
966         }
967       offset+=4;
968     }
969   printf("\n");
970  
971   /* Check if we are done */
972   if(ielen < (offset + 2))
973     return;
974
975   /* Now, we have authentication suites. */
976   cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
977   offset += 2;
978   printf("                        Authentication Suites (%d) : ", cnt);
979
980   if(ielen < (offset + 4*cnt))
981     return;
982
983   for(i = 0; i < cnt; i++)
984     {
985       if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
986         {
987           printf("Proprietary  ");
988         }
989       else
990         {
991           switch(iebuf[offset+3])
992             {
993             case 0x00:
994               printf("Reserved  ");
995               break;
996
997             case 0x01:
998               printf("802.1X  ");
999               break;
1000
1001             case 0x02:
1002               printf("PSK  ");
1003               break;
1004
1005             default:
1006               printf("Unknown  ");
1007               break;
1008             }
1009         }
1010        offset+=4;
1011      }
1012   printf("\n");
1013  
1014   /* Check if we are done */
1015   if(ielen < (offset + 1))
1016     return;
1017
1018   /* Otherwise, we have capabilities bytes.
1019    * For now, we only care about preauth which is in bit position 1 of the
1020    * first byte.  (But, preauth with WPA version 1 isn't supposed to be 
1021    * allowed.) 8-) */
1022   if(iebuf[offset] & 0x01)
1023     {
1024       printf("                       Preauthentication Supported\n");
1025     }
1026 }
1027  
1028 /*------------------------------------------------------------------*/
1029 /*
1030  * Process a generic IE and display the info in human readable form
1031  * for some of the most interesting ones.
1032  * For now, we only decode the WPA IEs.
1033  */
1034 static inline void
1035 iw_print_gen_ie(unsigned char * buffer,
1036                 int             buflen)
1037 {
1038   int offset = 0;
1039
1040   /* Loop on each IE, each IE is minimum 2 bytes */
1041   while(offset <= (buflen - 2))
1042     {
1043       printf("                    IE: ");
1044
1045       /* Check IE type */
1046       switch(buffer[offset])
1047         {
1048         case 0xdd:      /* WPA1 (and other) */
1049         case 0x30:      /* WPA2 */
1050           iw_print_ie_wpa(buffer + offset, buflen);
1051           break;
1052         default:
1053           iw_print_ie_unknown(buffer + offset, buflen);
1054         }
1055       /* Skip over this IE to the next one in the list. */
1056       offset += buffer[offset+1] + 2;
1057     }
1058 }
1059
1060 /*------------------------------------------------------------------*/
1061 /*
1062  * Print one element from the scanning results
1063  */
1064 static inline void
1065 print_scanning_token(struct stream_descr *      stream, /* Stream of events */
1066                      struct iw_event *          event,  /* Extracted token */
1067                      struct iwscan_state *      state,
1068                      struct iw_range *  iw_range,       /* Range info */
1069                      int                has_range)
1070 {
1071   char          buffer[128];    /* Temporary buffer */
1072
1073   /* Now, let's decode the event */
1074   switch(event->cmd)
1075     {
1076     case SIOCGIWAP:
1077       printf("          Cell %02d - Address: %s\n", state->ap_num,
1078              iw_saether_ntop(&event->u.ap_addr, buffer));
1079       state->ap_num++;
1080       break;
1081     case SIOCGIWNWID:
1082       if(event->u.nwid.disabled)
1083         printf("                    NWID:off/any\n");
1084       else
1085         printf("                    NWID:%X\n", event->u.nwid.value);
1086       break;
1087     case SIOCGIWFREQ:
1088       {
1089         double          freq;                   /* Frequency/channel */
1090         int             channel = -1;           /* Converted to channel */
1091         freq = iw_freq2float(&(event->u.freq));
1092         /* Convert to channel if possible */
1093         if(has_range)
1094           channel = iw_freq_to_channel(freq, iw_range);
1095         iw_print_freq(buffer, sizeof(buffer),
1096                       freq, channel, event->u.freq.flags);
1097         printf("                    %s\n", buffer);
1098       }
1099       break;
1100     case SIOCGIWMODE:
1101       printf("                    Mode:%s\n",
1102              iw_operation_mode[event->u.mode]);
1103       break;
1104     case SIOCGIWNAME:
1105       printf("                    Protocol:%-1.16s\n", event->u.name);
1106       break;
1107     case SIOCGIWESSID:
1108       {
1109         char essid[IW_ESSID_MAX_SIZE+1];
1110         memset(essid, '\0', sizeof(essid));
1111         if((event->u.essid.pointer) && (event->u.essid.length))
1112           memcpy(essid, event->u.essid.pointer, event->u.essid.length);
1113         if(event->u.essid.flags)
1114           {
1115             /* Does it have an ESSID index ? */
1116             if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
1117               printf("                    ESSID:\"%s\" [%d]\n", essid,
1118                      (event->u.essid.flags & IW_ENCODE_INDEX));
1119             else
1120               printf("                    ESSID:\"%s\"\n", essid);
1121           }
1122         else
1123           printf("                    ESSID:off/any/hidden\n");
1124       }
1125       break;
1126     case SIOCGIWENCODE:
1127       {
1128         unsigned char   key[IW_ENCODING_TOKEN_MAX];
1129         if(event->u.data.pointer)
1130           memcpy(key, event->u.data.pointer, event->u.data.length);
1131         else
1132           event->u.data.flags |= IW_ENCODE_NOKEY;
1133         printf("                    Encryption key:");
1134         if(event->u.data.flags & IW_ENCODE_DISABLED)
1135           printf("off\n");
1136         else
1137           {
1138             /* Display the key */
1139             iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
1140                          event->u.data.flags);
1141             printf("%s", buffer);
1142
1143             /* Other info... */
1144             if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
1145               printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
1146             if(event->u.data.flags & IW_ENCODE_RESTRICTED)
1147               printf("   Security mode:restricted");
1148             if(event->u.data.flags & IW_ENCODE_OPEN)
1149               printf("   Security mode:open");
1150             printf("\n");
1151           }
1152       }
1153       break;
1154     case SIOCGIWRATE:
1155       if(state->val_index == 0)
1156         printf("                    Bit Rates:");
1157       else
1158         if((state->val_index % 5) == 0)
1159           printf("\n                              ");
1160         else
1161           printf("; ");
1162       iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
1163       printf("%s", buffer);
1164       /* Check for termination */
1165       if(stream->value == NULL)
1166         {
1167           printf("\n");
1168           state->val_index = 0;
1169         }
1170       else
1171         state->val_index++;
1172       break;
1173     case IWEVQUAL:
1174       {
1175         iw_print_stats(buffer, sizeof(buffer),
1176                        &event->u.qual, iw_range, has_range);
1177         printf("                    %s\n", buffer);
1178         break;
1179       }
1180     case IWEVGENIE:
1181       /* Informations Elements are complex, let's do only some of them */
1182       iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
1183       break;
1184     case IWEVCUSTOM:
1185       {
1186         char custom[IW_CUSTOM_MAX+1];
1187         if((event->u.data.pointer) && (event->u.data.length))
1188           memcpy(custom, event->u.data.pointer, event->u.data.length);
1189         custom[event->u.data.length] = '\0';
1190         printf("                    Extra:%s\n", custom);
1191       }
1192       break;
1193     default:
1194       printf("                    (Unknown Wireless Token 0x%04X)\n",
1195              event->cmd);
1196    }    /* switch(event->cmd) */
1197 }
1198
1199 /*------------------------------------------------------------------*/
1200 /*
1201  * Perform a scanning on one device
1202  */
1203 static int
1204 print_scanning_info(int         skfd,
1205                     char *      ifname,
1206                     char *      args[],         /* Command line args */
1207                     int         count)          /* Args count */
1208 {
1209   struct iwreq          wrq;
1210   unsigned char *       buffer = NULL;          /* Results */
1211   int                   buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
1212   struct iw_range       range;
1213   int                   has_range;
1214   struct timeval        tv;                             /* Select timeout */
1215   int                   timeout = 15000000;             /* 15s */
1216
1217   /* Avoid "Unused parameter" warning */
1218   args = args; count = count;
1219
1220   /* Get range stuff */
1221   has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
1222
1223   /* Check if the interface could support scanning. */
1224   if((!has_range) || (range.we_version_compiled < 14))
1225     {
1226       fprintf(stderr, "%-8.16s  Interface doesn't support scanning.\n\n",
1227               ifname);
1228       return(-1);
1229     }
1230
1231   /* Init timeout value -> 250ms*/
1232   tv.tv_sec = 0;
1233   tv.tv_usec = 250000;
1234
1235   /*
1236    * Here we should look at the command line args and set the IW_SCAN_ flags
1237    * properly
1238    */
1239   wrq.u.data.pointer = NULL;            /* Later */
1240   wrq.u.data.flags = 0;
1241   wrq.u.data.length = 0;
1242
1243   /* Initiate Scanning */
1244   if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
1245     {
1246       if(errno != EPERM)
1247         {
1248           fprintf(stderr, "%-8.16s  Interface doesn't support scanning : %s\n\n",
1249                   ifname, strerror(errno));
1250           return(-1);
1251         }
1252       /* If we don't have the permission to initiate the scan, we may
1253        * still have permission to read left-over results.
1254        * But, don't wait !!! */
1255 #if 0
1256       /* Not cool, it display for non wireless interfaces... */
1257       fprintf(stderr, "%-8.16s  (Could not trigger scanning, just reading left-over results)\n", ifname);
1258 #endif
1259       tv.tv_usec = 0;
1260     }
1261   timeout -= tv.tv_usec;
1262
1263   /* Forever */
1264   while(1)
1265     {
1266       fd_set            rfds;           /* File descriptors for select */
1267       int               last_fd;        /* Last fd */
1268       int               ret;
1269
1270       /* Guess what ? We must re-generate rfds each time */
1271       FD_ZERO(&rfds);
1272       last_fd = -1;
1273
1274       /* In here, add the rtnetlink fd in the list */
1275
1276       /* Wait until something happens */
1277       ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
1278
1279       /* Check if there was an error */
1280       if(ret < 0)
1281         {
1282           if(errno == EAGAIN || errno == EINTR)
1283             continue;
1284           fprintf(stderr, "Unhandled signal - exiting...\n");
1285           return(-1);
1286         }
1287
1288       /* Check if there was a timeout */
1289       if(ret == 0)
1290         {
1291           unsigned char *       newbuf;
1292
1293         realloc:
1294           /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
1295           newbuf = realloc(buffer, buflen);
1296           if(newbuf == NULL)
1297             {
1298               if(buffer)
1299                 free(buffer);
1300               fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
1301               return(-1);
1302             }
1303           buffer = newbuf;
1304
1305           /* Try to read the results */
1306           wrq.u.data.pointer = buffer;
1307           wrq.u.data.flags = 0;
1308           wrq.u.data.length = buflen;
1309           if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
1310             {
1311               /* Check if buffer was too small (WE-17 only) */
1312               if((errno == E2BIG) && (range.we_version_compiled > 16))
1313                 {
1314                   /* Some driver may return very large scan results, either
1315                    * because there are many cells, or because they have many
1316                    * large elements in cells (like IWEVCUSTOM). Most will
1317                    * only need the regular sized buffer. We now use a dynamic
1318                    * allocation of the buffer to satisfy everybody. Of course,
1319                    * as we don't know in advance the size of the array, we try
1320                    * various increasing sizes. Jean II */
1321
1322                   /* Check if the driver gave us any hints. */
1323                   if(wrq.u.data.length > buflen)
1324                     buflen = wrq.u.data.length;
1325                   else
1326                     buflen *= 2;
1327
1328                   /* Try again */
1329                   goto realloc;
1330                 }
1331
1332               /* Check if results not available yet */
1333               if(errno == EAGAIN)
1334                 {
1335                   /* Restart timer for only 100ms*/
1336                   tv.tv_sec = 0;
1337                   tv.tv_usec = 100000;
1338                   timeout -= tv.tv_usec;
1339                   if(timeout > 0)
1340                     continue;   /* Try again later */
1341                 }
1342
1343               /* Bad error */
1344               free(buffer);
1345               fprintf(stderr, "%-8.16s  Failed to read scan data : %s\n\n",
1346                       ifname, strerror(errno));
1347               return(-2);
1348             }
1349           else
1350             /* We have the results, go to process them */
1351             break;
1352         }
1353
1354       /* In here, check if event and event type
1355        * if scan event, read results. All errors bad & no reset timeout */
1356     }
1357
1358   if(wrq.u.data.length)
1359     {
1360       struct iw_event           iwe;
1361       struct stream_descr       stream;
1362       struct iwscan_state       state = { .ap_num = 1, .val_index = 0 };
1363       int                       ret;
1364       
1365 #if 0
1366       /* Debugging code. In theory useless, because it's debugged ;-) */
1367       int       i;
1368       printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
1369       for(i = 1; i < wrq.u.data.length; i++)
1370         printf(":%02X", buffer[i]);
1371       printf("]\n");
1372 #endif
1373       printf("%-8.16s  Scan completed :\n", ifname);
1374       iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
1375       do
1376         {
1377           /* Extract an event and print it */
1378           ret = iw_extract_event_stream(&stream, &iwe,
1379                                         range.we_version_compiled);
1380           if(ret > 0)
1381             print_scanning_token(&stream, &iwe, &state,
1382                                  &range, has_range);
1383         }
1384       while(ret > 0);
1385       printf("\n");
1386     }
1387   else
1388     printf("%-8.16s  No scan results\n", ifname);
1389
1390   free(buffer);
1391   return(0);
1392 }
1393
1394 /******************** WIRELESS EVENT CAPABILITY ********************/
1395
1396 static const char *     event_capa_req[] =
1397 {
1398   [SIOCSIWNWID  - SIOCIWFIRST] = "Set NWID (kernel generated)",
1399   [SIOCSIWFREQ  - SIOCIWFIRST] = "Set Frequency/Channel (kernel generated)",
1400   [SIOCGIWFREQ  - SIOCIWFIRST] = "New Frequency/Channel",
1401   [SIOCSIWMODE  - SIOCIWFIRST] = "Set Mode (kernel generated)",
1402   [SIOCGIWTHRSPY - SIOCIWFIRST] = "Spy threshold crossed",
1403   [SIOCGIWAP    - SIOCIWFIRST] = "New Access Point/Cell address - roaming",
1404   [SIOCGIWSCAN  - SIOCIWFIRST] = "Scan request completed",
1405   [SIOCSIWESSID - SIOCIWFIRST] = "Set ESSID (kernel generated)",
1406   [SIOCGIWESSID - SIOCIWFIRST] = "New ESSID",
1407   [SIOCGIWRATE  - SIOCIWFIRST] = "New bit-rate",
1408   [SIOCSIWENCODE - SIOCIWFIRST] = "Set Encoding (kernel generated)",
1409   [SIOCGIWPOWER - SIOCIWFIRST] = NULL,
1410 };
1411
1412 static const char *     event_capa_evt[] =
1413 {
1414   [IWEVTXDROP   - IWEVFIRST] = "Tx packet dropped - retry exceeded",
1415   [IWEVCUSTOM   - IWEVFIRST] = "Custom driver event",
1416   [IWEVREGISTERED - IWEVFIRST] = "Registered node",
1417   [IWEVEXPIRED  - IWEVFIRST] = "Expired node",
1418 };
1419
1420 /*------------------------------------------------------------------*/
1421 /*
1422  * Print the number of available transmit powers for the device
1423  */
1424 static int
1425 print_event_capa_info(int               skfd,
1426                       char *            ifname,
1427                       char *            args[],         /* Command line args */
1428                       int               count)          /* Args count */
1429 {
1430   struct iw_range       range;
1431   int                   cmd;
1432
1433   /* Avoid "Unused parameter" warning */
1434   args = args; count = count;
1435
1436   /* Extract range info */
1437   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1438      (range.we_version_compiled < 10))
1439       fprintf(stderr, "%-8.16s  no wireless event capability information.\n\n",
1440                       ifname);
1441   else
1442     {
1443 #if 0
1444       /* Debugging ;-) */
1445       for(cmd = 0x8B00; cmd < 0x8C0F; cmd++)
1446         {
1447           int idx = IW_EVENT_CAPA_INDEX(cmd);
1448           int mask = IW_EVENT_CAPA_MASK(cmd);
1449           printf("0x%X - %d - %X\n", cmd, idx, mask);
1450         }
1451 #endif
1452
1453       printf("%-8.16s  Wireless Events supported :\n", ifname);
1454
1455       for(cmd = SIOCIWFIRST; cmd <= SIOCGIWPOWER; cmd++)
1456         {
1457           int idx = IW_EVENT_CAPA_INDEX(cmd);
1458           int mask = IW_EVENT_CAPA_MASK(cmd);
1459           if(range.event_capa[idx] & mask)
1460             printf("          0x%04X : %s\n",
1461                    cmd, event_capa_req[cmd - SIOCIWFIRST]);
1462         }
1463       for(cmd = IWEVFIRST; cmd <= IWEVEXPIRED; cmd++)
1464         {
1465           int idx = IW_EVENT_CAPA_INDEX(cmd);
1466           int mask = IW_EVENT_CAPA_MASK(cmd);
1467           if(range.event_capa[idx] & mask)
1468             printf("          0x%04X : %s\n",
1469                    cmd, event_capa_evt[cmd - IWEVFIRST]);
1470         }
1471       printf("\n");
1472     }
1473   return(0);
1474 }
1475
1476 /************************* COMMON UTILITIES *************************/
1477 /*
1478  * This section was initially written by Michael Tokarev <mjt@tls.msk.ru>
1479  * but heavily modified by me ;-)
1480  */
1481
1482 /*------------------------------------------------------------------*/
1483 /*
1484  * Map command line arguments to the proper procedure...
1485  */
1486 typedef struct iwlist_entry {
1487   const char *cmd;
1488   iw_enum_handler fn;
1489   int min_count;
1490   int max_count;
1491 } iwlist_cmd;
1492
1493 static const struct iwlist_entry iwlist_cmds[] = {
1494   { "scanning",         print_scanning_info,    0, 5 },
1495   { "frequency",        print_freq_info,        0, 0 },
1496   { "channel",          print_freq_info,        0, 0 },
1497   { "bitrate",          print_bitrate_info,     0, 0 },
1498   { "rate",             print_bitrate_info,     0, 0 },
1499   { "encryption",       print_keys_info,        0, 0 },
1500   { "key",              print_keys_info,        0, 0 },
1501   { "power",            print_pm_info,          0, 0 },
1502   { "txpower",          print_txpower_info,     0, 0 },
1503   { "retry",            print_retry_info,       0, 0 },
1504   { "ap",               print_ap_info,          0, 0 },
1505   { "accesspoints",     print_ap_info,          0, 0 },
1506   { "peers",            print_ap_info,          0, 0 },
1507   { "event",            print_event_capa_info,  0, 0 },
1508   { NULL, NULL, 0, 0 },
1509 };
1510
1511 /*------------------------------------------------------------------*/
1512 /*
1513  * Find the most appropriate command matching the command line
1514  */
1515 static inline const iwlist_cmd *
1516 find_command(const char *       cmd)
1517 {
1518   const iwlist_cmd *    found = NULL;
1519   int                   ambig = 0;
1520   unsigned int          len = strlen(cmd);
1521   int                   i;
1522
1523   /* Go through all commands */
1524   for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
1525     {
1526       /* No match -> next one */
1527       if(strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0)
1528         continue;
1529
1530       /* Exact match -> perfect */
1531       if(len == strlen(iwlist_cmds[i].cmd))
1532         return &iwlist_cmds[i];
1533
1534       /* Partial match */
1535       if(found == NULL)
1536         /* First time */
1537         found = &iwlist_cmds[i];
1538       else
1539         /* Another time */
1540         if (iwlist_cmds[i].fn != found->fn)
1541           ambig = 1;
1542     }
1543
1544   if(found == NULL)
1545     {
1546       fprintf(stderr, "iwlist: unknown command `%s'\n", cmd);
1547       return NULL;
1548     }
1549
1550   if(ambig)
1551     {
1552       fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd);
1553       return NULL;
1554     }
1555
1556   return found;
1557 }
1558
1559 /*------------------------------------------------------------------*/
1560 /*
1561  * Display help
1562  */
1563 static void iw_usage(int status)
1564 {
1565   FILE* f = status ? stderr : stdout;
1566   int i;
1567
1568   fprintf(f,   "Usage: iwlist [interface] %s\n", iwlist_cmds[0].cmd);
1569   for(i = 1; iwlist_cmds[i].cmd != NULL; ++i)
1570     fprintf(f, "              [interface] %s\n", iwlist_cmds[i].cmd);
1571   exit(status);
1572 }
1573
1574 /******************************* MAIN ********************************/
1575
1576 /*------------------------------------------------------------------*/
1577 /*
1578  * The main !
1579  */
1580 int
1581 main(int        argc,
1582      char **    argv)
1583 {
1584   int skfd;                     /* generic raw socket desc.     */
1585   char *dev;                    /* device name                  */
1586   char *cmd;                    /* command                      */
1587   char **args;                  /* Command arguments */
1588   int count;                    /* Number of arguments */
1589   const iwlist_cmd *iwcmd;
1590
1591   if(argc == 1 || argc > 3)
1592     iw_usage(1);
1593
1594   /* Those don't apply to all interfaces */
1595   if((argc == 2) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
1596     iw_usage(0);
1597   if((argc == 2) && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")))
1598     return(iw_print_version_info("iwlist"));
1599
1600   if(argc == 2)
1601     {
1602       cmd = argv[1];
1603       dev = NULL;
1604       args = NULL;
1605       count = 0;
1606     }
1607   else
1608     {
1609       cmd = argv[2];
1610       dev = argv[1];
1611       args = argv + 3;
1612       count = argc - 3;
1613     }
1614
1615   /* find a command */
1616   iwcmd = find_command(cmd);
1617   if(iwcmd == NULL)
1618     return 1;
1619
1620   /* Check arg numbers */
1621   if(count < iwcmd->min_count)
1622     {
1623       fprintf(stderr, "iwlist: command `%s' needs more arguments\n", cmd);
1624       return 1;
1625     }
1626   if(count > iwcmd->max_count)
1627     {
1628       fprintf(stderr, "iwlist: command `%s' needs fewer arguments\n", cmd);
1629       return 1;
1630     }
1631
1632   /* Create a channel to the NET kernel. */
1633   if((skfd = iw_sockets_open()) < 0)
1634     {
1635       perror("socket");
1636       return -1;
1637     }
1638
1639   /* do the actual work */
1640   if (dev)
1641     (*iwcmd->fn)(skfd, dev, args, count);
1642   else
1643     iw_enum_devices(skfd, iwcmd->fn, args, count);
1644
1645   /* Close the socket. */
1646   iw_sockets_close(skfd);
1647
1648   return 0;
1649 }