OSDN Git Service

Update README.md
[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.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  * 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[IW_ESSID_MAX_SIZE+1];
500         memset(essid, '\0', sizeof(essid));
501         if((event->u.essid.pointer) && (event->u.essid.length))
502           memcpy(essid, event->u.essid.pointer, event->u.essid.length);
503         if(event->u.essid.flags)
504           {
505             /* Does it have an ESSID index ? */
506             if((event->u.essid.flags & IW_ENCODE_INDEX) > 1)
507               printf("                    ESSID:\"%s\" [%d]\n", essid,
508                      (event->u.essid.flags & IW_ENCODE_INDEX));
509             else
510               printf("                    ESSID:\"%s\"\n", essid);
511           }
512         else
513           printf("                    ESSID:off/any/hidden\n");
514       }
515       break;
516     case SIOCGIWENCODE:
517       {
518         unsigned char   key[IW_ENCODING_TOKEN_MAX];
519         if(event->u.data.pointer)
520           memcpy(key, event->u.data.pointer, event->u.data.length);
521         else
522           event->u.data.flags |= IW_ENCODE_NOKEY;
523         printf("                    Encryption key:");
524         if(event->u.data.flags & IW_ENCODE_DISABLED)
525           printf("off\n");
526         else
527           {
528             /* Display the key */
529             iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
530                          event->u.data.flags);
531             printf("%s", buffer);
532
533             /* Other info... */
534             if((event->u.data.flags & IW_ENCODE_INDEX) > 1)
535               printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX);
536             if(event->u.data.flags & IW_ENCODE_RESTRICTED)
537               printf("   Security mode:restricted");
538             if(event->u.data.flags & IW_ENCODE_OPEN)
539               printf("   Security mode:open");
540             printf("\n");
541           }
542       }
543       break;
544     case SIOCGIWRATE:
545       if(state->val_index == 0)
546         printf("                    Bit Rates:");
547       else
548         if((state->val_index % 5) == 0)
549           printf("\n                              ");
550         else
551           printf("; ");
552       iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
553       printf("%s", buffer);
554       /* Check for termination */
555       if(stream->value == NULL)
556         {
557           printf("\n");
558           state->val_index = 0;
559         }
560       else
561         state->val_index++;
562       break;
563     case SIOCGIWMODUL:
564       {
565         unsigned int    modul = event->u.param.value;
566         int             i;
567         int             n = 0;
568         printf("                    Modulations :");
569         for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
570           {
571             if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
572               {
573                 if((n++ % 8) == 7)
574                   printf("\n                        ");
575                 else
576                   printf(" ; ");
577                 printf("%s", iw_modul_list[i].cmd);
578               }
579           }
580         printf("\n");
581       }
582       break;
583     case IWEVQUAL:
584       iw_print_stats(buffer, sizeof(buffer),
585                      &event->u.qual, iw_range, has_range);
586       printf("                    %s\n", buffer);
587       break;
588 #ifndef WE_ESSENTIAL
589     case IWEVGENIE:
590       /* Informations Elements are complex, let's do only some of them */
591       iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
592       break;
593 #endif  /* WE_ESSENTIAL */
594     case IWEVCUSTOM:
595       {
596         char custom[IW_CUSTOM_MAX+1];
597         if((event->u.data.pointer) && (event->u.data.length))
598           memcpy(custom, event->u.data.pointer, event->u.data.length);
599         custom[event->u.data.length] = '\0';
600         printf("                    Extra:%s\n", custom);
601       }
602       break;
603     default:
604       printf("                    (Unknown Wireless Token 0x%04X)\n",
605              event->cmd);
606    }    /* switch(event->cmd) */
607 }
608
609 /*------------------------------------------------------------------*/
610 /*
611  * Perform a scanning on one device
612  */
613 static int
614 print_scanning_info(int         skfd,
615                     char *      ifname,
616                     char *      args[],         /* Command line args */
617                     int         count)          /* Args count */
618 {
619   struct iwreq          wrq;
620   struct iw_scan_req    scanopt;                /* Options for 'set' */
621   int                   scanflags = 0;          /* Flags for scan */
622   unsigned char *       buffer = NULL;          /* Results */
623   int                   buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
624   struct iw_range       range;
625   int                   has_range;
626   struct timeval        tv;                             /* Select timeout */
627   int                   timeout = 15000000;             /* 15s */
628
629   /* Avoid "Unused parameter" warning */
630   args = args; count = count;
631
632   /* Debugging stuff */
633   if((IW_EV_LCP_PK2_LEN != IW_EV_LCP_PK_LEN) || (IW_EV_POINT_PK2_LEN != IW_EV_POINT_PK_LEN))
634     {
635       fprintf(stderr, "*** Please report to jt@hpl.hp.com your platform details\n");
636       fprintf(stderr, "*** and the following line :\n");
637       fprintf(stderr, "*** IW_EV_LCP_PK2_LEN = %zu ; IW_EV_POINT_PK2_LEN = %zu\n\n",
638               IW_EV_LCP_PK2_LEN, IW_EV_POINT_PK2_LEN);
639     }
640
641   /* Get range stuff */
642   has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
643
644   /* Check if the interface could support scanning. */
645   if((!has_range) || (range.we_version_compiled < 14))
646     {
647       fprintf(stderr, "%-8.16s  Interface doesn't support scanning.\n\n",
648               ifname);
649       return(-1);
650     }
651
652   /* Init timeout value -> 250ms between set and first get */
653   tv.tv_sec = 0;
654   tv.tv_usec = 250000;
655
656   /* Clean up set args */
657   memset(&scanopt, 0, sizeof(scanopt));
658
659   /* Parse command line arguments and extract options.
660    * Note : when we have enough options, we should use the parser
661    * from iwconfig... */
662   while(count > 0)
663     {
664       /* One arg is consumed (the option name) */
665       count--;
666       
667       /*
668        * Check for Active Scan (scan with specific essid)
669        */
670       if(!strncmp(args[0], "essid", 5))
671         {
672           if(count < 1)
673             {
674               fprintf(stderr, "Too few arguments for scanning option [%s]\n",
675                       args[0]);
676               return(-1);
677             }
678           args++;
679           count--;
680
681           /* Store the ESSID in the scan options */
682           scanopt.essid_len = strlen(args[0]);
683           memcpy(scanopt.essid, args[0], scanopt.essid_len);
684           /* Initialise BSSID as needed */
685           if(scanopt.bssid.sa_family == 0)
686             {
687               scanopt.bssid.sa_family = ARPHRD_ETHER;
688               memset(scanopt.bssid.sa_data, 0xff, ETH_ALEN);
689             }
690           /* Scan only this ESSID */
691           scanflags |= IW_SCAN_THIS_ESSID;
692         }
693       else
694         /* Check for last scan result (do not trigger scan) */
695         if(!strncmp(args[0], "last", 4))
696           {
697             /* Hack */
698             scanflags |= IW_SCAN_HACK;
699           }
700         else
701           {
702             fprintf(stderr, "Invalid scanning option [%s]\n", args[0]);
703             return(-1);
704           }
705
706       /* Next arg */
707       args++;
708     }
709
710   /* Check if we have scan options */
711   if(scanflags)
712     {
713       wrq.u.data.pointer = (caddr_t) &scanopt;
714       wrq.u.data.length = sizeof(scanopt);
715       wrq.u.data.flags = scanflags;
716     }
717   else
718     {
719       wrq.u.data.pointer = NULL;
720       wrq.u.data.flags = 0;
721       wrq.u.data.length = 0;
722     }
723
724   /* If only 'last' was specified on command line, don't trigger a scan */
725   if(scanflags == IW_SCAN_HACK)
726     {
727       /* Skip waiting */
728       tv.tv_usec = 0;
729     }
730   else
731     {
732       /* Initiate Scanning */
733       if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
734         {
735           if((errno != EPERM) || (scanflags != 0))
736             {
737               fprintf(stderr, "%-8.16s  Interface doesn't support scanning : %s\n\n",
738                       ifname, strerror(errno));
739               return(-1);
740             }
741           /* If we don't have the permission to initiate the scan, we may
742            * still have permission to read left-over results.
743            * But, don't wait !!! */
744 #if 0
745           /* Not cool, it display for non wireless interfaces... */
746           fprintf(stderr, "%-8.16s  (Could not trigger scanning, just reading left-over results)\n", ifname);
747 #endif
748           tv.tv_usec = 0;
749         }
750     }
751   timeout -= tv.tv_usec;
752
753   /* Forever */
754   while(1)
755     {
756       fd_set            rfds;           /* File descriptors for select */
757       int               last_fd;        /* Last fd */
758       int               ret;
759
760       /* Guess what ? We must re-generate rfds each time */
761       FD_ZERO(&rfds);
762       last_fd = -1;
763
764       /* In here, add the rtnetlink fd in the list */
765
766       /* Wait until something happens */
767       ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
768
769       /* Check if there was an error */
770       if(ret < 0)
771         {
772           if(errno == EAGAIN || errno == EINTR)
773             continue;
774           fprintf(stderr, "Unhandled signal - exiting...\n");
775           return(-1);
776         }
777
778       /* Check if there was a timeout */
779       if(ret == 0)
780         {
781           unsigned char *       newbuf;
782
783         realloc:
784           /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
785           newbuf = realloc(buffer, buflen);
786           if(newbuf == NULL)
787             {
788               if(buffer)
789                 free(buffer);
790               fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
791               return(-1);
792             }
793           buffer = newbuf;
794
795           /* Try to read the results */
796           wrq.u.data.pointer = buffer;
797           wrq.u.data.flags = 0;
798           wrq.u.data.length = buflen;
799           if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
800             {
801               /* Check if buffer was too small (WE-17 only) */
802               if((errno == E2BIG) && (range.we_version_compiled > 16))
803                 {
804                   /* Some driver may return very large scan results, either
805                    * because there are many cells, or because they have many
806                    * large elements in cells (like IWEVCUSTOM). Most will
807                    * only need the regular sized buffer. We now use a dynamic
808                    * allocation of the buffer to satisfy everybody. Of course,
809                    * as we don't know in advance the size of the array, we try
810                    * various increasing sizes. Jean II */
811
812                   /* Check if the driver gave us any hints. */
813                   if(wrq.u.data.length > buflen)
814                     buflen = wrq.u.data.length;
815                   else
816                     buflen *= 2;
817
818                   /* Try again */
819                   goto realloc;
820                 }
821
822               /* Check if results not available yet */
823               if(errno == EAGAIN)
824                 {
825                   /* Restart timer for only 100ms*/
826                   tv.tv_sec = 0;
827                   tv.tv_usec = 100000;
828                   timeout -= tv.tv_usec;
829                   if(timeout > 0)
830                     continue;   /* Try again later */
831                 }
832
833               /* Bad error */
834               free(buffer);
835               fprintf(stderr, "%-8.16s  Failed to read scan data : %s\n\n",
836                       ifname, strerror(errno));
837               return(-2);
838             }
839           else
840             /* We have the results, go to process them */
841             break;
842         }
843
844       /* In here, check if event and event type
845        * if scan event, read results. All errors bad & no reset timeout */
846     }
847
848   if(wrq.u.data.length)
849     {
850       struct iw_event           iwe;
851       struct stream_descr       stream;
852       struct iwscan_state       state = { .ap_num = 1, .val_index = 0 };
853       int                       ret;
854       
855 #ifdef DEBUG
856       /* Debugging code. In theory useless, because it's debugged ;-) */
857       int       i;
858       printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
859       for(i = 1; i < wrq.u.data.length; i++)
860         printf(":%02X", buffer[i]);
861       printf("]\n");
862 #endif
863       printf("%-8.16s  Scan completed :\n", ifname);
864       iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
865       do
866         {
867           /* Extract an event and print it */
868           ret = iw_extract_event_stream(&stream, &iwe,
869                                         range.we_version_compiled);
870           if(ret > 0)
871             print_scanning_token(&stream, &iwe, &state,
872                                  &range, has_range);
873         }
874       while(ret > 0);
875       printf("\n");
876     }
877   else
878     printf("%-8.16s  No scan results\n\n", ifname);
879
880   free(buffer);
881   return(0);
882 }
883
884 /*********************** FREQUENCIES/CHANNELS ***********************/
885
886 /*------------------------------------------------------------------*/
887 /*
888  * Print the number of channels and available frequency for the device
889  */
890 static int
891 print_freq_info(int             skfd,
892                 char *          ifname,
893                 char *          args[],         /* Command line args */
894                 int             count)          /* Args count */
895 {
896   struct iwreq          wrq;
897   struct iw_range       range;
898   double                freq;
899   int                   k;
900   int                   channel;
901   char                  buffer[128];    /* Temporary buffer */
902
903   /* Avoid "Unused parameter" warning */
904   args = args; count = count;
905
906   /* Get list of frequencies / channels */
907   if(iw_get_range_info(skfd, ifname, &range) < 0)
908       fprintf(stderr, "%-8.16s  no frequency information.\n\n",
909                       ifname);
910   else
911     {
912       if(range.num_frequency > 0)
913         {
914           printf("%-8.16s  %d channels in total; available frequencies :\n",
915                  ifname, range.num_channels);
916           /* Print them all */
917           for(k = 0; k < range.num_frequency; k++)
918             {
919               freq = iw_freq2float(&(range.freq[k]));
920               iw_print_freq_value(buffer, sizeof(buffer), freq);
921               printf("          Channel %.2d : %s\n",
922                      range.freq[k].i, buffer);
923             }
924         }
925       else
926         printf("%-8.16s  %d channels\n",
927                ifname, range.num_channels);
928
929       /* Get current frequency / channel and display it */
930       if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
931         {
932           freq = iw_freq2float(&(wrq.u.freq));
933           channel = iw_freq_to_channel(freq, &range);
934           iw_print_freq(buffer, sizeof(buffer),
935                         freq, channel, wrq.u.freq.flags);
936           printf("          Current %s\n\n", buffer);
937         }
938     }
939   return(0);
940 }
941
942 /***************************** BITRATES *****************************/
943
944 /*------------------------------------------------------------------*/
945 /*
946  * Print the number of available bitrates for the device
947  */
948 static int
949 print_bitrate_info(int          skfd,
950                    char *       ifname,
951                    char *       args[],         /* Command line args */
952                    int          count)          /* Args count */
953 {
954   struct iwreq          wrq;
955   struct iw_range       range;
956   int                   k;
957   char                  buffer[128];
958
959   /* Avoid "Unused parameter" warning */
960   args = args; count = count;
961
962   /* Extract range info */
963   if(iw_get_range_info(skfd, ifname, &range) < 0)
964       fprintf(stderr, "%-8.16s  no bit-rate information.\n\n",
965                       ifname);
966   else
967     {
968       if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
969         {
970           printf("%-8.16s  %d available bit-rates :\n",
971                  ifname, range.num_bitrates);
972           /* Print them all */
973           for(k = 0; k < range.num_bitrates; k++)
974             {
975               iw_print_bitrate(buffer, sizeof(buffer), range.bitrate[k]);
976               /* Maybe this should be %10s */
977               printf("\t  %s\n", buffer);
978             }
979         }
980       else
981         printf("%-8.16s  unknown bit-rate information.\n", ifname);
982
983       /* Get current bit rate */
984       if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
985         {
986           iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
987           printf("          Current Bit Rate%c%s\n",
988                  (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
989         }
990
991       /* Try to get the broadcast bitrate if it exist... */
992       if(range.bitrate_capa & IW_BITRATE_BROADCAST)
993         {
994           wrq.u.bitrate.flags = IW_BITRATE_BROADCAST;
995           if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
996             {
997               iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
998               printf("          Broadcast Bit Rate%c%s\n",
999                      (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
1000             }
1001         }
1002
1003       printf("\n");
1004     }
1005   return(0);
1006 }
1007
1008 /************************* ENCRYPTION KEYS *************************/
1009
1010 /*------------------------------------------------------------------*/
1011 /*
1012  * Print all the available encryption keys for the device
1013  */
1014 static int
1015 print_keys_info(int             skfd,
1016                 char *          ifname,
1017                 char *          args[],         /* Command line args */
1018                 int             count)          /* Args count */
1019 {
1020   struct iwreq          wrq;
1021   struct iw_range       range;
1022   unsigned char         key[IW_ENCODING_TOKEN_MAX];
1023   unsigned int          k;
1024   char                  buffer[128];
1025
1026   /* Avoid "Unused parameter" warning */
1027   args = args; count = count;
1028
1029   /* Extract range info */
1030   if(iw_get_range_info(skfd, ifname, &range) < 0)
1031       fprintf(stderr, "%-8.16s  no encryption keys information.\n\n",
1032                       ifname);
1033   else
1034     {
1035       printf("%-8.16s  ", ifname);
1036       /* Print key sizes */
1037       if((range.num_encoding_sizes > 0) &&
1038          (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
1039         {
1040           printf("%d key sizes : %d", range.num_encoding_sizes,
1041                  range.encoding_size[0] * 8);
1042           /* Print them all */
1043           for(k = 1; k < range.num_encoding_sizes; k++)
1044             printf(", %d", range.encoding_size[k] * 8);
1045           printf("bits\n          ");
1046         }
1047       /* Print the keys and associate mode */
1048       printf("%d keys available :\n", range.max_encoding_tokens);
1049       for(k = 1; k <= range.max_encoding_tokens; k++)
1050         {
1051           wrq.u.data.pointer = (caddr_t) key;
1052           wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
1053           wrq.u.data.flags = k;
1054           if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
1055             {
1056               fprintf(stderr, "Error reading wireless keys (SIOCGIWENCODE): %s\n", strerror(errno));
1057               break;
1058             }
1059           if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
1060              (wrq.u.data.length == 0))
1061             printf("\t\t[%d]: off\n", k);
1062           else
1063             {
1064               /* Display the key */
1065               iw_print_key(buffer, sizeof(buffer),
1066                            key, wrq.u.data.length, wrq.u.data.flags);
1067               printf("\t\t[%d]: %s", k, buffer);
1068
1069               /* Other info... */
1070               printf(" (%d bits)", wrq.u.data.length * 8);
1071               printf("\n");
1072             }
1073         }
1074       /* Print current key index and mode */
1075       wrq.u.data.pointer = (caddr_t) key;
1076       wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
1077       wrq.u.data.flags = 0;     /* Set index to zero to get current */
1078       if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
1079         {
1080           /* Note : if above fails, we have already printed an error
1081            * message int the loop above */
1082           printf("          Current Transmit Key: [%d]\n",
1083                  wrq.u.data.flags & IW_ENCODE_INDEX);
1084           if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
1085             printf("          Security mode:restricted\n");
1086           if(wrq.u.data.flags & IW_ENCODE_OPEN)
1087             printf("          Security mode:open\n");
1088         }
1089
1090       printf("\n\n");
1091     }
1092   return(0);
1093 }
1094
1095 /************************* POWER MANAGEMENT *************************/
1096
1097 /*------------------------------------------------------------------*/
1098 /*
1099  * Print Power Management info for each device
1100  */
1101 static int
1102 get_pm_value(int                skfd,
1103              char *             ifname,
1104              struct iwreq *     pwrq,
1105              int                flags,
1106              char *             buffer,
1107              int                buflen,
1108              int                we_version_compiled)
1109 {
1110   /* Get Another Power Management value */
1111   pwrq->u.power.flags = flags;
1112   if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, pwrq) >= 0)
1113     {
1114       /* Let's check the value and its type */
1115       if(pwrq->u.power.flags & IW_POWER_TYPE)
1116         {
1117           iw_print_pm_value(buffer, buflen,
1118                             pwrq->u.power.value, pwrq->u.power.flags,
1119                             we_version_compiled);
1120           printf("\n                 %s", buffer);
1121         }
1122     }
1123   return(pwrq->u.power.flags);
1124 }
1125
1126 /*------------------------------------------------------------------*/
1127 /*
1128  * Print Power Management range for each type
1129  */
1130 static void
1131 print_pm_value_range(char *             name,
1132                      int                mask,
1133                      int                iwr_flags,
1134                      int                iwr_min,
1135                      int                iwr_max,
1136                      char *             buffer,
1137                      int                buflen,
1138                      int                we_version_compiled)
1139 {
1140   if(iwr_flags & mask)
1141     {
1142       int       flags = (iwr_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
1143       /* Display if auto or fixed */
1144       printf("%s %s ; ",
1145              (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
1146              name);
1147       /* Print the range */
1148       iw_print_pm_value(buffer, buflen,
1149                         iwr_min, flags | IW_POWER_MIN,
1150                         we_version_compiled);
1151       printf("%s\n                          ", buffer);
1152       iw_print_pm_value(buffer, buflen,
1153                         iwr_max, flags | IW_POWER_MAX,
1154                         we_version_compiled);
1155       printf("%s\n          ", buffer);
1156     }
1157 }
1158
1159 /*------------------------------------------------------------------*/
1160 /*
1161  * Power Management types of values
1162  */
1163 static const unsigned int pm_type_flags[] = {
1164   IW_POWER_PERIOD,
1165   IW_POWER_TIMEOUT,
1166   IW_POWER_SAVING,
1167 };
1168 static const int pm_type_flags_size = (sizeof(pm_type_flags)/sizeof(pm_type_flags[0]));
1169
1170 /*------------------------------------------------------------------*/
1171 /*
1172  * Print Power Management info for each device
1173  */
1174 static int
1175 print_pm_info(int               skfd,
1176               char *            ifname,
1177               char *            args[],         /* Command line args */
1178               int               count)          /* Args count */
1179 {
1180   struct iwreq          wrq;
1181   struct iw_range       range;
1182   char                  buffer[128];
1183
1184   /* Avoid "Unused parameter" warning */
1185   args = args; count = count;
1186
1187   /* Extract range info */
1188   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1189      (range.we_version_compiled < 10))
1190       fprintf(stderr, "%-8.16s  no power management information.\n\n",
1191                       ifname);
1192   else
1193     {
1194       printf("%-8.16s  ", ifname);
1195
1196       /* Display modes availables */
1197       if(range.pm_capa & IW_POWER_MODE)
1198         {
1199           printf("Supported modes :\n          ");
1200           if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
1201             printf("\t\to Receive all packets (unicast & multicast)\n          ");
1202           if(range.pm_capa & IW_POWER_UNICAST_R)
1203             printf("\t\to Receive Unicast only (discard multicast)\n          ");
1204           if(range.pm_capa & IW_POWER_MULTICAST_R)
1205             printf("\t\to Receive Multicast only (discard unicast)\n          ");
1206           if(range.pm_capa & IW_POWER_FORCE_S)
1207             printf("\t\to Force sending using Power Management\n          ");
1208           if(range.pm_capa & IW_POWER_REPEATER)
1209             printf("\t\to Repeat multicast\n          ");
1210         }
1211       /* Display min/max period availables */
1212       print_pm_value_range("period ", IW_POWER_PERIOD,
1213                            range.pmp_flags, range.min_pmp, range.max_pmp,
1214                            buffer, sizeof(buffer), range.we_version_compiled);
1215       /* Display min/max timeout availables */
1216       print_pm_value_range("timeout", IW_POWER_TIMEOUT,
1217                            range.pmt_flags, range.min_pmt, range.max_pmt,
1218                            buffer, sizeof(buffer), range.we_version_compiled);
1219       /* Display min/max saving availables */
1220       print_pm_value_range("saving ", IW_POWER_SAVING,
1221                            range.pms_flags, range.min_pms, range.max_pms,
1222                            buffer, sizeof(buffer), range.we_version_compiled);
1223
1224       /* Get current Power Management settings */
1225       wrq.u.power.flags = 0;
1226       if(iw_get_ext(skfd, ifname, SIOCGIWPOWER, &wrq) >= 0)
1227         {
1228           int   flags = wrq.u.power.flags;
1229
1230           /* Is it disabled ? */
1231           if(wrq.u.power.disabled)
1232             printf("Current mode:off\n");
1233           else
1234             {
1235               unsigned int      pm_type = 0;
1236               unsigned int      pm_mask = 0;
1237               unsigned int      remain_mask = range.pm_capa & IW_POWER_TYPE;
1238               int               i = 0;
1239
1240               /* Let's check the mode */
1241               iw_print_pm_mode(buffer, sizeof(buffer), flags);
1242               printf("Current %s", buffer);
1243
1244               /* Let's check if nothing (simply on) */
1245               if((flags & IW_POWER_MODE) == IW_POWER_ON)
1246                 printf("mode:on");
1247
1248               /* Let's check the value and its type */
1249               if(wrq.u.power.flags & IW_POWER_TYPE)
1250                 {
1251                   iw_print_pm_value(buffer, sizeof(buffer),
1252                                     wrq.u.power.value, wrq.u.power.flags,
1253                                     range.we_version_compiled);
1254                   printf("\n                 %s", buffer);
1255                 }
1256
1257               while(1)
1258                 {
1259                   /* Deal with min/max for the current value */
1260                   pm_mask = 0;
1261                   /* If we have been returned a MIN value, ask for the MAX */
1262                   if(flags & IW_POWER_MIN)
1263                     pm_mask = IW_POWER_MAX;
1264                   /* If we have been returned a MAX value, ask for the MIN */
1265                   if(flags & IW_POWER_MAX)
1266                     pm_mask = IW_POWER_MIN;
1267                   /* If we have something to ask for... */
1268                   if(pm_mask)
1269                     {
1270                       pm_mask |= pm_type;
1271                       get_pm_value(skfd, ifname, &wrq, pm_mask,
1272                                    buffer, sizeof(buffer),
1273                                    range.we_version_compiled);
1274                     }
1275
1276                   /* Remove current type from mask */
1277                   remain_mask &= ~(wrq.u.power.flags);
1278
1279                   /* Check what other types we still have to read */
1280                   while(i < pm_type_flags_size)
1281                     {
1282                       pm_type = remain_mask & pm_type_flags[i];
1283                       if(pm_type)
1284                         break;
1285                       i++;
1286                     }
1287                   /* Nothing anymore : exit the loop */
1288                   if(!pm_type)
1289                     break;
1290
1291                   /* Ask for this other type of value */
1292                   flags = get_pm_value(skfd, ifname, &wrq, pm_type,
1293                                        buffer, sizeof(buffer),
1294                                        range.we_version_compiled);
1295                   /* Loop back for min/max */
1296                 }
1297               printf("\n");
1298             }
1299         }
1300       printf("\n");
1301     }
1302   return(0);
1303 }
1304
1305 #ifndef WE_ESSENTIAL
1306 /************************** TRANSMIT POWER **************************/
1307
1308 /*------------------------------------------------------------------*/
1309 /*
1310  * Print the number of available transmit powers for the device
1311  */
1312 static int
1313 print_txpower_info(int          skfd,
1314                    char *       ifname,
1315                    char *       args[],         /* Command line args */
1316                    int          count)          /* Args count */
1317 {
1318   struct iwreq          wrq;
1319   struct iw_range       range;
1320   int                   dbm;
1321   int                   mwatt;
1322   int                   k;
1323
1324   /* Avoid "Unused parameter" warning */
1325   args = args; count = count;
1326
1327   /* Extract range info */
1328   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1329      (range.we_version_compiled < 10))
1330       fprintf(stderr, "%-8.16s  no transmit-power information.\n\n",
1331                       ifname);
1332   else
1333     {
1334       if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
1335         printf("%-8.16s  unknown transmit-power information.\n\n", ifname);
1336       else
1337         {
1338           printf("%-8.16s  %d available transmit-powers :\n",
1339                  ifname, range.num_txpower);
1340           /* Print them all */
1341           for(k = 0; k < range.num_txpower; k++)
1342             {
1343               /* Check for relative values */
1344               if(range.txpower_capa & IW_TXPOW_RELATIVE)
1345                 {
1346                   printf("\t  %d (no units)\n", range.txpower[k]);
1347                 }
1348               else
1349                 {
1350                   if(range.txpower_capa & IW_TXPOW_MWATT)
1351                     {
1352                       dbm = iw_mwatt2dbm(range.txpower[k]);
1353                       mwatt = range.txpower[k];
1354                     }
1355                   else
1356                     {
1357                       dbm = range.txpower[k];
1358                       mwatt = iw_dbm2mwatt(range.txpower[k]);
1359                     }
1360                   printf("\t  %d dBm  \t(%d mW)\n", dbm, mwatt);
1361                 }
1362             }
1363         }
1364
1365       /* Get current Transmit Power */
1366       if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
1367         {
1368           printf("          Current Tx-Power");
1369           /* Disabled ? */
1370           if(wrq.u.txpower.disabled)
1371             printf(":off\n\n");
1372           else
1373             {
1374               /* Fixed ? */
1375               if(wrq.u.txpower.fixed)
1376                 printf("=");
1377               else
1378                 printf(":");
1379               /* Check for relative values */
1380               if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
1381                 {
1382                   /* I just hate relative value, because they are
1383                    * driver specific, so not very meaningfull to apps.
1384                    * But, we have to support that, because
1385                    * this is the way hardware is... */
1386                   printf("\t  %d (no units)\n", wrq.u.txpower.value);
1387                 }
1388               else
1389                 {
1390                   if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
1391                     {
1392                       dbm = iw_mwatt2dbm(wrq.u.txpower.value);
1393                       mwatt = wrq.u.txpower.value;
1394                     }
1395                   else
1396                     {
1397                       dbm = wrq.u.txpower.value;
1398                       mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
1399                     }
1400                   printf("%d dBm  \t(%d mW)\n\n", dbm, mwatt);
1401                 }
1402             }
1403         }
1404     }
1405   return(0);
1406 }
1407
1408 /*********************** RETRY LIMIT/LIFETIME ***********************/
1409
1410 /*------------------------------------------------------------------*/
1411 /*
1412  * Print one retry value
1413  */
1414 static int
1415 get_retry_value(int             skfd,
1416                 char *          ifname,
1417                 struct iwreq *  pwrq,
1418                 int             flags,
1419                 char *          buffer,
1420                 int             buflen,
1421                 int             we_version_compiled)
1422 {
1423   /* Get Another retry value */
1424   pwrq->u.retry.flags = flags;
1425   if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, pwrq) >= 0)
1426     {
1427       /* Let's check the value and its type */
1428       if(pwrq->u.retry.flags & IW_RETRY_TYPE)
1429         {
1430           iw_print_retry_value(buffer, buflen,
1431                                pwrq->u.retry.value, pwrq->u.retry.flags,
1432                                we_version_compiled);
1433           printf("%s\n                 ", buffer);
1434         }
1435     }
1436   return(pwrq->u.retry.flags);
1437 }
1438
1439 /*------------------------------------------------------------------*/
1440 /*
1441  * Print Power Management range for each type
1442  */
1443 static void
1444 print_retry_value_range(char *          name,
1445                         int             mask,
1446                         int             iwr_flags,
1447                         int             iwr_min,
1448                         int             iwr_max,
1449                         char *          buffer,
1450                         int             buflen,
1451                         int             we_version_compiled)
1452 {
1453   if(iwr_flags & mask)
1454     {
1455       int       flags = (iwr_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
1456       /* Display if auto or fixed */
1457       printf("%s %s ; ",
1458              (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
1459              name);
1460       /* Print the range */
1461       iw_print_retry_value(buffer, buflen,
1462                            iwr_min, flags | IW_POWER_MIN,
1463                            we_version_compiled);
1464       printf("%s\n                           ", buffer);
1465       iw_print_retry_value(buffer, buflen,
1466                            iwr_max, flags | IW_POWER_MAX,
1467                            we_version_compiled);
1468       printf("%s\n          ", buffer);
1469     }
1470 }
1471
1472 /*------------------------------------------------------------------*/
1473 /*
1474  * Print Retry info for each device
1475  */
1476 static int
1477 print_retry_info(int            skfd,
1478                  char *         ifname,
1479                  char *         args[],         /* Command line args */
1480                  int            count)          /* Args count */
1481 {
1482   struct iwreq          wrq;
1483   struct iw_range       range;
1484   char                  buffer[128];
1485
1486   /* Avoid "Unused parameter" warning */
1487   args = args; count = count;
1488
1489   /* Extract range info */
1490   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1491      (range.we_version_compiled < 11))
1492     fprintf(stderr, "%-8.16s  no retry limit/lifetime information.\n\n",
1493             ifname);
1494   else
1495     {
1496       printf("%-8.16s  ", ifname);
1497
1498       /* Display min/max limit availables */
1499       print_retry_value_range("limit   ", IW_RETRY_LIMIT, range.retry_flags,
1500                               range.min_retry, range.max_retry,
1501                               buffer, sizeof(buffer),
1502                               range.we_version_compiled);
1503       /* Display min/max lifetime availables */
1504       print_retry_value_range("lifetime", IW_RETRY_LIFETIME, 
1505                               range.r_time_flags,
1506                               range.min_r_time, range.max_r_time,
1507                               buffer, sizeof(buffer),
1508                               range.we_version_compiled);
1509
1510       /* Get current retry settings */
1511       wrq.u.retry.flags = 0;
1512       if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
1513         {
1514           int   flags = wrq.u.retry.flags;
1515
1516           /* Is it disabled ? */
1517           if(wrq.u.retry.disabled)
1518             printf("Current mode:off\n          ");
1519           else
1520             {
1521               unsigned int      retry_type = 0;
1522               unsigned int      retry_mask = 0;
1523               unsigned int      remain_mask = range.retry_capa & IW_RETRY_TYPE;
1524
1525               /* Let's check the mode */
1526               printf("Current mode:on\n                 ");
1527
1528               /* Let's check the value and its type */
1529               if(wrq.u.retry.flags & IW_RETRY_TYPE)
1530                 {
1531                   iw_print_retry_value(buffer, sizeof(buffer),
1532                                        wrq.u.retry.value, wrq.u.retry.flags,
1533                                        range.we_version_compiled);
1534                   printf("%s\n                 ", buffer);
1535                 }
1536
1537               while(1)
1538                 {
1539                   /* Deal with min/max/short/long for the current value */
1540                   retry_mask = 0;
1541                   /* If we have been returned a MIN value, ask for the MAX */
1542                   if(flags & IW_RETRY_MIN)
1543                     retry_mask = IW_RETRY_MAX;
1544                   /* If we have been returned a MAX value, ask for the MIN */
1545                   if(flags & IW_RETRY_MAX)
1546                     retry_mask = IW_RETRY_MIN;
1547                   /* Same for SHORT and LONG */
1548                   if(flags & IW_RETRY_SHORT)
1549                     retry_mask = IW_RETRY_LONG;
1550                   if(flags & IW_RETRY_LONG)
1551                     retry_mask = IW_RETRY_SHORT;
1552                   /* If we have something to ask for... */
1553                   if(retry_mask)
1554                     {
1555                       retry_mask |= retry_type;
1556                       get_retry_value(skfd, ifname, &wrq, retry_mask,
1557                                       buffer, sizeof(buffer),
1558                                       range.we_version_compiled);
1559                     }
1560
1561                   /* And if we have both a limit and a lifetime,
1562                    * ask the other one */
1563                   remain_mask &= ~(wrq.u.retry.flags);
1564                   retry_type = remain_mask;
1565                   /* Nothing anymore : exit the loop */
1566                   if(!retry_type)
1567                     break;
1568
1569                   /* Ask for this other type of value */
1570                   flags = get_retry_value(skfd, ifname, &wrq, retry_type,
1571                                           buffer, sizeof(buffer),
1572                                           range.we_version_compiled);
1573                   /* Loop back for min/max/short/long */
1574                 }
1575             }
1576         }
1577       printf("\n");
1578     }
1579   return(0);
1580 }
1581
1582 /************************ ACCESS POINT LIST ************************/
1583 /*
1584  * Note : now that we have scanning support, this is depracted and
1585  * won't survive long. Actually, next version it's out !
1586  */
1587
1588 /*------------------------------------------------------------------*/
1589 /*
1590  * Display the list of ap addresses and the associated stats
1591  * Exacly the same as the spy list, only with different IOCTL and messages
1592  */
1593 static int
1594 print_ap_info(int       skfd,
1595               char *    ifname,
1596               char *    args[],         /* Command line args */
1597               int       count)          /* Args count */
1598 {
1599   struct iwreq          wrq;
1600   char          buffer[(sizeof(struct iw_quality) +
1601                         sizeof(struct sockaddr)) * IW_MAX_AP];
1602   char          temp[128];
1603   struct sockaddr *     hwa;
1604   struct iw_quality *   qual;
1605   iwrange       range;
1606   int           has_range = 0;
1607   int           has_qual = 0;
1608   int           n;
1609   int           i;
1610
1611   /* Avoid "Unused parameter" warning */
1612   args = args; count = count;
1613
1614   /* Collect stats */
1615   wrq.u.data.pointer = (caddr_t) buffer;
1616   wrq.u.data.length = IW_MAX_AP;
1617   wrq.u.data.flags = 0;
1618   if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
1619     {
1620       fprintf(stderr, "%-8.16s  Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
1621       return(-1);
1622     }
1623
1624   /* Number of addresses */
1625   n = wrq.u.data.length;
1626   has_qual = wrq.u.data.flags;
1627
1628   /* The two lists */
1629   hwa = (struct sockaddr *) buffer;
1630   qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
1631
1632   /* Check if we have valid mac address type */
1633   if(iw_check_mac_addr_type(skfd, ifname) < 0)
1634     {
1635       fprintf(stderr, "%-8.16s  Interface doesn't support MAC addresses\n\n", ifname);
1636       return(-2);
1637     }
1638
1639   /* Get range info if we can */
1640   if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
1641     has_range = 1;
1642
1643   /* Display it */
1644   if(n == 0)
1645     printf("%-8.16s  No Peers/Access-Point in range\n", ifname);
1646   else
1647     printf("%-8.16s  Peers/Access-Points in range:\n", ifname);
1648   for(i = 0; i < n; i++)
1649     {
1650       if(has_qual)
1651         {
1652           /* Print stats for this address */
1653           printf("    %s : ", iw_saether_ntop(&hwa[i], temp));
1654           iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
1655           printf("%s\n", temp);
1656         }
1657       else
1658         /* Only print the address */
1659         printf("    %s\n", iw_saether_ntop(&hwa[i], temp));
1660     }
1661   printf("\n");
1662   return(0);
1663 }
1664
1665 /******************** WIRELESS EVENT CAPABILITY ********************/
1666
1667 static const char *     event_capa_req[] =
1668 {
1669   [SIOCSIWNWID  - SIOCIWFIRST] = "Set NWID (kernel generated)",
1670   [SIOCSIWFREQ  - SIOCIWFIRST] = "Set Frequency/Channel (kernel generated)",
1671   [SIOCGIWFREQ  - SIOCIWFIRST] = "New Frequency/Channel",
1672   [SIOCSIWMODE  - SIOCIWFIRST] = "Set Mode (kernel generated)",
1673   [SIOCGIWTHRSPY - SIOCIWFIRST] = "Spy threshold crossed",
1674   [SIOCGIWAP    - SIOCIWFIRST] = "New Access Point/Cell address - roaming",
1675   [SIOCGIWSCAN  - SIOCIWFIRST] = "Scan request completed",
1676   [SIOCSIWESSID - SIOCIWFIRST] = "Set ESSID (kernel generated)",
1677   [SIOCGIWESSID - SIOCIWFIRST] = "New ESSID",
1678   [SIOCGIWRATE  - SIOCIWFIRST] = "New bit-rate",
1679   [SIOCSIWENCODE - SIOCIWFIRST] = "Set Encoding (kernel generated)",
1680   [SIOCGIWPOWER - SIOCIWFIRST] = NULL,
1681 };
1682
1683 static const char *     event_capa_evt[] =
1684 {
1685   [IWEVTXDROP   - IWEVFIRST] = "Tx packet dropped - retry exceeded",
1686   [IWEVCUSTOM   - IWEVFIRST] = "Custom driver event",
1687   [IWEVREGISTERED - IWEVFIRST] = "Registered node",
1688   [IWEVEXPIRED  - IWEVFIRST] = "Expired node",
1689 };
1690
1691 /*------------------------------------------------------------------*/
1692 /*
1693  * Print the event capability for the device
1694  */
1695 static int
1696 print_event_capa_info(int               skfd,
1697                       char *            ifname,
1698                       char *            args[],         /* Command line args */
1699                       int               count)          /* Args count */
1700 {
1701   struct iw_range       range;
1702   int                   cmd;
1703
1704   /* Avoid "Unused parameter" warning */
1705   args = args; count = count;
1706
1707   /* Extract range info */
1708   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1709      (range.we_version_compiled < 10))
1710       fprintf(stderr, "%-8.16s  no wireless event capability information.\n\n",
1711                       ifname);
1712   else
1713     {
1714 #ifdef DEBUG
1715       /* Debugging ;-) */
1716       for(cmd = 0x8B00; cmd < 0x8C0F; cmd++)
1717         {
1718           int idx = IW_EVENT_CAPA_INDEX(cmd);
1719           int mask = IW_EVENT_CAPA_MASK(cmd);
1720           printf("0x%X - %d - %X\n", cmd, idx, mask);
1721         }
1722 #endif
1723
1724       printf("%-8.16s  Wireless Events supported :\n", ifname);
1725
1726       for(cmd = SIOCIWFIRST; cmd <= SIOCGIWPOWER; cmd++)
1727         {
1728           int idx = IW_EVENT_CAPA_INDEX(cmd);
1729           int mask = IW_EVENT_CAPA_MASK(cmd);
1730           if(range.event_capa[idx] & mask)
1731             printf("          0x%04X : %s\n",
1732                    cmd, event_capa_req[cmd - SIOCIWFIRST]);
1733         }
1734       for(cmd = IWEVFIRST; cmd <= IWEVEXPIRED; cmd++)
1735         {
1736           int idx = IW_EVENT_CAPA_INDEX(cmd);
1737           int mask = IW_EVENT_CAPA_MASK(cmd);
1738           if(range.event_capa[idx] & mask)
1739             printf("          0x%04X : %s\n",
1740                    cmd, event_capa_evt[cmd - IWEVFIRST]);
1741         }
1742       printf("\n");
1743     }
1744   return(0);
1745 }
1746
1747 /*************************** WPA SUPPORT ***************************/
1748
1749 /*------------------------------------------------------------------*/
1750 /*
1751  * Print the authentication parameters for the device
1752  */
1753 static int
1754 print_auth_info(int             skfd,
1755                 char *          ifname,
1756                 char *          args[],         /* Command line args */
1757                 int             count)          /* Args count */
1758 {
1759   struct iwreq          wrq;
1760   struct iw_range       range;
1761   unsigned int          k;
1762
1763   /* Avoid "Unused parameter" warning */
1764   args = args; count = count;
1765
1766   /* Extract range info */
1767   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1768      (range.we_version_compiled < 18))
1769       fprintf(stderr, "%-8.16s  no authentication information.\n\n",
1770                       ifname);
1771   else
1772     {
1773       /* Print WPA/802.1x/802.11i security parameters */
1774       if(!range.enc_capa)
1775         {
1776         printf("%-8.16s  unknown authentication information.\n\n", ifname);
1777         }
1778       else
1779         {
1780           /* Display advanced encryption capabilities */
1781           printf("%-8.16s  Authentication capabilities :", ifname);
1782           iw_print_mask_name(range.enc_capa,
1783                              iw_auth_capa_name, IW_AUTH_CAPA_NUM,
1784                                  "\n\t\t");
1785           printf("\n");
1786
1787           /* Extract all auth settings */
1788           for(k = 0; k < IW_AUTH_SETTINGS_NUM; k++)
1789             { 
1790               wrq.u.param.flags = iw_auth_settings[k].value;
1791               if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
1792                 {
1793                   printf("          Current %s :", iw_auth_settings[k].label);
1794                   if(iw_auth_settings[k].names != NULL)
1795                     iw_print_mask_name(wrq.u.param.value,
1796                                        iw_auth_settings[k].names,
1797                                        iw_auth_settings[k].num_names,
1798                                        "\n\t\t");
1799                   else
1800                     printf((wrq.u.param.value) ? " yes" : " no");
1801                   printf("\n");
1802                 }
1803             }
1804         }
1805
1806       printf("\n\n");
1807     }
1808   return(0);
1809 }
1810
1811 /*------------------------------------------------------------------*/
1812 /*
1813  * Print all the available wpa keys for the device
1814  */
1815 static int
1816 print_wpakeys_info(int          skfd,
1817                    char *       ifname,
1818                    char *       args[],         /* Command line args */
1819                    int          count)          /* Args count */
1820 {
1821   struct iwreq          wrq;
1822   struct iw_range       range;
1823   unsigned char         extbuf[IW_EXTKEY_SIZE];
1824   struct iw_encode_ext  *extinfo;
1825   unsigned int          k;
1826   char                  buffer[128];
1827
1828   /* Avoid "Unused parameter" warning */
1829   args = args; count = count;
1830
1831   /* This always point to the same place */
1832   extinfo = (struct iw_encode_ext *) extbuf;
1833
1834   /* Extract range info */
1835   if(iw_get_range_info(skfd, ifname, &range) < 0)
1836       fprintf(stderr, "%-8.16s  no wpa key information.\n\n",
1837                       ifname);
1838   else
1839     {
1840       printf("%-8.16s  ", ifname);
1841       /* Print key sizes */
1842       if((range.num_encoding_sizes > 0) &&
1843          (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
1844         {
1845           printf("%d key sizes : %d", range.num_encoding_sizes,
1846                  range.encoding_size[0] * 8);
1847           /* Print them all */
1848           for(k = 1; k < range.num_encoding_sizes; k++)
1849             printf(", %d", range.encoding_size[k] * 8);
1850           printf("bits\n          ");
1851         }
1852
1853       /* Print the keys */
1854       printf("%d keys available :\n", range.max_encoding_tokens);
1855       for(k = 1; k <= range.max_encoding_tokens; k++)
1856         {
1857           /* Cleanup. Driver may not fill everything */
1858           memset(extbuf, '\0', IW_EXTKEY_SIZE);
1859
1860           /* Get whole struct containing one WPA key */
1861           wrq.u.data.pointer = (caddr_t) extbuf;
1862           wrq.u.data.length = IW_EXTKEY_SIZE;
1863           wrq.u.data.flags = k;
1864           if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) < 0)
1865             {
1866               fprintf(stderr, "Error reading wpa keys (SIOCGIWENCODEEXT): %s\n", strerror(errno));
1867               break;
1868             }
1869
1870           /* Sanity check */
1871           if(wrq.u.data.length < 
1872              (sizeof(struct iw_encode_ext) + extinfo->key_len))
1873             break;
1874
1875           /* Check if key is disabled */
1876           if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
1877              (extinfo->key_len == 0))
1878             printf("\t\t[%d]: off\n", k);
1879           else
1880             {
1881               /* Display the key */
1882               iw_print_key(buffer, sizeof(buffer),
1883                            extinfo->key, extinfo->key_len, wrq.u.data.flags);
1884               printf("\t\t[%d]: %s", k, buffer);
1885
1886               /* Key size */
1887               printf(" (%d bits)", extinfo->key_len * 8);
1888               printf("\n");
1889
1890               /* Other info... */
1891               printf("\t\t     Address: %s\n",
1892                      iw_saether_ntop(&extinfo->addr, buffer));
1893
1894               printf("\t\t     Algorithm:");
1895               iw_print_value_name(extinfo->alg,
1896                                   iw_encode_alg_name, IW_ENCODE_ALG_NUM);
1897
1898               printf("\n\t\t     Flags: 0x%08x\n", extinfo->ext_flags);
1899               if (extinfo->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID)
1900                 printf("\t\t        tx-seq-valid\n");
1901               if (extinfo->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
1902                 printf("\t\t        rx-seq-valid\n");
1903               if (extinfo->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
1904                 printf("\t\t        group-key\n");
1905             }
1906         }
1907       /* Print current key index and mode */
1908       wrq.u.data.pointer = (caddr_t) extbuf;
1909       wrq.u.data.length = IW_EXTKEY_SIZE;
1910       wrq.u.data.flags = 0;     /* Set index to zero to get current */
1911       if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) >= 0)
1912         {
1913           /* Note : if above fails, we have already printed an error
1914            * message int the loop above */
1915           printf("          Current Transmit Key: [%d]\n",
1916                  wrq.u.data.flags & IW_ENCODE_INDEX);
1917           if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
1918             printf("          Security mode:restricted\n");
1919           if(wrq.u.data.flags & IW_ENCODE_OPEN)
1920             printf("          Security mode:open\n");
1921         }
1922
1923       printf("\n\n");
1924     }
1925   return(0);
1926 }
1927
1928 /*------------------------------------------------------------------*/
1929 /*
1930  * Print the Generic IE for the device
1931  * Note : indentation is broken. We need to fix that.
1932  */
1933 static int
1934 print_gen_ie_info(int           skfd,
1935                   char *        ifname,
1936                   char *        args[],         /* Command line args */
1937                   int           count)          /* Args count */
1938 {
1939   struct iwreq          wrq;
1940   unsigned char         buf[IW_GENERIC_IE_MAX];
1941
1942   /* Avoid "Unused parameter" warning */
1943   args = args; count = count;
1944
1945   wrq.u.data.pointer = (caddr_t)buf;
1946   wrq.u.data.length = IW_GENERIC_IE_MAX;
1947   wrq.u.data.flags = 0;
1948
1949   if(iw_get_ext(skfd, ifname, SIOCGIWGENIE, &wrq) < 0)
1950     fprintf(stderr, "%-8.16s  no generic IE (%s).\n\n",
1951             ifname, strerror(errno));
1952   else
1953     {
1954       fprintf(stderr, "%-8.16s\n", ifname);
1955       if(wrq.u.data.length == 0)
1956         printf("          empty generic IE\n");
1957       else
1958         iw_print_gen_ie(buf, wrq.u.data.length);
1959       printf("\n");
1960     }
1961   return(0);
1962 }
1963
1964 /**************************** MODULATION ****************************/
1965
1966 /*------------------------------------------------------------------*/
1967 /*
1968  * Print Modulation info for each device
1969  */
1970 static int
1971 print_modul_info(int            skfd,
1972                  char *         ifname,
1973                  char *         args[],         /* Command line args */
1974                  int            count)          /* Args count */
1975 {
1976   struct iwreq          wrq;
1977   struct iw_range       range;
1978
1979   /* Avoid "Unused parameter" warning */
1980   args = args; count = count;
1981
1982   /* Extract range info */
1983   if((iw_get_range_info(skfd, ifname, &range) < 0) ||
1984      (range.we_version_compiled < 11))
1985     fprintf(stderr, "%-8.16s  no modulation information.\n\n",
1986             ifname);
1987   else
1988     {
1989       if(range.modul_capa == 0x0)
1990         printf("%-8.16s  unknown modulation information.\n\n", ifname);
1991       else
1992         {
1993           int i;
1994           printf("%-8.16s  Modulations available :\n", ifname);
1995
1996           /* Display each modulation available */
1997           for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
1998             {
1999               if((range.modul_capa & iw_modul_list[i].mask)
2000                  == iw_modul_list[i].mask)
2001                 printf("              %-8s: %s\n",
2002                        iw_modul_list[i].cmd, iw_modul_list[i].verbose);
2003             }
2004
2005           /* Get current modulations settings */
2006           wrq.u.param.flags = 0;
2007           if(iw_get_ext(skfd, ifname, SIOCGIWMODUL, &wrq) >= 0)
2008             {
2009               unsigned int      modul = wrq.u.param.value;
2010               int               n = 0;
2011
2012               printf("          Current modulations %c",
2013                      wrq.u.param.fixed ? '=' : ':');
2014
2015               /* Display each modulation enabled */
2016               for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
2017                 {
2018                   if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
2019                     {
2020                       if((n++ % 8) == 0)
2021                         printf("\n              ");
2022                       else
2023                         printf(" ; ");
2024                       printf("%s", iw_modul_list[i].cmd);
2025                     }
2026                 }
2027
2028               printf("\n");
2029             }
2030           printf("\n");
2031         }
2032     }
2033   return(0);
2034 }
2035 #endif  /* WE_ESSENTIAL */
2036
2037 /************************* COMMON UTILITIES *************************/
2038 /*
2039  * This section was initially written by Michael Tokarev <mjt@tls.msk.ru>
2040  * but heavily modified by me ;-)
2041  */
2042
2043 /*------------------------------------------------------------------*/
2044 /*
2045  * Map command line arguments to the proper procedure...
2046  */
2047 typedef struct iwlist_entry {
2048   const char *          cmd;            /* Command line shorthand */
2049   iw_enum_handler       fn;             /* Subroutine */
2050   int                   max_count;
2051   const char *          argsname;       /* Args as human readable string */
2052 } iwlist_cmd;
2053
2054 static const struct iwlist_entry iwlist_cmds[] = {
2055   { "scanning",         print_scanning_info,    -1, "[essid NNN] [last]" },
2056   { "frequency",        print_freq_info,        0, NULL },
2057   { "channel",          print_freq_info,        0, NULL },
2058   { "bitrate",          print_bitrate_info,     0, NULL },
2059   { "rate",             print_bitrate_info,     0, NULL },
2060   { "encryption",       print_keys_info,        0, NULL },
2061   { "keys",             print_keys_info,        0, NULL },
2062   { "power",            print_pm_info,          0, NULL },
2063 #ifndef WE_ESSENTIAL
2064   { "txpower",          print_txpower_info,     0, NULL },
2065   { "retry",            print_retry_info,       0, NULL },
2066   { "ap",               print_ap_info,          0, NULL },
2067   { "accesspoints",     print_ap_info,          0, NULL },
2068   { "peers",            print_ap_info,          0, NULL },
2069   { "event",            print_event_capa_info,  0, NULL },
2070   { "auth",             print_auth_info,        0, NULL },
2071   { "wpakeys",          print_wpakeys_info,     0, NULL },
2072   { "genie",            print_gen_ie_info,      0, NULL },
2073   { "modulation",       print_modul_info,       0, NULL },
2074 #endif  /* WE_ESSENTIAL */
2075   { NULL, NULL, 0, 0 },
2076 };
2077
2078 /*------------------------------------------------------------------*/
2079 /*
2080  * Find the most appropriate command matching the command line
2081  */
2082 static inline const iwlist_cmd *
2083 find_command(const char *       cmd)
2084 {
2085   const iwlist_cmd *    found = NULL;
2086   int                   ambig = 0;
2087   unsigned int          len = strlen(cmd);
2088   int                   i;
2089
2090   /* Go through all commands */
2091   for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
2092     {
2093       /* No match -> next one */
2094       if(strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0)
2095         continue;
2096
2097       /* Exact match -> perfect */
2098       if(len == strlen(iwlist_cmds[i].cmd))
2099         return &iwlist_cmds[i];
2100
2101       /* Partial match */
2102       if(found == NULL)
2103         /* First time */
2104         found = &iwlist_cmds[i];
2105       else
2106         /* Another time */
2107         if (iwlist_cmds[i].fn != found->fn)
2108           ambig = 1;
2109     }
2110
2111   if(found == NULL)
2112     {
2113       fprintf(stderr, "iwlist: unknown command `%s' (check 'iwlist --help').\n", cmd);
2114       return NULL;
2115     }
2116
2117   if(ambig)
2118     {
2119       fprintf(stderr, "iwlist: command `%s' is ambiguous (check 'iwlist --help').\n", cmd);
2120       return NULL;
2121     }
2122
2123   return found;
2124 }
2125
2126 /*------------------------------------------------------------------*/
2127 /*
2128  * Display help
2129  */
2130 static void iw_usage(int status)
2131 {
2132   FILE *                f = status ? stderr : stdout;
2133   int                   i;
2134
2135   for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
2136     {
2137       fprintf(f, "%s [interface] %s %s\n",
2138               (i ? "             " : "Usage: iwlist"),
2139               iwlist_cmds[i].cmd,
2140               iwlist_cmds[i].argsname ? iwlist_cmds[i].argsname : "");
2141     }
2142
2143   exit(status);
2144 }
2145
2146 /******************************* MAIN ********************************/
2147
2148 /*------------------------------------------------------------------*/
2149 /*
2150  * The main !
2151  */
2152 int
2153 main(int        argc,
2154      char **    argv)
2155 {
2156   int skfd;                     /* generic raw socket desc.     */
2157   char *dev;                    /* device name                  */
2158   char *cmd;                    /* command                      */
2159   char **args;                  /* Command arguments */
2160   int count;                    /* Number of arguments */
2161   const iwlist_cmd *iwcmd;
2162
2163   if(argc < 2)
2164     iw_usage(1);
2165
2166   /* Those don't apply to all interfaces */
2167   if((argc == 2) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
2168     iw_usage(0);
2169   if((argc == 2) && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")))
2170     return(iw_print_version_info("iwlist"));
2171
2172   if(argc == 2)
2173     {
2174       cmd = argv[1];
2175       dev = NULL;
2176       args = NULL;
2177       count = 0;
2178     }
2179   else
2180     {
2181       cmd = argv[2];
2182       dev = argv[1];
2183       args = argv + 3;
2184       count = argc - 3;
2185     }
2186
2187   /* find a command */
2188   iwcmd = find_command(cmd);
2189   if(iwcmd == NULL)
2190     return 1;
2191
2192   /* Check arg numbers */
2193   if((iwcmd->max_count >= 0) && (count > iwcmd->max_count))
2194     {
2195       fprintf(stderr, "iwlist: command `%s' needs fewer arguments (max %d)\n",
2196               iwcmd->cmd, iwcmd->max_count);
2197       return 1;
2198     }
2199
2200   /* Create a channel to the NET kernel. */
2201   if((skfd = iw_sockets_open()) < 0)
2202     {
2203       perror("socket");
2204       return -1;
2205     }
2206
2207   /* do the actual work */
2208   if (dev)
2209     (*iwcmd->fn)(skfd, dev, args, count);
2210   else
2211     iw_enum_devices(skfd, iwcmd->fn, args, count);
2212
2213   /* Close the socket. */
2214   iw_sockets_close(skfd);
2215
2216   return 0;
2217 }