/*
* Wireless Tools
*
- * Jean II - HPLB '99 - HPL 99->01
+ * Jean II - HPLB '99 - HPL 99->07
*
* This tool can access various piece of information on the card
* not part of iwconfig...
* You need to link this code against "iwlist.c" and "-lm".
*
* This file is released under the GPL license.
- * Copyright (c) 1997-2002 Jean Tourrilhes <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes <jt@hpl.hp.com>
*/
-#include "iwlib.h" /* Header */
+#include "iwlib-private.h" /* Private header */
#include <sys/time.h>
-/*********************** FREQUENCIES/CHANNELS ***********************/
+/****************************** TYPES ******************************/
+
+/*
+ * Scan state and meta-information, used to decode events...
+ */
+typedef struct iwscan_state
+{
+ /* State */
+ int ap_num; /* Access Point number 1->N */
+ int val_index; /* Value in table 0->(N-1) */
+} iwscan_state;
+
+/*
+ * Bit to name mapping
+ */
+typedef struct iwmask_name
+{
+ unsigned int mask; /* bit mask for the value */
+ const char * name; /* human readable name for the value */
+} iwmask_name;
+
+/*
+ * Types of authentication parameters
+ */
+typedef struct iw_auth_descr
+{
+ int value; /* Type of auth value */
+ const char * label; /* User readable version */
+ const struct iwmask_name * names; /* Names for this value */
+ const int num_names; /* Number of names */
+} iw_auth_descr;
+
+/**************************** CONSTANTS ****************************/
+
+#define IW_SCAN_HACK 0x8000
+
+#define IW_EXTKEY_SIZE (sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX)
+
+/* ------------------------ WPA CAPA NAMES ------------------------ */
+/*
+ * This is the user readable name of a bunch of WPA constants in wireless.h
+ * Maybe this should go in iwlib.c ?
+ */
+
+#ifndef WE_ESSENTIAL
+#define IW_ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
+
+//static const struct iwmask_name iw_enc_mode_name[] = {
+// { IW_ENCODE_RESTRICTED, "restricted" },
+// { IW_ENCODE_OPEN, "open" },
+//};
+//#define IW_ENC_MODE_NUM IW_ARRAY_LEN(iw_enc_mode_name)
+
+static const struct iwmask_name iw_auth_capa_name[] = {
+ { IW_ENC_CAPA_WPA, "WPA" },
+ { IW_ENC_CAPA_WPA2, "WPA2" },
+ { IW_ENC_CAPA_CIPHER_TKIP, "CIPHER-TKIP" },
+ { IW_ENC_CAPA_CIPHER_CCMP, "CIPHER-CCMP" },
+};
+#define IW_AUTH_CAPA_NUM IW_ARRAY_LEN(iw_auth_capa_name)
+
+static const struct iwmask_name iw_auth_cypher_name[] = {
+ { IW_AUTH_CIPHER_NONE, "none" },
+ { IW_AUTH_CIPHER_WEP40, "WEP-40" },
+ { IW_AUTH_CIPHER_TKIP, "TKIP" },
+ { IW_AUTH_CIPHER_CCMP, "CCMP" },
+ { IW_AUTH_CIPHER_WEP104, "WEP-104" },
+};
+#define IW_AUTH_CYPHER_NUM IW_ARRAY_LEN(iw_auth_cypher_name)
+
+static const struct iwmask_name iw_wpa_ver_name[] = {
+ { IW_AUTH_WPA_VERSION_DISABLED, "disabled" },
+ { IW_AUTH_WPA_VERSION_WPA, "WPA" },
+ { IW_AUTH_WPA_VERSION_WPA2, "WPA2" },
+};
+#define IW_WPA_VER_NUM IW_ARRAY_LEN(iw_wpa_ver_name)
+
+static const struct iwmask_name iw_auth_key_mgmt_name[] = {
+ { IW_AUTH_KEY_MGMT_802_1X, "802.1x" },
+ { IW_AUTH_KEY_MGMT_PSK, "PSK" },
+};
+#define IW_AUTH_KEY_MGMT_NUM IW_ARRAY_LEN(iw_auth_key_mgmt_name)
+
+static const struct iwmask_name iw_auth_alg_name[] = {
+ { IW_AUTH_ALG_OPEN_SYSTEM, "open" },
+ { IW_AUTH_ALG_SHARED_KEY, "shared-key" },
+ { IW_AUTH_ALG_LEAP, "LEAP" },
+};
+#define IW_AUTH_ALG_NUM IW_ARRAY_LEN(iw_auth_alg_name)
+
+static const struct iw_auth_descr iw_auth_settings[] = {
+ { IW_AUTH_WPA_VERSION, "WPA version", iw_wpa_ver_name, IW_WPA_VER_NUM },
+ { IW_AUTH_KEY_MGMT, "Key management", iw_auth_key_mgmt_name, IW_AUTH_KEY_MGMT_NUM },
+ { IW_AUTH_CIPHER_PAIRWISE, "Pairwise cipher", iw_auth_cypher_name, IW_AUTH_CYPHER_NUM },
+ { IW_AUTH_CIPHER_GROUP, "Pairwise cipher", iw_auth_cypher_name, IW_AUTH_CYPHER_NUM },
+ { IW_AUTH_TKIP_COUNTERMEASURES, "TKIP countermeasures", NULL, 0 },
+ { IW_AUTH_DROP_UNENCRYPTED, "Drop unencrypted", NULL, 0 },
+ { IW_AUTH_80211_AUTH_ALG, "Authentication algorithm", iw_auth_alg_name, IW_AUTH_ALG_NUM },
+ { IW_AUTH_RX_UNENCRYPTED_EAPOL, "Receive unencrypted EAPOL", NULL, 0 },
+ { IW_AUTH_ROAMING_CONTROL, "Roaming control", NULL, 0 },
+ { IW_AUTH_PRIVACY_INVOKED, "Privacy invoked", NULL, 0 },
+};
+#define IW_AUTH_SETTINGS_NUM IW_ARRAY_LEN(iw_auth_settings)
+
+/* Values for the IW_ENCODE_ALG_* returned by SIOCSIWENCODEEXT */
+static const char * iw_encode_alg_name[] = {
+ "none",
+ "WEP",
+ "TKIP",
+ "CCMP",
+ "unknown"
+};
+#define IW_ENCODE_ALG_NUM IW_ARRAY_LEN(iw_encode_alg_name)
+
+#ifndef IW_IE_CIPHER_NONE
+/* Cypher values in GENIE (pairwise and group) */
+#define IW_IE_CIPHER_NONE 0
+#define IW_IE_CIPHER_WEP40 1
+#define IW_IE_CIPHER_TKIP 2
+#define IW_IE_CIPHER_WRAP 3
+#define IW_IE_CIPHER_CCMP 4
+#define IW_IE_CIPHER_WEP104 5
+/* Key management in GENIE */
+#define IW_IE_KEY_MGMT_NONE 0
+#define IW_IE_KEY_MGMT_802_1X 1
+#define IW_IE_KEY_MGMT_PSK 2
+#endif /* IW_IE_CIPHER_NONE */
+
+/* Values for the IW_IE_CIPHER_* in GENIE */
+static const char * iw_ie_cypher_name[] = {
+ "none",
+ "WEP-40",
+ "TKIP",
+ "WRAP",
+ "CCMP",
+ "WEP-104",
+};
+#define IW_IE_CYPHER_NUM IW_ARRAY_LEN(iw_ie_cypher_name)
+
+/* Values for the IW_IE_KEY_MGMT_* in GENIE */
+static const char * iw_ie_key_mgmt_name[] = {
+ "none",
+ "802.1x",
+ "PSK",
+};
+#define IW_IE_KEY_MGMT_NUM IW_ARRAY_LEN(iw_ie_key_mgmt_name)
+
+#endif /* WE_ESSENTIAL */
+
+/************************* WPA SUBROUTINES *************************/
+#ifndef WE_ESSENTIAL
/*------------------------------------------------------------------*/
/*
- * Print the number of channels and available frequency for the device
+ * Print all names corresponding to a mask.
+ * This may want to be used in iw_print_retry_value() ?
*/
-static int
-print_freq_info(int skfd,
- char * ifname,
- char * args[], /* Command line args */
- int count) /* Args count */
+static void
+iw_print_mask_name(unsigned int mask,
+ const struct iwmask_name names[],
+ const unsigned int num_names,
+ const char * sep)
{
- float freq;
- struct iw_range range;
- int k;
+ unsigned int i;
- /* Avoid "Unused parameter" warning */
- args = args; count = count;
+ /* Print out all names for the bitmask */
+ for(i = 0; i < num_names; i++)
+ {
+ if(mask & names[i].mask)
+ {
+ /* Print out */
+ printf("%s%s", sep, names[i].name);
+ /* Remove the bit from the mask */
+ mask &= ~names[i].mask;
+ }
+ }
+ /* If there is unconsumed bits... */
+ if(mask != 0)
+ printf("%sUnknown", sep);
+}
- if(iw_get_range_info(skfd, ifname, &range) < 0)
- fprintf(stderr, "%-8.8s no frequency information.\n\n",
- ifname);
+/*------------------------------------------------------------------*/
+/*
+ * Print the name corresponding to a value, with overflow check.
+ */
+static void
+iw_print_value_name(unsigned int value,
+ const char * names[],
+ const unsigned int num_names)
+{
+ if(value >= num_names)
+ printf(" unknown (%d)", value);
else
+ printf(" %s", names[value]);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Parse, and display the results of an unknown IE.
+ *
+ */
+static void
+iw_print_ie_unknown(unsigned char * iebuf,
+ int buflen)
+{
+ int ielen = iebuf[1] + 2;
+ int i;
+
+ if(ielen > buflen)
+ ielen = buflen;
+
+ printf("Unknown: ");
+ for(i = 0; i < ielen; i++)
+ printf("%02X", iebuf[i]);
+ printf("\n");
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Parse, and display the results of a WPA or WPA2 IE.
+ *
+ */
+static inline void
+iw_print_ie_wpa(unsigned char * iebuf,
+ int buflen)
+{
+ int ielen = iebuf[1] + 2;
+ int offset = 2; /* Skip the IE id, and the length. */
+ unsigned char wpa1_oui[3] = {0x00, 0x50, 0xf2};
+ unsigned char wpa2_oui[3] = {0x00, 0x0f, 0xac};
+ unsigned char * wpa_oui;
+ int i;
+ uint16_t ver = 0;
+ uint16_t cnt = 0;
+
+ if(ielen > buflen)
+ ielen = buflen;
+
+#ifdef DEBUG
+ /* Debugging code. In theory useless, because it's debugged ;-) */
+ printf("IE raw value %d [%02X", buflen, iebuf[0]);
+ for(i = 1; i < buflen; i++)
+ printf(":%02X", iebuf[i]);
+ printf("]\n");
+#endif
+
+ switch(iebuf[0])
{
- if(range.num_frequency > 0)
+ case 0x30: /* WPA2 */
+ /* Check if we have enough data */
+ if(ielen < 4)
{
- printf("%-8.8s %d channels in total; available frequencies :\n",
- ifname, range.num_channels);
- /* Print them all */
- for(k = 0; k < range.num_frequency; k++)
- {
- printf("\t Channel %.2d : ", range.freq[k].i);
- freq = iw_freq2float(&(range.freq[k]));
- if(freq >= GIGA)
- printf("%g GHz\n", freq / GIGA);
- else
- if(freq >= MEGA)
- printf("%g MHz\n", freq / MEGA);
- else
- printf("%g kHz\n", freq / KILO);
- }
- printf("\n\n");
+ iw_print_ie_unknown(iebuf, buflen);
+ return;
}
+
+ wpa_oui = wpa2_oui;
+ break;
+
+ case 0xdd: /* WPA or else */
+ wpa_oui = wpa1_oui;
+
+ /* Not all IEs that start with 0xdd are WPA.
+ * So check that the OUI is valid. Note : offset==2 */
+ if((ielen < 8)
+ || (memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+ || (iebuf[offset + 3] != 0x01))
+ {
+ iw_print_ie_unknown(iebuf, buflen);
+ return;
+ }
+
+ /* Skip the OUI type */
+ offset += 4;
+ break;
+
+ default:
+ return;
+ }
+
+ /* Pick version number (little endian) */
+ ver = iebuf[offset] | (iebuf[offset + 1] << 8);
+ offset += 2;
+
+ if(iebuf[0] == 0xdd)
+ printf("WPA Version %d\n", ver);
+ if(iebuf[0] == 0x30)
+ printf("IEEE 802.11i/WPA2 Version %d\n", ver);
+
+ /* From here, everything is technically optional. */
+
+ /* Check if we are done */
+ if(ielen < (offset + 4))
+ {
+ /* We have a short IE. So we should assume TKIP/TKIP. */
+ printf(" Group Cipher : TKIP\n");
+ printf(" Pairwise Cipher : TKIP\n");
+ return;
+ }
+
+ /* Next we have our group cipher. */
+ if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+ {
+ printf(" Group Cipher : Proprietary\n");
+ }
+ else
+ {
+ printf(" Group Cipher :");
+ iw_print_value_name(iebuf[offset+3],
+ iw_ie_cypher_name, IW_IE_CYPHER_NUM);
+ printf("\n");
+ }
+ offset += 4;
+
+ /* Check if we are done */
+ if(ielen < (offset + 2))
+ {
+ /* We don't have a pairwise cipher, or auth method. Assume TKIP. */
+ printf(" Pairwise Ciphers : TKIP\n");
+ return;
+ }
+
+ /* Otherwise, we have some number of pairwise ciphers. */
+ cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
+ offset += 2;
+ printf(" Pairwise Ciphers (%d) :", cnt);
+
+ if(ielen < (offset + 4*cnt))
+ return;
+
+ for(i = 0; i < cnt; i++)
+ {
+ if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+ {
+ printf(" Proprietary");
+ }
else
- printf("%-8.8s %d channels\n\n",
- ifname, range.num_channels);
+ {
+ iw_print_value_name(iebuf[offset+3],
+ iw_ie_cypher_name, IW_IE_CYPHER_NUM);
+ }
+ offset+=4;
+ }
+ printf("\n");
+
+ /* Check if we are done */
+ if(ielen < (offset + 2))
+ return;
+
+ /* Now, we have authentication suites. */
+ cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
+ offset += 2;
+ printf(" Authentication Suites (%d) :", cnt);
+
+ if(ielen < (offset + 4*cnt))
+ return;
+
+ for(i = 0; i < cnt; i++)
+ {
+ if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+ {
+ printf(" Proprietary");
+ }
+ else
+ {
+ iw_print_value_name(iebuf[offset+3],
+ iw_ie_key_mgmt_name, IW_IE_KEY_MGMT_NUM);
+ }
+ offset+=4;
+ }
+ printf("\n");
+
+ /* Check if we are done */
+ if(ielen < (offset + 1))
+ return;
+
+ /* Otherwise, we have capabilities bytes.
+ * For now, we only care about preauth which is in bit position 1 of the
+ * first byte. (But, preauth with WPA version 1 isn't supposed to be
+ * allowed.) 8-) */
+ if(iebuf[offset] & 0x01)
+ {
+ printf(" Preauthentication Supported\n");
}
- return(0);
}
+
+/*------------------------------------------------------------------*/
+/*
+ * Process a generic IE and display the info in human readable form
+ * for some of the most interesting ones.
+ * For now, we only decode the WPA IEs.
+ */
+static inline void
+iw_print_gen_ie(unsigned char * buffer,
+ int buflen)
+{
+ int offset = 0;
-/************************ ACCESS POINT LIST ************************/
+ /* Loop on each IE, each IE is minimum 2 bytes */
+ while(offset <= (buflen - 2))
+ {
+ printf(" IE: ");
+
+ /* Check IE type */
+ switch(buffer[offset])
+ {
+ case 0xdd: /* WPA1 (and other) */
+ case 0x30: /* WPA2 */
+ iw_print_ie_wpa(buffer + offset, buflen);
+ break;
+ default:
+ iw_print_ie_unknown(buffer + offset, buflen);
+ }
+ /* Skip over this IE to the next one in the list. */
+ offset += buffer[offset+1] + 2;
+ }
+}
+#endif /* WE_ESSENTIAL */
+
+/***************************** SCANNING *****************************/
+/*
+ * This one behave quite differently from the others
+ *
+ * Note that we don't use the scanning capability of iwlib (functions
+ * iw_process_scan() and iw_scan()). The main reason is that
+ * iw_process_scan() return only a subset of the scan data to the caller,
+ * for example custom elements and bitrates are ommited. Here, we
+ * do the complete job...
+ */
/*------------------------------------------------------------------*/
/*
- * Display the list of ap addresses and the associated stats
- * Exacly the same as the spy list, only with different IOCTL and messages
+ * Print one element from the scanning results
+ */
+static inline void
+print_scanning_token(struct stream_descr * stream, /* Stream of events */
+ struct iw_event * event, /* Extracted token */
+ struct iwscan_state * state,
+ struct iw_range * iw_range, /* 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", state->ap_num,
+ iw_saether_ntop(&event->u.ap_addr, buffer));
+ state->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:
+ {
+ double freq; /* Frequency/channel */
+ int channel = -1; /* Converted to channel */
+ freq = iw_freq2float(&(event->u.freq));
+ /* Convert to channel if possible */
+ if(has_range)
+ channel = iw_freq_to_channel(freq, iw_range);
+ iw_print_freq(buffer, sizeof(buffer),
+ freq, channel, event->u.freq.flags);
+ printf(" %s\n", buffer);
+ }
+ break;
+ case SIOCGIWMODE:
+ /* Note : event->u.mode is unsigned, no need to check <= 0 */
+ if(event->u.mode >= IW_NUM_OPER_MODE)
+ event->u.mode = IW_NUM_OPER_MODE;
+ printf(" Mode:%s\n",
+ iw_operation_mode[event->u.mode]);
+ break;
+ case SIOCGIWNAME:
+ printf(" Protocol:%-1.16s\n", event->u.name);
+ break;
+ case SIOCGIWESSID:
+ {
+ char essid[4*IW_ESSID_MAX_SIZE+1];
+ memset(essid, '\0', sizeof(essid));
+ if((event->u.essid.pointer) && (event->u.essid.length))
+ iw_essid_escape(essid,
+ event->u.essid.pointer, event->u.essid.length);
+ 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/hidden\n");
+ }
+ break;
+ case SIOCGIWENCODE:
+ {
+ unsigned char key[IW_ENCODING_TOKEN_MAX];
+ if(event->u.data.pointer)
+ memcpy(key, event->u.data.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, sizeof(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(" Security mode:restricted");
+ if(event->u.data.flags & IW_ENCODE_OPEN)
+ printf(" Security mode:open");
+ printf("\n");
+ }
+ }
+ break;
+ case SIOCGIWRATE:
+ if(state->val_index == 0)
+ printf(" Bit Rates:");
+ else
+ if((state->val_index % 5) == 0)
+ printf("\n ");
+ else
+ printf("; ");
+ iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
+ printf("%s", buffer);
+ /* Check for termination */
+ if(stream->value == NULL)
+ {
+ printf("\n");
+ state->val_index = 0;
+ }
+ else
+ state->val_index++;
+ break;
+ case SIOCGIWMODUL:
+ {
+ unsigned int modul = event->u.param.value;
+ int i;
+ int n = 0;
+ printf(" Modulations :");
+ for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
+ {
+ if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
+ {
+ if((n++ % 8) == 7)
+ printf("\n ");
+ else
+ printf(" ; ");
+ printf("%s", iw_modul_list[i].cmd);
+ }
+ }
+ printf("\n");
+ }
+ break;
+ case IWEVQUAL:
+ iw_print_stats(buffer, sizeof(buffer),
+ &event->u.qual, iw_range, has_range);
+ printf(" %s\n", buffer);
+ break;
+#ifndef WE_ESSENTIAL
+ case IWEVGENIE:
+ /* Informations Elements are complex, let's do only some of them */
+ iw_print_gen_ie(event->u.data.pointer, event->u.data.length);
+ break;
+#endif /* WE_ESSENTIAL */
+ case IWEVCUSTOM:
+ {
+ char custom[IW_CUSTOM_MAX+1];
+ if((event->u.data.pointer) && (event->u.data.length))
+ memcpy(custom, event->u.data.pointer, event->u.data.length);
+ custom[event->u.data.length] = '\0';
+ printf(" Extra:%s\n", custom);
+ }
+ break;
+ default:
+ printf(" (Unknown Wireless Token 0x%04X)\n",
+ event->cmd);
+ } /* switch(event->cmd) */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Perform a scanning on one device
*/
static int
-print_ap_info(int skfd,
- char * ifname,
- char * args[], /* Command line args */
- int count) /* Args count */
+print_scanning_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
{
struct iwreq wrq;
- char buffer[(sizeof(struct iw_quality) +
- sizeof(struct sockaddr)) * IW_MAX_AP];
- char temp[128];
- struct sockaddr * hwa;
- struct iw_quality * qual;
- iwrange range;
- int has_range = 0;
- int has_qual = 0;
- int n;
- int i;
+ struct iw_scan_req scanopt; /* Options for 'set' */
+ int scanflags = 0; /* Flags for scan */
+ unsigned char * buffer = NULL; /* Results */
+ int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
+ struct iw_range range;
+ int has_range;
+ struct timeval tv; /* Select timeout */
+ int timeout = 15000000; /* 15s */
/* Avoid "Unused parameter" warning */
args = args; count = count;
- /* Collect stats */
- wrq.u.data.pointer = (caddr_t) buffer;
- wrq.u.data.length = IW_MAX_AP;
- wrq.u.data.flags = 0;
- if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
+ /* Debugging stuff */
+ if((IW_EV_LCP_PK2_LEN != IW_EV_LCP_PK_LEN) || (IW_EV_POINT_PK2_LEN != IW_EV_POINT_PK_LEN))
{
- fprintf(stderr, "%-8.8s Interface doesn't have a list of Access Points\n\n", ifname);
+ fprintf(stderr, "*** Please report to jt@hpl.hp.com your platform details\n");
+ fprintf(stderr, "*** and the following line :\n");
+ fprintf(stderr, "*** IW_EV_LCP_PK2_LEN = %zu ; IW_EV_POINT_PK2_LEN = %zu\n\n",
+ IW_EV_LCP_PK2_LEN, IW_EV_POINT_PK2_LEN);
+ }
+
+ /* Get range stuff */
+ has_range = (iw_get_range_info(skfd, ifname, &range) >= 0);
+
+ /* Check if the interface could support scanning. */
+ if((!has_range) || (range.we_version_compiled < 14))
+ {
+ fprintf(stderr, "%-8.16s Interface doesn't support scanning.\n\n",
+ ifname);
return(-1);
}
- /* Number of addresses */
- n = wrq.u.data.length;
- has_qual = wrq.u.data.flags;
+ /* Init timeout value -> 250ms between set and first get */
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
- /* The two lists */
- hwa = (struct sockaddr *) buffer;
- qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
+ /* Clean up set args */
+ memset(&scanopt, 0, sizeof(scanopt));
- /* Check if we have valid mac address type */
- if(iw_check_mac_addr_type(skfd, ifname) < 0)
+ /* Parse command line arguments and extract options.
+ * Note : when we have enough options, we should use the parser
+ * from iwconfig... */
+ while(count > 0)
{
- fprintf(stderr, "%-8.8s Interface doesn't support MAC addresses\n\n", ifname);
- return(-2);
+ /* One arg is consumed (the option name) */
+ count--;
+
+ /*
+ * Check for Active Scan (scan with specific essid)
+ */
+ if(!strncmp(args[0], "essid", 5))
+ {
+ if(count < 1)
+ {
+ fprintf(stderr, "Too few arguments for scanning option [%s]\n",
+ args[0]);
+ return(-1);
+ }
+ args++;
+ count--;
+
+ /* Store the ESSID in the scan options */
+ scanopt.essid_len = strlen(args[0]);
+ memcpy(scanopt.essid, args[0], scanopt.essid_len);
+ /* Initialise BSSID as needed */
+ if(scanopt.bssid.sa_family == 0)
+ {
+ scanopt.bssid.sa_family = ARPHRD_ETHER;
+ memset(scanopt.bssid.sa_data, 0xff, ETH_ALEN);
+ }
+ /* Scan only this ESSID */
+ scanflags |= IW_SCAN_THIS_ESSID;
+ }
+ else
+ /* Check for last scan result (do not trigger scan) */
+ if(!strncmp(args[0], "last", 4))
+ {
+ /* Hack */
+ scanflags |= IW_SCAN_HACK;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid scanning option [%s]\n", args[0]);
+ return(-1);
+ }
+
+ /* Next arg */
+ args++;
}
- /* Get range info if we can */
- if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
- has_range = 1;
+ /* Check if we have scan options */
+ if(scanflags)
+ {
+ wrq.u.data.pointer = (caddr_t) &scanopt;
+ wrq.u.data.length = sizeof(scanopt);
+ wrq.u.data.flags = scanflags;
+ }
+ else
+ {
+ wrq.u.data.pointer = NULL;
+ wrq.u.data.flags = 0;
+ wrq.u.data.length = 0;
+ }
- /* Display it */
- if(n == 0)
- printf("%-8.8s No Access Point in range\n", ifname);
+ /* If only 'last' was specified on command line, don't trigger a scan */
+ if(scanflags == IW_SCAN_HACK)
+ {
+ /* Skip waiting */
+ tv.tv_usec = 0;
+ }
else
- printf("%-8.8s Access Points in range:\n", ifname);
- for(i = 0; i < n; i++)
{
- if(has_qual)
+ /* Initiate Scanning */
+ if(iw_set_ext(skfd, ifname, SIOCSIWSCAN, &wrq) < 0)
{
- /* Print stats for this address */
- printf(" %s : ", iw_pr_ether(temp, hwa[i].sa_data));
- iw_print_stats(temp, &qual[i], &range, has_range);
- printf("%s\n", temp);
+ if((errno != EPERM) || (scanflags != 0))
+ {
+ fprintf(stderr, "%-8.16s 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.16s (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)
+ {
+ unsigned char * newbuf;
+
+ realloc:
+ /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
+ newbuf = realloc(buffer, buflen);
+ if(newbuf == NULL)
+ {
+ if(buffer)
+ free(buffer);
+ fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
+ return(-1);
+ }
+ buffer = newbuf;
+
+ /* Try to read the results */
+ wrq.u.data.pointer = buffer;
+ wrq.u.data.flags = 0;
+ wrq.u.data.length = buflen;
+ if(iw_get_ext(skfd, ifname, SIOCGIWSCAN, &wrq) < 0)
+ {
+ /* Check if buffer was too small (WE-17 only) */
+ if((errno == E2BIG) && (range.we_version_compiled > 16)
+ && (buflen < 0xFFFF))
+ {
+ /* Some driver may return very large scan results, either
+ * because there are many cells, or because they have many
+ * large elements in cells (like IWEVCUSTOM). Most will
+ * only need the regular sized buffer. We now use a dynamic
+ * allocation of the buffer to satisfy everybody. Of course,
+ * as we don't know in advance the size of the array, we try
+ * various increasing sizes. Jean II */
+
+ /* Check if the driver gave us any hints. */
+ if(wrq.u.data.length > buflen)
+ buflen = wrq.u.data.length;
+ else
+ buflen *= 2;
+
+ /* wrq.u.data.length is 16 bits so max size is 65535 */
+ if(buflen > 0xFFFF)
+ buflen = 0xFFFF;
+
+ /* Try again */
+ goto realloc;
+ }
+
+ /* 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 */
+ free(buffer);
+ fprintf(stderr, "%-8.16s 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 */
+ }
+
+ if(wrq.u.data.length)
+ {
+ struct iw_event iwe;
+ struct stream_descr stream;
+ struct iwscan_state state = { .ap_num = 1, .val_index = 0 };
+ int ret;
+
+#ifdef DEBUG
+ /* Debugging code. In theory useless, because it's debugged ;-) */
+ int i;
+ printf("Scan result %d [%02X", wrq.u.data.length, buffer[0]);
+ for(i = 1; i < wrq.u.data.length; i++)
+ printf(":%02X", buffer[i]);
+ printf("]\n");
+#endif
+ printf("%-8.16s Scan completed :\n", ifname);
+ iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
+ do
+ {
+ /* Extract an event and print it */
+ ret = iw_extract_event_stream(&stream, &iwe,
+ range.we_version_compiled);
+ if(ret > 0)
+ print_scanning_token(&stream, &iwe, &state,
+ &range, has_range);
+ }
+ while(ret > 0);
+ printf("\n");
+ }
+ else
+ printf("%-8.16s No scan results\n\n", ifname);
+
+ free(buffer);
+ return(0);
+}
+
+/*********************** FREQUENCIES/CHANNELS ***********************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the number of channels and available frequency for the device
+ */
+static int
+print_freq_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
+{
+ struct iwreq wrq;
+ struct iw_range range;
+ double freq;
+ int k;
+ int channel;
+ char buffer[128]; /* Temporary buffer */
+
+ /* Avoid "Unused parameter" warning */
+ args = args; count = count;
+
+ /* Get list of frequencies / channels */
+ if(iw_get_range_info(skfd, ifname, &range) < 0)
+ fprintf(stderr, "%-8.16s no frequency information.\n\n",
+ ifname);
+ else
+ {
+ if(range.num_frequency > 0)
+ {
+ printf("%-8.16s %d channels in total; available frequencies :\n",
+ ifname, range.num_channels);
+ /* Print them all */
+ for(k = 0; k < range.num_frequency; k++)
+ {
+ freq = iw_freq2float(&(range.freq[k]));
+ iw_print_freq_value(buffer, sizeof(buffer), freq);
+ printf(" Channel %.2d : %s\n",
+ range.freq[k].i, buffer);
+ }
}
else
- /* Only print the address */
- printf(" %s\n", iw_pr_ether(temp, hwa[i].sa_data));
+ printf("%-8.16s %d channels\n",
+ ifname, range.num_channels);
+
+ /* Get current frequency / channel and display it */
+ if(iw_get_ext(skfd, ifname, SIOCGIWFREQ, &wrq) >= 0)
+ {
+ freq = iw_freq2float(&(wrq.u.freq));
+ channel = iw_freq_to_channel(freq, &range);
+ iw_print_freq(buffer, sizeof(buffer),
+ freq, channel, wrq.u.freq.flags);
+ printf(" Current %s\n\n", buffer);
+ }
}
- printf("\n");
return(0);
}
char * args[], /* Command line args */
int count) /* Args count */
{
+ struct iwreq wrq;
struct iw_range range;
int k;
char buffer[128];
/* Extract range info */
if(iw_get_range_info(skfd, ifname, &range) < 0)
- fprintf(stderr, "%-8.8s no bit-rate information.\n\n",
+ fprintf(stderr, "%-8.16s no bit-rate information.\n\n",
ifname);
else
{
- if((range.num_bitrates > 0) && (range.num_bitrates < IW_MAX_BITRATES))
+ if((range.num_bitrates > 0) && (range.num_bitrates <= IW_MAX_BITRATES))
{
- printf("%-8.8s %d available bit-rates :\n",
+ printf("%-8.16s %d available bit-rates :\n",
ifname, range.num_bitrates);
/* Print them all */
for(k = 0; k < range.num_bitrates; k++)
{
- iw_print_bitrate(buffer, range.bitrate[k]);
+ iw_print_bitrate(buffer, sizeof(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);
+ printf("%-8.16s unknown bit-rate information.\n", ifname);
+
+ /* Get current bit rate */
+ if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
+ {
+ iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
+ printf(" Current Bit Rate%c%s\n",
+ (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
+ }
+
+ /* Try to get the broadcast bitrate if it exist... */
+ if(range.bitrate_capa & IW_BITRATE_BROADCAST)
+ {
+ wrq.u.bitrate.flags = IW_BITRATE_BROADCAST;
+ if(iw_get_ext(skfd, ifname, SIOCGIWRATE, &wrq) >= 0)
+ {
+ iw_print_bitrate(buffer, sizeof(buffer), wrq.u.bitrate.value);
+ printf(" Broadcast Bit Rate%c%s\n",
+ (wrq.u.bitrate.fixed ? '=' : ':'), buffer);
+ }
+ }
+
+ printf("\n");
}
return(0);
}
/*------------------------------------------------------------------*/
/*
- * Print the number of available encryption key for the device
+ * Print all the available encryption keys for the device
*/
static int
print_keys_info(int skfd,
struct iwreq wrq;
struct iw_range range;
unsigned char key[IW_ENCODING_TOKEN_MAX];
- int k;
+ unsigned int k;
char buffer[128];
/* Avoid "Unused parameter" warning */
/* Extract range info */
if(iw_get_range_info(skfd, ifname, &range) < 0)
- fprintf(stderr, "%-8.8s no encryption keys information.\n\n",
+ fprintf(stderr, "%-8.16s no encryption keys information.\n\n",
ifname);
else
{
- printf("%-8.8s ", ifname);
+ printf("%-8.16s ", ifname);
/* Print key sizes */
if((range.num_encoding_sizes > 0) &&
(range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
wrq.u.data.flags = k;
if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
{
- fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
+ fprintf(stderr, "Error reading wireless keys (SIOCGIWENCODE): %s\n", strerror(errno));
break;
}
if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
else
{
/* Display the key */
- iw_print_key(buffer, key, wrq.u.data.length, wrq.u.data.flags);
+ iw_print_key(buffer, sizeof(buffer),
+ key, wrq.u.data.length, wrq.u.data.flags);
printf("\t\t[%d]: %s", k, buffer);
/* Other info... */
printf("\n");
}
}
- /* Print current key and mode */
+ /* Print current key index and mode */
wrq.u.data.pointer = (caddr_t) key;
wrq.u.data.length = IW_ENCODING_TOKEN_MAX;
wrq.u.data.flags = 0; /* Set index to zero to get current */
- if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) < 0)
+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODE, &wrq) >= 0)
{
- fprintf(stderr, "SIOCGIWENCODE: %s\n", strerror(errno));
- return(-1);
+ /* Note : if above fails, we have already printed an error
+ * message int the loop above */
+ printf(" Current Transmit Key: [%d]\n",
+ wrq.u.data.flags & IW_ENCODE_INDEX);
+ if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
+ printf(" Security mode:restricted\n");
+ if(wrq.u.data.flags & IW_ENCODE_OPEN)
+ printf(" Security mode:open\n");
}
- printf(" Current Transmit Key: [%d]\n",
- wrq.u.data.flags & IW_ENCODE_INDEX);
- if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
- printf(" Encryption mode:restricted\n");
- if(wrq.u.data.flags & IW_ENCODE_OPEN)
- printf(" Encryption mode:open\n");
printf("\n\n");
}
/*
* Print Power Management info for each device
*/
-static inline int
+static int
get_pm_value(int skfd,
char * ifname,
struct iwreq * pwrq,
int flags,
- char * buffer)
+ char * buffer,
+ int buflen,
+ int we_version_compiled)
{
/* Get Another Power Management value */
pwrq->u.power.flags = flags;
/* Let's check the value and its type */
if(pwrq->u.power.flags & IW_POWER_TYPE)
{
- iw_print_pm_value(buffer, pwrq->u.power.value, pwrq->u.power.flags);
+ iw_print_pm_value(buffer, buflen,
+ pwrq->u.power.value, pwrq->u.power.flags,
+ we_version_compiled);
printf("\n %s", buffer);
}
}
/*------------------------------------------------------------------*/
/*
+ * Print Power Management range for each type
+ */
+static void
+print_pm_value_range(char * name,
+ int mask,
+ int iwr_flags,
+ int iwr_min,
+ int iwr_max,
+ char * buffer,
+ int buflen,
+ int we_version_compiled)
+{
+ if(iwr_flags & mask)
+ {
+ int flags = (iwr_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
+ /* Display if auto or fixed */
+ printf("%s %s ; ",
+ (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
+ name);
+ /* Print the range */
+ iw_print_pm_value(buffer, buflen,
+ iwr_min, flags | IW_POWER_MIN,
+ we_version_compiled);
+ printf("%s\n ", buffer);
+ iw_print_pm_value(buffer, buflen,
+ iwr_max, flags | IW_POWER_MAX,
+ we_version_compiled);
+ printf("%s\n ", buffer);
+ }
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Power Management types of values
+ */
+static const unsigned int pm_type_flags[] = {
+ IW_POWER_PERIOD,
+ IW_POWER_TIMEOUT,
+ IW_POWER_SAVING,
+};
+static const int pm_type_flags_size = (sizeof(pm_type_flags)/sizeof(pm_type_flags[0]));
+
+/*------------------------------------------------------------------*/
+/*
* Print Power Management info for each device
*/
static int
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",
+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
+ (range.we_version_compiled < 10))
+ fprintf(stderr, "%-8.16s no power management information.\n\n",
ifname);
else
{
- printf("%-8.8s ", ifname);
-#if WIRELESS_EXT > 9
+ printf("%-8.16s ", ifname);
+
/* Display modes availables */
if(range.pm_capa & IW_POWER_MODE)
{
printf("\t\to Repeat multicast\n ");
}
/* Display min/max period availables */
- if(range.pmp_flags & IW_POWER_PERIOD)
- {
- int flags = (range.pmp_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
- /* Display if auto or fixed */
- if(range.pmp_flags & IW_POWER_MIN)
- printf("Auto period ; ");
- else
- printf("Fixed period ; ");
- /* Print the range */
- iw_print_pm_value(buffer, range.min_pmp, flags | IW_POWER_MIN);
- printf("%s\n ", buffer);
- iw_print_pm_value(buffer, range.max_pmp, flags | IW_POWER_MAX);
- printf("%s\n ", buffer);
-
- }
+ print_pm_value_range("period ", IW_POWER_PERIOD,
+ range.pmp_flags, range.min_pmp, range.max_pmp,
+ buffer, sizeof(buffer), range.we_version_compiled);
/* Display min/max timeout availables */
- if(range.pmt_flags & IW_POWER_TIMEOUT)
- {
- int flags = (range.pmt_flags & ~(IW_POWER_MIN | IW_POWER_MAX));
- /* Display if auto or fixed */
- if(range.pmt_flags & IW_POWER_MIN)
- printf("Auto timeout ; ");
- else
- printf("Fixed timeout ; ");
- /* Print the range */
- iw_print_pm_value(buffer, range.min_pmt, flags | IW_POWER_MIN);
- printf("%s\n ", buffer);
- iw_print_pm_value(buffer, range.max_pmt, flags | IW_POWER_MAX);
- printf("%s\n ", buffer);
-
- }
-#endif /* WIRELESS_EXT > 9 */
+ print_pm_value_range("timeout", IW_POWER_TIMEOUT,
+ range.pmt_flags, range.min_pmt, range.max_pmt,
+ buffer, sizeof(buffer), range.we_version_compiled);
+ /* Display min/max saving availables */
+ print_pm_value_range("saving ", IW_POWER_SAVING,
+ range.pms_flags, range.min_pms, range.max_pms,
+ buffer, sizeof(buffer), range.we_version_compiled);
/* Get current Power Management settings */
wrq.u.power.flags = 0;
/* Is it disabled ? */
if(wrq.u.power.disabled)
- printf("Current mode:off\n ");
+ printf("Current mode:off\n");
else
{
- int pm_mask = 0;
+ unsigned int pm_type = 0;
+ unsigned int pm_mask = 0;
+ unsigned int remain_mask = range.pm_capa & IW_POWER_TYPE;
+ int i = 0;
/* Let's check the mode */
- iw_print_pm_mode(buffer, flags);
+ iw_print_pm_mode(buffer, sizeof(buffer), flags);
printf("Current %s", buffer);
/* Let's check if nothing (simply on) */
if((flags & IW_POWER_MODE) == IW_POWER_ON)
printf("mode:on");
- printf("\n ");
/* Let's check the value and its type */
if(wrq.u.power.flags & IW_POWER_TYPE)
{
- iw_print_pm_value(buffer,
- wrq.u.power.value, wrq.u.power.flags);
- printf("%s", buffer);
+ iw_print_pm_value(buffer, sizeof(buffer),
+ wrq.u.power.value, wrq.u.power.flags,
+ range.we_version_compiled);
+ printf("\n %s", buffer);
}
- /* If we have been returned a MIN value, ask for the MAX */
- if(flags & IW_POWER_MIN)
- pm_mask = IW_POWER_MAX;
- /* If we have been returned a MAX value, ask for the MIN */
- if(flags & IW_POWER_MAX)
- pm_mask = IW_POWER_MIN;
- /* If we have something to ask for... */
- if(pm_mask)
- get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
-
-#if WIRELESS_EXT > 9
- /* And if we have both a period and a timeout, ask the other */
- pm_mask = (range.pm_capa & (~(wrq.u.power.flags) &
- IW_POWER_TYPE));
- if(pm_mask)
+ while(1)
{
- int base_mask = pm_mask;
- flags = get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
+ /* Deal with min/max for the current value */
pm_mask = 0;
-
/* If we have been returned a MIN value, ask for the MAX */
if(flags & IW_POWER_MIN)
- pm_mask = IW_POWER_MAX | base_mask;
+ pm_mask = IW_POWER_MAX;
/* If we have been returned a MAX value, ask for the MIN */
if(flags & IW_POWER_MAX)
- pm_mask = IW_POWER_MIN | base_mask;
+ pm_mask = IW_POWER_MIN;
/* If we have something to ask for... */
if(pm_mask)
- get_pm_value(skfd, ifname, &wrq, pm_mask, buffer);
+ {
+ pm_mask |= pm_type;
+ get_pm_value(skfd, ifname, &wrq, pm_mask,
+ buffer, sizeof(buffer),
+ range.we_version_compiled);
+ }
+
+ /* Remove current type from mask */
+ remain_mask &= ~(wrq.u.power.flags);
+
+ /* Check what other types we still have to read */
+ while(i < pm_type_flags_size)
+ {
+ pm_type = remain_mask & pm_type_flags[i];
+ if(pm_type)
+ break;
+ i++;
+ }
+ /* Nothing anymore : exit the loop */
+ if(!pm_type)
+ break;
+
+ /* Ask for this other type of value */
+ flags = get_pm_value(skfd, ifname, &wrq, pm_type,
+ buffer, sizeof(buffer),
+ range.we_version_compiled);
+ /* Loop back for min/max */
}
-#endif /* WIRELESS_EXT > 9 */
+ printf("\n");
}
}
printf("\n");
return(0);
}
+#ifndef WE_ESSENTIAL
/************************** TRANSMIT POWER **************************/
/*------------------------------------------------------------------*/
char * args[], /* Command line args */
int count) /* Args count */
{
+ struct iwreq wrq;
struct iw_range range;
int dbm;
int mwatt;
/* Avoid "Unused parameter" warning */
args = args; count = count;
-#if WIRELESS_EXT > 9
/* Extract range info */
- if(iw_get_range_info(skfd, ifname, &range) < 0)
- fprintf(stderr, "%-8.8s no transmit-power information.\n\n",
+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
+ (range.we_version_compiled < 10))
+ fprintf(stderr, "%-8.16s no transmit-power information.\n\n",
ifname);
else
{
- if((range.num_txpower > 0) && (range.num_txpower < IW_MAX_TXPOWER))
+ if((range.num_txpower <= 0) || (range.num_txpower > IW_MAX_TXPOWER))
+ printf("%-8.16s unknown transmit-power information.\n\n", ifname);
+ else
{
- printf("%-8.8s %d available transmit-powers :\n",
+ printf("%-8.16s %d available transmit-powers :\n",
ifname, range.num_txpower);
/* Print them all */
for(k = 0; k < range.num_txpower; k++)
{
- if(range.txpower_capa & IW_TXPOW_MWATT)
+ /* Check for relative values */
+ if(range.txpower_capa & IW_TXPOW_RELATIVE)
{
- dbm = iw_mwatt2dbm(range.txpower[k]);
- mwatt = range.txpower[k];
+ printf("\t %d (no units)\n", range.txpower[k]);
}
else
{
- dbm = range.txpower[k];
- mwatt = iw_dbm2mwatt(range.txpower[k]);
+ if(range.txpower_capa & IW_TXPOW_MWATT)
+ {
+ dbm = iw_mwatt2dbm(range.txpower[k]);
+ mwatt = range.txpower[k];
+ }
+ else
+ {
+ dbm = range.txpower[k];
+ mwatt = iw_dbm2mwatt(range.txpower[k]);
+ }
+ printf("\t %d dBm \t(%d mW)\n", dbm, mwatt);
+ }
+ }
+ }
+
+ /* Get current Transmit Power */
+ if(iw_get_ext(skfd, ifname, SIOCGIWTXPOW, &wrq) >= 0)
+ {
+ printf(" Current Tx-Power");
+ /* Disabled ? */
+ if(wrq.u.txpower.disabled)
+ printf(":off\n\n");
+ else
+ {
+ /* Fixed ? */
+ if(wrq.u.txpower.fixed)
+ printf("=");
+ else
+ printf(":");
+ /* Check for relative values */
+ if(wrq.u.txpower.flags & IW_TXPOW_RELATIVE)
+ {
+ /* I just hate relative value, because they are
+ * driver specific, so not very meaningfull to apps.
+ * But, we have to support that, because
+ * this is the way hardware is... */
+ printf("\t %d (no units)\n", wrq.u.txpower.value);
+ }
+ else
+ {
+ if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
+ {
+ dbm = iw_mwatt2dbm(wrq.u.txpower.value);
+ mwatt = wrq.u.txpower.value;
+ }
+ else
+ {
+ dbm = wrq.u.txpower.value;
+ mwatt = iw_dbm2mwatt(wrq.u.txpower.value);
+ }
+ printf("%d dBm \t(%d mW)\n\n", dbm, mwatt);
}
- printf("\t %d dBm \t(%d mW)\n", dbm, mwatt);
}
- printf("\n\n");
}
- else
- printf("%-8.8s No transmit-powers ? Please update driver...\n\n", ifname);
}
-#endif /* WIRELESS_EXT > 9 */
return(0);
}
/*********************** RETRY LIMIT/LIFETIME ***********************/
-#if WIRELESS_EXT > 10
/*------------------------------------------------------------------*/
/*
* Print one retry value
*/
-static inline int
+static int
get_retry_value(int skfd,
char * ifname,
struct iwreq * pwrq,
int flags,
- char * buffer)
+ char * buffer,
+ int buflen,
+ int we_version_compiled)
{
/* Get Another retry value */
pwrq->u.retry.flags = flags;
/* Let's check the value and its type */
if(pwrq->u.retry.flags & IW_RETRY_TYPE)
{
- iw_print_retry_value(buffer,
- pwrq->u.retry.value, pwrq->u.retry.flags);
+ iw_print_retry_value(buffer, buflen,
+ pwrq->u.retry.value, pwrq->u.retry.flags,
+ we_version_compiled);
printf("%s\n ", buffer);
}
}
/*------------------------------------------------------------------*/
/*
+ * Print Power Management range for each type
+ */
+static void
+print_retry_value_range(char * name,
+ int mask,
+ int iwr_flags,
+ int iwr_min,
+ int iwr_max,
+ char * buffer,
+ int buflen,
+ int we_version_compiled)
+{
+ if(iwr_flags & mask)
+ {
+ int flags = (iwr_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
+ /* Display if auto or fixed */
+ printf("%s %s ; ",
+ (iwr_flags & IW_POWER_MIN) ? "Auto " : "Fixed",
+ name);
+ /* Print the range */
+ iw_print_retry_value(buffer, buflen,
+ iwr_min, flags | IW_POWER_MIN,
+ we_version_compiled);
+ printf("%s\n ", buffer);
+ iw_print_retry_value(buffer, buflen,
+ iwr_max, flags | IW_POWER_MAX,
+ we_version_compiled);
+ printf("%s\n ", buffer);
+ }
+}
+
+/*------------------------------------------------------------------*/
+/*
* Print Retry info for each device
*/
static int
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",
- ifname);
+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
+ (range.we_version_compiled < 11))
+ fprintf(stderr, "%-8.16s no retry limit/lifetime information.\n\n",
+ ifname);
else
{
- printf("%-8.8s ", ifname);
+ printf("%-8.16s ", ifname);
/* Display min/max limit availables */
- if(range.retry_flags & IW_RETRY_LIMIT)
+ print_retry_value_range("limit ", IW_RETRY_LIMIT, range.retry_flags,
+ range.min_retry, range.max_retry,
+ buffer, sizeof(buffer),
+ range.we_version_compiled);
+ /* Display min/max lifetime availables */
+ print_retry_value_range("lifetime", IW_RETRY_LIFETIME,
+ range.r_time_flags,
+ range.min_r_time, range.max_r_time,
+ buffer, sizeof(buffer),
+ range.we_version_compiled);
+
+ /* Get current retry settings */
+ wrq.u.retry.flags = 0;
+ if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
{
- int flags = (range.retry_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
- /* Display if auto or fixed */
- if(range.retry_flags & IW_RETRY_MIN)
- printf("Auto limit ; ");
+ int flags = wrq.u.retry.flags;
+
+ /* Is it disabled ? */
+ if(wrq.u.retry.disabled)
+ printf("Current mode:off\n ");
else
- printf("Fixed limit ; ");
- /* Print the range */
- iw_print_retry_value(buffer, range.min_retry, flags | IW_RETRY_MIN);
- printf("%s\n ", buffer);
- iw_print_retry_value(buffer, range.max_retry, flags | IW_RETRY_MAX);
- printf("%s\n ", buffer);
-
+ {
+ unsigned int retry_type = 0;
+ unsigned int retry_mask = 0;
+ unsigned int remain_mask = range.retry_capa & IW_RETRY_TYPE;
+
+ /* Let's check the mode */
+ printf("Current mode:on\n ");
+
+ /* Let's check the value and its type */
+ if(wrq.u.retry.flags & IW_RETRY_TYPE)
+ {
+ iw_print_retry_value(buffer, sizeof(buffer),
+ wrq.u.retry.value, wrq.u.retry.flags,
+ range.we_version_compiled);
+ printf("%s\n ", buffer);
+ }
+
+ while(1)
+ {
+ /* Deal with min/max/short/long for the current value */
+ retry_mask = 0;
+ /* If we have been returned a MIN value, ask for the MAX */
+ if(flags & IW_RETRY_MIN)
+ retry_mask = IW_RETRY_MAX;
+ /* If we have been returned a MAX value, ask for the MIN */
+ if(flags & IW_RETRY_MAX)
+ retry_mask = IW_RETRY_MIN;
+ /* Same for SHORT and LONG */
+ if(flags & IW_RETRY_SHORT)
+ retry_mask = IW_RETRY_LONG;
+ if(flags & IW_RETRY_LONG)
+ retry_mask = IW_RETRY_SHORT;
+ /* If we have something to ask for... */
+ if(retry_mask)
+ {
+ retry_mask |= retry_type;
+ get_retry_value(skfd, ifname, &wrq, retry_mask,
+ buffer, sizeof(buffer),
+ range.we_version_compiled);
+ }
+
+ /* And if we have both a limit and a lifetime,
+ * ask the other one */
+ remain_mask &= ~(wrq.u.retry.flags);
+ retry_type = remain_mask;
+ /* Nothing anymore : exit the loop */
+ if(!retry_type)
+ break;
+
+ /* Ask for this other type of value */
+ flags = get_retry_value(skfd, ifname, &wrq, retry_type,
+ buffer, sizeof(buffer),
+ range.we_version_compiled);
+ /* Loop back for min/max/short/long */
+ }
+ }
}
- /* Display min/max lifetime availables */
- if(range.r_time_flags & IW_RETRY_LIFETIME)
+ printf("\n");
+ }
+ return(0);
+}
+
+/************************ ACCESS POINT LIST ************************/
+/*
+ * Note : now that we have scanning support, this is depracted and
+ * won't survive long. Actually, next version it's out !
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Display the list of ap addresses and the associated stats
+ * Exacly the same as the spy list, only with different IOCTL and messages
+ */
+static int
+print_ap_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
+{
+ struct iwreq wrq;
+ char buffer[(sizeof(struct iw_quality) +
+ sizeof(struct sockaddr)) * IW_MAX_AP];
+ char temp[128];
+ struct sockaddr * hwa;
+ struct iw_quality * qual;
+ iwrange range;
+ int has_range = 0;
+ int has_qual = 0;
+ 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;
+ wrq.u.data.flags = 0;
+ if(iw_get_ext(skfd, ifname, SIOCGIWAPLIST, &wrq) < 0)
+ {
+ fprintf(stderr, "%-8.16s Interface doesn't have a list of Peers/Access-Points\n\n", ifname);
+ return(-1);
+ }
+
+ /* Number of addresses */
+ n = wrq.u.data.length;
+ has_qual = wrq.u.data.flags;
+
+ /* The two lists */
+ hwa = (struct sockaddr *) buffer;
+ qual = (struct iw_quality *) (buffer + (sizeof(struct sockaddr) * n));
+
+ /* Check if we have valid mac address type */
+ if(iw_check_mac_addr_type(skfd, ifname) < 0)
+ {
+ fprintf(stderr, "%-8.16s Interface doesn't support MAC addresses\n\n", ifname);
+ return(-2);
+ }
+
+ /* Get range info if we can */
+ if(iw_get_range_info(skfd, ifname, &(range)) >= 0)
+ has_range = 1;
+
+ /* Display it */
+ if(n == 0)
+ printf("%-8.16s No Peers/Access-Point in range\n", ifname);
+ else
+ printf("%-8.16s Peers/Access-Points in range:\n", ifname);
+ for(i = 0; i < n; i++)
+ {
+ if(has_qual)
+ {
+ /* Print stats for this address */
+ printf(" %s : ", iw_saether_ntop(&hwa[i], temp));
+ iw_print_stats(temp, sizeof(buffer), &qual[i], &range, has_range);
+ printf("%s\n", temp);
+ }
+ else
+ /* Only print the address */
+ printf(" %s\n", iw_saether_ntop(&hwa[i], temp));
+ }
+ printf("\n");
+ return(0);
+}
+
+/******************** WIRELESS EVENT CAPABILITY ********************/
+
+static const char * event_capa_req[] =
+{
+ [SIOCSIWNWID - SIOCIWFIRST] = "Set NWID (kernel generated)",
+ [SIOCSIWFREQ - SIOCIWFIRST] = "Set Frequency/Channel (kernel generated)",
+ [SIOCGIWFREQ - SIOCIWFIRST] = "New Frequency/Channel",
+ [SIOCSIWMODE - SIOCIWFIRST] = "Set Mode (kernel generated)",
+ [SIOCGIWTHRSPY - SIOCIWFIRST] = "Spy threshold crossed",
+ [SIOCGIWAP - SIOCIWFIRST] = "New Access Point/Cell address - roaming",
+ [SIOCGIWSCAN - SIOCIWFIRST] = "Scan request completed",
+ [SIOCSIWESSID - SIOCIWFIRST] = "Set ESSID (kernel generated)",
+ [SIOCGIWESSID - SIOCIWFIRST] = "New ESSID",
+ [SIOCGIWRATE - SIOCIWFIRST] = "New bit-rate",
+ [SIOCSIWENCODE - SIOCIWFIRST] = "Set Encoding (kernel generated)",
+ [SIOCGIWPOWER - SIOCIWFIRST] = NULL,
+};
+
+static const char * event_capa_evt[] =
+{
+ [IWEVTXDROP - IWEVFIRST] = "Tx packet dropped - retry exceeded",
+ [IWEVCUSTOM - IWEVFIRST] = "Custom driver event",
+ [IWEVREGISTERED - IWEVFIRST] = "Registered node",
+ [IWEVEXPIRED - IWEVFIRST] = "Expired node",
+};
+
+static const struct iwmask_name iw_scan_capa_name[] = {
+ { IW_SCAN_CAPA_ESSID, "ESSID" },
+ { IW_SCAN_CAPA_BSSID, "BSSID" },
+ { IW_SCAN_CAPA_CHANNEL, "Channel" },
+ { IW_SCAN_CAPA_MODE, "Mode" },
+ { IW_SCAN_CAPA_RATE, "Rate" },
+ { IW_SCAN_CAPA_TYPE, "Type" },
+ { IW_SCAN_CAPA_TIME, "Time" },
+};
+#define IW_SCAN_CAPA_NUM IW_ARRAY_LEN(iw_scan_capa_name)
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the event capability for the device
+ */
+static int
+print_event_capa_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
+{
+ struct iw_range range;
+ int cmd;
+
+ /* Avoid "Unused parameter" warning */
+ args = args; count = count;
+
+ /* Extract range info */
+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
+ (range.we_version_compiled < 10))
+ fprintf(stderr, "%-8.16s no wireless event capability information.\n\n",
+ ifname);
+ else
+ {
+#ifdef DEBUG
+ /* Debugging ;-) */
+ for(cmd = 0x8B00; cmd < 0x8C0F; cmd++)
+ {
+ int idx = IW_EVENT_CAPA_INDEX(cmd);
+ int mask = IW_EVENT_CAPA_MASK(cmd);
+ printf("0x%X - %d - %X\n", cmd, idx, mask);
+ }
+#endif
+
+ printf("%-8.16s Wireless Events supported :\n", ifname);
+
+ for(cmd = SIOCIWFIRST; cmd <= SIOCGIWPOWER; cmd++)
+ {
+ int idx = IW_EVENT_CAPA_INDEX(cmd);
+ int mask = IW_EVENT_CAPA_MASK(cmd);
+ if(range.event_capa[idx] & mask)
+ printf(" 0x%04X : %s\n",
+ cmd, event_capa_req[cmd - SIOCIWFIRST]);
+ }
+ for(cmd = IWEVFIRST; cmd <= IWEVEXPIRED; cmd++)
+ {
+ int idx = IW_EVENT_CAPA_INDEX(cmd);
+ int mask = IW_EVENT_CAPA_MASK(cmd);
+ if(range.event_capa[idx] & mask)
+ printf(" 0x%04X : %s\n",
+ cmd, event_capa_evt[cmd - IWEVFIRST]);
+ }
+ printf("\n");
+
+ /* Add Scanning Capacity as a bonus, if available */
+ if(range.scan_capa != 0)
+ {
+ printf("%-8.16s Scanning capabilities :", ifname);
+ iw_print_mask_name(range.scan_capa,
+ iw_scan_capa_name, IW_SCAN_CAPA_NUM,
+ "\n\t\t- ");
+ printf("\n\n");
+ }
+ }
+ return(0);
+}
+
+/*************************** WPA SUPPORT ***************************/
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the authentication parameters for the device
+ */
+static int
+print_auth_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
+{
+ struct iwreq wrq;
+ struct iw_range range;
+ unsigned int k;
+
+ /* Avoid "Unused parameter" warning */
+ args = args; count = count;
+
+ /* Extract range info */
+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
+ (range.we_version_compiled < 18))
+ fprintf(stderr, "%-8.16s no authentication information.\n\n",
+ ifname);
+ else
+ {
+ /* Print WPA/802.1x/802.11i security parameters */
+ if(!range.enc_capa)
+ {
+ printf("%-8.16s unknown authentication information.\n\n", ifname);
+ }
+ else
+ {
+ /* Display advanced encryption capabilities */
+ printf("%-8.16s Authentication capabilities :", ifname);
+ iw_print_mask_name(range.enc_capa,
+ iw_auth_capa_name, IW_AUTH_CAPA_NUM,
+ "\n\t\t");
+ printf("\n");
+
+ /* Extract all auth settings */
+ for(k = 0; k < IW_AUTH_SETTINGS_NUM; k++)
+ {
+ wrq.u.param.flags = iw_auth_settings[k].value;
+ if(iw_get_ext(skfd, ifname, SIOCGIWAUTH, &wrq) >= 0)
+ {
+ printf(" Current %s :", iw_auth_settings[k].label);
+ if(iw_auth_settings[k].names != NULL)
+ iw_print_mask_name(wrq.u.param.value,
+ iw_auth_settings[k].names,
+ iw_auth_settings[k].num_names,
+ "\n\t\t");
+ else
+ printf((wrq.u.param.value) ? " yes" : " no");
+ printf("\n");
+ }
+ }
+ }
+
+ printf("\n\n");
+ }
+ return(0);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Print all the available wpa keys for the device
+ */
+static int
+print_wpakeys_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
+{
+ struct iwreq wrq;
+ struct iw_range range;
+ unsigned char extbuf[IW_EXTKEY_SIZE];
+ struct iw_encode_ext *extinfo;
+ unsigned int k;
+ char buffer[128];
+
+ /* Avoid "Unused parameter" warning */
+ args = args; count = count;
+
+ /* This always point to the same place */
+ extinfo = (struct iw_encode_ext *) extbuf;
+
+ /* Extract range info */
+ if(iw_get_range_info(skfd, ifname, &range) < 0)
+ fprintf(stderr, "%-8.16s no wpa key information.\n\n",
+ ifname);
+ else
+ {
+ printf("%-8.16s ", ifname);
+ /* Print key sizes */
+ if((range.num_encoding_sizes > 0) &&
+ (range.num_encoding_sizes < IW_MAX_ENCODING_SIZES))
{
- int flags = (range.r_time_flags & ~(IW_RETRY_MIN | IW_RETRY_MAX));
- /* Display if auto or fixed */
- if(range.r_time_flags & IW_RETRY_MIN)
- printf("Auto lifetime ; ");
- else
- printf("Fixed lifetime ; ");
- /* Print the range */
- iw_print_retry_value(buffer, range.min_r_time, flags | IW_RETRY_MIN);
- printf("%s\n ", buffer);
- iw_print_retry_value(buffer, range.max_r_time, flags | IW_RETRY_MAX);
- printf("%s\n ", buffer);
-
+ printf("%d key sizes : %d", range.num_encoding_sizes,
+ range.encoding_size[0] * 8);
+ /* Print them all */
+ for(k = 1; k < range.num_encoding_sizes; k++)
+ printf(", %d", range.encoding_size[k] * 8);
+ printf("bits\n ");
}
- /* Get current retry settings */
- wrq.u.retry.flags = 0;
- if(iw_get_ext(skfd, ifname, SIOCGIWRETRY, &wrq) >= 0)
+ /* Print the keys */
+ printf("%d keys available :\n", range.max_encoding_tokens);
+ for(k = 1; k <= range.max_encoding_tokens; k++)
{
- int flags = wrq.u.retry.flags;
+ /* Cleanup. Driver may not fill everything */
+ memset(extbuf, '\0', IW_EXTKEY_SIZE);
- /* Is it disabled ? */
- if(wrq.u.retry.disabled)
- printf("Current mode:off\n ");
- else
+ /* Get whole struct containing one WPA key */
+ wrq.u.data.pointer = (caddr_t) extbuf;
+ wrq.u.data.length = IW_EXTKEY_SIZE;
+ wrq.u.data.flags = k;
+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) < 0)
{
- int retry_mask = 0;
+ fprintf(stderr, "Error reading wpa keys (SIOCGIWENCODEEXT): %s\n", strerror(errno));
+ break;
+ }
- /* Let's check the mode */
- printf("Current mode:on\n ");
+ /* Sanity check */
+ if(wrq.u.data.length <
+ (sizeof(struct iw_encode_ext) + extinfo->key_len))
+ break;
- /* Let's check the value and its type */
- if(wrq.u.retry.flags & IW_RETRY_TYPE)
- {
- iw_print_retry_value(buffer,
- wrq.u.retry.value, wrq.u.retry.flags);
- printf("%s", buffer);
- }
+ /* Check if key is disabled */
+ if((wrq.u.data.flags & IW_ENCODE_DISABLED) ||
+ (extinfo->key_len == 0))
+ printf("\t\t[%d]: off\n", k);
+ else
+ {
+ /* Display the key */
+ iw_print_key(buffer, sizeof(buffer),
+ extinfo->key, extinfo->key_len, wrq.u.data.flags);
+ printf("\t\t[%d]: %s", k, buffer);
- /* If we have been returned a MIN value, ask for the MAX */
- if(flags & IW_RETRY_MIN)
- retry_mask = IW_RETRY_MAX;
- /* If we have been returned a MAX value, ask for the MIN */
- if(flags & IW_RETRY_MAX)
- retry_mask = IW_RETRY_MIN;
- /* If we have something to ask for... */
- if(retry_mask)
- get_retry_value(skfd, ifname, &wrq, retry_mask, buffer);
-
- /* And if we have both a period and a timeout, ask the other */
- retry_mask = (range.retry_capa & (~(wrq.u.retry.flags) &
- IW_RETRY_TYPE));
- if(retry_mask)
- {
- int base_mask = retry_mask;
- flags = get_retry_value(skfd, ifname, &wrq, retry_mask,
- buffer);
- retry_mask = 0;
+ /* Key size */
+ printf(" (%d bits)", extinfo->key_len * 8);
+ printf("\n");
- /* If we have been returned a MIN value, ask for the MAX */
- if(flags & IW_RETRY_MIN)
- retry_mask = IW_RETRY_MAX | base_mask;
- /* If we have been returned a MAX value, ask for the MIN */
- if(flags & IW_RETRY_MAX)
- retry_mask = IW_RETRY_MIN | base_mask;
- /* If we have something to ask for... */
- if(retry_mask)
- get_retry_value(skfd, ifname, &wrq, retry_mask, buffer);
- }
+ /* Other info... */
+ printf("\t\t Address: %s\n",
+ iw_saether_ntop(&extinfo->addr, buffer));
+
+ printf("\t\t Algorithm:");
+ iw_print_value_name(extinfo->alg,
+ iw_encode_alg_name, IW_ENCODE_ALG_NUM);
+
+ printf("\n\t\t Flags: 0x%08x\n", extinfo->ext_flags);
+ if (extinfo->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID)
+ printf("\t\t tx-seq-valid\n");
+ if (extinfo->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
+ printf("\t\t rx-seq-valid\n");
+ if (extinfo->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+ printf("\t\t group-key\n");
}
}
- printf("\n");
+ /* Print current key index and mode */
+ wrq.u.data.pointer = (caddr_t) extbuf;
+ wrq.u.data.length = IW_EXTKEY_SIZE;
+ wrq.u.data.flags = 0; /* Set index to zero to get current */
+ if(iw_get_ext(skfd, ifname, SIOCGIWENCODEEXT, &wrq) >= 0)
+ {
+ /* Note : if above fails, we have already printed an error
+ * message int the loop above */
+ printf(" Current Transmit Key: [%d]\n",
+ wrq.u.data.flags & IW_ENCODE_INDEX);
+ if(wrq.u.data.flags & IW_ENCODE_RESTRICTED)
+ printf(" Security mode:restricted\n");
+ if(wrq.u.data.flags & IW_ENCODE_OPEN)
+ printf(" Security mode:open\n");
+ }
+
+ printf("\n\n");
}
return(0);
}
-#endif /* WIRELESS_EXT > 10 */
-
-/***************************** SCANNING *****************************/
-/*
- * This one behave quite differently from the others
- */
-#if WIRELESS_EXT > 13
/*------------------------------------------------------------------*/
/*
- * Print one element from the scanning results
+ * Print the Generic IE for the device
+ * Note : indentation is broken. We need to fix that.
*/
-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)
+static int
+print_gen_ie_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
{
- char buffer[128]; /* Temporary buffer */
+ struct iwreq wrq;
+ unsigned char buf[IW_GENERIC_IE_MAX];
- /* 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);
+ /* Avoid "Unused parameter" warning */
+ args = args; count = count;
- /* 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) */
+ wrq.u.data.pointer = (caddr_t)buf;
+ wrq.u.data.length = IW_GENERIC_IE_MAX;
+ wrq.u.data.flags = 0;
- /* May have changed */
- return(ap_num);
+ if(iw_get_ext(skfd, ifname, SIOCGIWGENIE, &wrq) < 0)
+ fprintf(stderr, "%-8.16s no generic IE (%s).\n\n",
+ ifname, strerror(errno));
+ else
+ {
+ fprintf(stderr, "%-8.16s\n", ifname);
+ if(wrq.u.data.length == 0)
+ printf(" empty generic IE\n");
+ else
+ iw_print_gen_ie(buf, wrq.u.data.length);
+ printf("\n");
+ }
+ return(0);
}
+/**************************** MODULATION ****************************/
+
/*------------------------------------------------------------------*/
/*
- * Perform a scanning on one device
+ * Print Modulation info for each device
*/
static int
-print_scanning_info(int skfd,
- char * ifname,
- char * args[], /* Command line args */
- int count) /* Args count */
+print_modul_info(int skfd,
+ char * ifname,
+ char * args[], /* Command line args */
+ int count) /* Args count */
{
struct iwreq wrq;
- unsigned char buffer[IW_SCAN_MAX_DATA]; /* Results */
- struct timeval tv; /* Select timeout */
- int timeout = 5000000; /* 5s */
+ struct iw_range range;
/* 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)
+ /* Extract range info */
+ if((iw_get_range_info(skfd, ifname, &range) < 0) ||
+ (range.we_version_compiled < 11))
+ fprintf(stderr, "%-8.16s no modulation information.\n\n",
+ ifname);
+ else
{
- if(errno != EPERM)
+ if(range.modul_capa == 0x0)
+ printf("%-8.16s unknown modulation information.\n\n", ifname);
+ else
{
- 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;
+ int i;
+ printf("%-8.16s Modulations available :\n", ifname);
- /* Guess what ? We must re-generate rfds each time */
- FD_ZERO(&rfds);
- last_fd = -1;
-
- /* In here, add the rtnetlink fd in the list */
+ /* Display each modulation available */
+ for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
+ {
+ if((range.modul_capa & iw_modul_list[i].mask)
+ == iw_modul_list[i].mask)
+ printf(" %-8s: %s\n",
+ iw_modul_list[i].cmd, iw_modul_list[i].verbose);
+ }
- /* Wait until something happens */
- ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
+ /* Get current modulations settings */
+ wrq.u.param.flags = 0;
+ if(iw_get_ext(skfd, ifname, SIOCGIWMODUL, &wrq) >= 0)
+ {
+ unsigned int modul = wrq.u.param.value;
+ int n = 0;
- /* Check if there was an error */
- if(ret < 0)
- {
- if(errno == EAGAIN || errno == EINTR)
- continue;
- fprintf(stderr, "Unhandled signal - exiting...\n");
- return(-1);
- }
+ printf(" Current modulations %c",
+ wrq.u.param.fixed ? '=' : ':');
- /* 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)
+ /* Display each modulation enabled */
+ for(i = 0; i < IW_SIZE_MODUL_LIST; i++)
{
- /* Restart timer for only 100ms*/
- tv.tv_sec = 0;
- tv.tv_usec = 100000;
- timeout -= tv.tv_usec;
- if(timeout > 0)
- continue; /* Try again later */
+ if((modul & iw_modul_list[i].mask) == iw_modul_list[i].mask)
+ {
+ if((n++ % 8) == 0)
+ printf("\n ");
+ else
+ printf(" ; ");
+ printf("%s", iw_modul_list[i].cmd);
+ }
}
- /* Bad error */
- fprintf(stderr, "%-8.8s Failed to read scan data : %s\n\n",
- ifname, strerror(errno));
- return(-2);
+ printf("\n");
}
- 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 */
- }
-
- if(wrq.u.data.length)
- {
- 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);
+ printf("\n");
}
- while(ret > 0);
- printf("\n");
}
- else
- printf("%-8.8s No scan results\n", ifname);
-
return(0);
}
-#endif /* WIRELESS_EXT > 13 */
+#endif /* WE_ESSENTIAL */
/************************* COMMON UTILITIES *************************/
/*
- * This section was written by Michael Tokarev <mjt@tls.msk.ru>
- * But modified by me ;-)
+ * This section was initially written by Michael Tokarev <mjt@tls.msk.ru>
+ * but heavily modified by me ;-)
*/
-/* command list */
+/*------------------------------------------------------------------*/
+/*
+ * Map command line arguments to the proper procedure...
+ */
typedef struct iwlist_entry {
- const char *cmd;
- iw_enum_handler fn;
- int min_count;
- int max_count;
+ const char * cmd; /* Command line shorthand */
+ iw_enum_handler fn; /* Subroutine */
+ int max_count;
+ const char * argsname; /* Args as human readable string */
} iwlist_cmd;
static const struct iwlist_entry iwlist_cmds[] = {
- { "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, 0, 0 },
-#endif
-#if WIRELESS_EXT > 13
- { "scanning", print_scanning_info, 0, 5 },
-#endif
+ { "scanning", print_scanning_info, -1, "[essid NNN] [last]" },
+ { "frequency", print_freq_info, 0, NULL },
+ { "channel", print_freq_info, 0, NULL },
+ { "bitrate", print_bitrate_info, 0, NULL },
+ { "rate", print_bitrate_info, 0, NULL },
+ { "encryption", print_keys_info, 0, NULL },
+ { "keys", print_keys_info, 0, NULL },
+ { "power", print_pm_info, 0, NULL },
+#ifndef WE_ESSENTIAL
+ { "txpower", print_txpower_info, 0, NULL },
+ { "retry", print_retry_info, 0, NULL },
+ { "ap", print_ap_info, 0, NULL },
+ { "accesspoints", print_ap_info, 0, NULL },
+ { "peers", print_ap_info, 0, NULL },
+ { "event", print_event_capa_info, 0, NULL },
+ { "auth", print_auth_info, 0, NULL },
+ { "wpakeys", print_wpakeys_info, 0, NULL },
+ { "genie", print_gen_ie_info, 0, NULL },
+ { "modulation", print_modul_info, 0, NULL },
+#endif /* WE_ESSENTIAL */
{ NULL, NULL, 0, 0 },
};
if(found == NULL)
{
- fprintf(stderr, "iwlist: unknown command `%s'\n", cmd);
+ fprintf(stderr, "iwlist: unknown command `%s' (check 'iwlist --help').\n", cmd);
return NULL;
}
if(ambig)
{
- fprintf(stderr, "iwlist: command `%s' is ambiguous\n", cmd);
+ fprintf(stderr, "iwlist: command `%s' is ambiguous (check 'iwlist --help').\n", cmd);
return NULL;
}
*/
static void iw_usage(int status)
{
- FILE* f = status ? stderr : stdout;
- int i;
+ FILE * f = status ? stderr : stdout;
+ int i;
+
+ for(i = 0; iwlist_cmds[i].cmd != NULL; ++i)
+ {
+ fprintf(f, "%s [interface] %s %s\n",
+ (i ? " " : "Usage: iwlist"),
+ iwlist_cmds[i].cmd,
+ iwlist_cmds[i].argsname ? iwlist_cmds[i].argsname : "");
+ }
- 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);
}
char **args; /* Command arguments */
int count; /* Number of arguments */
const iwlist_cmd *iwcmd;
+ int goterr = 0;
- if(argc == 1 || argc > 3)
+ if(argc < 2)
iw_usage(1);
- if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+ /* Those don't apply to all interfaces */
+ if((argc == 2) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
iw_usage(0);
+ if((argc == 2) && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")))
+ return(iw_print_version_info("iwlist"));
- if (argc == 2)
+ if(argc == 2)
{
cmd = argv[1];
dev = 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)
+ if((iwcmd->max_count >= 0) && (count > iwcmd->max_count))
{
- fprintf(stderr, "iwlist: command `%s' needs fewer arguments\n", cmd);
+ fprintf(stderr, "iwlist: command `%s' needs fewer arguments (max %d)\n",
+ iwcmd->cmd, iwcmd->max_count);
return 1;
}
/* do the actual work */
if (dev)
- (*iwcmd->fn)(skfd, dev, args, count);
+ goterr = (*iwcmd->fn)(skfd, dev, args, count);
else
iw_enum_devices(skfd, iwcmd->fn, args, count);
/* Close the socket. */
- close(skfd);
+ iw_sockets_close(skfd);
- return 0;
+ return goterr;
}