OSDN Git Service

Update to v30-pre9
[android-x86/external-wireless-tools.git] / wireless_tools / iwlist.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB '99 - HPL 99->07
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-2007 Jean Tourrilhes <jt@hpl.hp.com>
12  */
13
14 #include "iwlib-private.h"              /* Private 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  * Bit to name mapping
31  */
32 typedef struct iwmask_name
33 {
34   unsigned int  mask;   /* bit mask for the value */
35   const char *  name;   /* human readable name for the value */
36 } iwmask_name;
37
38 /*
39  * Types of authentication parameters
40  */
41 typedef struct iw_auth_descr
42 {
43   int                           value;          /* Type of auth value */
44   const char *                  label;          /* User readable version */
45   const struct iwmask_name *    names;          /* Names for this value */
46   const int                     num_names;      /* Number of names */
47 } iw_auth_descr;
48
49 /**************************** CONSTANTS ****************************/
50
51 #define IW_SCAN_HACK            0x8000
52
53 #define IW_EXTKEY_SIZE  (sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX)
54
55 /* ------------------------ WPA CAPA NAMES ------------------------ */
56 /*
57  * This is the user readable name of a bunch of WPA constants in wireless.h
58  * Maybe this should go in iwlib.c ?
59  */
60
61 #ifndef WE_ESSENTIAL
62 #define IW_ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
63
64 //static const struct iwmask_name iw_enc_mode_name[] = {
65 //  { IW_ENCODE_RESTRICTED,     "restricted" },
66 //  { IW_ENCODE_OPEN,           "open" },
67 //};
68 //#define       IW_ENC_MODE_NUM         IW_ARRAY_LEN(iw_enc_mode_name)
69
70 static const struct iwmask_name iw_auth_capa_name[] = {
71   { IW_ENC_CAPA_WPA,            "WPA" },
72   { IW_ENC_CAPA_WPA2,           "WPA2" },
73   { IW_ENC_CAPA_CIPHER_TKIP,    "CIPHER-TKIP" },
74   { IW_ENC_CAPA_CIPHER_CCMP,    "CIPHER-CCMP" },
75 };
76 #define IW_AUTH_CAPA_NUM        IW_ARRAY_LEN(iw_auth_capa_name)
77
78 static const struct iwmask_name iw_auth_cypher_name[] = {
79   { IW_AUTH_CIPHER_NONE,        "none" },
80   { IW_AUTH_CIPHER_WEP40,       "WEP-40" },
81   { IW_AUTH_CIPHER_TKIP,        "TKIP" },
82   { IW_AUTH_CIPHER_CCMP,        "CCMP" },
83   { IW_AUTH_CIPHER_WEP104,      "WEP-104" },
84 };
85 #define IW_AUTH_CYPHER_NUM      IW_ARRAY_LEN(iw_auth_cypher_name)
86
87 static const struct iwmask_name iw_wpa_ver_name[] = {
88   { IW_AUTH_WPA_VERSION_DISABLED,       "disabled" },
89   { IW_AUTH_WPA_VERSION_WPA,            "WPA" },
90   { IW_AUTH_WPA_VERSION_WPA2,           "WPA2" },
91 };
92 #define IW_WPA_VER_NUM          IW_ARRAY_LEN(iw_wpa_ver_name)
93
94 static const struct iwmask_name iw_auth_key_mgmt_name[] = {
95   { IW_AUTH_KEY_MGMT_802_1X,    "802.1x" },
96   { IW_AUTH_KEY_MGMT_PSK,       "PSK" },
97 };
98 #define IW_AUTH_KEY_MGMT_NUM    IW_ARRAY_LEN(iw_auth_key_mgmt_name)
99
100 static const struct iwmask_name iw_auth_alg_name[] = {
101   { IW_AUTH_ALG_OPEN_SYSTEM,    "open" },
102   { IW_AUTH_ALG_SHARED_KEY,     "shared-key" },
103   { IW_AUTH_ALG_LEAP,           "LEAP" },
104 };
105 #define IW_AUTH_ALG_NUM         IW_ARRAY_LEN(iw_auth_alg_name)
106
107 static const struct iw_auth_descr       iw_auth_settings[] = {
108   { IW_AUTH_WPA_VERSION, "WPA version", iw_wpa_ver_name, IW_WPA_VER_NUM },
109   { IW_AUTH_KEY_MGMT, "Key management", iw_auth_key_mgmt_name, IW_AUTH_KEY_MGMT_NUM },
110   { IW_AUTH_CIPHER_PAIRWISE, "Pairwise cipher", iw_auth_cypher_name, IW_AUTH_CYPHER_NUM },
111   { IW_AUTH_CIPHER_GROUP, "Pairwise cipher", iw_auth_cypher_name, IW_AUTH_CYPHER_NUM },
112   { IW_AUTH_TKIP_COUNTERMEASURES, "TKIP countermeasures", NULL, 0 },
113   { IW_AUTH_DROP_UNENCRYPTED, "Drop unencrypted", NULL, 0 },
114   { IW_AUTH_80211_AUTH_ALG, "Authentication algorithm", iw_auth_alg_name, IW_AUTH_ALG_NUM },
115   { IW_AUTH_RX_UNENCRYPTED_EAPOL, "Receive unencrypted EAPOL", NULL, 0 },
116   { IW_AUTH_ROAMING_CONTROL, "Roaming control", NULL, 0 },
117   { IW_AUTH_PRIVACY_INVOKED, "Privacy invoked", NULL, 0 },
118 };
119 #define IW_AUTH_SETTINGS_NUM            IW_ARRAY_LEN(iw_auth_settings)
120
121 /* Values for the IW_ENCODE_ALG_* returned by SIOCSIWENCODEEXT */
122 static const char *     iw_encode_alg_name[] = {
123         "none",
124         "WEP",
125         "TKIP",
126         "CCMP",
127         "unknown"
128 };
129 #define IW_ENCODE_ALG_NUM               IW_ARRAY_LEN(iw_encode_alg_name)
130
131 #ifndef IW_IE_CIPHER_NONE
132 /* Cypher values in GENIE (pairwise and group) */
133 #define IW_IE_CIPHER_NONE       0
134 #define IW_IE_CIPHER_WEP40      1
135 #define IW_IE_CIPHER_TKIP       2
136 #define IW_IE_CIPHER_WRAP       3
137 #define IW_IE_CIPHER_CCMP       4
138 #define IW_IE_CIPHER_WEP104     5
139 /* Key management in GENIE */
140 #define IW_IE_KEY_MGMT_NONE     0
141 #define IW_IE_KEY_MGMT_802_1X   1
142 #define IW_IE_KEY_MGMT_PSK      2
143 #endif  /* IW_IE_CIPHER_NONE */
144
145 /* Values for the IW_IE_CIPHER_* in GENIE */
146 static const char *     iw_ie_cypher_name[] = {
147         "none",
148         "WEP-40",
149         "TKIP",
150         "WRAP",
151         "CCMP",
152         "WEP-104",
153 };
154 #define IW_IE_CYPHER_NUM        IW_ARRAY_LEN(iw_ie_cypher_name)
155
156 /* Values for the IW_IE_KEY_MGMT_* in GENIE */
157 static const char *     iw_ie_key_mgmt_name[] = {
158         "none",
159         "802.1x",
160         "PSK",
161 };
162 #define IW_IE_KEY_MGMT_NUM      IW_ARRAY_LEN(iw_ie_key_mgmt_name)
163
164 #endif  /* WE_ESSENTIAL */
165
166 /************************* WPA SUBROUTINES *************************/
167
168 #ifndef WE_ESSENTIAL
169 /*------------------------------------------------------------------*/
170 /*
171  * Print all names corresponding to a mask.
172  * This may want to be used in iw_print_retry_value() ?
173  */
174 static void 
175 iw_print_mask_name(unsigned int                 mask,
176                    const struct iwmask_name     names[],
177                    const unsigned int           num_names,
178                    const char *                 sep)
179 {
180   unsigned int  i;
181
182   /* Print out all names for the bitmask */
183   for(i = 0; i < num_names; i++)
184     {
185       if(mask & names[i].mask)
186         {
187           /* Print out */
188           printf("%s%s", sep, names[i].name);
189           /* Remove the bit from the mask */
190           mask &= ~names[i].mask;
191         }
192     }
193   /* If there is unconsumed bits... */
194   if(mask != 0)
195     printf("%sUnknown", sep);
196 }
197
198 /*------------------------------------------------------------------*/
199 /*
200  * Print the name corresponding to a value, with overflow check.
201  */
202 static void
203 iw_print_value_name(unsigned int                value,
204                     const char *                names[],
205                     const unsigned int          num_names)
206 {
207   if(value >= num_names)
208     printf(" unknown (%d)", value);
209   else
210     printf(" %s", names[value]);
211 }
212
213 /*------------------------------------------------------------------*/
214 /*
215  * Parse, and display the results of an unknown IE.
216  *
217  */
218 static void 
219 iw_print_ie_unknown(unsigned char *     iebuf,
220                     int                 buflen)
221 {
222   int   ielen = iebuf[1] + 2;
223   int   i;
224
225   if(ielen > buflen)
226     ielen = buflen;
227
228   printf("Unknown: ");
229   for(i = 0; i < ielen; i++)
230     printf("%02X", iebuf[i]);
231   printf("\n");
232 }
233
234 /*------------------------------------------------------------------*/
235 /*
236  * Parse, and display the results of a WPA or WPA2 IE.
237  *
238  */
239 static inline void 
240 iw_print_ie_wpa(unsigned char * iebuf,
241                 int             buflen)
242 {
243   int                   ielen = iebuf[1] + 2;
244   int                   offset = 2;     /* Skip the IE id, and the length. */
245   unsigned char         wpa1_oui[3] = {0x00, 0x50, 0xf2};
246   unsigned char         wpa2_oui[3] = {0x00, 0x0f, 0xac};
247   unsigned char *       wpa_oui;
248   int                   i;
249   uint16_t              ver = 0;
250   uint16_t              cnt = 0;
251
252   if(ielen > buflen)
253     ielen = buflen;
254
255 #ifdef DEBUG
256   /* Debugging code. In theory useless, because it's debugged ;-) */
257   printf("IE raw value %d [%02X", buflen, iebuf[0]);
258   for(i = 1; i < buflen; i++)
259     printf(":%02X", iebuf[i]);
260   printf("]\n");
261 #endif
262
263   switch(iebuf[0])
264     {
265     case 0x30:          /* WPA2 */
266       /* Check if we have enough data */
267       if(ielen < 4)
268         {
269           iw_print_ie_unknown(iebuf, buflen);
270           return;
271         }
272
273       wpa_oui = wpa2_oui;
274       break;
275
276     case 0xdd:          /* WPA or else */
277       wpa_oui = wpa1_oui;
278  
279       /* Not all IEs that start with 0xdd are WPA. 
280        * So check that the OUI is valid. Note : offset==2 */
281       if((ielen < 8)
282          || (memcmp(&iebuf[offset], wpa_oui, 3) != 0)
283          || (iebuf[offset + 3] != 0x01))
284         {
285           iw_print_ie_unknown(iebuf, buflen);
286           return;
287         }
288
289       /* Skip the OUI type */
290       offset += 4;
291       break;
292
293     default:
294       return;
295     }
296   
297   /* Pick version number (little endian) */
298   ver = iebuf[offset] | (iebuf[offset + 1] << 8);
299   offset += 2;
300
301   if(iebuf[0] == 0xdd)
302     printf("WPA Version %d\n", ver);
303   if(iebuf[0] == 0x30)
304     printf("IEEE 802.11i/WPA2 Version %d\n", ver);
305
306   /* From here, everything is technically optional. */
307
308   /* Check if we are done */
309   if(ielen < (offset + 4))
310     {
311       /* We have a short IE.  So we should assume TKIP/TKIP. */
312       printf("                        Group Cipher : TKIP\n");
313       printf("                        Pairwise Cipher : TKIP\n");
314       return;
315     }
316  
317   /* Next we have our group cipher. */
318   if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
319     {
320       printf("                        Group Cipher : Proprietary\n");
321     }
322   else
323     {
324       printf("                        Group Cipher :");
325       iw_print_value_name(iebuf[offset+3],
326                           iw_ie_cypher_name, IW_IE_CYPHER_NUM);
327       printf("\n");
328     }
329   offset += 4;
330
331   /* Check if we are done */
332   if(ielen < (offset + 2))
333     {
334       /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
335       printf("                        Pairwise Ciphers : TKIP\n");
336       return;
337     }
338
339   /* Otherwise, we have some number of pairwise ciphers. */
340   cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
341   offset += 2;
342   printf("                        Pairwise Ciphers (%d) :", cnt);
343
344   if(ielen < (offset + 4*cnt))
345     return;
346
347   for(i = 0; i < cnt; i++)
348     {
349       if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
350         {
351           printf(" Proprietary");
352         }
353       else
354         {
355           iw_print_value_name(iebuf[offset+3],
356                               iw_ie_cypher_name, IW_IE_CYPHER_NUM);
357         }
358       offset+=4;
359     }
360   printf("\n");
361  
362   /* Check if we are done */
363   if(ielen < (offset + 2))
364     return;
365
366   /* Now, we have authentication suites. */
367   cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
368   offset += 2;
369   printf("                        Authentication Suites (%d) :", cnt);
370
371   if(ielen < (offset + 4*cnt))
372     return;
373
374   for(i = 0; i < cnt; i++)
375     {
376       if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
377         {
378           printf(" Proprietary");
379         }
380       else
381         {
382           iw_print_value_name(iebuf[offset+3],
383                               iw_ie_key_mgmt_name, IW_IE_KEY_MGMT_NUM);
384         }
385        offset+=4;
386      }
387   printf("\n");
388  
389   /* Check if we are done */
390   if(ielen < (offset + 1))
391     return;
392
393   /* Otherwise, we have capabilities bytes.
394    * For now, we only care about preauth which is in bit position 1 of the
395    * first byte.  (But, preauth with WPA version 1 isn't supposed to be 
396    * allowed.) 8-) */
397   if(iebuf[offset] & 0x01)
398     {
399       printf("                       Preauthentication Supported\n");
400     }
401 }
402  
403 /*------------------------------------------------------------------*/
404 /*
405  * Process a generic IE and display the info in human readable form
406  * for some of the most interesting ones.
407  * For now, we only decode the WPA IEs.
408  */
409 static inline void
410 iw_print_gen_ie(unsigned char * buffer,
411                 int             buflen)
412 {
413   int offset = 0;
414
415   /* Loop on each IE, each IE is minimum 2 bytes */
416   while(offset <= (buflen - 2))
417     {
418       printf("                    IE: ");
419
420       /* Check IE type */
421       switch(buffer[offset])
422         {
423         case 0xdd:      /* WPA1 (and other) */
424         case 0x30:      /* WPA2 */
425           iw_print_ie_wpa(buffer + offset, buflen);
426           break;
427         default:
428           iw_print_ie_unknown(buffer + offset, buflen);
429         }
430       /* Skip over this IE to the next one in the list. */
431       offset += buffer[offset+1] + 2;
432     }
433 }
434 #endif  /* WE_ESSENTIAL */
435
436 /***************************** SCANNING *****************************/
437 /*
438  * This one behave quite differently from the others
439  *
440  * Note that we don't use the scanning capability of iwlib (functions
441  * iw_process_scan() and iw_scan()). The main reason is that
442  * iw_process_scan() return only a subset of the scan data to the caller,
443  * for example custom elements and bitrates are ommited. Here, we
444  * do the complete job...
445  */
446
447 /*------------------------------------------------------------------*/
448 /*
449  * Print one element from the scanning results
450  */
451 static inline void
452 print_scanning_token(struct stream_descr *      stream, /* Stream of events */
453                      struct iw_event *          event,  /* Extracted token */
454                      struct iwscan_state *      state,
455                      struct iw_range *  iw_range,       /* Range info */
456                      int                has_range)
457 {
458   char          buffer[128];    /* Temporary buffer */
459
460   /* Now, let's decode the event */
461   switch(event->cmd)
462     {
463     case SIOCGIWAP:
464       printf("          Cell %02d - Address: %s\n", state->ap_num,
465              iw_saether_ntop(&event->u.ap_addr, buffer));
466       state->ap_num++;
467       break;
468     case SIOCGIWNWID:
469       if(event->u.nwid.disabled)
470         printf("                    NWID:off/any\n");
471       else
472         printf("                    NWID:%X\n", event->u.nwid.value);
473       break;
474     case SIOCGIWFREQ:
475       {
476         double          freq;                   /* Frequency/channel */
477         int             channel = -1;           /* Converted to channel */
478         freq = iw_freq2float(&(event->u.freq));
479         /* Convert to channel if possible */
480         if(has_range)
481           channel = iw_freq_to_channel(freq, iw_range);
482         iw_print_freq(buffer, sizeof(buffer),
483                       freq, channel, event->u.freq.flags);
484         printf("                    %s\n", buffer);
485       }
486       break;
487     case SIOCGIWMODE:
488       /* Note : event->u.mode is unsigned, no need to check <= 0 */
489       if(event->u.mode >= IW_NUM_OPER_MODE)
490         event->u.mode = IW_NUM_OPER_MODE;
491       printf("                    Mode:%s\n",
492              iw_operation_mode[event->u.mode]);
493       break;
494     case SIOCGIWNAME:
495       printf("                    Protocol:%-1.16s\n", event->u.name);
496       break;
497     case SIOCGIWESSID:
498       {
499         char essid[4*IW_ESSID_MAX_SIZE+1];
500         memset(essid, '\0', sizeof(essid));
501         if((event->u.essid.pointer) && (event->u.essid.length))
502           iw_essid_escape(essid,
503                           event->u.essid.pointer, event->u.essid.length);
504         if(event->u.essid.flags)
505           {
506             /* Does it have an ESSID index ? */
507             if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
508               printf("                    ESSID:\"%s\" [%d]\n", essid,
509                      (event->u.essid.flags & IW_ENCODE_INDEX));
510             else
511               printf("                    ESSID:\"%s\"\n", essid);
512           }
513         else
514           printf("                    ESSID:off/any/hidden\n");
515       }
516       break;
517     case SIOCGIWENCODE:
518       {
519         unsigned char   key[IW_ENCODING_TOKEN_MAX];
520         if(event->u.data.pointer)
521           memcpy(key, event->u.data.pointer, event->u.data.length);
522         else
523           event->u.data.flags |= IW_ENCODE_NOKEY;
524         printf("                    Encryption key:");
525         if(event->u.data.flags & IW_ENCODE_DISABLED)
526           printf("off\n");
527         else
528           {
529             /* Display the key */
530             iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
531                          event->u.data.flags);
532             printf("%s", buffer);
533
534             /* Other info... */
535             if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
536               printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
537             if(event->u.data.flags & IW_ENCODE_RESTRICTED)
538               printf("   Security mode:restricted");
539             if(event->u.data.flags & IW_ENCODE_OPEN)
540               printf("   Security mode:open");
541             printf("\n");
542           }
543       }
544       break;
545     case SIOCGIWRATE:
546       if(state->val_index == 0)
547         printf("                    Bit Rates:");
548       else
549         if((state->val_index % 5) == 0)
550           printf("\n                              ");
551         else
552           printf("; ");
553       iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
554       printf("%s", buffer);
555       /* Check for termination */
556       if(stream->value == NULL)
557         {
558           printf("\n");
559           state->val_index = 0;
560         }
561       else
562         state->val_index++;
563       break;
564     case SIOCGIWMODUL:
565       {
566         unsigned int    modul = event->u.param.value;
567         int             i;
568         int             n = 0;
569         printf("                    Modulations :");
570         for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
571           {
572             if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
573               {
574                 if((n++ % 8) == 7)
575                   printf("\n                        ");
576                 else
577                   printf(" ; ");
578                 printf("%s", iw_modul_list[i].cmd);
579               }
580           }
581         printf("\n");
582       }
583       break;
584     case IWEVQUAL:
585       iw_print_stats(buffer, sizeof(buffer),
586                      &event->u.qual, iw_range, has_range);
587       printf("                    %s\n", buffer);
588       break;
589 #ifndef WE_ESSENTIAL
590     case IWEVGENIE:
591       /* Informations Elements are complex, let's do only some of them */
592       iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
593       break;
594 #endif  /* WE_ESSENTIAL */
595     case IWEVCUSTOM:
596       {
597         char custom[IW_CUSTOM_MAX+1];
598         if((event->u.data.pointer) && (event->u.data.length))
599           memcpy(custom, event->u.data.pointer, event->u.data.length);
600         custom[event->u.data.length] = '\0';
601         printf("                    Extra:%s\n", custom);
602       }
603       break;
604     default:
605       printf("                    (Unknown Wireless Token 0x%04X)\n",
606              event->cmd);
607    }    /* switch(event->cmd) */
608 }
609
610 /*------------------------------------------------------------------*/
611 /*
612  * Perform a scanning on one device
613  */
614 static int
615 print_scanning_info(int         skfd,
616                     char *      ifname,
617                     char *      args[],         /* Command line args */
618                     int         count)          /* Args count */
619 {
620   struct iwreq          wrq;
621   struct iw_scan_req    scanopt;                /* Options for 'set' */
622   int                   scanflags = 0;          /* Flags for scan */
623   unsigned char *       buffer = NULL;          /* Results */
624   int                   buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
625   struct iw_range       range;
626   int                   has_range;
627   struct timeval        tv;                             /* Select timeout */
628   int                   timeout = 15000000;             /* 15s */
629
630   /* Avoid "Unused parameter" warning */
631   args = args; count = count;
632
633   /* Debugging stuff */
634   if((IW_EV_LCP_PK2_LEN != IW_EV_LCP_PK_LEN) || (IW_EV_POINT_PK2_LEN != IW_EV_POINT_PK_LEN))
635     {
636       fprintf(stderr, "*** Please report to jt@hpl.hp.com your platform details\n");
637       fprintf(stderr, "*** and the following line :\n");
638       fprintf(stderr, "*** IW_EV_LCP_PK2_LEN = %zu ; IW_EV_POINT_PK2_LEN = %zu\n\n",
639               IW_EV_LCP_PK2_LEN, IW_EV_POINT_PK2_LEN);
640     }
641
642   /* Get range stuff */
643   has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
644
645   /* Check if the interface could support scanning. */
646   if((!has_range) || (range.we_version_compiled < 14))
647     {
648       fprintf(stderr, "%-8.16s  Interface doesn't support scanning.\n\n",
649               ifname);
650       return(-1);
651     }
652
653   /* Init timeout value -> 250ms between set and first get */
654   tv.tv_sec = 0;
655   tv.tv_usec = 250000;
656
657   /* Clean up set args */
658   memset(&scanopt, 0, sizeof(scanopt));
659
660   /* Parse command line arguments and extract options.
661    * Note : when we have enough options, we should use the parser
662    * from iwconfig... */
663   while(count > 0)
664     {
665       /* One arg is consumed (the option name) */
666       count--;
667       
668       /*
669        * Check for Active Scan (scan with specific essid)
670        */
671       if(!strncmp(args[0], "essid", 5))
672         {
673           if(count < 1)
674             {
675               fprintf(stderr, "Too few arguments for scanning option [%s]\n",
676                       args[0]);
677               return(-1);
678             }
679           args++;
680           count--;
681
682           /* Store the ESSID in the scan options */
683           scanopt.essid_len = strlen(args[0]);
684           memcpy(scanopt.essid, args[0], scanopt.essid_len);
685           /* Initialise BSSID as needed */
686           if(scanopt.bssid.sa_family == 0)
687             {
688               scanopt.bssid.sa_family = ARPHRD_ETHER;
689               memset(scanopt.bssid.sa_data, 0xff, ETH_ALEN);
690             }
691           /* Scan only this ESSID */
692           scanflags |= IW_SCAN_THIS_ESSID;
693         }
694       else
695         /* Check for last scan result (do not trigger scan) */
696         if(!strncmp(args[0], "last", 4))
697           {
698             /* Hack */
699             scanflags |= IW_SCAN_HACK;
700           }
701         else
702           {
703             fprintf(stderr, "Invalid scanning option [%s]\n", args[0]);
704             return(-1);
705           }
706
707       /* Next arg */
708       args++;
709     }
710
711   /* Check if we have scan options */
712   if(scanflags)
713     {
714       wrq.u.data.pointer = (caddr_t) &scanopt;
715       wrq.u.data.length = sizeof(scanopt);
716       wrq.u.data.flags = scanflags;
717     }
718   else
719     {
720       wrq.u.data.pointer = NULL;
721       wrq.u.data.flags = 0;
722       wrq.u.data.length = 0;
723     }
724
725   /* If only 'last' was specified on command line, don't trigger a scan */
726   if(scanflags == IW_SCAN_HACK)
727     {
728       /* Skip waiting */
729       tv.tv_usec = 0;
730     }
731   else
732     {
733       /* Initiate Scanning */
734       if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
735         {
736           if((errno != EPERM) || (scanflags != 0))
737             {
738               fprintf(stderr, "%-8.16s  Interface doesn't support scanning : %s\n\n",
739                       ifname, strerror(errno));
740               return(-1);
741             }
742           /* If we don't have the permission to initiate the scan, we may
743            * still have permission to read left-over results.
744            * But, don't wait !!! */
745 #if 0
746           /* Not cool, it display for non wireless interfaces... */
747           fprintf(stderr, "%-8.16s  (Could not trigger scanning, just reading left-over results)\n", ifname);
748 #endif
749           tv.tv_usec = 0;
750         }
751     }
752   timeout -= tv.tv_usec;
753
754   /* Forever */
755   while(1)
756     {
757       fd_set            rfds;           /* File descriptors for select */
758       int               last_fd;        /* Last fd */
759       int               ret;
760
761       /* Guess what ? We must re-generate rfds each time */
762       FD_ZERO(&rfds);
763       last_fd = -1;
764
765       /* In here, add the rtnetlink fd in the list */
766
767       /* Wait until something happens */
768       ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
769
770       /* Check if there was an error */
771       if(ret < 0)
772         {
773           if(errno == EAGAIN || errno == EINTR)
774             continue;
775           fprintf(stderr, "Unhandled signal - exiting...\n");
776           return(-1);
777         }
778
779       /* Check if there was a timeout */
780       if(ret == 0)
781         {
782           unsigned char *       newbuf;
783
784         realloc:
785           /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
786           newbuf = realloc(buffer, buflen);
787           if(newbuf == NULL)
788             {
789               if(buffer)
790                 free(buffer);
791               fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
792               return(-1);
793             }
794           buffer = newbuf;
795
796           /* Try to read the results */
797           wrq.u.data.pointer = buffer;
798           wrq.u.data.flags = 0;
799           wrq.u.data.length = buflen;
800           if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
801             {
802               /* Check if buffer was too small (WE-17 only) */
803               if((errno == E2BIG) && (range.we_version_compiled > 16)
804                  && (buflen < 0xFFFF))
805                 {
806                   /* Some driver may return very large scan results, either
807                    * because there are many cells, or because they have many
808                    * large elements in cells (like IWEVCUSTOM). Most will
809                    * only need the regular sized buffer. We now use a dynamic
810                    * allocation of the buffer to satisfy everybody. Of course,
811                    * as we don't know in advance the size of the array, we try
812                    * various increasing sizes. Jean II */
813
814                   /* Check if the driver gave us any hints. */
815                   if(wrq.u.data.length > buflen)
816                     buflen = wrq.u.data.length;
817                   else
818                     buflen *= 2;
819
820                   /* wrq.u.data.length is 16 bits so max size is 65535 */
821                   if(buflen > 0xFFFF)
822                     buflen = 0xFFFF;
823
824                   /* Try again */
825                   goto realloc;
826                 }
827
828               /* Check if results not available yet */
829               if(errno == EAGAIN)
830                 {
831                   /* Restart timer for only 100ms*/
832                   tv.tv_sec = 0;
833                   tv.tv_usec = 100000;
834                   timeout -= tv.tv_usec;
835                   if(timeout > 0)
836                     continue;   /* Try again later */
837                 }
838
839               /* Bad error */
840               free(buffer);
841               fprintf(stderr, "%-8.16s  Failed to read scan data : %s\n\n",
842                       ifname, strerror(errno));
843               return(-2);
844             }
845           else
846             /* We have the results, go to process them */
847             break;
848         }
849
850       /* In here, check if event and event type
851        * if scan event, read results. All errors bad & no reset timeout */
852     }
853
854   if(wrq.u.data.length)
855     {
856       struct iw_event           iwe;
857       struct stream_descr       stream;
858       struct iwscan_state       state = { .ap_num = 1, .val_index = 0 };
859       int                       ret;
860       
861 #ifdef DEBUG
862       /* Debugging code. In theory useless, because it's debugged ;-) */
863       int       i;
864       printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
865       for(i = 1; i < wrq.u.data.length; i++)
866         printf(":%02X", buffer[i]);
867       printf("]\n");
868 #endif
869       printf("%-8.16s  Scan completed :\n", ifname);
870       iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
871       do
872         {
873           /* Extract an event and print it */
874           ret = iw_extract_event_stream(&stream, &iwe,
875                                         range.we_version_compiled);
876           if(ret > 0)
877             print_scanning_token(&stream, &iwe, &state,
878                                  &range, has_range);
879         }
880       while(ret > 0);
881       printf("\n");
882     }
883   else
884     printf("%-8.16s  No scan results\n\n", ifname);
885
886   free(buffer);
887   return(0);
888 }
889
890 /*********************** FREQUENCIES/CHANNELS ***********************/
891
892 /*------------------------------------------------------------------*/
893 /*
894  * Print the number of channels and available frequency for the device
895  */
896 static int
897 print_freq_info(int             skfd,
898                 char *          ifname,
899                 char *          args[],         /* Command line args */
900                 int             count)          /* Args count */
901 {
902   struct iwreq          wrq;
903   struct iw_range       range;
904   double                freq;
905   int                   k;
906   int                   channel;
907   char                  buffer[128];    /* Temporary buffer */
908
909   /* Avoid "Unused parameter" warning */
910   args = args; count = count;
911
912   /* Get list of frequencies / channels */
913   if(iw_get_range_info(skfd, ifname, &range) < 0)
914       fprintf(stderr, "%-8.16s  no frequency information.\n\n",
915                       ifname);
916   else
917     {
918       if(range.num_frequency > 0)
919         {
920           printf("%-8.16s  %d channels in total; available frequencies :\n",
921                  ifname, range.num_channels);
922           /* Print them all */
923           for(k = 0; k < range.num_frequency; k++)
924             {
925               freq = iw_freq2float(&(range.freq[k]));
926               iw_print_freq_value(buffer, sizeof(buffer), freq);
927               printf("          Channel %.2d : %s\n",
928                      range.freq[k].i, buffer);
929             }
930         }
931       else
932         printf("%-8.16s  %d channels\n",
933                ifname, range.num_channels);
934
935       /* Get current frequency / channel and display it */
936       if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
937         {
938           freq = iw_freq2float(&(wrq.u.freq));
939           channel = iw_freq_to_channel(freq, &range);
940           iw_print_freq(buffer, sizeof(buffer),
941                         freq, channel, wrq.u.freq.flags);
942           printf("          Current %s\n\n", buffer);
943         }
944     }
945   return(0);
946 }
947
948 /***************************** BITRATES *****************************/
949
950 /*------------------------------------------------------------------*/
951 /*
952  * Print the number of available bitrates for the device
953  */
954 static int
955 print_bitrate_info(int          skfd,
956                    char *       ifname,
957                    char *       args[],         /* Command line args */
958                    int          count)          /* Args count */
959 {
960   struct iwreq          wrq;
961   struct iw_range       range;
962   int                   k;
963   char                  buffer[128];
964
965   /* Avoid "Unused parameter" warning */
966   args = args; count = count;
967
968   /* Extract range info */
969   if(iw_get_range_info(skfd, ifname, &range) < 0)
970       fprintf(stderr, "%-8.16s  no bit-rate information.\n\n",
971                       ifname);
972   else
973     {
974       if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
975         {
976           printf("%-8.16s  %d available bit-rates :\n",
977                  ifname, range.num_bitrates);
978           /* Print them all */
979           for(k = 0; k < range.num_bitrates; k++)
980             {
981               iw_print_bitrate(buffer, sizeof(buffer), range.bitrate[k]);
982               /* Maybe this should be %10s */
983               printf("\t  %s\n", buffer);
984             }
985         }
986       else
987         printf("%-8.16s  unknown bit-rate information.\n", ifname);
988
989       /* Get current bit rate */
990       if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
991         {
992           iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
993           printf("          Current Bit Rate%c%s\n",
994                  (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
995         }
996
997       /* Try to get the broadcast bitrate if it exist... */
998       if(range.bitrate_capa & IW_BITRATE_BROADCAST)
999         {
1000           wrq.u.bitrate.flags = IW_BITRATE_BROADCAST;
1001           if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
1002             {
1003               iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
1004               printf("          Broadcast Bit Rate%c%s\n",
1005                      (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
1006             }
1007         }
1008
1009       printf("\n");
1010     }
1011   return(0);
1012 }
1013
1014 /************************* ENCRYPTION KEYS *************************/
1015
1016 /*------------------------------------------------------------------*/
1017 /*
1018  * Print all the available encryption keys for the device
1019  */
1020 static int
1021 print_keys_info(int             skfd,
1022                 char *          ifname,
1023                 char *          args[],         /* Command line args */
1024                 int             count)          /* Args count */
1025 {
1026   struct iwreq          wrq;
1027   struct iw_range       range;
1028   unsigned char         key[IW_ENCODING_TOKEN_MAX];
1029   unsigned int          k;
1030   char                  buffer[128];
1031
1032   /* Avoid "Unused parameter" warning */
1033   args = args; count = count;
1034
1035   /* Extract range info */
1036   if(iw_get_range_info(skfd, ifname, &range) < 0)
1037       fprintf(stderr, "%-8.16s  no encryption keys information.\n\n",
1038                       ifname);
1039   else
1040     {
1041       printf("%-8.16s  ", ifname);
1042       /* Print key sizes */
1043       if((range.num_encoding_sizes > 0) &&
1044          (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
1045         {
1046           printf("%d key sizes : %d", range.num_encoding_sizes,
1047                  range.encoding_size[0] * 8);
1048           /* Print them all */
1049           for(k = 1; k < range.num_encoding_sizes; k++)
1050             printf(", %d", range.encoding_size[k] * 8);
1051           printf("bits\n          ");
1052         }
1053       /* Print the keys and associate mode */
1054       printf("%d keys available :\n", range.max_encoding_tokens);
1055       for(k = 1; k <= range.max_encoding_tokens; k++)
1056         {
1057           wrq.u.data.pointer = (caddr_t) key;
1058           wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
1059           wrq.u.data.flags = k;
1060           if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
1061             {
1062               fprintf(stderr, "Error reading wireless keys (SIOCGIWENCODE): %s\n", strerror(errno));
1063               break;
1064             }
1065           if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
1066              (wrq.u.data.length == 0))
1067             printf("\t\t[%d]: off\n", k);
1068           else
1069             {
1070               /* Display the key */
1071               iw_print_key(buffer, sizeof(buffer),
1072                            key, wrq.u.data.length, wrq.u.data.flags);
1073               printf("\t\t[%d]: %s", k, buffer);
1074
1075               /* Other info... */
1076               printf(" (%d bits)", wrq.u.data.length * 8);
1077               printf("\n");
1078             }
1079         }
1080       /* Print current key index and mode */
1081       wrq.u.data.pointer = (caddr_t) key;
1082       wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
1083       wrq.u.data.flags = 0;     /* Set index to zero to get current */
1084       if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
1085         {
1086           /* Note : if above fails, we have already printed an error
1087            * message int the loop above */
1088           printf("          Current Transmit Key: [%d]\n",
1089                  wrq.u.data.flags & IW_ENCODE_INDEX);
1090           if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
1091             printf("          Security mode:restricted\n");
1092           if(wrq.u.data.flags & IW_ENCODE_OPEN)
1093             printf("          Security mode:open\n");
1094         }
1095
1096       printf("\n\n");
1097     }
1098   return(0);
1099 }
1100
1101 /************************* POWER MANAGEMENT *************************/
1102
1103 /*------------------------------------------------------------------*/
1104 /*
1105  * Print Power Management info for each device
1106  */
1107 static int
1108 get_pm_value(int                skfd,
1109              char *             ifname,
1110              struct iwreq *     pwrq,
1111              int                flags,
1112              char *             buffer,
1113              int                buflen,
1114              int                we_version_compiled)
1115 {
1116   /* Get Another Power Management value */
1117   pwrq->u.power.flags = flags;
1118   if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, pwrq) >= 0)
1119     {
1120       /* Let's check the value and its type */
1121       if(pwrq->u.power.flags & IW_POWER_TYPE)
1122         {
1123           iw_print_pm_value(buffer, buflen,
1124                             pwrq->u.power.value, pwrq->u.power.flags,
1125                             we_version_compiled);
1126           printf("\n                 %s", buffer);
1127         }
1128     }
1129   return(pwrq->u.power.flags);
1130 }
1131
1132 /*------------------------------------------------------------------*/
1133 /*
1134  * Print Power Management range for each type
1135  */
1136 static void
1137 print_pm_value_range(char *             name,
1138                      int                mask,
1139                      int                iwr_flags,
1140                      int                iwr_min,
1141                      int                iwr_max,
1142                      char *             buffer,
1143                      int                buflen,
1144                      int                we_version_compiled)
1145 {
1146   if(iwr_flags & mask)
1147     {
1148       int       flags = (iwr_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
1149       /* Display if auto or fixed */
1150       printf("%s %s ; ",
1151              (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
1152              name);
1153       /* Print the range */
1154       iw_print_pm_value(buffer, buflen,
1155                         iwr_min, flags | IW_POWER_MIN,
1156                         we_version_compiled);
1157       printf("%s\n                          ", buffer);
1158       iw_print_pm_value(buffer, buflen,
1159                         iwr_max, flags | IW_POWER_MAX,
1160                         we_version_compiled);
1161       printf("%s\n          ", buffer);
1162     }
1163 }
1164
1165 /*------------------------------------------------------------------*/
1166 /*
1167  * Power Management types of values
1168  */
1169 static const unsigned int pm_type_flags[] = {
1170   IW_POWER_PERIOD,
1171   IW_POWER_TIMEOUT,
1172   IW_POWER_SAVING,
1173 };
1174 static const int pm_type_flags_size = (sizeof(pm_type_flags)/sizeof(pm_type_flags[0]));
1175
1176 /*------------------------------------------------------------------*/
1177 /*
1178  * Print Power Management info for each device
1179  */
1180 static int
1181 print_pm_info(int               skfd,
1182               char *            ifname,
1183               char *            args[],         /* Command line args */
1184               int               count)          /* Args count */
1185 {
1186   struct iwreq          wrq;
1187   struct iw_range       range;
1188   char                  buffer[128];
1189
1190   /* Avoid "Unused parameter" warning */
1191   args = args; count = count;
1192
1193   /* Extract range info */
1194   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1195      (range.we_version_compiled < 10))
1196       fprintf(stderr, "%-8.16s  no power management information.\n\n",
1197                       ifname);
1198   else
1199     {
1200       printf("%-8.16s  ", ifname);
1201
1202       /* Display modes availables */
1203       if(range.pm_capa & IW_POWER_MODE)
1204         {
1205           printf("Supported modes :\n          ");
1206           if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
1207             printf("\t\to Receive all packets (unicast & multicast)\n          ");
1208           if(range.pm_capa & IW_POWER_UNICAST_R)
1209             printf("\t\to Receive Unicast only (discard multicast)\n          ");
1210           if(range.pm_capa & IW_POWER_MULTICAST_R)
1211             printf("\t\to Receive Multicast only (discard unicast)\n          ");
1212           if(range.pm_capa & IW_POWER_FORCE_S)
1213             printf("\t\to Force sending using Power Management\n          ");
1214           if(range.pm_capa & IW_POWER_REPEATER)
1215             printf("\t\to Repeat multicast\n          ");
1216         }
1217       /* Display min/max period availables */
1218       print_pm_value_range("period ", IW_POWER_PERIOD,
1219                            range.pmp_flags, range.min_pmp, range.max_pmp,
1220                            buffer, sizeof(buffer), range.we_version_compiled);
1221       /* Display min/max timeout availables */
1222       print_pm_value_range("timeout", IW_POWER_TIMEOUT,
1223                            range.pmt_flags, range.min_pmt, range.max_pmt,
1224                            buffer, sizeof(buffer), range.we_version_compiled);
1225       /* Display min/max saving availables */
1226       print_pm_value_range("saving ", IW_POWER_SAVING,
1227                            range.pms_flags, range.min_pms, range.max_pms,
1228                            buffer, sizeof(buffer), range.we_version_compiled);
1229
1230       /* Get current Power Management settings */
1231       wrq.u.power.flags = 0;
1232       if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
1233         {
1234           int   flags = wrq.u.power.flags;
1235
1236           /* Is it disabled ? */
1237           if(wrq.u.power.disabled)
1238             printf("Current mode:off\n");
1239           else
1240             {
1241               unsigned int      pm_type = 0;
1242               unsigned int      pm_mask = 0;
1243               unsigned int      remain_mask = range.pm_capa & IW_POWER_TYPE;
1244               int               i = 0;
1245
1246               /* Let's check the mode */
1247               iw_print_pm_mode(buffer, sizeof(buffer), flags);
1248               printf("Current %s", buffer);
1249
1250               /* Let's check if nothing (simply on) */
1251               if((flags & IW_POWER_MODE) == IW_POWER_ON)
1252                 printf("mode:on");
1253
1254               /* Let's check the value and its type */
1255               if(wrq.u.power.flags & IW_POWER_TYPE)
1256                 {
1257                   iw_print_pm_value(buffer, sizeof(buffer),
1258                                     wrq.u.power.value, wrq.u.power.flags,
1259                                     range.we_version_compiled);
1260                   printf("\n                 %s", buffer);
1261                 }
1262
1263               while(1)
1264                 {
1265                   /* Deal with min/max for the current value */
1266                   pm_mask = 0;
1267                   /* If we have been returned a MIN value, ask for the MAX */
1268                   if(flags & IW_POWER_MIN)
1269                     pm_mask = IW_POWER_MAX;
1270                   /* If we have been returned a MAX value, ask for the MIN */
1271                   if(flags & IW_POWER_MAX)
1272                     pm_mask = IW_POWER_MIN;
1273                   /* If we have something to ask for... */
1274                   if(pm_mask)
1275                     {
1276                       pm_mask |= pm_type;
1277                       get_pm_value(skfd, ifname, &wrq, pm_mask,
1278                                    buffer, sizeof(buffer),
1279                                    range.we_version_compiled);
1280                     }
1281
1282                   /* Remove current type from mask */
1283                   remain_mask &= ~(wrq.u.power.flags);
1284
1285                   /* Check what other types we still have to read */
1286                   while(i < pm_type_flags_size)
1287                     {
1288                       pm_type = remain_mask & pm_type_flags[i];
1289                       if(pm_type)
1290                         break;
1291                       i++;
1292                     }
1293                   /* Nothing anymore : exit the loop */
1294                   if(!pm_type)
1295                     break;
1296
1297                   /* Ask for this other type of value */
1298                   flags = get_pm_value(skfd, ifname, &wrq, pm_type,
1299                                        buffer, sizeof(buffer),
1300                                        range.we_version_compiled);
1301                   /* Loop back for min/max */
1302                 }
1303               printf("\n");
1304             }
1305         }
1306       printf("\n");
1307     }
1308   return(0);
1309 }
1310
1311 #ifndef WE_ESSENTIAL
1312 /************************** TRANSMIT POWER **************************/
1313
1314 /*------------------------------------------------------------------*/
1315 /*
1316  * Print the number of available transmit powers for the device
1317  */
1318 static int
1319 print_txpower_info(int          skfd,
1320                    char *       ifname,
1321                    char *       args[],         /* Command line args */
1322                    int          count)          /* Args count */
1323 {
1324   struct iwreq          wrq;
1325   struct iw_range       range;
1326   int                   dbm;
1327   int                   mwatt;
1328   int                   k;
1329
1330   /* Avoid "Unused parameter" warning */
1331   args = args; count = count;
1332
1333   /* Extract range info */
1334   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1335      (range.we_version_compiled < 10))
1336       fprintf(stderr, "%-8.16s  no transmit-power information.\n\n",
1337                       ifname);
1338   else
1339     {
1340       if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
1341         printf("%-8.16s  unknown transmit-power information.\n\n", ifname);
1342       else
1343         {
1344           printf("%-8.16s  %d available transmit-powers :\n",
1345                  ifname, range.num_txpower);
1346           /* Print them all */
1347           for(k = 0; k < range.num_txpower; k++)
1348             {
1349               /* Check for relative values */
1350               if(range.txpower_capa & IW_TXPOW_RELATIVE)
1351                 {
1352                   printf("\t  %d (no units)\n", range.txpower[k]);
1353                 }
1354               else
1355                 {
1356                   if(range.txpower_capa & IW_TXPOW_MWATT)
1357                     {
1358                       dbm = iw_mwatt2dbm(range.txpower[k]);
1359                       mwatt = range.txpower[k];
1360                     }
1361                   else
1362                     {
1363                       dbm = range.txpower[k];
1364                       mwatt = iw_dbm2mwatt(range.txpower[k]);
1365                     }
1366                   printf("\t  %d dBm  \t(%d mW)\n", dbm, mwatt);
1367                 }
1368             }
1369         }
1370
1371       /* Get current Transmit Power */
1372       if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
1373         {
1374           printf("          Current Tx-Power");
1375           /* Disabled ? */
1376           if(wrq.u.txpower.disabled)
1377             printf(":off\n\n");
1378           else
1379             {
1380               /* Fixed ? */
1381               if(wrq.u.txpower.fixed)
1382                 printf("=");
1383               else
1384                 printf(":");
1385               /* Check for relative values */
1386               if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
1387                 {
1388                   /* I just hate relative value, because they are
1389                    * driver specific, so not very meaningfull to apps.
1390                    * But, we have to support that, because
1391                    * this is the way hardware is... */
1392                   printf("\t  %d (no units)\n", wrq.u.txpower.value);
1393                 }
1394               else
1395                 {
1396                   if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
1397                     {
1398                       dbm = iw_mwatt2dbm(wrq.u.txpower.value);
1399                       mwatt = wrq.u.txpower.value;
1400                     }
1401                   else
1402                     {
1403                       dbm = wrq.u.txpower.value;
1404                       mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
1405                     }
1406                   printf("%d dBm  \t(%d mW)\n\n", dbm, mwatt);
1407                 }
1408             }
1409         }
1410     }
1411   return(0);
1412 }
1413
1414 /*********************** RETRY LIMIT/LIFETIME ***********************/
1415
1416 /*------------------------------------------------------------------*/
1417 /*
1418  * Print one retry value
1419  */
1420 static int
1421 get_retry_value(int             skfd,
1422                 char *          ifname,
1423                 struct iwreq *  pwrq,
1424                 int             flags,
1425                 char *          buffer,
1426                 int             buflen,
1427                 int             we_version_compiled)
1428 {
1429   /* Get Another retry value */
1430   pwrq->u.retry.flags = flags;
1431   if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, pwrq) >= 0)
1432     {
1433       /* Let's check the value and its type */
1434       if(pwrq->u.retry.flags & IW_RETRY_TYPE)
1435         {
1436           iw_print_retry_value(buffer, buflen,
1437                                pwrq->u.retry.value, pwrq->u.retry.flags,
1438                                we_version_compiled);
1439           printf("%s\n                 ", buffer);
1440         }
1441     }
1442   return(pwrq->u.retry.flags);
1443 }
1444
1445 /*------------------------------------------------------------------*/
1446 /*
1447  * Print Power Management range for each type
1448  */
1449 static void
1450 print_retry_value_range(char *          name,
1451                         int             mask,
1452                         int             iwr_flags,
1453                         int             iwr_min,
1454                         int             iwr_max,
1455                         char *          buffer,
1456                         int             buflen,
1457                         int             we_version_compiled)
1458 {
1459   if(iwr_flags & mask)
1460     {
1461       int       flags = (iwr_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
1462       /* Display if auto or fixed */
1463       printf("%s %s ; ",
1464              (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
1465              name);
1466       /* Print the range */
1467       iw_print_retry_value(buffer, buflen,
1468                            iwr_min, flags | IW_POWER_MIN,
1469                            we_version_compiled);
1470       printf("%s\n                           ", buffer);
1471       iw_print_retry_value(buffer, buflen,
1472                            iwr_max, flags | IW_POWER_MAX,
1473                            we_version_compiled);
1474       printf("%s\n          ", buffer);
1475     }
1476 }
1477
1478 /*------------------------------------------------------------------*/
1479 /*
1480  * Print Retry info for each device
1481  */
1482 static int
1483 print_retry_info(int            skfd,
1484                  char *         ifname,
1485                  char *         args[],         /* Command line args */
1486                  int            count)          /* Args count */
1487 {
1488   struct iwreq          wrq;
1489   struct iw_range       range;
1490   char                  buffer[128];
1491
1492   /* Avoid "Unused parameter" warning */
1493   args = args; count = count;
1494
1495   /* Extract range info */
1496   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1497      (range.we_version_compiled < 11))
1498     fprintf(stderr, "%-8.16s  no retry limit/lifetime information.\n\n",
1499             ifname);
1500   else
1501     {
1502       printf("%-8.16s  ", ifname);
1503
1504       /* Display min/max limit availables */
1505       print_retry_value_range("limit   ", IW_RETRY_LIMIT, range.retry_flags,
1506                               range.min_retry, range.max_retry,
1507                               buffer, sizeof(buffer),
1508                               range.we_version_compiled);
1509       /* Display min/max lifetime availables */
1510       print_retry_value_range("lifetime", IW_RETRY_LIFETIME, 
1511                               range.r_time_flags,
1512                               range.min_r_time, range.max_r_time,
1513                               buffer, sizeof(buffer),
1514                               range.we_version_compiled);
1515
1516       /* Get current retry settings */
1517       wrq.u.retry.flags = 0;
1518       if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
1519         {
1520           int   flags = wrq.u.retry.flags;
1521
1522           /* Is it disabled ? */
1523           if(wrq.u.retry.disabled)
1524             printf("Current mode:off\n          ");
1525           else
1526             {
1527               unsigned int      retry_type = 0;
1528               unsigned int      retry_mask = 0;
1529               unsigned int      remain_mask = range.retry_capa & IW_RETRY_TYPE;
1530
1531               /* Let's check the mode */
1532               printf("Current mode:on\n                 ");
1533
1534               /* Let's check the value and its type */
1535               if(wrq.u.retry.flags & IW_RETRY_TYPE)
1536                 {
1537                   iw_print_retry_value(buffer, sizeof(buffer),
1538                                        wrq.u.retry.value, wrq.u.retry.flags,
1539                                        range.we_version_compiled);
1540                   printf("%s\n                 ", buffer);
1541                 }
1542
1543               while(1)
1544                 {
1545                   /* Deal with min/max/short/long for the current value */
1546                   retry_mask = 0;
1547                   /* If we have been returned a MIN value, ask for the MAX */
1548                   if(flags & IW_RETRY_MIN)
1549                     retry_mask = IW_RETRY_MAX;
1550                   /* If we have been returned a MAX value, ask for the MIN */
1551                   if(flags & IW_RETRY_MAX)
1552                     retry_mask = IW_RETRY_MIN;
1553                   /* Same for SHORT and LONG */
1554                   if(flags & IW_RETRY_SHORT)
1555                     retry_mask = IW_RETRY_LONG;
1556                   if(flags & IW_RETRY_LONG)
1557                     retry_mask = IW_RETRY_SHORT;
1558                   /* If we have something to ask for... */
1559                   if(retry_mask)
1560                     {
1561                       retry_mask |= retry_type;
1562                       get_retry_value(skfd, ifname, &wrq, retry_mask,
1563                                       buffer, sizeof(buffer),
1564                                       range.we_version_compiled);
1565                     }
1566
1567                   /* And if we have both a limit and a lifetime,
1568                    * ask the other one */
1569                   remain_mask &= ~(wrq.u.retry.flags);
1570                   retry_type = remain_mask;
1571                   /* Nothing anymore : exit the loop */
1572                   if(!retry_type)
1573                     break;
1574
1575                   /* Ask for this other type of value */
1576                   flags = get_retry_value(skfd, ifname, &wrq, retry_type,
1577                                           buffer, sizeof(buffer),
1578                                           range.we_version_compiled);
1579                   /* Loop back for min/max/short/long */
1580                 }
1581             }
1582         }
1583       printf("\n");
1584     }
1585   return(0);
1586 }
1587
1588 /************************ ACCESS POINT LIST ************************/
1589 /*
1590  * Note : now that we have scanning support, this is depracted and
1591  * won't survive long. Actually, next version it's out !
1592  */
1593
1594 /*------------------------------------------------------------------*/
1595 /*
1596  * Display the list of ap addresses and the associated stats
1597  * Exacly the same as the spy list, only with different IOCTL and messages
1598  */
1599 static int
1600 print_ap_info(int       skfd,
1601               char *    ifname,
1602               char *    args[],         /* Command line args */
1603               int       count)          /* Args count */
1604 {
1605   struct iwreq          wrq;
1606   char          buffer[(sizeof(struct iw_quality) +
1607                         sizeof(struct sockaddr)) * IW_MAX_AP];
1608   char          temp[128];
1609   struct sockaddr *     hwa;
1610   struct iw_quality *   qual;
1611   iwrange       range;
1612   int           has_range = 0;
1613   int           has_qual = 0;
1614   int           n;
1615   int           i;
1616
1617   /* Avoid "Unused parameter" warning */
1618   args = args; count = count;
1619
1620   /* Collect stats */
1621   wrq.u.data.pointer = (caddr_t) buffer;
1622   wrq.u.data.length = IW_MAX_AP;
1623   wrq.u.data.flags = 0;
1624   if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
1625     {
1626       fprintf(stderr, "%-8.16s  Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
1627       return(-1);
1628     }
1629
1630   /* Number of addresses */
1631   n = wrq.u.data.length;
1632   has_qual = wrq.u.data.flags;
1633
1634   /* The two lists */
1635   hwa = (struct sockaddr *) buffer;
1636   qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
1637
1638   /* Check if we have valid mac address type */
1639   if(iw_check_mac_addr_type(skfd, ifname) < 0)
1640     {
1641       fprintf(stderr, "%-8.16s  Interface doesn't support MAC addresses\n\n", ifname);
1642       return(-2);
1643     }
1644
1645   /* Get range info if we can */
1646   if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
1647     has_range = 1;
1648
1649   /* Display it */
1650   if(n == 0)
1651     printf("%-8.16s  No Peers/Access-Point in range\n", ifname);
1652   else
1653     printf("%-8.16s  Peers/Access-Points in range:\n", ifname);
1654   for(i = 0; i < n; i++)
1655     {
1656       if(has_qual)
1657         {
1658           /* Print stats for this address */
1659           printf("    %s : ", iw_saether_ntop(&hwa[i], temp));
1660           iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
1661           printf("%s\n", temp);
1662         }
1663       else
1664         /* Only print the address */
1665         printf("    %s\n", iw_saether_ntop(&hwa[i], temp));
1666     }
1667   printf("\n");
1668   return(0);
1669 }
1670
1671 /******************** WIRELESS EVENT CAPABILITY ********************/
1672
1673 static const char *     event_capa_req[] =
1674 {
1675   [SIOCSIWNWID  - SIOCIWFIRST] = "Set NWID (kernel generated)",
1676   [SIOCSIWFREQ  - SIOCIWFIRST] = "Set Frequency/Channel (kernel generated)",
1677   [SIOCGIWFREQ  - SIOCIWFIRST] = "New Frequency/Channel",
1678   [SIOCSIWMODE  - SIOCIWFIRST] = "Set Mode (kernel generated)",
1679   [SIOCGIWTHRSPY - SIOCIWFIRST] = "Spy threshold crossed",
1680   [SIOCGIWAP    - SIOCIWFIRST] = "New Access Point/Cell address - roaming",
1681   [SIOCGIWSCAN  - SIOCIWFIRST] = "Scan request completed",
1682   [SIOCSIWESSID - SIOCIWFIRST] = "Set ESSID (kernel generated)",
1683   [SIOCGIWESSID - SIOCIWFIRST] = "New ESSID",
1684   [SIOCGIWRATE  - SIOCIWFIRST] = "New bit-rate",
1685   [SIOCSIWENCODE - SIOCIWFIRST] = "Set Encoding (kernel generated)",
1686   [SIOCGIWPOWER - SIOCIWFIRST] = NULL,
1687 };
1688
1689 static const char *     event_capa_evt[] =
1690 {
1691   [IWEVTXDROP   - IWEVFIRST] = "Tx packet dropped - retry exceeded",
1692   [IWEVCUSTOM   - IWEVFIRST] = "Custom driver event",
1693   [IWEVREGISTERED - IWEVFIRST] = "Registered node",
1694   [IWEVEXPIRED  - IWEVFIRST] = "Expired node",
1695 };
1696
1697 static const struct iwmask_name iw_scan_capa_name[] = {
1698   { IW_SCAN_CAPA_ESSID,         "ESSID" },
1699   { IW_SCAN_CAPA_BSSID,         "BSSID" },
1700   { IW_SCAN_CAPA_CHANNEL,       "Channel" },
1701   { IW_SCAN_CAPA_MODE,          "Mode" },
1702   { IW_SCAN_CAPA_RATE,          "Rate" },
1703   { IW_SCAN_CAPA_TYPE,          "Type" },
1704   { IW_SCAN_CAPA_TIME,          "Time" },
1705 };
1706 #define IW_SCAN_CAPA_NUM        IW_ARRAY_LEN(iw_scan_capa_name)
1707
1708 /*------------------------------------------------------------------*/
1709 /*
1710  * Print the event capability for the device
1711  */
1712 static int
1713 print_event_capa_info(int               skfd,
1714                       char *            ifname,
1715                       char *            args[],         /* Command line args */
1716                       int               count)          /* Args count */
1717 {
1718   struct iw_range       range;
1719   int                   cmd;
1720
1721   /* Avoid "Unused parameter" warning */
1722   args = args; count = count;
1723
1724   /* Extract range info */
1725   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1726      (range.we_version_compiled < 10))
1727       fprintf(stderr, "%-8.16s  no wireless event capability information.\n\n",
1728                       ifname);
1729   else
1730     {
1731 #ifdef DEBUG
1732       /* Debugging ;-) */
1733       for(cmd = 0x8B00; cmd < 0x8C0F; cmd++)
1734         {
1735           int idx = IW_EVENT_CAPA_INDEX(cmd);
1736           int mask = IW_EVENT_CAPA_MASK(cmd);
1737           printf("0x%X - %d - %X\n", cmd, idx, mask);
1738         }
1739 #endif
1740
1741       printf("%-8.16s  Wireless Events supported :\n", ifname);
1742
1743       for(cmd = SIOCIWFIRST; cmd <= SIOCGIWPOWER; cmd++)
1744         {
1745           int idx = IW_EVENT_CAPA_INDEX(cmd);
1746           int mask = IW_EVENT_CAPA_MASK(cmd);
1747           if(range.event_capa[idx] & mask)
1748             printf("          0x%04X : %s\n",
1749                    cmd, event_capa_req[cmd - SIOCIWFIRST]);
1750         }
1751       for(cmd = IWEVFIRST; cmd <= IWEVEXPIRED; cmd++)
1752         {
1753           int idx = IW_EVENT_CAPA_INDEX(cmd);
1754           int mask = IW_EVENT_CAPA_MASK(cmd);
1755           if(range.event_capa[idx] & mask)
1756             printf("          0x%04X : %s\n",
1757                    cmd, event_capa_evt[cmd - IWEVFIRST]);
1758         }
1759       printf("\n");
1760
1761       /* Add Scanning Capacity as a bonus, if available */
1762       if(range.scan_capa != 0)
1763         {
1764           printf("%-8.16s  Scanning capabilities :", ifname);
1765           iw_print_mask_name(range.scan_capa,
1766                              iw_scan_capa_name, IW_SCAN_CAPA_NUM,
1767                              "\n\t\t- ");
1768           printf("\n\n");
1769         }
1770     }
1771   return(0);
1772 }
1773
1774 /*************************** WPA SUPPORT ***************************/
1775
1776 /*------------------------------------------------------------------*/
1777 /*
1778  * Print the authentication parameters for the device
1779  */
1780 static int
1781 print_auth_info(int             skfd,
1782                 char *          ifname,
1783                 char *          args[],         /* Command line args */
1784                 int             count)          /* Args count */
1785 {
1786   struct iwreq          wrq;
1787   struct iw_range       range;
1788   unsigned int          k;
1789
1790   /* Avoid "Unused parameter" warning */
1791   args = args; count = count;
1792
1793   /* Extract range info */
1794   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1795      (range.we_version_compiled < 18))
1796       fprintf(stderr, "%-8.16s  no authentication information.\n\n",
1797                       ifname);
1798   else
1799     {
1800       /* Print WPA/802.1x/802.11i security parameters */
1801       if(!range.enc_capa)
1802         {
1803         printf("%-8.16s  unknown authentication information.\n\n", ifname);
1804         }
1805       else
1806         {
1807           /* Display advanced encryption capabilities */
1808           printf("%-8.16s  Authentication capabilities :", ifname);
1809           iw_print_mask_name(range.enc_capa,
1810                              iw_auth_capa_name, IW_AUTH_CAPA_NUM,
1811                                  "\n\t\t");
1812           printf("\n");
1813
1814           /* Extract all auth settings */
1815           for(k = 0; k < IW_AUTH_SETTINGS_NUM; k++)
1816             { 
1817               wrq.u.param.flags = iw_auth_settings[k].value;
1818               if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
1819                 {
1820                   printf("          Current %s :", iw_auth_settings[k].label);
1821                   if(iw_auth_settings[k].names != NULL)
1822                     iw_print_mask_name(wrq.u.param.value,
1823                                        iw_auth_settings[k].names,
1824                                        iw_auth_settings[k].num_names,
1825                                        "\n\t\t");
1826                   else
1827                     printf((wrq.u.param.value) ? " yes" : " no");
1828                   printf("\n");
1829                 }
1830             }
1831         }
1832
1833       printf("\n\n");
1834     }
1835   return(0);
1836 }
1837
1838 /*------------------------------------------------------------------*/
1839 /*
1840  * Print all the available wpa keys for the device
1841  */
1842 static int
1843 print_wpakeys_info(int          skfd,
1844                    char *       ifname,
1845                    char *       args[],         /* Command line args */
1846                    int          count)          /* Args count */
1847 {
1848   struct iwreq          wrq;
1849   struct iw_range       range;
1850   unsigned char         extbuf[IW_EXTKEY_SIZE];
1851   struct iw_encode_ext  *extinfo;
1852   unsigned int          k;
1853   char                  buffer[128];
1854
1855   /* Avoid "Unused parameter" warning */
1856   args = args; count = count;
1857
1858   /* This always point to the same place */
1859   extinfo = (struct iw_encode_ext *) extbuf;
1860
1861   /* Extract range info */
1862   if(iw_get_range_info(skfd, ifname, &range) < 0)
1863       fprintf(stderr, "%-8.16s  no wpa key information.\n\n",
1864                       ifname);
1865   else
1866     {
1867       printf("%-8.16s  ", ifname);
1868       /* Print key sizes */
1869       if((range.num_encoding_sizes > 0) &&
1870          (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
1871         {
1872           printf("%d key sizes : %d", range.num_encoding_sizes,
1873                  range.encoding_size[0] * 8);
1874           /* Print them all */
1875           for(k = 1; k < range.num_encoding_sizes; k++)
1876             printf(", %d", range.encoding_size[k] * 8);
1877           printf("bits\n          ");
1878         }
1879
1880       /* Print the keys */
1881       printf("%d keys available :\n", range.max_encoding_tokens);
1882       for(k = 1; k <= range.max_encoding_tokens; k++)
1883         {
1884           /* Cleanup. Driver may not fill everything */
1885           memset(extbuf, '\0', IW_EXTKEY_SIZE);
1886
1887           /* Get whole struct containing one WPA key */
1888           wrq.u.data.pointer = (caddr_t) extbuf;
1889           wrq.u.data.length = IW_EXTKEY_SIZE;
1890           wrq.u.data.flags = k;
1891           if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) < 0)
1892             {
1893               fprintf(stderr, "Error reading wpa keys (SIOCGIWENCODEEXT): %s\n", strerror(errno));
1894               break;
1895             }
1896
1897           /* Sanity check */
1898           if(wrq.u.data.length < 
1899              (sizeof(struct iw_encode_ext) + extinfo->key_len))
1900             break;
1901
1902           /* Check if key is disabled */
1903           if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
1904              (extinfo->key_len == 0))
1905             printf("\t\t[%d]: off\n", k);
1906           else
1907             {
1908               /* Display the key */
1909               iw_print_key(buffer, sizeof(buffer),
1910                            extinfo->key, extinfo->key_len, wrq.u.data.flags);
1911               printf("\t\t[%d]: %s", k, buffer);
1912
1913               /* Key size */
1914               printf(" (%d bits)", extinfo->key_len * 8);
1915               printf("\n");
1916
1917               /* Other info... */
1918               printf("\t\t     Address: %s\n",
1919                      iw_saether_ntop(&extinfo->addr, buffer));
1920
1921               printf("\t\t     Algorithm:");
1922               iw_print_value_name(extinfo->alg,
1923                                   iw_encode_alg_name, IW_ENCODE_ALG_NUM);
1924
1925               printf("\n\t\t     Flags: 0x%08x\n", extinfo->ext_flags);
1926               if (extinfo->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID)
1927                 printf("\t\t        tx-seq-valid\n");
1928               if (extinfo->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
1929                 printf("\t\t        rx-seq-valid\n");
1930               if (extinfo->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1931                 printf("\t\t        group-key\n");
1932             }
1933         }
1934       /* Print current key index and mode */
1935       wrq.u.data.pointer = (caddr_t) extbuf;
1936       wrq.u.data.length = IW_EXTKEY_SIZE;
1937       wrq.u.data.flags = 0;     /* Set index to zero to get current */
1938       if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) >= 0)
1939         {
1940           /* Note : if above fails, we have already printed an error
1941            * message int the loop above */
1942           printf("          Current Transmit Key: [%d]\n",
1943                  wrq.u.data.flags & IW_ENCODE_INDEX);
1944           if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
1945             printf("          Security mode:restricted\n");
1946           if(wrq.u.data.flags & IW_ENCODE_OPEN)
1947             printf("          Security mode:open\n");
1948         }
1949
1950       printf("\n\n");
1951     }
1952   return(0);
1953 }
1954
1955 /*------------------------------------------------------------------*/
1956 /*
1957  * Print the Generic IE for the device
1958  * Note : indentation is broken. We need to fix that.
1959  */
1960 static int
1961 print_gen_ie_info(int           skfd,
1962                   char *        ifname,
1963                   char *        args[],         /* Command line args */
1964                   int           count)          /* Args count */
1965 {
1966   struct iwreq          wrq;
1967   unsigned char         buf[IW_GENERIC_IE_MAX];
1968
1969   /* Avoid "Unused parameter" warning */
1970   args = args; count = count;
1971
1972   wrq.u.data.pointer = (caddr_t)buf;
1973   wrq.u.data.length = IW_GENERIC_IE_MAX;
1974   wrq.u.data.flags = 0;
1975
1976   if(iw_get_ext(skfd, ifname, SIOCGIWGENIE, &wrq) < 0)
1977     fprintf(stderr, "%-8.16s  no generic IE (%s).\n\n",
1978             ifname, strerror(errno));
1979   else
1980     {
1981       fprintf(stderr, "%-8.16s\n", ifname);
1982       if(wrq.u.data.length == 0)
1983         printf("          empty generic IE\n");
1984       else
1985         iw_print_gen_ie(buf, wrq.u.data.length);
1986       printf("\n");
1987     }
1988   return(0);
1989 }
1990
1991 /**************************** MODULATION ****************************/
1992
1993 /*------------------------------------------------------------------*/
1994 /*
1995  * Print Modulation info for each device
1996  */
1997 static int
1998 print_modul_info(int            skfd,
1999                  char *         ifname,
2000                  char *         args[],         /* Command line args */
2001                  int            count)          /* Args count */
2002 {
2003   struct iwreq          wrq;
2004   struct iw_range       range;
2005
2006   /* Avoid "Unused parameter" warning */
2007   args = args; count = count;
2008
2009   /* Extract range info */
2010   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
2011      (range.we_version_compiled < 11))
2012     fprintf(stderr, "%-8.16s  no modulation information.\n\n",
2013             ifname);
2014   else
2015     {
2016       if(range.modul_capa == 0x0)
2017         printf("%-8.16s  unknown modulation information.\n\n", ifname);
2018       else
2019         {
2020           int i;
2021           printf("%-8.16s  Modulations available :\n", ifname);
2022
2023           /* Display each modulation available */
2024           for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
2025             {
2026               if((range.modul_capa & iw_modul_list[i].mask)
2027                  == iw_modul_list[i].mask)
2028                 printf("              %-8s: %s\n",
2029                        iw_modul_list[i].cmd, iw_modul_list[i].verbose);
2030             }
2031
2032           /* Get current modulations settings */
2033           wrq.u.param.flags = 0;
2034           if(iw_get_ext(skfd, ifname, SIOCGIWMODUL, &wrq) >= 0)
2035             {
2036               unsigned int      modul = wrq.u.param.value;
2037               int               n = 0;
2038
2039               printf("          Current modulations %c",
2040                      wrq.u.param.fixed ? '=' : ':');
2041
2042               /* Display each modulation enabled */
2043               for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
2044                 {
2045                   if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
2046                     {
2047                       if((n++ % 8) == 0)
2048                         printf("\n              ");
2049                       else
2050                         printf(" ; ");
2051                       printf("%s", iw_modul_list[i].cmd);
2052                     }
2053                 }
2054
2055               printf("\n");
2056             }
2057           printf("\n");
2058         }
2059     }
2060   return(0);
2061 }
2062 #endif  /* WE_ESSENTIAL */
2063
2064 /************************* COMMON UTILITIES *************************/
2065 /*
2066  * This section was initially written by Michael Tokarev <mjt@tls.msk.ru>
2067  * but heavily modified by me ;-)
2068  */
2069
2070 /*------------------------------------------------------------------*/
2071 /*
2072  * Map command line arguments to the proper procedure...
2073  */
2074 typedef struct iwlist_entry {
2075   const char *          cmd;            /* Command line shorthand */
2076   iw_enum_handler       fn;             /* Subroutine */
2077   int                   max_count;
2078   const char *          argsname;       /* Args as human readable string */
2079 } iwlist_cmd;
2080
2081 static const struct iwlist_entry iwlist_cmds[] = {
2082   { "scanning",         print_scanning_info,    -1, "[essid NNN] [last]" },
2083   { "frequency",        print_freq_info,        0, NULL },
2084   { "channel",          print_freq_info,        0, NULL },
2085   { "bitrate",          print_bitrate_info,     0, NULL },
2086   { "rate",             print_bitrate_info,     0, NULL },
2087   { "encryption",       print_keys_info,        0, NULL },
2088   { "keys",             print_keys_info,        0, NULL },
2089   { "power",            print_pm_info,          0, NULL },
2090 #ifndef WE_ESSENTIAL
2091   { "txpower",          print_txpower_info,     0, NULL },
2092   { "retry",            print_retry_info,       0, NULL },
2093   { "ap",               print_ap_info,          0, NULL },
2094   { "accesspoints",     print_ap_info,          0, NULL },
2095   { "peers",            print_ap_info,          0, NULL },
2096   { "event",            print_event_capa_info,  0, NULL },
2097   { "auth",             print_auth_info,        0, NULL },
2098   { "wpakeys",          print_wpakeys_info,     0, NULL },
2099   { "genie",            print_gen_ie_info,      0, NULL },
2100   { "modulation",       print_modul_info,       0, NULL },
2101 #endif  /* WE_ESSENTIAL */
2102   { NULL, NULL, 0, 0 },
2103 };
2104
2105 /*------------------------------------------------------------------*/
2106 /*
2107  * Find the most appropriate command matching the command line
2108  */
2109 static inline const iwlist_cmd *
2110 find_command(const char *       cmd)
2111 {
2112   const iwlist_cmd *    found = NULL;
2113   int                   ambig = 0;
2114   unsigned int          len = strlen(cmd);
2115   int                   i;
2116
2117   /* Go through all commands */
2118   for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
2119     {
2120       /* No match -> next one */
2121       if(strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0)
2122         continue;
2123
2124       /* Exact match -> perfect */
2125       if(len == strlen(iwlist_cmds[i].cmd))
2126         return &iwlist_cmds[i];
2127
2128       /* Partial match */
2129       if(found == NULL)
2130         /* First time */
2131         found = &iwlist_cmds[i];
2132       else
2133         /* Another time */
2134         if (iwlist_cmds[i].fn != found->fn)
2135           ambig = 1;
2136     }
2137
2138   if(found == NULL)
2139     {
2140       fprintf(stderr, "iwlist: unknown command `%s' (check 'iwlist --help').\n", cmd);
2141       return NULL;
2142     }
2143
2144   if(ambig)
2145     {
2146       fprintf(stderr, "iwlist: command `%s' is ambiguous (check 'iwlist --help').\n", cmd);
2147       return NULL;
2148     }
2149
2150   return found;
2151 }
2152
2153 /*------------------------------------------------------------------*/
2154 /*
2155  * Display help
2156  */
2157 static void iw_usage(int status)
2158 {
2159   FILE *                f = status ? stderr : stdout;
2160   int                   i;
2161
2162   for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
2163     {
2164       fprintf(f, "%s [interface] %s %s\n",
2165               (i ? "             " : "Usage: iwlist"),
2166               iwlist_cmds[i].cmd,
2167               iwlist_cmds[i].argsname ? iwlist_cmds[i].argsname : "");
2168     }
2169
2170   exit(status);
2171 }
2172
2173 /******************************* MAIN ********************************/
2174
2175 /*------------------------------------------------------------------*/
2176 /*
2177  * The main !
2178  */
2179 int
2180 main(int        argc,
2181      char **    argv)
2182 {
2183   int skfd;                     /* generic raw socket desc.     */
2184   char *dev;                    /* device name                  */
2185   char *cmd;                    /* command                      */
2186   char **args;                  /* Command arguments */
2187   int count;                    /* Number of arguments */
2188   const iwlist_cmd *iwcmd;
2189   int goterr = 0;
2190
2191   if(argc < 2)
2192     iw_usage(1);
2193
2194   /* Those don't apply to all interfaces */
2195   if((argc == 2) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
2196     iw_usage(0);
2197   if((argc == 2) && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")))
2198     return(iw_print_version_info("iwlist"));
2199
2200   if(argc == 2)
2201     {
2202       cmd = argv[1];
2203       dev = NULL;
2204       args = NULL;
2205       count = 0;
2206     }
2207   else
2208     {
2209       cmd = argv[2];
2210       dev = argv[1];
2211       args = argv + 3;
2212       count = argc - 3;
2213     }
2214
2215   /* find a command */
2216   iwcmd = find_command(cmd);
2217   if(iwcmd == NULL)
2218     return 1;
2219
2220   /* Check arg numbers */
2221   if((iwcmd->max_count >= 0) && (count > iwcmd->max_count))
2222     {
2223       fprintf(stderr, "iwlist: command `%s' needs fewer arguments (max %d)\n",
2224               iwcmd->cmd, iwcmd->max_count);
2225       return 1;
2226     }
2227
2228   /* Create a channel to the NET kernel. */
2229   if((skfd = iw_sockets_open()) < 0)
2230     {
2231       perror("socket");
2232       return -1;
2233     }
2234
2235   /* do the actual work */
2236   if (dev)
2237     goterr = (*iwcmd->fn)(skfd, dev, args, count);
2238   else
2239     iw_enum_devices(skfd, iwcmd->fn, args, count);
2240
2241   /* Close the socket. */
2242   iw_sockets_close(skfd);
2243
2244   return goterr;
2245 }