OSDN Git Service

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