*/
#include "iwlib.h" /* Header */
+#include <sys/time.h>
/*********************** FREQUENCIES/CHANNELS ***********************/
/*
* 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);
printf("%-8.8s %d channels\n\n",
ifname, range.num_channels);
}
+ return(0);
}
/************************ ACCESS POINT LIST ************************/
* 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) +
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;
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 */
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 */
printf(" %s\n", iw_pr_ether(temp, hwa[i].sa_data));
}
printf("\n");
+ return(0);
}
/***************************** BITRATES *****************************/
/*
* 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)
/* 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 *************************/
/*
* 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;
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",
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);
printf("\n\n");
}
+ return(0);
}
/************************* POWER MANAGEMENT *************************/
/*
* 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",
/* 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 */
}
printf("\n");
}
+ return(0);
}
/************************** TRANSMIT POWER **************************/
/*
* 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)
printf("%-8.8s No transmit-powers ? Please update driver...\n\n", ifname);
}
#endif /* WIRELESS_EXT > 9 */
+ return(0);
}
/*********************** RETRY LIMIT/LIFETIME ***********************/
/*
* 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",
}
printf("\n");
}
+ return(0);
}
#endif /* WIRELESS_EXT > 10 */
-/************************* COMMON UTILITIES *************************/
+/***************************** SCANNING *****************************/
/*
- * This section was written by Michael Tokarev <mjt@tls.msk.ru>
+ * 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 <mjt@tls.msk.ru>
+ * 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 ********************************/
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)
/* 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);