OSDN Git Service

50db6c91f09e42a80879a54990e745a0744ccc13
[android-x86/external-wireless-tools.git] / wireless_tools / iwlist.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPLB '99 - HPL 99->01
5  *
6  * This tool can access various piece of information on the card
7  * not part of iwconfig...
8  * You need to link this code against "iwcommon.c" and "-lm".
9  *
10  * This file is released under the GPL license.
11  */
12
13 #include "iwlib.h"              /* Header */
14
15 /*********************** FREQUENCIES/CHANNELS ***********************/
16
17 /*------------------------------------------------------------------*/
18 /*
19  * Print the number of channels and available frequency for the device
20  */
21 static void
22 print_freq_info(int             skfd,
23                 char *          ifname)
24 {
25   float                 freq;
26   struct iw_range       range;
27   int                   k;
28
29   if(iw_get_range_info(skfd, ifname, &range) < 0)
30       fprintf(stderr, "%-8.8s  no frequency information.\n\n",
31                       ifname);
32   else
33     {
34       if(range.num_frequency > 0)
35         {
36           printf("%-8.8s  %d channels in total; available frequencies :\n",
37                  ifname, range.num_channels);
38           /* Print them all */
39           for(k = 0; k < range.num_frequency; k++)
40             {
41               printf("\t  Channel %.2d : ", range.freq[k].i);
42               freq = iw_freq2float(&(range.freq[k]));
43               if(freq >= GIGA)
44                 printf("%g GHz\n", freq / GIGA);
45               else
46                 if(freq >= MEGA)
47                   printf("%g MHz\n", freq / MEGA);
48                 else
49                   printf("%g kHz\n", freq / KILO);
50             }
51           printf("\n\n");
52         }
53       else
54         printf("%-8.8s  %d channels\n\n",
55                ifname, range.num_channels);
56     }
57 }
58
59 /************************ ACCESS POINT LIST ************************/
60
61 /*------------------------------------------------------------------*/
62 /*
63  * Display the list of ap addresses and the associated stats
64  * Exacly the same as the spy list, only with different IOCTL and messages
65  */
66 static void
67 print_ap_info(int       skfd,
68               char *    ifname)
69 {
70   struct iwreq          wrq;
71   char          buffer[(sizeof(struct iw_quality) +
72                         sizeof(struct sockaddr)) * IW_MAX_AP];
73   char          temp[128];
74   struct sockaddr *     hwa;
75   struct iw_quality *   qual;
76   iwrange       range;
77   int           has_range = 0;
78   int           has_qual = 0;
79   int           n;
80   int           i;
81
82   /* Collect stats */
83   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
84   wrq.u.data.pointer = (caddr_t) buffer;
85   wrq.u.data.length = 0;
86   wrq.u.data.flags = 0;
87   if(ioctl(skfd, SIOCGIWAPLIST, &wrq) < 0)
88     {
89       fprintf(stderr, "%-8.8s  Interface doesn't have a list of Access Points\n\n", ifname);
90       return;
91     }
92
93   /* Number of addresses */
94   n = wrq.u.data.length;
95   has_qual = wrq.u.data.flags;
96
97   /* The two lists */
98   hwa = (struct sockaddr *) buffer;
99   qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
100
101   /* Check if we have valid address types */
102   if(iw_check_addr_type(skfd, ifname) < 0)
103     {
104       fprintf(stderr, "%-8.8s  Interface doesn't support MAC & IP addresses\n\n", ifname);
105       return;
106     }
107
108   /* Get range info if we can */
109   if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
110     has_range = 1;
111
112   /* Display it */
113   if(n == 0)
114     printf("%-8.8s  No Access Point in range\n", ifname);
115   else
116     printf("%-8.8s  Access Points in range:\n", ifname);
117   for(i = 0; i < n; i++)
118     {
119       if(has_qual)
120         {
121           /* Print stats for this address */
122           printf("    %s : ", iw_pr_ether(temp, hwa[i].sa_data));
123           iw_print_stats(temp, &qual[i], &range, has_range);
124           printf("%s\n", temp);
125         }
126       else
127         /* Only print the address */
128         printf("    %s\n", iw_pr_ether(temp, hwa[i].sa_data));
129     }
130   printf("\n");
131 }
132
133 /***************************** BITRATES *****************************/
134
135 /*------------------------------------------------------------------*/
136 /*
137  * Print the number of available bitrates for the device
138  */
139 static void
140 print_bitrate_info(int          skfd,
141                    char *       ifname)
142 {
143   float                 bitrate;
144   struct iw_range       range;
145   int                   k;
146
147   /* Extract range info */
148   if(iw_get_range_info(skfd, ifname, &range) < 0)
149       fprintf(stderr, "%-8.8s  no bit-rate information.\n\n",
150                       ifname);
151   else
152     {
153       if((range.num_bitrates > 0) && (range.num_bitrates < IW_MAX_BITRATES))
154         {
155           printf("%-8.8s  %d available bit-rates :\n",
156                  ifname, range.num_bitrates);
157           /* Print them all */
158           for(k = 0; k < range.num_bitrates; k++)
159             {
160               printf("\t  ");
161               bitrate = range.bitrate[k];
162               if(bitrate >= GIGA)
163                 printf("%g Gb/s\n", bitrate / GIGA);
164               else
165                 if(bitrate >= MEGA)
166                   printf("%g Mb/s\n", bitrate / MEGA);
167                 else
168                   printf("%g kb/s\n", bitrate / KILO);
169             }
170           printf("\n\n");
171         }
172       else
173         printf("%-8.8s  No bit-rates ? Please update driver...\n\n", ifname);
174     }
175 }
176
177 /************************* ENCRYPTION KEYS *************************/
178
179 /*------------------------------------------------------------------*/
180 /*
181  * Print the number of available encryption key for the device
182  */
183 static void
184 print_keys_info(int             skfd,
185                 char *          ifname)
186 {
187   struct iwreq          wrq;
188   struct iw_range       range;
189   unsigned char         key[IW_ENCODING_TOKEN_MAX];
190   int                   k;
191   char                  buffer[128];
192
193   /* Extract range info */
194   if(iw_get_range_info(skfd, ifname, &range) < 0)
195       fprintf(stderr, "%-8.8s  no encryption keys information.\n\n",
196                       ifname);
197   else
198     {
199       printf("%-8.8s  ", ifname);
200       /* Print key sizes */
201       if((range.num_encoding_sizes > 0) &&
202          (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
203         {
204           printf("%d key sizes : %d", range.num_encoding_sizes,
205                  range.encoding_size[0] * 8);
206           /* Print them all */
207           for(k = 1; k < range.num_encoding_sizes; k++)
208             printf(", %d", range.encoding_size[k] * 8);
209           printf("bits\n          ");
210         }
211       /* Print the keys and associate mode */
212       printf("%d keys available :\n", range.max_encoding_tokens);
213       for(k = 1; k <= range.max_encoding_tokens; k++)
214         {
215           strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
216           wrq.u.data.pointer = (caddr_t) key;
217           wrq.u.data.length = 0;
218           wrq.u.data.flags = k;
219           if(ioctl(skfd, SIOCGIWENCODE, &wrq) < 0)
220             {
221               fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
222               break;
223             }
224           if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
225              (wrq.u.data.length == 0))
226             printf("\t\t[%d]: off\n", k);
227           else
228             {
229               /* Display the key */
230               iw_print_key(buffer, key, wrq.u.data.length, wrq.u.data.flags);
231               printf("\t\t[%d]: %s", k, buffer);
232
233               /* Other info... */
234               printf(" (%d bits)", wrq.u.data.length * 8);
235               printf("\n");
236             }
237         }
238       /* Print current key and mode */
239       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
240       wrq.u.data.pointer = (caddr_t) key;
241       wrq.u.data.length = 0;
242       wrq.u.data.flags = 0;     /* Set index to zero to get current */
243       if(ioctl(skfd, SIOCGIWENCODE, &wrq) < 0)
244         {
245           fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
246           return;
247         }
248       printf("          Current Transmit Key: [%d]\n",
249              wrq.u.data.flags & IW_ENCODE_INDEX);
250       if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
251         printf("          Encryption mode:restricted\n");
252       if(wrq.u.data.flags & IW_ENCODE_OPEN)
253         printf("          Encryption mode:open\n");
254
255       printf("\n\n");
256     }
257 }
258
259 /************************* POWER MANAGEMENT *************************/
260
261 /*------------------------------------------------------------------*/
262 /*
263  * Print Power Management info for each device
264  */
265 static inline int
266 get_pm_value(int                skfd,
267              char *             ifname,
268              struct iwreq *     pwrq,
269              int                flags,
270              char *             buffer)
271 {
272   /* Get Another Power Management value */
273   strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);
274   pwrq->u.power.flags = flags;
275   if(ioctl(skfd, SIOCGIWPOWER, pwrq) >= 0)
276     {
277       /* Let's check the value and its type */
278       if(pwrq->u.power.flags & IW_POWER_TYPE)
279         {
280           iw_print_pm_value(buffer, pwrq->u.power.value, pwrq->u.power.flags);
281           printf("\n                 %s", buffer);
282         }
283     }
284   return(pwrq->u.power.flags);
285 }
286
287 /*------------------------------------------------------------------*/
288 /*
289  * Print Power Management info for each device
290  */
291 static void
292 print_pm_info(int               skfd,
293               char *            ifname)
294 {
295   struct iwreq          wrq;
296   struct iw_range       range;
297   char                  buffer[128];
298
299   /* Extract range info */
300   if(iw_get_range_info(skfd, ifname, &range) < 0)
301       fprintf(stderr, "%-8.8s  no power management information.\n\n",
302                       ifname);
303   else
304     {
305       printf("%-8.8s  ", ifname);
306 #if WIRELESS_EXT > 9
307       /* Display modes availables */
308       if(range.pm_capa & IW_POWER_MODE)
309         {
310           printf("Supported modes :\n          ");
311           if(range.pm_capa & (IW_POWER_UNICAST_R | IW_POWER_MULTICAST_R))
312             printf("\t\to Receive all packets (unicast & multicast)\n          ");
313           if(range.pm_capa & IW_POWER_UNICAST_R)
314             printf("\t\to Receive Unicast only (discard multicast)\n          ");
315           if(range.pm_capa & IW_POWER_MULTICAST_R)
316             printf("\t\to Receive Multicast only (discard unicast)\n          ");
317           if(range.pm_capa & IW_POWER_FORCE_S)
318             printf("\t\to Force sending using Power Management\n          ");
319           if(range.pm_capa & IW_POWER_REPEATER)
320             printf("\t\to Repeat multicast\n          ");
321         }
322       /* Display min/max period availables */
323       if(range.pmp_flags & IW_POWER_PERIOD)
324         {
325           int   flags = (range.pmp_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
326           /* Display if auto or fixed */
327           if(range.pmp_flags & IW_POWER_MIN)
328             printf("Auto  period  ; ");
329           else
330             printf("Fixed period  ; ");
331           /* Print the range */
332           iw_print_pm_value(buffer, range.min_pmp, flags | IW_POWER_MIN);
333           printf("%s\n                          ", buffer);
334           iw_print_pm_value(buffer, range.max_pmp, flags | IW_POWER_MAX);
335           printf("%s\n          ", buffer);
336           
337         }
338       /* Display min/max timeout availables */
339       if(range.pmt_flags & IW_POWER_TIMEOUT)
340         {
341           int   flags = (range.pmt_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
342           /* Display if auto or fixed */
343           if(range.pmt_flags & IW_POWER_MIN)
344             printf("Auto  timeout ; ");
345           else
346             printf("Fixed timeout ; ");
347           /* Print the range */
348           iw_print_pm_value(buffer, range.min_pmt, flags | IW_POWER_MIN);
349           printf("%s\n                          ", buffer);
350           iw_print_pm_value(buffer, range.max_pmt, flags | IW_POWER_MAX);
351           printf("%s\n          ", buffer);
352           
353         }
354 #endif /* WIRELESS_EXT > 9 */
355
356       /* Get current Power Management settings */
357       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
358       wrq.u.power.flags = 0;
359       if(ioctl(skfd, SIOCGIWPOWER, &wrq) >= 0)
360         {
361           int   flags = wrq.u.power.flags;
362
363           /* Is it disabled ? */
364           if(wrq.u.power.disabled)
365             printf("Current mode:off\n          ");
366           else
367             {
368               int       pm_mask = 0;
369
370               /* Let's check the mode */
371               iw_print_pm_mode(buffer, flags);
372               printf("Current%s", buffer);
373
374               /* Let's check if nothing (simply on) */
375               if((flags & IW_POWER_MODE) == IW_POWER_ON)
376                 printf(" mode:on");
377               printf("\n                 ");
378
379               /* Let's check the value and its type */
380               if(wrq.u.power.flags & IW_POWER_TYPE)
381                 {
382                   iw_print_pm_value(buffer,
383                                     wrq.u.power.value, wrq.u.power.flags);
384                   printf("%s", buffer);
385                 }
386
387               /* If we have been returned a MIN value, ask for the MAX */
388               if(flags & IW_POWER_MIN)
389                 pm_mask = IW_POWER_MAX;
390               /* If we have been returned a MAX value, ask for the MIN */
391               if(flags & IW_POWER_MAX)
392                 pm_mask = IW_POWER_MIN;
393               /* If we have something to ask for... */
394               if(pm_mask)
395                 get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
396
397 #if WIRELESS_EXT > 9
398               /* And if we have both a period and a timeout, ask the other */
399               pm_mask = (range.pm_capa & (~(wrq.u.power.flags) &
400                                           IW_POWER_TYPE));
401               if(pm_mask)
402                 {
403                   int   base_mask = pm_mask;
404                   flags = get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
405                   pm_mask = 0;
406
407                   /* If we have been returned a MIN value, ask for the MAX */
408                   if(flags & IW_POWER_MIN)
409                     pm_mask = IW_POWER_MAX | base_mask;
410                   /* If we have been returned a MAX value, ask for the MIN */
411                   if(flags & IW_POWER_MAX)
412                     pm_mask = IW_POWER_MIN | base_mask;
413                   /* If we have something to ask for... */
414                   if(pm_mask)
415                     get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
416                 }
417 #endif /* WIRELESS_EXT > 9 */
418             }
419         }
420       printf("\n");
421     }
422 }
423
424 /************************** TRANSMIT POWER **************************/
425
426 /*------------------------------------------------------------------*/
427 /*
428  * Print the number of available transmit powers for the device
429  */
430 static void
431 print_txpower_info(int          skfd,
432                    char *       ifname)
433 {
434   struct iw_range       range;
435   int                   dbm;
436   int                   mwatt;
437   int                   k;
438
439 #if WIRELESS_EXT > 9
440   /* Extract range info */
441   if(iw_get_range_info(skfd, ifname, &range) < 0)
442       fprintf(stderr, "%-8.8s  no transmit-power information.\n\n",
443                       ifname);
444   else
445     {
446       if((range.num_txpower > 0) && (range.num_txpower < IW_MAX_TXPOWER))
447         {
448           printf("%-8.8s  %d available transmit-powers :\n",
449                  ifname, range.num_txpower);
450           /* Print them all */
451           for(k = 0; k < range.num_txpower; k++)
452             {
453               if(range.txpower_capa & IW_TXPOW_MWATT)
454                 {
455                   dbm = iw_mwatt2dbm(range.txpower[k]);
456                   mwatt = range.txpower[k];
457                 }
458               else
459                 {
460                   dbm = range.txpower[k];
461                   mwatt = iw_dbm2mwatt(range.txpower[k]);
462                 }
463               printf("\t  %d dBm  \t(%d mW)\n", dbm, mwatt);
464             }
465           printf("\n\n");
466         }
467       else
468         printf("%-8.8s  No transmit-powers ? Please update driver...\n\n", ifname);
469     }
470 #endif /* WIRELESS_EXT > 9 */
471 }
472
473 /*********************** RETRY LIMIT/LIFETIME ***********************/
474
475 #if WIRELESS_EXT > 10
476 /*------------------------------------------------------------------*/
477 /*
478  * Print one retry value
479  */
480 static inline int
481 get_retry_value(int             skfd,
482                 char *          ifname,
483                 struct iwreq *  pwrq,
484                 int             flags,
485                 char *          buffer)
486 {
487   /* Get Another retry value */
488   strncpy(pwrq->ifr_name, ifname, IFNAMSIZ);
489   pwrq->u.retry.flags = flags;
490   if(ioctl(skfd, SIOCGIWRETRY, pwrq) >= 0)
491     {
492       /* Let's check the value and its type */
493       if(pwrq->u.retry.flags & IW_RETRY_TYPE)
494         {
495           iw_print_retry_value(buffer,
496                                pwrq->u.retry.value, pwrq->u.retry.flags);
497           printf("%s\n                 ", buffer);
498         }
499     }
500   return(pwrq->u.retry.flags);
501 }
502
503 /*------------------------------------------------------------------*/
504 /*
505  * Print Retry info for each device
506  */
507 static void
508 print_retry_info(int            skfd,
509                  char *         ifname)
510 {
511   struct iwreq          wrq;
512   struct iw_range       range;
513   char                  buffer[128];
514
515   /* Extract range info */
516   if(iw_get_range_info(skfd, ifname, &range) < 0)
517       fprintf(stderr, "%-8.8s  no retry limit/lifetime information.\n\n",
518               ifname);
519   else
520     {
521       printf("%-8.8s  ", ifname);
522
523       /* Display min/max limit availables */
524       if(range.retry_flags & IW_RETRY_LIMIT)
525         {
526           int   flags = (range.retry_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
527           /* Display if auto or fixed */
528           if(range.retry_flags & IW_RETRY_MIN)
529             printf("Auto  limit    ; ");
530           else
531             printf("Fixed limit    ; ");
532           /* Print the range */
533           iw_print_retry_value(buffer, range.min_retry, flags | IW_RETRY_MIN);
534           printf("%s\n                           ", buffer);
535           iw_print_retry_value(buffer, range.max_retry, flags | IW_RETRY_MAX);
536           printf("%s\n          ", buffer);
537           
538         }
539       /* Display min/max lifetime availables */
540       if(range.r_time_flags & IW_RETRY_LIFETIME)
541         {
542           int   flags = (range.r_time_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
543           /* Display if auto or fixed */
544           if(range.r_time_flags & IW_RETRY_MIN)
545             printf("Auto  lifetime ; ");
546           else
547             printf("Fixed lifetime ; ");
548           /* Print the range */
549           iw_print_retry_value(buffer, range.min_r_time, flags | IW_RETRY_MIN);
550           printf("%s\n                           ", buffer);
551           iw_print_retry_value(buffer, range.max_r_time, flags | IW_RETRY_MAX);
552           printf("%s\n          ", buffer);
553           
554         }
555
556       /* Get current retry settings */
557       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
558       wrq.u.retry.flags = 0;
559       if(ioctl(skfd, SIOCGIWRETRY, &wrq) >= 0)
560         {
561           int   flags = wrq.u.retry.flags;
562
563           /* Is it disabled ? */
564           if(wrq.u.retry.disabled)
565             printf("Current mode:off\n          ");
566           else
567             {
568               int       retry_mask = 0;
569
570               /* Let's check the mode */
571               printf("Current mode:on\n                 ");
572
573               /* Let's check the value and its type */
574               if(wrq.u.retry.flags & IW_RETRY_TYPE)
575                 {
576                   iw_print_retry_value(buffer,
577                                        wrq.u.retry.value, wrq.u.retry.flags);
578                   printf("%s", buffer);
579                 }
580
581               /* If we have been returned a MIN value, ask for the MAX */
582               if(flags & IW_RETRY_MIN)
583                 retry_mask = IW_RETRY_MAX;
584               /* If we have been returned a MAX value, ask for the MIN */
585               if(flags & IW_RETRY_MAX)
586                 retry_mask = IW_RETRY_MIN;
587               /* If we have something to ask for... */
588               if(retry_mask)
589                 get_retry_value(skfd, ifname, &wrq, retry_mask, buffer);
590
591               /* And if we have both a period and a timeout, ask the other */
592               retry_mask = (range.retry_capa & (~(wrq.u.retry.flags) &
593                                           IW_RETRY_TYPE));
594               if(retry_mask)
595                 {
596                   int   base_mask = retry_mask;
597                   flags = get_retry_value(skfd, ifname, &wrq, retry_mask,
598                                           buffer);
599                   retry_mask = 0;
600
601                   /* If we have been returned a MIN value, ask for the MAX */
602                   if(flags & IW_RETRY_MIN)
603                     retry_mask = IW_RETRY_MAX | base_mask;
604                   /* If we have been returned a MAX value, ask for the MIN */
605                   if(flags & IW_RETRY_MAX)
606                     retry_mask = IW_RETRY_MIN | base_mask;
607                   /* If we have something to ask for... */
608                   if(retry_mask)
609                     get_retry_value(skfd, ifname, &wrq, retry_mask, buffer);
610                 }
611             }
612         }
613       printf("\n");
614     }
615 }
616
617 #endif  /* WIRELESS_EXT > 10 */
618
619 /************************* COMMON UTILITIES *************************/
620 /*
621  * This section was written by Michael Tokarev <mjt@tls.msk.ru>
622  */
623
624 /*------------------------------------------------------------------*/
625 /*
626  * Enumerate devices and call specified routine
627  */
628 static void
629 enum_devices(int skfd, void (*fn)(int skfd, char *ifname))
630 {
631   char          buff[1024];
632   struct ifconf ifc;
633   struct ifreq *ifr;
634   int i;
635
636   /* Get list of active devices */
637   ifc.ifc_len = sizeof(buff);
638   ifc.ifc_buf = buff;
639   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
640     {
641       fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno));
642       return;
643     }
644   ifr = ifc.ifc_req;
645
646   /* Print them */
647   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
648     (*fn)(skfd, ifr->ifr_name);
649 }
650
651 /* command list */
652 typedef struct iwlist_entry {
653   const char *cmd;
654   void (*fn)(int skfd, char *ifname);
655 } iwlist_cmd;
656
657 static const struct iwlist_entry iwlist_cmds[] = {
658   { "frequency",    print_freq_info },
659   { "channel",      print_freq_info },
660   { "ap",           print_ap_info },
661   { "accesspoints", print_ap_info },
662   { "bitrate",      print_bitrate_info },
663   { "rate",         print_bitrate_info },
664   { "encription",   print_keys_info },
665   { "key",          print_keys_info },
666   { "power",        print_pm_info },
667   { "txpower",      print_txpower_info },
668 #if WIRELESS_EXT > 10
669   { "retry",        print_retry_info },
670 #endif
671   { NULL, 0 },
672 };
673
674 /* Display help */
675 static void usage(FILE *f)
676 {
677   int i;
678   for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
679     fprintf(f, "%s [interface] %s\n",
680             i ? "             " :
681                 "Usage: iwlist",
682             iwlist_cmds[i].cmd);
683 }
684
685 /******************************* MAIN ********************************/
686
687 /*------------------------------------------------------------------*/
688 /*
689  * The main !
690  */
691 int
692 main(int        argc,
693      char **    argv)
694 {
695   int skfd = -1;                /* generic raw socket desc.     */
696   char *dev;                    /* device name                  */
697   char *cmd;                    /* command                      */
698   int i;
699
700   if(argc == 1 || argc > 3)
701     {
702       usage(stderr);
703       return 1;
704     }
705   if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
706     {
707       usage(stdout);
708       return 0;
709     }
710   if (argc == 2)
711     {
712       cmd = argv[1];
713       dev = NULL;
714     }
715   else
716     {
717       cmd = argv[2];
718       dev = argv[1];
719     }
720
721   /* find a command */
722   {
723     int found = -1, ambig = 0;
724     int len = strlen(cmd);
725     for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
726       {
727         if (strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0)
728           continue;
729         if (len == strlen(iwlist_cmds[i].cmd))  /* exact match */
730           {
731             found = i;
732             ambig = 0;
733             break;
734           }
735         if (found < 0)
736           found = i;
737         else if (iwlist_cmds[i].fn != iwlist_cmds[found].fn)
738           ambig = 1;
739       }
740     if (found < 0)
741       {
742         fprintf(stderr, "iwlist: unknown command `%s'\n", cmd);
743         return 1;
744       }
745     if (ambig)
746       {
747         fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd);
748         return 1;
749       }
750     i = found;
751   }
752
753   /* Create a channel to the NET kernel. */
754   if((skfd = iw_sockets_open()) < 0)
755     {
756       perror("socket");
757       return -1;
758     }
759
760   /* do the actual work */
761   if (dev)
762     (*iwlist_cmds[i].fn)(skfd, dev);
763   else
764     enum_devices(skfd, iwlist_cmds[i].fn);
765
766   /* Close the socket. */
767   close(skfd);
768
769   return 0;
770 }