X-Git-Url: http://git.osdn.net/view?p=android-x86%2Fexternal-wireless-tools.git;a=blobdiff_plain;f=wireless_tools%2Fiwlist.c;fp=wireless_tools%2Fiwlist.c;h=0703f3e81a7e3a03eff2a14dcc02a9248bef75c1;hp=30640e6ad671f7aa935594621ec2486e80bd530a;hb=92c266503ddec9d3bd219978c118a77a46dc12d4;hpb=358fbc0574da2a7a460cfec4628e470e7affc236 diff --git a/wireless_tools/iwlist.c b/wireless_tools/iwlist.c index 30640e6..0703f3e 100644 --- a/wireless_tools/iwlist.c +++ b/wireless_tools/iwlist.c @@ -12,6 +12,7 @@ */ #include "iwlib.h" /* Header */ +#include /*********************** FREQUENCIES/CHANNELS ***********************/ @@ -19,14 +20,19 @@ /* * Print the number of channels and available frequency for the device */ -static void +static int print_freq_info(int skfd, - char * ifname) + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { float freq; struct iw_range range; int k; + /* Avoid "Unused parameter" warning */ + args = args; count = count; + if(iw_get_range_info(skfd, ifname, &range) < 0) fprintf(stderr, "%-8.8s no frequency information.\n\n", ifname); @@ -55,6 +61,7 @@ print_freq_info(int skfd, printf("%-8.8s %d channels\n\n", ifname, range.num_channels); } + return(0); } /************************ ACCESS POINT LIST ************************/ @@ -64,9 +71,11 @@ print_freq_info(int skfd, * Display the list of ap addresses and the associated stats * Exacly the same as the spy list, only with different IOCTL and messages */ -static void +static int print_ap_info(int skfd, - char * ifname) + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { struct iwreq wrq; char buffer[(sizeof(struct iw_quality) + @@ -80,6 +89,9 @@ print_ap_info(int skfd, int n; int i; + /* Avoid "Unused parameter" warning */ + args = args; count = count; + /* Collect stats */ wrq.u.data.pointer = (caddr_t) buffer; wrq.u.data.length = IW_MAX_AP; @@ -87,7 +99,7 @@ print_ap_info(int skfd, if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0) { fprintf(stderr, "%-8.8s Interface doesn't have a list of Access Points\n\n", ifname); - return; + return(-1); } /* Number of addresses */ @@ -102,7 +114,7 @@ print_ap_info(int skfd, if(iw_check_mac_addr_type(skfd, ifname) < 0) { fprintf(stderr, "%-8.8s Interface doesn't support MAC addresses\n\n", ifname); - return; + return(-2); } /* Get range info if we can */ @@ -128,6 +140,7 @@ print_ap_info(int skfd, printf(" %s\n", iw_pr_ether(temp, hwa[i].sa_data)); } printf("\n"); + return(0); } /***************************** BITRATES *****************************/ @@ -136,13 +149,18 @@ print_ap_info(int skfd, /* * Print the number of available bitrates for the device */ -static void +static int print_bitrate_info(int skfd, - char * ifname) + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { - float bitrate; struct iw_range range; int k; + char buffer[128]; + + /* Avoid "Unused parameter" warning */ + args = args; count = count; /* Extract range info */ if(iw_get_range_info(skfd, ifname, &range) < 0) @@ -157,21 +175,16 @@ print_bitrate_info(int skfd, /* Print them all */ for(k = 0; k < range.num_bitrates; k++) { - printf("\t "); - bitrate = range.bitrate[k]; - if(bitrate >= GIGA) - printf("%g Gb/s\n", bitrate / GIGA); - else - if(bitrate >= MEGA) - printf("%g Mb/s\n", bitrate / MEGA); - else - printf("%g kb/s\n", bitrate / KILO); + iw_print_bitrate(buffer, range.bitrate[k]); + /* Maybe this should be %10s */ + printf("\t %s\n", buffer); } printf("\n\n"); } else printf("%-8.8s No bit-rates ? Please update driver...\n\n", ifname); } + return(0); } /************************* ENCRYPTION KEYS *************************/ @@ -180,9 +193,11 @@ print_bitrate_info(int skfd, /* * Print the number of available encryption key for the device */ -static void +static int print_keys_info(int skfd, - char * ifname) + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { struct iwreq wrq; struct iw_range range; @@ -190,6 +205,9 @@ print_keys_info(int skfd, int k; char buffer[128]; + /* Avoid "Unused parameter" warning */ + args = args; count = count; + /* Extract range info */ if(iw_get_range_info(skfd, ifname, &range) < 0) fprintf(stderr, "%-8.8s no encryption keys information.\n\n", @@ -241,7 +259,7 @@ print_keys_info(int skfd, if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0) { fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno)); - return; + return(-1); } printf(" Current Transmit Key: [%d]\n", wrq.u.data.flags & IW_ENCODE_INDEX); @@ -252,6 +270,7 @@ print_keys_info(int skfd, printf("\n\n"); } + return(0); } /************************* POWER MANAGEMENT *************************/ @@ -285,14 +304,19 @@ get_pm_value(int skfd, /* * Print Power Management info for each device */ -static void +static int print_pm_info(int skfd, - char * ifname) + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { struct iwreq wrq; struct iw_range range; char buffer[128]; + /* Avoid "Unused parameter" warning */ + args = args; count = count; + /* Extract range info */ if(iw_get_range_info(skfd, ifname, &range) < 0) fprintf(stderr, "%-8.8s no power management information.\n\n", @@ -365,11 +389,11 @@ print_pm_info(int skfd, /* Let's check the mode */ iw_print_pm_mode(buffer, flags); - printf("Current%s", buffer); + printf("Current %s", buffer); /* Let's check if nothing (simply on) */ if((flags & IW_POWER_MODE) == IW_POWER_ON) - printf(" mode:on"); + printf("mode:on"); printf("\n "); /* Let's check the value and its type */ @@ -415,6 +439,7 @@ print_pm_info(int skfd, } printf("\n"); } + return(0); } /************************** TRANSMIT POWER **************************/ @@ -423,15 +448,20 @@ print_pm_info(int skfd, /* * Print the number of available transmit powers for the device */ -static void +static int print_txpower_info(int skfd, - char * ifname) + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { struct iw_range range; int dbm; int mwatt; int k; + /* Avoid "Unused parameter" warning */ + args = args; count = count; + #if WIRELESS_EXT > 9 /* Extract range info */ if(iw_get_range_info(skfd, ifname, &range) < 0) @@ -464,6 +494,7 @@ print_txpower_info(int skfd, printf("%-8.8s No transmit-powers ? Please update driver...\n\n", ifname); } #endif /* WIRELESS_EXT > 9 */ + return(0); } /*********************** RETRY LIMIT/LIFETIME ***********************/ @@ -499,14 +530,19 @@ get_retry_value(int skfd, /* * Print Retry info for each device */ -static void +static int print_retry_info(int skfd, - char * ifname) + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { struct iwreq wrq; struct iw_range range; char buffer[128]; + /* Avoid "Unused parameter" warning */ + args = args; count = count; + /* Extract range info */ if(iw_get_range_info(skfd, ifname, &range) < 0) fprintf(stderr, "%-8.8s no retry limit/lifetime information.\n\n", @@ -606,74 +642,360 @@ print_retry_info(int skfd, } printf("\n"); } + return(0); } #endif /* WIRELESS_EXT > 10 */ -/************************* COMMON UTILITIES *************************/ +/***************************** SCANNING *****************************/ /* - * This section was written by Michael Tokarev + * This one behave quite differently from the others + */ +#if WIRELESS_EXT > 13 +/*------------------------------------------------------------------*/ +/* + * Print one element from the scanning results */ +static inline int +print_scanning_token(struct iw_event * event, /* Extracted token */ + int ap_num, /* AP number */ + struct iw_range * iwrange, /* Range info */ + int has_range) +{ + char buffer[128]; /* Temporary buffer */ + + /* Now, let's decode the event */ + switch(event->cmd) + { + case SIOCGIWAP: + printf(" Cell %02d - Address: %s\n", ap_num, + iw_pr_ether(buffer, event->u.ap_addr.sa_data)); + ap_num++; + break; + case SIOCGIWNWID: + if(event->u.nwid.disabled) + printf(" NWID:off/any\n"); + else + printf(" NWID:%X\n", event->u.nwid.value); + break; + case SIOCGIWFREQ: + { + float freq; /* Frequency/channel */ + freq = iw_freq2float(&(event->u.freq)); + iw_print_freq(buffer, freq); + printf(" %s\n", buffer); + } + break; + case SIOCGIWMODE: + printf(" Mode:%s\n", + iw_operation_mode[event->u.mode]); + break; + case SIOCGIWESSID: + { + char essid[IW_ESSID_MAX_SIZE+1]; + if((event->u.essid.pointer) && (event->u.essid.length)) + memcpy(essid, event->u.essid.pointer, event->u.essid.length); + essid[event->u.essid.length] = '\0'; + if(event->u.essid.flags) + { + /* Does it have an ESSID index ? */ + if((event->u.essid.flags & IW_ENCODE_INDEX) > 1) + printf(" ESSID:\"%s\" [%d]\n", essid, + (event->u.essid.flags & IW_ENCODE_INDEX)); + else + printf(" ESSID:\"%s\"\n", essid); + } + else + printf(" ESSID:off/any\n"); + } + break; + case SIOCGIWENCODE: + { + unsigned char key[IW_ENCODING_TOKEN_MAX]; + if(event->u.data.pointer) + memcpy(key, event->u.essid.pointer, event->u.data.length); + else + event->u.data.flags |= IW_ENCODE_NOKEY; + printf(" Encryption key:"); + if(event->u.data.flags & IW_ENCODE_DISABLED) + printf("off\n"); + else + { + /* Display the key */ + iw_print_key(buffer, key, event->u.data.length, + event->u.data.flags); + printf("%s", buffer); + + /* Other info... */ + if((event->u.data.flags & IW_ENCODE_INDEX) > 1) + printf(" [%d]", event->u.data.flags & IW_ENCODE_INDEX); + if(event->u.data.flags & IW_ENCODE_RESTRICTED) + printf(" Encryption mode:restricted"); + if(event->u.data.flags & IW_ENCODE_OPEN) + printf(" Encryption mode:open"); + printf("\n"); + } + } + break; + case SIOCGIWRATE: + iw_print_bitrate(buffer, event->u.bitrate.value); + printf(" Bit Rate:%s\n", buffer); + break; + case IWEVQUAL: + { + event->u.qual.updated = 0x0; /* Not that reliable, disable */ + iw_print_stats(buffer, &event->u.qual, iwrange, has_range); + printf(" %s\n", buffer); + break; + } + default: + printf(" (Unknown Wireless Token 0x%04X)\n", + event->cmd); + } /* switch(event->cmd) */ + + /* May have changed */ + return(ap_num); +} /*------------------------------------------------------------------*/ /* - * Enumerate devices and call specified routine + * Perform a scanning on one device */ -static void -enum_devices(int skfd, void (*fn)(int skfd, char *ifname)) +static int +print_scanning_info(int skfd, + char * ifname, + char * args[], /* Command line args */ + int count) /* Args count */ { - char buff[1024]; - struct ifconf ifc; - struct ifreq *ifr; - int i; + struct iwreq wrq; + unsigned char buffer[IW_SCAN_MAX_DATA]; /* Results */ + struct timeval tv; /* Select timeout */ + int timeout = 5000000; /* 5s */ + + /* Avoid "Unused parameter" warning */ + args = args; count = count; + + /* Init timeout value -> 250ms*/ + tv.tv_sec = 0; + tv.tv_usec = 250000; + + /* + * Here we should look at the command line args and set the IW_SCAN_ flags + * properly + */ + wrq.u.param.flags = IW_SCAN_DEFAULT; + wrq.u.param.value = 0; /* Later */ + + /* Initiate Scanning */ + if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0) + { + if(errno != EPERM) + { + fprintf(stderr, "%-8.8s Interface doesn't support scanning : %s\n\n", + ifname, strerror(errno)); + return(-1); + } + /* If we don't have the permission to initiate the scan, we may + * still have permission to read left-over results. + * But, don't wait !!! */ +#if 0 + /* Not cool, it display for non wireless interfaces... */ + fprintf(stderr, "%-8.8s (Could not trigger scanning, just reading left-over results)\n", ifname); +#endif + tv.tv_usec = 0; + } + timeout -= tv.tv_usec; + + /* Forever */ + while(1) + { + fd_set rfds; /* File descriptors for select */ + int last_fd; /* Last fd */ + int ret; + + /* Guess what ? We must re-generate rfds each time */ + FD_ZERO(&rfds); + last_fd = -1; + + /* In here, add the rtnetlink fd in the list */ + + /* Wait until something happens */ + ret = select(last_fd + 1, &rfds, NULL, NULL, &tv); + + /* Check if there was an error */ + if(ret < 0) + { + if(errno == EAGAIN || errno == EINTR) + continue; + fprintf(stderr, "Unhandled signal - exiting...\n"); + return(-1); + } + + /* Check if there was a timeout */ + if(ret == 0) + { + /* Try to read the results */ + wrq.u.data.pointer = buffer; + wrq.u.data.flags = 0; + wrq.u.data.length = sizeof(buffer); + if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0) + { + /* Check if results not available yet */ + if(errno == EAGAIN) + { + /* Restart timer for only 100ms*/ + tv.tv_sec = 0; + tv.tv_usec = 100000; + timeout -= tv.tv_usec; + if(timeout > 0) + continue; /* Try again later */ + } + + /* Bad error */ + fprintf(stderr, "%-8.8s Failed to read scan data : %s\n\n", + ifname, strerror(errno)); + return(-2); + } + else + /* We have the results, go to process them */ + break; + } + + /* In here, check if event and event type + * if scan event, read results. All errors bad & no reset timeout */ + } - /* Get list of active devices */ - ifc.ifc_len = sizeof(buff); - ifc.ifc_buf = buff; - if(ioctl(skfd, SIOCGIFCONF, &ifc) < 0) + if(wrq.u.data.length) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); - return; + struct iw_event iwe; + struct stream_descr stream; + int ap_num = 1; + int ret; + struct iw_range range; + int has_range; +#if 0 + /* Debugging code. In theory useless, because it's debugged ;-) */ + int i; + printf("Scan result [%02X", buffer[0]); + for(i = 1; i < wrq.u.data.length; i++) + printf(":%02X", buffer[i]); + printf("]\n"); +#endif + has_range = (iw_get_range_info(skfd, ifname, &range) >= 0); + printf("%-8.8s Scan completed :\n", ifname); + iw_init_event_stream(&stream, buffer, wrq.u.data.length); + do + { + /* Extract an event and print it */ + ret = iw_extract_event_stream(&stream, &iwe); + if(ret > 0) + ap_num = print_scanning_token(&iwe, ap_num, &range, has_range); + } + while(ret > 0); + printf("\n"); } - ifr = ifc.ifc_req; + else + printf("%-8.8s No scan results\n", ifname); - /* Print them */ - for(i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) - (*fn)(skfd, ifr->ifr_name); + return(0); } +#endif /* WIRELESS_EXT > 13 */ + +/************************* COMMON UTILITIES *************************/ +/* + * This section was written by Michael Tokarev + * But modified by me ;-) + */ /* command list */ typedef struct iwlist_entry { const char *cmd; - void (*fn)(int skfd, char *ifname); + iw_enum_handler fn; + int min_count; + int max_count; } iwlist_cmd; static const struct iwlist_entry iwlist_cmds[] = { - { "frequency", print_freq_info }, - { "channel", print_freq_info }, - { "ap", print_ap_info }, - { "accesspoints", print_ap_info }, - { "bitrate", print_bitrate_info }, - { "rate", print_bitrate_info }, - { "encryption", print_keys_info }, - { "key", print_keys_info }, - { "power", print_pm_info }, - { "txpower", print_txpower_info }, + { "frequency", print_freq_info, 0, 0 }, + { "channel", print_freq_info, 0, 0 }, + { "ap", print_ap_info, 0, 0 }, + { "accesspoints", print_ap_info, 0, 0 }, + { "bitrate", print_bitrate_info, 0, 0 }, + { "rate", print_bitrate_info, 0, 0 }, + { "encryption", print_keys_info, 0, 0 }, + { "key", print_keys_info, 0, 0 }, + { "power", print_pm_info, 0, 0 }, + { "txpower", print_txpower_info, 0, 0 }, #if WIRELESS_EXT > 10 - { "retry", print_retry_info }, + { "retry", print_retry_info, 0, 0 }, #endif - { NULL, 0 }, +#if WIRELESS_EXT > 13 + { "scanning", print_scanning_info, 0, 5 }, +#endif + { NULL, NULL, 0, 0 }, }; -/* Display help */ -static void usage(FILE *f) +/*------------------------------------------------------------------*/ +/* + * Find the most appropriate command matching the command line + */ +static inline const iwlist_cmd * +find_command(const char * cmd) { - int i; + const iwlist_cmd * found = NULL; + int ambig = 0; + unsigned int len = strlen(cmd); + int i; + + /* Go through all commands */ for(i = 0; iwlist_cmds[i].cmd != NULL; ++i) - fprintf(f, "%s [interface] %s\n", - i ? " " : - "Usage: iwlist", - iwlist_cmds[i].cmd); + { + /* No match -> next one */ + if(strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0) + continue; + + /* Exact match -> perfect */ + if(len == strlen(iwlist_cmds[i].cmd)) + return &iwlist_cmds[i]; + + /* Partial match */ + if(found == NULL) + /* First time */ + found = &iwlist_cmds[i]; + else + /* Another time */ + if (iwlist_cmds[i].fn != found->fn) + ambig = 1; + } + + if(found == NULL) + { + fprintf(stderr, "iwlist: unknown command `%s'\n", cmd); + return NULL; + } + + if(ambig) + { + fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd); + return NULL; + } + + return found; +} + +/*------------------------------------------------------------------*/ +/* + * Display help + */ +static void iw_usage(int status) +{ + FILE* f = status ? stderr : stdout; + int i; + + fprintf(f, "Usage: iwlist [interface] %s\n", iwlist_cmds[0].cmd); + for(i = 1; iwlist_cmds[i].cmd != NULL; ++i) + fprintf(f, " [interface] %s\n", iwlist_cmds[i].cmd); + exit(status); } /******************************* MAIN ********************************/ @@ -686,63 +1008,50 @@ int main(int argc, char ** argv) { - int skfd = -1; /* generic raw socket desc. */ + int skfd; /* generic raw socket desc. */ char *dev; /* device name */ char *cmd; /* command */ - int i; + char **args; /* Command arguments */ + int count; /* Number of arguments */ + const iwlist_cmd *iwcmd; if(argc == 1 || argc > 3) - { - usage(stderr); - return 1; - } + iw_usage(1); + if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) - { - usage(stdout); - return 0; - } + iw_usage(0); + if (argc == 2) { cmd = argv[1]; dev = NULL; + args = NULL; + count = 0; } else { cmd = argv[2]; dev = argv[1]; + args = argv + 3; + count = argc - 3; } /* find a command */ - { - int found = -1, ambig = 0; - int len = strlen(cmd); - for(i = 0; iwlist_cmds[i].cmd != NULL; ++i) - { - if (strncasecmp(iwlist_cmds[i].cmd, cmd, len) != 0) - continue; - if (len == strlen(iwlist_cmds[i].cmd)) /* exact match */ - { - found = i; - ambig = 0; - break; - } - if (found < 0) - found = i; - else if (iwlist_cmds[i].fn != iwlist_cmds[found].fn) - ambig = 1; - } - if (found < 0) - { - fprintf(stderr, "iwlist: unknown command `%s'\n", cmd); - return 1; - } - if (ambig) - { - fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd); - return 1; - } - i = found; - } + iwcmd = find_command(cmd); + if(iwcmd == NULL) + return 1; + + /* Check arg numbers */ + if(count < iwcmd->min_count) + { + fprintf(stderr, "iwlist: command `%s' needs more arguments\n", cmd); + return 1; + } + if(count > iwcmd->max_count) + { + fprintf(stderr, "iwlist: command `%s' needs fewer arguments\n", cmd); + return 1; + } /* Create a channel to the NET kernel. */ if((skfd = iw_sockets_open()) < 0) @@ -753,9 +1062,9 @@ main(int argc, /* do the actual work */ if (dev) - (*iwlist_cmds[i].fn)(skfd, dev); + (*iwcmd->fn)(skfd, dev, args, count); else - enum_devices(skfd, iwlist_cmds[i].fn); + iw_enum_devices(skfd, iwcmd->fn, args, count); /* Close the socket. */ close(skfd);