OSDN Git Service

v24
[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
21 /*
22  * Note on Pcmcia Schemes :
23  * ----------------------
24  *      The purpose of this tool is to use the ESSID discovery mechanism
25  * to select the appropriate Pcmcia Scheme. The card tell us which
26  * ESSID it has found, and we can then select the appropriate Pcmcia
27  * Scheme for this ESSID (Wireless config (encrypt keys) and IP config).
28  *      The way to do it is as follows :
29  *                      cardctl scheme "essidany"
30  *                      delay 100
31  *                      $scheme = iwgetid --scheme
32  *                      cardctl scheme $scheme
33  *      Of course, you need to add a scheme called "essidany" with the
34  * following setting :
35  *                      essidany,*,*,*)
36  *                              ESSID="any"
37  *                              IPADDR="10.0.0.1"
38  *
39  *      This can also be integrated int he Pcmcia scripts.
40  *      Some drivers don't activate the card up to "ifconfig up".
41  * Therefore, they wont scan ESSID up to this point, so we can't
42  * read it reliably in Pcmcia scripts.
43  *      I guess the proper way to write the network script is as follows :
44  *                      if($scheme == "iwgetid") {
45  *                              iwconfig $name essid any
46  *                              iwconfig $name nwid any
47  *                              ifconfig $name up
48  *                              delay 100
49  *                              $scheme = iwgetid $name --scheme
50  *                              ifconfig $name down
51  *                      }
52  *
53  *      This is pseudo code, but you get an idea...
54  *      The "ifconfig up" activate the card.
55  *      The "delay" is necessary to let time for the card scan the
56  * frequencies and associate with the AP.
57  *      The "ifconfig down" is necessary to allow the driver to optimise
58  * the wireless parameters setting (minimise number of card resets).
59  *
60  *      Another cute idea is to have a list of Pcmcia Schemes to try
61  * and to keep the first one that associate (AP address != 0). This
62  * would be necessary for closed networks and cards that can't
63  * discover essid...
64  *
65  * Jean II - 29/3/01
66  */
67
68 /*************************** SUBROUTINES ***************************/
69 /*
70  * Just for the heck of it, let's try to not link with iwlib.
71  * This will keep the binary small and tiny...
72  */
73
74 /*------------------------------------------------------------------*/
75 /*
76  * Open a socket.
77  * Depending on the protocol present, open the right socket. The socket
78  * will allow us to talk to the driver.
79  */
80 int
81 iw_sockets_open(void)
82 {
83         int ipx_sock = -1;              /* IPX socket                   */
84         int ax25_sock = -1;             /* AX.25 socket                 */
85         int inet_sock = -1;             /* INET socket                  */
86         int ddp_sock = -1;              /* Appletalk DDP socket         */
87
88         /*
89          * Now pick any (exisiting) useful socket family for generic queries
90          * Note : don't open all the socket, only returns when one matches,
91          * all protocols might not be valid.
92          * Workaround by Jim Kaba <jkaba@sarnoff.com>
93          * Note : in 99% of the case, we will just open the inet_sock.
94          * The remaining 1% case are not fully correct...
95          */
96         inet_sock=socket(AF_INET, SOCK_DGRAM, 0);
97         if(inet_sock!=-1)
98                 return inet_sock;
99         ipx_sock=socket(AF_IPX, SOCK_DGRAM, 0);
100         if(ipx_sock!=-1)
101                 return ipx_sock;
102         ax25_sock=socket(AF_AX25, SOCK_DGRAM, 0);
103         if(ax25_sock!=-1)
104                 return ax25_sock;
105         ddp_sock=socket(AF_APPLETALK, SOCK_DGRAM, 0);
106         /*
107          * If this is -1 we have no known network layers and its time to jump.
108          */
109         return ddp_sock;
110 }
111
112 /*------------------------------------------------------------------*/
113 /*
114  * Display an Ethernet address in readable format.
115  */
116 void
117 iw_ether_ntop(const struct ether_addr* eth, char* buf)
118 {
119   sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
120           eth->ether_addr_octet[0], eth->ether_addr_octet[1],
121           eth->ether_addr_octet[2], eth->ether_addr_octet[3],
122           eth->ether_addr_octet[4], eth->ether_addr_octet[5]);
123 }
124
125 /************************ DISPLAY ESSID/NWID ************************/
126
127 /*------------------------------------------------------------------*/
128 /*
129  * Display the ESSID if possible
130  */
131 static int
132 print_essid(int                 skfd,
133             const char *        ifname,
134             int                 format)
135 {
136   struct iwreq          wrq;
137   char                  essid[IW_ESSID_MAX_SIZE + 1];   /* ESSID */
138   char                  pessid[IW_ESSID_MAX_SIZE + 1];  /* Pcmcia format */
139   unsigned int          i;
140   unsigned int          j;
141
142   /* Get ESSID */
143   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
144   wrq.u.essid.pointer = (caddr_t) essid;
145   wrq.u.essid.length = 0;
146   wrq.u.essid.flags = 0;
147   if(ioctl(skfd, SIOCGIWESSID, &wrq) < 0)
148     return(-1);
149
150   switch(format)
151     {
152     case FORMAT_SCHEME:
153       /* Strip all white space and stuff */
154       j = 0;
155       for(i = 0; i < strlen(essid); i++)
156         if(isalnum(essid[i]))
157           pessid[j++] = essid[i];
158       pessid[j] = '\0';
159       if((j == 0) || (j > 32))
160         return(-2);
161       printf("%s\n", pessid);
162       break;
163     default:
164       printf("%-8.8s  ESSID:\"%s\"\n", ifname, essid);
165       break;
166     }
167
168   return(0);
169 }
170
171 /*------------------------------------------------------------------*/
172 /*
173  * Display the NWID if possible
174  */
175 static int
176 print_nwid(int          skfd,
177            const char * ifname,
178            int          format)
179 {
180   struct iwreq          wrq;
181
182   /* Get network ID */
183   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
184   if(ioctl(skfd, SIOCGIWNWID, &wrq) < 0)
185     return(-1);
186
187   switch(format)
188     {
189     case FORMAT_SCHEME:
190       /* Prefix with nwid to avoid name space collisions */
191       printf("nwid%X\n", wrq.u.nwid.value);
192       break;
193     default:
194       printf("%-8.8s  NWID:%X\n", ifname, wrq.u.nwid.value);
195       break;
196     }
197
198   return(0);
199 }
200
201 /**************************** AP ADDRESS ****************************/
202
203 /*------------------------------------------------------------------*/
204 /*
205  * Display the AP Address if possible
206  */
207 static int
208 print_ap(int            skfd,
209          const char *   ifname,
210          int            format)
211 {
212   struct iwreq          wrq;
213   char                  buffer[64];
214
215   /* Get AP Address */
216   strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
217   if(ioctl(skfd, SIOCGIWAP, &wrq) < 0)
218     return(-1);
219
220   /* Print */
221   iw_ether_ntop((const struct ether_addr *) wrq.u.ap_addr.sa_data, buffer);
222   switch(format)
223     {
224     case FORMAT_SCHEME:
225       /* I think ':' are not problematic, because Pcmcia scripts
226        * seem to handle them properly... */
227       printf("%s\n", buffer);
228       break;
229     default:
230       printf("%-8.8s  Access Point: %s\n", ifname, buffer);
231       break;
232     }
233
234   return(0);
235 }
236
237 /******************************* MAIN ********************************/
238
239 /*------------------------------------------------------------------*/
240 /*
241  * Check options and call the proper handler
242  */
243 static int
244 print_one_device(int            skfd,
245                  int            format,
246                  int            wtype,
247                  const char*    ifname)
248 {
249   int ret;
250
251   /* Check wtype */
252   if(wtype == WTYPE_AP)
253     {
254       /* Try to print an AP */
255       ret = print_ap(skfd, ifname, format);
256       return(ret);
257     }
258
259   /* Try to print an ESSID */
260   ret = print_essid(skfd, ifname, format);
261
262   if(ret < 0)
263     {
264       /* Try to print a nwid */
265       ret = print_nwid(skfd, ifname, format);
266     }
267
268   return(ret);
269 }
270
271 /*------------------------------------------------------------------*/
272 /*
273  * Try the various devices until one return something we can use
274  */
275 static int
276 scan_devices(int                skfd,
277              int                format,
278              int                wtype)
279 {
280   char          buff[1024];
281   struct ifconf ifc;
282   struct ifreq *ifr;
283   int           i;
284
285   /* Get list of active devices */
286   ifc.ifc_len = sizeof(buff);
287   ifc.ifc_buf = buff;
288   if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
289     {
290       perror("SIOCGIFCONF");
291       return(-1);
292     }
293   ifr = ifc.ifc_req;
294
295   /* Print the first match */
296   for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++)
297     {
298       if(print_one_device(skfd, format, wtype, ifr->ifr_name) >= 0)
299         return 0;
300     }
301   return(-1);
302 }
303
304 /*------------------------------------------------------------------*/
305 /*
306  * helper
307  */
308 static void
309 iw_usage(int status)
310 {
311   fputs("Usage iwgetid [OPTIONS] [ifname]\n"
312         "  Options are:\n"
313         "    -a,--ap      Print the access point address\n"
314         "    -h,--help    Print this message\n"
315         "    -s,--scheme  Format the output as a PCMCIA scheme identifier\n",
316         status ? stderr : stdout);
317   exit(status);
318 }
319
320 static const struct option long_opts[] = {
321   { "ap", no_argument, NULL, 'a' },
322   { "help", no_argument, NULL, 'h' },
323   { "scheme", no_argument, NULL, 's' },
324   { NULL, 0, NULL, 0 }
325 };
326
327 /*------------------------------------------------------------------*/
328 /*
329  * The main !
330  */
331 int
332 main(int        argc,
333      char **    argv)
334 {
335   int   skfd;                   /* generic raw socket desc.     */
336   int   format = FORMAT_DEFAULT;
337   int   wtype = WTYPE_ESSID;
338   int   opt;
339   int   ret = -1;
340
341   /* Check command line arguments */
342   while((opt = getopt_long(argc, argv, "ahs", long_opts, NULL)) > 0)
343     {
344       switch(opt)
345         {
346         case 'a':
347           /* User wants AP/Cell Address */
348           wtype = WTYPE_AP;
349           break;
350
351         case 'h':
352           iw_usage(0);
353           break;
354
355         case 's':
356           /* User wants a Scheme format */
357           format = FORMAT_SCHEME;
358           break;
359
360         default:
361           iw_usage(1);
362           break;
363         }
364     }
365   if(optind + 1 < argc) {
366     fputs("Too many arguments.\n", stderr);
367     iw_usage(1);
368   }
369
370   /* Create a channel to the NET kernel. */
371   if((skfd = iw_sockets_open()) < 0)
372     {
373       perror("socket");
374       return(-1);
375     }
376
377   /* Check if first argument is a device name */
378   if(optind < argc)
379     {
380       /* Yes : query only this device */
381       ret = print_one_device(skfd, format, wtype, argv[optind]);
382     }
383   else
384     {
385       /* No : query all devices and print first found */
386       ret = scan_devices(skfd, format, wtype);
387     }
388
389   fflush(stdout);
390   close(skfd);
391   return(ret);
392 }