blob: 1d74910cd4b9ea59e0e4007bfe5c14521c1417ac [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
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 */
87int
88iw_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 */
123void
124iw_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 */
136double
137iw_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 */
156void
157iw_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/*------------------------------------------------------------------*/
177const 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 */
191static int
192print_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 */
235static int
236print_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 */
267static int
268print_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 */
303static int
304print_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 */
337static int
338print_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 */
369static int
370print_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 */
414static int
415print_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 */
462static int
463scan_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 */
495static void
496iw_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
510static 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 */
524int
525main(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}