OSDN Git Service

Add Android.mk
[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-private.h"              /* Private 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 + 2];   /* ESSID */
88   char                  pessid[4 * IW_ESSID_MAX_SIZE + 1];      /* Printable 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 + 2;
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 < wrq.u.essid.length; 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       iw_essid_escape(pessid, essid, wrq.u.essid.length);
120       printf("%-8.16s  ESSID:\"%s\"\n", ifname, pessid);
121       break;
122     }
123
124   return(0);
125 }
126
127 /*------------------------------------------------------------------*/
128 /*
129  * Display the NWID if possible
130  */
131 static int
132 print_nwid(int          skfd,
133            const char * ifname,
134            int          format)
135 {
136   struct iwreq          wrq;
137
138   /* Get network ID */
139   if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) < 0)
140     return(-1);
141
142   switch(format)
143     {
144     case FORMAT_SCHEME:
145       /* Prefix with nwid to avoid name space collisions */
146       printf("nwid%X\n", wrq.u.nwid.value);
147       break;
148     case FORMAT_RAW:
149       printf("%X\n", wrq.u.nwid.value);
150       break;
151     default:
152       printf("%-8.16s  NWID:%X\n", ifname, wrq.u.nwid.value);
153       break;
154     }
155
156   return(0);
157 }
158
159 /**************************** AP ADDRESS ****************************/
160
161 /*------------------------------------------------------------------*/
162 /*
163  * Display the AP Address if possible
164  */
165 static int
166 print_ap(int            skfd,
167          const char *   ifname,
168          int            format)
169 {
170   struct iwreq          wrq;
171   char                  buffer[64];
172
173   /* Get AP Address */
174   if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) < 0)
175     return(-1);
176
177   /* Print */
178   iw_ether_ntop((const struct ether_addr *) wrq.u.ap_addr.sa_data, buffer);
179   switch(format)
180     {
181     case FORMAT_SCHEME:
182       /* I think ':' are not problematic, because Pcmcia scripts
183        * seem to handle them properly... */
184     case FORMAT_RAW:
185       printf("%s\n", buffer);
186       break;
187     default:
188       printf("%-8.16s  Access Point/Cell: %s\n", ifname, buffer);
189       break;
190     }
191
192   return(0);
193 }
194
195 /****************************** OTHER ******************************/
196
197 /*------------------------------------------------------------------*/
198 /*
199  * Display the frequency (or channel) if possible
200  */
201 static int
202 print_freq(int          skfd,
203            const char * ifname,
204            int          format)
205 {
206   struct iwreq          wrq;
207   double                freq;
208   char                  buffer[64];
209
210   /* Get frequency / channel */
211   if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
212     return(-1);
213
214   /* Print */
215   freq = iw_freq2float(&(wrq.u.freq));
216   switch(format)
217     {
218     case FORMAT_SCHEME:
219       /* Prefix with freq to avoid name space collisions */
220       printf("freq%g\n", freq);
221       break;
222     case FORMAT_RAW:
223       printf("%g\n", freq);
224       break;
225     default:
226       iw_print_freq(buffer, sizeof(buffer), freq, -1, wrq.u.freq.flags);
227       printf("%-8.16s  %s\n", ifname, buffer);
228       break;
229     }
230
231   return(0);
232 }
233
234 /*------------------------------------------------------------------*/
235 /*
236  * Display the channel (converted from frequency) if possible
237  */
238 static int
239 print_channel(int               skfd,
240               const char *      ifname,
241               int               format)
242 {
243   struct iwreq          wrq;
244   struct iw_range       range;
245   double                freq;
246   int                   channel;
247
248   /* Get frequency / channel */
249   if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0)
250     return(-1);
251
252   /* Convert to channel */
253   if(iw_get_range_info(skfd, ifname, &range) < 0)
254     return(-2);
255   freq = iw_freq2float(&(wrq.u.freq));
256   if(freq < KILO)
257     channel = (int) freq;
258   else
259     {
260       channel = iw_freq_to_channel(freq, &range);
261       if(channel < 0)
262         return(-3);
263     }
264
265   /* Print */
266   switch(format)
267     {
268     case FORMAT_SCHEME:
269       /* Prefix with freq to avoid name space collisions */
270       printf("channel%d\n", channel);
271       break;
272     case FORMAT_RAW:
273       printf("%d\n", channel);
274       break;
275     default:
276       printf("%-8.16s  Channel:%d\n", ifname, channel);
277       break;
278     }
279
280   return(0);
281 }
282
283 /*------------------------------------------------------------------*/
284 /*
285  * Display the mode if possible
286  */
287 static int
288 print_mode(int          skfd,
289            const char * ifname,
290            int          format)
291 {
292   struct iwreq          wrq;
293
294   /* Get frequency / channel */
295   if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) < 0)
296     return(-1);
297   if(wrq.u.mode >= IW_NUM_OPER_MODE)
298     return(-2);
299
300   /* Print */
301   switch(format)
302     {
303     case FORMAT_SCHEME:
304       /* Strip all white space and stuff */
305       if(wrq.u.mode == IW_MODE_ADHOC)
306         printf("AdHoc\n");
307       else
308         printf("%s\n", iw_operation_mode[wrq.u.mode]);
309       break;
310     case FORMAT_RAW:
311       printf("%d\n", wrq.u.mode);
312       break;
313     default:
314       printf("%-8.16s  Mode:%s\n", ifname, iw_operation_mode[wrq.u.mode]);
315       break;
316     }
317
318   return(0);
319 }
320
321 /*------------------------------------------------------------------*/
322 /*
323  * Display the ESSID if possible
324  */
325 static int
326 print_protocol(int              skfd,
327                const char *     ifname,
328                int              format)
329 {
330   struct iwreq          wrq;
331   char                  proto[IFNAMSIZ + 1];    /* Protocol */
332   char                  pproto[IFNAMSIZ + 1];   /* Pcmcia format */
333   unsigned int          i;
334   unsigned int          j;
335
336   /* Get Protocol name */
337   if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0)
338     return(-1);
339   strncpy(proto, wrq.u.name, IFNAMSIZ);
340   proto[IFNAMSIZ] = '\0';
341
342   switch(format)
343     {
344     case FORMAT_SCHEME:
345       /* Strip all white space and stuff */
346       j = 0;
347       for(i = 0; i < strlen(proto); i++)
348         if(isalnum(proto[i]))
349           pproto[j++] = proto[i];
350       pproto[j] = '\0';
351       if((j == 0) || (j > 32))
352         return(-2);
353       printf("%s\n", pproto);
354       break;
355     case FORMAT_RAW:
356       printf("%s\n", proto);
357       break;
358     default:
359       printf("%-8.16s  Protocol Name:\"%s\"\n", ifname, proto);
360       break;
361     }
362
363   return(0);
364 }
365
366 /******************************* MAIN ********************************/
367
368 /*------------------------------------------------------------------*/
369 /*
370  * Check options and call the proper handler
371  */
372 static int
373 print_one_device(int            skfd,
374                  int            format,
375                  int            wtype,
376                  const char*    ifname)
377 {
378   int ret;
379
380   /* Check wtype */
381   switch(wtype)
382     {
383     case WTYPE_AP:
384       /* Try to print an AP */
385       ret = print_ap(skfd, ifname, format);
386       break;
387
388     case WTYPE_CHANNEL:
389       /* Try to print channel */
390       ret = print_channel(skfd, ifname, format);
391       break;
392
393     case WTYPE_FREQ:
394       /* Try to print frequency */
395       ret = print_freq(skfd, ifname, format);
396       break;
397
398     case WTYPE_MODE:
399       /* Try to print the mode */
400       ret = print_mode(skfd, ifname, format);
401       break;
402
403     case WTYPE_PROTO:
404       /* Try to print the protocol */
405       ret = print_protocol(skfd, ifname, format);
406       break;
407
408     default:
409       /* Try to print an ESSID */
410       ret = print_essid(skfd, ifname, format);
411       if(ret < 0)
412         {
413           /* Try to print a nwid */
414           ret = print_nwid(skfd, ifname, format);
415         }
416     }
417
418   return(ret);
419 }
420
421 /*------------------------------------------------------------------*/
422 /*
423  * Try the various devices until one return something we can use
424  *
425  * Note : we can't use iw_enum_devices() because we want a different
426  * behaviour :
427  *      1) Stop at the first valid wireless device
428  *      2) Only go through active devices
429  */
430 static int
431 scan_devices(int                skfd,
432              int                format,
433              int                wtype)
434 {
435   char          buff[1024];
436   struct ifconf ifc;
437   struct ifreq *ifr;
438   int           i;
439
440   /* Get list of active devices */
441   ifc.ifc_len = sizeof(buff);
442   ifc.ifc_buf = buff;
443   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
444     {
445       perror("SIOCGIFCONF");
446       return(-1);
447     }
448   ifr = ifc.ifc_req;
449
450   /* Print the first match */
451   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
452     {
453       if(print_one_device(skfd, format, wtype, ifr->ifr_name) >= 0)
454         return 0;
455     }
456   return(-1);
457 }
458
459 /*------------------------------------------------------------------*/
460 /*
461  * helper
462  */
463 static void
464 iw_usage(int status)
465 {
466   fputs("Usage iwgetid [OPTIONS] [ifname]\n"
467         "  Options are:\n"
468         "    -a,--ap       Print the access point address\n"
469         "    -c,--channel  Print the current channel\n"
470         "    -f,--freq     Print the current frequency\n"
471         "    -m,--mode     Print the current mode\n"
472         "    -p,--protocol Print the protocol name\n"
473         "    -r,--raw      Format the output as raw value for shell scripts\n"
474         "    -s,--scheme   Format the output as a PCMCIA scheme identifier\n"
475         "    -h,--help     Print this message\n",
476         status ? stderr : stdout);
477   exit(status);
478 }
479
480 static const struct option long_opts[] = {
481   { "ap", no_argument, NULL, 'a' },
482   { "channel", no_argument, NULL, 'c' },
483   { "freq", no_argument, NULL, 'f' },
484   { "mode", no_argument, NULL, 'm' },
485   { "protocol", no_argument, NULL, 'p' },
486   { "help", no_argument, NULL, 'h' },
487   { "raw", no_argument, NULL, 'r' },
488   { "scheme", no_argument, NULL, 's' },
489   { NULL, 0, NULL, 0 }
490 };
491
492 /*------------------------------------------------------------------*/
493 /*
494  * The main !
495  */
496 int
497 main(int        argc,
498      char **    argv)
499 {
500   int   skfd;                   /* generic raw socket desc.     */
501   int   format = FORMAT_DEFAULT;
502   int   wtype = WTYPE_ESSID;
503   int   opt;
504   int   ret = -1;
505
506   /* Check command line arguments */
507   while((opt = getopt_long(argc, argv, "acfhmprs", long_opts, NULL)) > 0)
508     {
509       switch(opt)
510         {
511         case 'a':
512           /* User wants AP/Cell Address */
513           wtype = WTYPE_AP;
514           break;
515
516         case 'c':
517           /* User wants channel only */
518           wtype = WTYPE_CHANNEL;
519           break;
520
521         case 'f':
522           /* User wants frequency/channel */
523           wtype = WTYPE_FREQ;
524           break;
525
526         case 'm':
527           /* User wants the mode */
528           wtype = WTYPE_MODE;
529           break;
530
531         case 'p':
532           /* User wants the protocol */
533           wtype = WTYPE_PROTO;
534           break;
535
536         case 'h':
537           iw_usage(0);
538           break;
539
540         case 'r':
541           /* User wants a Raw format */
542           format = FORMAT_RAW;
543           break;
544
545         case 's':
546           /* User wants a Scheme format */
547           format = FORMAT_SCHEME;
548           break;
549
550         default:
551           iw_usage(1);
552           break;
553         }
554     }
555   if(optind + 1 < argc) {
556     fputs("Too many arguments.\n", stderr);
557     iw_usage(1);
558   }
559
560   /* Create a channel to the NET kernel. */
561   if((skfd = iw_sockets_open()) < 0)
562     {
563       perror("socket");
564       return(-1);
565     }
566
567   /* Check if first argument is a device name */
568   if(optind < argc)
569     {
570       /* Yes : query only this device */
571       ret = print_one_device(skfd, format, wtype, argv[optind]);
572     }
573   else
574     {
575       /* No : query all devices and print first found */
576       ret = scan_devices(skfd, format, wtype);
577     }
578
579   fflush(stdout);
580   iw_sockets_close(skfd);
581   return(ret);
582 }