OSDN Git Service

v28
[android-x86/external-wireless-tools.git] / wireless_tools / iwgetid.c
1 /*
2  *      Wireless Tools
3  *
4  *              Jean II - HPL '01
5  *
6  * Just print the ESSID or NWID...
7  *
8  * This file is released under the GPL license.
9  *     Copyright (c) 1997-2004 Jean Tourrilhes <jt@hpl.hp.com>
10  */
11
12 #include "iwlib.h"              /* Header */
13
14 #include <getopt.h>
15
16 /*
17  * Note on Pcmcia Schemes :
18  * ----------------------
19  *      The purpose of this tool is to use the ESSID discovery mechanism
20  * to select the appropriate Pcmcia Scheme. The card tell us which
21  * ESSID it has found, and we can then select the appropriate Pcmcia
22  * Scheme for this ESSID (Wireless config (encrypt keys) and IP config).
23  *      The way to do it is as follows :
24  *                      cardctl scheme "essidany"
25  *                      delay 100
26  *                      $scheme = iwgetid --scheme
27  *                      cardctl scheme $scheme
28  *      Of course, you need to add a scheme called "essidany" with the
29  * following setting :
30  *                      essidany,*,*,*)
31  *                              ESSID="any"
32  *                              IPADDR="10.0.0.1"
33  *
34  *      This can also be integrated int he Pcmcia scripts.
35  *      Some drivers don't activate the card up to "ifconfig up".
36  * Therefore, they wont scan ESSID up to this point, so we can't
37  * read it reliably in Pcmcia scripts.
38  *      I guess the proper way to write the network script is as follows :
39  *                      if($scheme == "iwgetid") {
40  *                              iwconfig $name essid any
41  *                              iwconfig $name nwid any
42  *                              ifconfig $name up
43  *                              delay 100
44  *                              $scheme = iwgetid $name --scheme
45  *                              ifconfig $name down
46  *                      }
47  *
48  *      This is pseudo code, but you get an idea...
49  *      The "ifconfig up" activate the card.
50  *      The "delay" is necessary to let time for the card scan the
51  * frequencies and associate with the AP.
52  *      The "ifconfig down" is necessary to allow the driver to optimise
53  * the wireless parameters setting (minimise number of card resets).
54  *
55  *      Another cute idea is to have a list of Pcmcia Schemes to try
56  * and to keep the first one that associate (AP address != 0). This
57  * would be necessary for closed networks and cards that can't
58  * discover essid...
59  *
60  * Jean II - 29/3/01
61  */
62
63 /**************************** CONSTANTS ****************************/
64
65 #define FORMAT_DEFAULT  0       /* Nice looking display for the user */
66 #define FORMAT_SCHEME   1       /* To be used as a Pcmcia Scheme */
67 #define FORMAT_RAW      2       /* Raw value, for shell scripts */
68 #define WTYPE_ESSID     0       /* Display ESSID or NWID */
69 #define WTYPE_AP        1       /* Display AP/Cell Address */
70 #define WTYPE_FREQ      2       /* Display frequency/channel */
71 #define WTYPE_CHANNEL   3       /* Display channel (converted from freq) */
72 #define WTYPE_MODE      4       /* Display mode */
73 #define WTYPE_PROTO     5       /* Display protocol name */
74
75 /************************ DISPLAY ESSID/NWID ************************/
76
77 /*------------------------------------------------------------------*/
78 /*
79  * Display the ESSID if possible
80  */
81 static int
82 print_essid(int                 skfd,
83             const char *        ifname,
84             int                 format)
85 {
86   struct iwreq          wrq;
87   char                  essid[IW_ESSID_MAX_SIZE + 1];   /* ESSID */
88   char                  pessid[IW_ESSID_MAX_SIZE + 1];  /* Pcmcia format */
89   unsigned int          i;
90   unsigned int          j;
91
92   /* Make sure ESSID is always NULL terminated */
93   memset(essid, 0, sizeof(essid));
94
95   /* Get ESSID */
96   wrq.u.essid.pointer = (caddr_t) essid;
97   wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
98   wrq.u.essid.flags = 0;
99   if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) < 0)
100     return(-1);
101
102   switch(format)
103     {
104     case FORMAT_SCHEME:
105       /* Strip all white space and stuff */
106       j = 0;
107       for(i = 0; i < strlen(essid); i++)
108         if(isalnum(essid[i]))
109           pessid[j++] = essid[i];
110       pessid[j] = '\0';
111       if((j == 0) || (j > 32))
112         return(-2);
113       printf("%s\n", pessid);
114       break;
115     case FORMAT_RAW:
116       printf("%s\n", essid);
117       break;
118     default:
119       printf("%-8.16s  ESSID:\"%s\"\n", ifname, essid);
120       break;
121     }
122
123   return(0);
124 }
125
126 /*------------------------------------------------------------------*/
127 /*
128  * Display the NWID if possible
129  */
130 static int
131 print_nwid(int          skfd,
132            const char * ifname,
133            int          format)
134 {
135   struct iwreq          wrq;
136
137   /* Get network ID */
138   if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) < 0)
139     return(-1);
140
141   switch(format)
142     {
143     case FORMAT_SCHEME:
144       /* Prefix with nwid to avoid name space collisions */
145       printf("nwid%X\n", wrq.u.nwid.value);
146       break;
147     case FORMAT_RAW:
148       printf("%X\n", wrq.u.nwid.value);
149       break;
150     default:
151       printf("%-8.16s  NWID:%X\n", ifname, wrq.u.nwid.value);
152       break;
153     }
154
155   return(0);
156 }
157
158 /**************************** AP ADDRESS ****************************/
159
160 /*------------------------------------------------------------------*/
161 /*
162  * Display the AP Address if possible
163  */
164 static int
165 print_ap(int            skfd,
166          const char *   ifname,
167          int            format)
168 {
169   struct iwreq          wrq;
170   char                  buffer[64];
171
172   /* Get AP Address */
173   if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) < 0)
174     return(-1);
175
176   /* Print */
177   iw_ether_ntop((const struct ether_addr *) wrq.u.ap_addr.sa_data, buffer);
178   switch(format)
179     {
180     case FORMAT_SCHEME:
181       /* I think ':' are not problematic, because Pcmcia scripts
182        * seem to handle them properly... */
183     case FORMAT_RAW:
184       printf("%s\n", buffer);
185       break;
186     default:
187       printf("%-8.16s  Access Point/Cell: %s\n", ifname, buffer);
188       break;
189     }
190
191   return(0);
192 }
193
194 /****************************** OTHER ******************************/
195
196 /*------------------------------------------------------------------*/
197 /*
198  * Display the frequency (or channel) if possible
199  */
200 static int
201 print_freq(int          skfd,
202            const char * ifname,
203            int          format)
204 {
205   struct iwreq          wrq;
206   double                freq;
207   char                  buffer[64];
208
209   /* Get frequency / channel */
210   if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
211     return(-1);
212
213   /* Print */
214   freq = iw_freq2float(&(wrq.u.freq));
215   switch(format)
216     {
217     case FORMAT_SCHEME:
218       /* Prefix with freq to avoid name space collisions */
219       printf("freq%g\n", freq);
220       break;
221     case FORMAT_RAW:
222       printf("%g\n", freq);
223       break;
224     default:
225       iw_print_freq(buffer, sizeof(buffer), freq, -1, wrq.u.freq.flags);
226       printf("%-8.16s  %s\n", ifname, buffer);
227       break;
228     }
229
230   return(0);
231 }
232
233 /*------------------------------------------------------------------*/
234 /*
235  * Display the channel (converted from frequency) if possible
236  */
237 static int
238 print_channel(int               skfd,
239               const char *      ifname,
240               int               format)
241 {
242   struct iwreq          wrq;
243   struct iw_range       range;
244   double                freq;
245   int                   channel;
246
247   /* Get frequency / channel */
248   if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
249     return(-1);
250
251   /* Convert to channel */
252   if(iw_get_range_info(skfd, ifname, &range) < 0)
253     return(-2);
254   freq = iw_freq2float(&(wrq.u.freq));
255   if(freq < KILO)
256     channel = (int) freq;
257   else
258     {
259       channel = iw_freq_to_channel(freq, &range);
260       if(channel < 0)
261         return(-3);
262     }
263
264   /* Print */
265   switch(format)
266     {
267     case FORMAT_SCHEME:
268       /* Prefix with freq to avoid name space collisions */
269       printf("channel%d\n", channel);
270       break;
271     case FORMAT_RAW:
272       printf("%d\n", channel);
273       break;
274     default:
275       printf("%-8.16s  Channel:%d\n", ifname, channel);
276       break;
277     }
278
279   return(0);
280 }
281
282 /*------------------------------------------------------------------*/
283 /*
284  * Display the mode if possible
285  */
286 static int
287 print_mode(int          skfd,
288            const char * ifname,
289            int          format)
290 {
291   struct iwreq          wrq;
292
293   /* Get frequency / channel */
294   if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) < 0)
295     return(-1);
296   if(wrq.u.mode >= IW_NUM_OPER_MODE)
297     return(-2);
298
299   /* Print */
300   switch(format)
301     {
302     case FORMAT_SCHEME:
303       /* Strip all white space and stuff */
304       if(wrq.u.mode == IW_MODE_ADHOC)
305         printf("AdHoc\n");
306       else
307         printf("%s\n", iw_operation_mode[wrq.u.mode]);
308       break;
309     case FORMAT_RAW:
310       printf("%d\n", wrq.u.mode);
311       break;
312     default:
313       printf("%-8.16s  Mode:%s\n", ifname, iw_operation_mode[wrq.u.mode]);
314       break;
315     }
316
317   return(0);
318 }
319
320 /*------------------------------------------------------------------*/
321 /*
322  * Display the ESSID if possible
323  */
324 static int
325 print_protocol(int              skfd,
326                const char *     ifname,
327                int              format)
328 {
329   struct iwreq          wrq;
330   char                  proto[IFNAMSIZ + 1];    /* Protocol */
331   char                  pproto[IFNAMSIZ + 1];   /* Pcmcia format */
332   unsigned int          i;
333   unsigned int          j;
334
335   /* Get Protocol name */
336   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
337     return(-1);
338   strncpy(proto, wrq.u.name, IFNAMSIZ);
339   proto[IFNAMSIZ] = '\0';
340
341   switch(format)
342     {
343     case FORMAT_SCHEME:
344       /* Strip all white space and stuff */
345       j = 0;
346       for(i = 0; i < strlen(proto); i++)
347         if(isalnum(proto[i]))
348           pproto[j++] = proto[i];
349       pproto[j] = '\0';
350       if((j == 0) || (j > 32))
351         return(-2);
352       printf("%s\n", pproto);
353       break;
354     case FORMAT_RAW:
355       printf("%s\n", proto);
356       break;
357     default:
358       printf("%-8.16s  Protocol Name:\"%s\"\n", ifname, proto);
359       break;
360     }
361
362   return(0);
363 }
364
365 /******************************* MAIN ********************************/
366
367 /*------------------------------------------------------------------*/
368 /*
369  * Check options and call the proper handler
370  */
371 static int
372 print_one_device(int            skfd,
373                  int            format,
374                  int            wtype,
375                  const char*    ifname)
376 {
377   int ret;
378
379   /* Check wtype */
380   switch(wtype)
381     {
382     case WTYPE_AP:
383       /* Try to print an AP */
384       ret = print_ap(skfd, ifname, format);
385       break;
386
387     case WTYPE_CHANNEL:
388       /* Try to print channel */
389       ret = print_channel(skfd, ifname, format);
390       break;
391
392     case WTYPE_FREQ:
393       /* Try to print frequency */
394       ret = print_freq(skfd, ifname, format);
395       break;
396
397     case WTYPE_MODE:
398       /* Try to print the mode */
399       ret = print_mode(skfd, ifname, format);
400       break;
401
402     case WTYPE_PROTO:
403       /* Try to print the protocol */
404       ret = print_protocol(skfd, ifname, format);
405       break;
406
407     default:
408       /* Try to print an ESSID */
409       ret = print_essid(skfd, ifname, format);
410       if(ret < 0)
411         {
412           /* Try to print a nwid */
413           ret = print_nwid(skfd, ifname, format);
414         }
415     }
416
417   return(ret);
418 }
419
420 /*------------------------------------------------------------------*/
421 /*
422  * Try the various devices until one return something we can use
423  *
424  * Note : we can't use iw_enum_devices() because we want a different
425  * behaviour :
426  *      1) Stop at the first valid wireless device
427  *      2) Only go through active devices
428  */
429 static int
430 scan_devices(int                skfd,
431              int                format,
432              int                wtype)
433 {
434   char          buff[1024];
435   struct ifconf ifc;
436   struct ifreq *ifr;
437   int           i;
438
439   /* Get list of active devices */
440   ifc.ifc_len = sizeof(buff);
441   ifc.ifc_buf = buff;
442   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
443     {
444       perror("SIOCGIFCONF");
445       return(-1);
446     }
447   ifr = ifc.ifc_req;
448
449   /* Print the first match */
450   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
451     {
452       if(print_one_device(skfd, format, wtype, ifr->ifr_name) >= 0)
453         return 0;
454     }
455   return(-1);
456 }
457
458 /*------------------------------------------------------------------*/
459 /*
460  * helper
461  */
462 static void
463 iw_usage(int status)
464 {
465   fputs("Usage iwgetid [OPTIONS] [ifname]\n"
466         "  Options are:\n"
467         "    -a,--ap       Print the access point address\n"
468         "    -c,--channel  Print the current channel\n"
469         "    -f,--freq     Print the current frequency\n"
470         "    -m,--mode     Print the current mode\n"
471         "    -p,--protocol Print the protocol name\n"
472         "    -r,--raw      Format the output as raw value for shell scripts\n"
473         "    -s,--scheme   Format the output as a PCMCIA scheme identifier\n"
474         "    -h,--help     Print this message\n",
475         status ? stderr : stdout);
476   exit(status);
477 }
478
479 static const struct option long_opts[] = {
480   { "ap", no_argument, NULL, 'a' },
481   { "channel", no_argument, NULL, 'c' },
482   { "freq", no_argument, NULL, 'f' },
483   { "mode", no_argument, NULL, 'm' },
484   { "protocol", no_argument, NULL, 'p' },
485   { "help", no_argument, NULL, 'h' },
486   { "raw", no_argument, NULL, 'r' },
487   { "scheme", no_argument, NULL, 's' },
488   { NULL, 0, NULL, 0 }
489 };
490
491 /*------------------------------------------------------------------*/
492 /*
493  * The main !
494  */
495 int
496 main(int        argc,
497      char **    argv)
498 {
499   int   skfd;                   /* generic raw socket desc.     */
500   int   format = FORMAT_DEFAULT;
501   int   wtype = WTYPE_ESSID;
502   int   opt;
503   int   ret = -1;
504
505   /* Check command line arguments */
506   while((opt = getopt_long(argc, argv, "acfhmprs", long_opts, NULL)) > 0)
507     {
508       switch(opt)
509         {
510         case 'a':
511           /* User wants AP/Cell Address */
512           wtype = WTYPE_AP;
513           break;
514
515         case 'c':
516           /* User wants channel only */
517           wtype = WTYPE_CHANNEL;
518           break;
519
520         case 'f':
521           /* User wants frequency/channel */
522           wtype = WTYPE_FREQ;
523           break;
524
525         case 'm':
526           /* User wants the mode */
527           wtype = WTYPE_MODE;
528           break;
529
530         case 'p':
531           /* User wants the protocol */
532           wtype = WTYPE_PROTO;
533           break;
534
535         case 'h':
536           iw_usage(0);
537           break;
538
539         case 'r':
540           /* User wants a Raw format */
541           format = FORMAT_RAW;
542           break;
543
544         case 's':
545           /* User wants a Scheme format */
546           format = FORMAT_SCHEME;
547           break;
548
549         default:
550           iw_usage(1);
551           break;
552         }
553     }
554   if(optind + 1 < argc) {
555     fputs("Too many arguments.\n", stderr);
556     iw_usage(1);
557   }
558
559   /* Create a channel to the NET kernel. */
560   if((skfd = iw_sockets_open()) < 0)
561     {
562       perror("socket");
563       return(-1);
564     }
565
566   /* Check if first argument is a device name */
567   if(optind < argc)
568     {
569       /* Yes : query only this device */
570       ret = print_one_device(skfd, format, wtype, argv[optind]);
571     }
572   else
573     {
574       /* No : query all devices and print first found */
575       ret = scan_devices(skfd, format, wtype);
576     }
577
578   fflush(stdout);
579   iw_sockets_close(skfd);
580   return(ret);
581 }