OSDN Git Service

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