/* * Wireless Tools * * Jean II - HPL '01 * * Just print the ESSID or NWID... * * This file is released under the GPL license. * Copyright (c) 1997-2004 Jean Tourrilhes */ #include "iwlib.h" /* Header */ #include /* * Note on Pcmcia Schemes : * ---------------------- * The purpose of this tool is to use the ESSID discovery mechanism * to select the appropriate Pcmcia Scheme. The card tell us which * ESSID it has found, and we can then select the appropriate Pcmcia * Scheme for this ESSID (Wireless config (encrypt keys) and IP config). * The way to do it is as follows : * cardctl scheme "essidany" * delay 100 * $scheme = iwgetid --scheme * cardctl scheme $scheme * Of course, you need to add a scheme called "essidany" with the * following setting : * essidany,*,*,*) * ESSID="any" * IPADDR="10.0.0.1" * * This can also be integrated int he Pcmcia scripts. * Some drivers don't activate the card up to "ifconfig up". * Therefore, they wont scan ESSID up to this point, so we can't * read it reliably in Pcmcia scripts. * I guess the proper way to write the network script is as follows : * if($scheme == "iwgetid") { * iwconfig $name essid any * iwconfig $name nwid any * ifconfig $name up * delay 100 * $scheme = iwgetid $name --scheme * ifconfig $name down * } * * This is pseudo code, but you get an idea... * The "ifconfig up" activate the card. * The "delay" is necessary to let time for the card scan the * frequencies and associate with the AP. * The "ifconfig down" is necessary to allow the driver to optimise * the wireless parameters setting (minimise number of card resets). * * Another cute idea is to have a list of Pcmcia Schemes to try * and to keep the first one that associate (AP address != 0). This * would be necessary for closed networks and cards that can't * discover essid... * * Jean II - 29/3/01 */ /**************************** CONSTANTS ****************************/ #define FORMAT_DEFAULT 0 /* Nice looking display for the user */ #define FORMAT_SCHEME 1 /* To be used as a Pcmcia Scheme */ #define FORMAT_RAW 2 /* Raw value, for shell scripts */ #define WTYPE_ESSID 0 /* Display ESSID or NWID */ #define WTYPE_AP 1 /* Display AP/Cell Address */ #define WTYPE_FREQ 2 /* Display frequency/channel */ #define WTYPE_CHANNEL 3 /* Display channel (converted from freq) */ #define WTYPE_MODE 4 /* Display mode */ #define WTYPE_PROTO 5 /* Display protocol name */ /************************ DISPLAY ESSID/NWID ************************/ /*------------------------------------------------------------------*/ /* * Display the ESSID if possible */ static int print_essid(int skfd, const char * ifname, int format) { struct iwreq wrq; char essid[IW_ESSID_MAX_SIZE + 2]; /* ESSID */ char pessid[4 * IW_ESSID_MAX_SIZE + 1]; /* Printable format */ unsigned int i; unsigned int j; /* Make sure ESSID is always NULL terminated */ memset(essid, 0, sizeof(essid)); /* Get ESSID */ wrq.u.essid.pointer = (caddr_t) essid; wrq.u.essid.length = IW_ESSID_MAX_SIZE + 2; wrq.u.essid.flags = 0; if(iw_get_ext(skfd, ifname, SIOCGIWESSID, &wrq) < 0) return(-1); switch(format) { case FORMAT_SCHEME: /* Strip all white space and stuff */ j = 0; for(i = 0; i < strlen(essid); i++) if(isalnum(essid[i])) pessid[j++] = essid[i]; pessid[j] = '\0'; if((j == 0) || (j > 32)) return(-2); printf("%s\n", pessid); break; case FORMAT_RAW: printf("%s\n", essid); break; default: printf("%-8.16s ESSID:\"%s\"\n", ifname, essid); break; } return(0); } /*------------------------------------------------------------------*/ /* * Display the NWID if possible */ static int print_nwid(int skfd, const char * ifname, int format) { struct iwreq wrq; /* Get network ID */ if(iw_get_ext(skfd, ifname, SIOCGIWNWID, &wrq) < 0) return(-1); switch(format) { case FORMAT_SCHEME: /* Prefix with nwid to avoid name space collisions */ printf("nwid%X\n", wrq.u.nwid.value); break; case FORMAT_RAW: printf("%X\n", wrq.u.nwid.value); break; default: printf("%-8.16s NWID:%X\n", ifname, wrq.u.nwid.value); break; } return(0); } /**************************** AP ADDRESS ****************************/ /*------------------------------------------------------------------*/ /* * Display the AP Address if possible */ static int print_ap(int skfd, const char * ifname, int format) { struct iwreq wrq; char buffer[64]; /* Get AP Address */ if(iw_get_ext(skfd, ifname, SIOCGIWAP, &wrq) < 0) return(-1); /* Print */ iw_ether_ntop((const struct ether_addr *) wrq.u.ap_addr.sa_data, buffer); switch(format) { case FORMAT_SCHEME: /* I think ':' are not problematic, because Pcmcia scripts * seem to handle them properly... */ case FORMAT_RAW: printf("%s\n", buffer); break; default: printf("%-8.16s Access Point/Cell: %s\n", ifname, buffer); break; } return(0); } /****************************** OTHER ******************************/ /*------------------------------------------------------------------*/ /* * Display the frequency (or channel) if possible */ static int print_freq(int skfd, const char * ifname, int format) { struct iwreq wrq; double freq; char buffer[64]; /* Get frequency / channel */ if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0) return(-1); /* Print */ freq = iw_freq2float(&(wrq.u.freq)); switch(format) { case FORMAT_SCHEME: /* Prefix with freq to avoid name space collisions */ printf("freq%g\n", freq); break; case FORMAT_RAW: printf("%g\n", freq); break; default: iw_print_freq(buffer, sizeof(buffer), freq, -1, wrq.u.freq.flags); printf("%-8.16s %s\n", ifname, buffer); break; } return(0); } /*------------------------------------------------------------------*/ /* * Display the channel (converted from frequency) if possible */ static int print_channel(int skfd, const char * ifname, int format) { struct iwreq wrq; struct iw_range range; double freq; int channel; /* Get frequency / channel */ if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) < 0) return(-1); /* Convert to channel */ if(iw_get_range_info(skfd, ifname, &range) < 0) return(-2); freq = iw_freq2float(&(wrq.u.freq)); if(freq < KILO) channel = (int) freq; else { channel = iw_freq_to_channel(freq, &range); if(channel < 0) return(-3); } /* Print */ switch(format) { case FORMAT_SCHEME: /* Prefix with freq to avoid name space collisions */ printf("channel%d\n", channel); break; case FORMAT_RAW: printf("%d\n", channel); break; default: printf("%-8.16s Channel:%d\n", ifname, channel); break; } return(0); } /*------------------------------------------------------------------*/ /* * Display the mode if possible */ static int print_mode(int skfd, const char * ifname, int format) { struct iwreq wrq; /* Get frequency / channel */ if(iw_get_ext(skfd, ifname, SIOCGIWMODE, &wrq) < 0) return(-1); if(wrq.u.mode >= IW_NUM_OPER_MODE) return(-2); /* Print */ switch(format) { case FORMAT_SCHEME: /* Strip all white space and stuff */ if(wrq.u.mode == IW_MODE_ADHOC) printf("AdHoc\n"); else printf("%s\n", iw_operation_mode[wrq.u.mode]); break; case FORMAT_RAW: printf("%d\n", wrq.u.mode); break; default: printf("%-8.16s Mode:%s\n", ifname, iw_operation_mode[wrq.u.mode]); break; } return(0); } /*------------------------------------------------------------------*/ /* * Display the ESSID if possible */ static int print_protocol(int skfd, const char * ifname, int format) { struct iwreq wrq; char proto[IFNAMSIZ + 1]; /* Protocol */ char pproto[IFNAMSIZ + 1]; /* Pcmcia format */ unsigned int i; unsigned int j; /* Get Protocol name */ if(iw_get_ext(skfd, ifname, SIOCGIWNAME, &wrq) < 0) return(-1); strncpy(proto, wrq.u.name, IFNAMSIZ); proto[IFNAMSIZ] = '\0'; switch(format) { case FORMAT_SCHEME: /* Strip all white space and stuff */ j = 0; for(i = 0; i < strlen(proto); i++) if(isalnum(proto[i])) pproto[j++] = proto[i]; pproto[j] = '\0'; if((j == 0) || (j > 32)) return(-2); printf("%s\n", pproto); break; case FORMAT_RAW: printf("%s\n", proto); break; default: printf("%-8.16s Protocol Name:\"%s\"\n", ifname, proto); break; } return(0); } /******************************* MAIN ********************************/ /*------------------------------------------------------------------*/ /* * Check options and call the proper handler */ static int print_one_device(int skfd, int format, int wtype, const char* ifname) { int ret; /* Check wtype */ switch(wtype) { case WTYPE_AP: /* Try to print an AP */ ret = print_ap(skfd, ifname, format); break; case WTYPE_CHANNEL: /* Try to print channel */ ret = print_channel(skfd, ifname, format); break; case WTYPE_FREQ: /* Try to print frequency */ ret = print_freq(skfd, ifname, format); break; case WTYPE_MODE: /* Try to print the mode */ ret = print_mode(skfd, ifname, format); break; case WTYPE_PROTO: /* Try to print the protocol */ ret = print_protocol(skfd, ifname, format); break; default: /* Try to print an ESSID */ ret = print_essid(skfd, ifname, format); if(ret < 0) { /* Try to print a nwid */ ret = print_nwid(skfd, ifname, format); } } return(ret); } /*------------------------------------------------------------------*/ /* * Try the various devices until one return something we can use * * Note : we can't use iw_enum_devices() because we want a different * behaviour : * 1) Stop at the first valid wireless device * 2) Only go through active devices */ static int scan_devices(int skfd, int format, int wtype) { char buff[1024]; struct ifconf ifc; struct ifreq *ifr; int i; /* Get list of active devices */ ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { perror("SIOCGIFCONF"); return(-1); } ifr = ifc.ifc_req; /* Print the first match */ for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { if(print_one_device(skfd, format, wtype, ifr->ifr_name) >= 0) return 0; } return(-1); } /*------------------------------------------------------------------*/ /* * helper */ static void iw_usage(int status) { fputs("Usage iwgetid [OPTIONS] [ifname]\n" " Options are:\n" " -a,--ap Print the access point address\n" " -c,--channel Print the current channel\n" " -f,--freq Print the current frequency\n" " -m,--mode Print the current mode\n" " -p,--protocol Print the protocol name\n" " -r,--raw Format the output as raw value for shell scripts\n" " -s,--scheme Format the output as a PCMCIA scheme identifier\n" " -h,--help Print this message\n", status ? stderr : stdout); exit(status); } static const struct option long_opts[] = { { "ap", no_argument, NULL, 'a' }, { "channel", no_argument, NULL, 'c' }, { "freq", no_argument, NULL, 'f' }, { "mode", no_argument, NULL, 'm' }, { "protocol", no_argument, NULL, 'p' }, { "help", no_argument, NULL, 'h' }, { "raw", no_argument, NULL, 'r' }, { "scheme", no_argument, NULL, 's' }, { NULL, 0, NULL, 0 } }; /*------------------------------------------------------------------*/ /* * The main ! */ int main(int argc, char ** argv) { int skfd; /* generic raw socket desc. */ int format = FORMAT_DEFAULT; int wtype = WTYPE_ESSID; int opt; int ret = -1; /* Check command line arguments */ while((opt = getopt_long(argc, argv, "acfhmprs", long_opts, NULL)) > 0) { switch(opt) { case 'a': /* User wants AP/Cell Address */ wtype = WTYPE_AP; break; case 'c': /* User wants channel only */ wtype = WTYPE_CHANNEL; break; case 'f': /* User wants frequency/channel */ wtype = WTYPE_FREQ; break; case 'm': /* User wants the mode */ wtype = WTYPE_MODE; break; case 'p': /* User wants the protocol */ wtype = WTYPE_PROTO; break; case 'h': iw_usage(0); break; case 'r': /* User wants a Raw format */ format = FORMAT_RAW; break; case 's': /* User wants a Scheme format */ format = FORMAT_SCHEME; break; default: iw_usage(1); break; } } if(optind + 1 < argc) { fputs("Too many arguments.\n", stderr); iw_usage(1); } /* Create a channel to the NET kernel. */ if((skfd = iw_sockets_open()) < 0) { perror("socket"); return(-1); } /* Check if first argument is a device name */ if(optind < argc) { /* Yes : query only this device */ ret = print_one_device(skfd, format, wtype, argv[optind]); } else { /* No : query all devices and print first found */ ret = scan_devices(skfd, format, wtype); } fflush(stdout); iw_sockets_close(skfd); return(ret); }