memcpy(name, buf, (end - buf));
name[end - buf] = '\0';
- return(end + 2);
+ /* Return value currently unused, just make sure it's non-NULL */
+ return(end);
}
/*------------------------------------------------------------------*/
int i;
#ifndef IW_RESTRIC_ENUM
- /* Check if /proc/net/wireless is available */
+ /* Check if /proc/net/dev is available */
fh = fopen(PROC_NET_DEV, "r");
#else
/* Check if /proc/net/wireless is available */
char name[IFNAMSIZ + 1];
char *s;
+ /* Skip empty or almost empty lines. It seems that in some
+ * cases fgets return a line with only a newline. */
+ if((buff[0] == '\0') || (buff[1] == '\0'))
+ continue;
+
/* Extract interface name */
s = iw_get_ifname(name, sizeof(name), buff);
if(!s)
- /* Failed to parse, complain and continue */
+ {
+ /* Failed to parse, complain and continue */
#ifndef IW_RESTRIC_ENUM
- fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
+ fprintf(stderr, "Cannot parse " PROC_NET_DEV "\n");
#else
- fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
+ fprintf(stderr, "Cannot parse " PROC_NET_WIRELESS "\n");
#endif
+ }
else
/* Got it, print info about this interface */
(*fn)(skfd, name, args, count);
/* We don't like future versions of WE, because we can't cope with
* the unknown */
- if(range->we_version_compiled > WE_VERSION)
+ if(range->we_version_compiled > WE_MAX_VERSION)
{
fprintf(stderr, "Warning: Driver for device %s has been compiled with version %d\n", ifname, range->we_version_compiled);
fprintf(stderr, "of Wireless Extension, while this program supports up to version %d.\n", WE_VERSION);
*/
if(info->has_essid)
{
+ int we_kernel_version;
+ we_kernel_version = iw_get_kernel_we_version();
+
wrq.u.essid.pointer = (caddr_t) info->essid;
wrq.u.essid.length = strlen(info->essid) + 1;
wrq.u.data.flags = info->essid_on;
+ if(we_kernel_version > 20)
+ wrq.u.essid.length--;
if(iw_set_ext(skfd, ifname, SIOCSIWESSID, &wrq) < 0)
{
/*------------------------------------------------------------------*/
/*
* Read /proc/net/wireless to get the latest statistics
+ * Note : strtok not thread safe, not used in WE-12 and later.
*/
int
iw_get_stats(int skfd,
* Relative/percent values are always encoded unsigned, between 0 and 255.
* Absolute/dBm values are always encoded negative, between -255 and 0.
*
- * How do we separate relative from absolute values ? We use the
- * range to do that. The range allow to specify the real min/max
- * of the value. As the range struct only specify one bound of the
- * value, we assume that the other bound is 0 (zero).
+ * How do we separate relative from absolute values ?
+ * The old way is to use the range to do that. As of WE-19, we have
+ * an explicit IW_QUAL_DBM flag in updated...
+ * The range allow to specify the real min/max of the value. As the
+ * range struct only specify one bound of the value, we assume that
+ * the other bound is 0 (zero).
* For relative values, range is [0 ; range->max].
* For absolute values, range is [range->max ; 0].
*
* Jean II
*/
- /* Just do it */
- if(has_range && (qual->level != 0))
+ /* Just do it...
+ * The old way to detect dBm require both the range and a non-null
+ * level (which confuse the test). The new way can deal with level of 0
+ * because it does an explicit test on the flag. */
+ if(has_range && ((qual->level != 0) || (qual->updated & IW_QUAL_DBM)))
{
/* Deal with quality : always a relative value */
if(!(qual->updated & IW_QUAL_QUAL_INVALID))
buflen -= len;
}
- /* If the statistics are in dBm or relative */
- if(qual->level > range->max_qual.level)
+ /* Check if the statistics are in dBm or relative */
+ if((qual->updated & IW_QUAL_DBM)
+ || (qual->level > range->max_qual.level))
{
/* Deal with signal level in dBm (absolute power measurement) */
if(!(qual->updated & IW_QUAL_LEVEL_INVALID))
/*
* Parse a key from the command line.
* Return size of the key, or 0 (no key) or -1 (error)
+ * If the key is too long, it's simply truncated...
*/
int
iw_in_key(const char * input,
keylen = strlen(input + 2); /* skip "s:" */
if(keylen > IW_ENCODING_TOKEN_MAX)
keylen = IW_ENCODING_TOKEN_MAX;
- strncpy(key, input + 2, keylen);
+ memcpy(key, input + 2, keylen);
}
else
if(!strncmp(input, "p:", 2))
}
else
{
- char * buff;
- char * hex;
- char * out;
- char * p;
+ const char * p;
+ int dlen; /* Digits sequence length */
+ unsigned char out[IW_ENCODING_TOKEN_MAX];
/* Third case : as hexadecimal digits */
- buff = malloc(IW_ENCODING_TOKEN_MAX + strlen(input) + 1);
- if(buff == NULL)
- {
- fprintf(stderr, "Malloc failed (string too long ?)\n");
- return(-1);
- }
- /* Preserve original buffers (both in & out) */
- hex = buff + IW_ENCODING_TOKEN_MAX;
- strcpy(hex, input); /* Size checked */
- out = buff;
-
- /* Parse */
- p = strtok(hex, "-:;.,");
- while((p != (char *) NULL) && (keylen < IW_ENCODING_TOKEN_MAX))
+ p = input;
+ dlen = -1;
+
+ /* Loop until we run out of chars in input or overflow the output */
+ while(*p != '\0')
{
int temph;
int templ;
int count;
- int len;
+ /* No more chars in this sequence */
+ if(dlen <= 0)
+ {
+ /* Skip separator */
+ if(dlen == 0)
+ p++;
+ /* Calculate num of char to next separator */
+ dlen = strcspn(p, "-:;.,");
+ }
/* Get each char separatly (and not by two) so that we don't
* get confused by 'enc' (=> '0E'+'0C') and similar */
count = sscanf(p, "%1X%1X", &temph, &templ);
if(count < 1)
return(-1); /* Error -> non-hex char */
/* Fixup odd strings such as '123' is '01'+'23' and not '12'+'03'*/
- len = strlen(p);
- if(len % 2)
+ if(dlen % 2)
count = 1;
- /* Put back two chars as one byte */
+ /* Put back two chars as one byte and output */
if(count == 2)
templ |= temph << 4;
else
templ = temph;
out[keylen++] = (unsigned char) (templ & 0xFF);
- /* Check where to get next char from */
- if(len > count) /* Token not finished yet */
- p += count;
- else
- p = strtok((char *) NULL, "-:;.,");
+ /* Check overflow in output */
+ if(keylen >= IW_ENCODING_TOKEN_MAX)
+ break;
+ /* Move on to next chars */
+ p += count;
+ dlen -= count;
}
+ /* We use a temporary output buffer 'out' so that if there is
+ * an error, we don't overwrite the original key buffer.
+ * Because of the way iwconfig loop on multiple key/enc arguments
+ * until it finds an error in here, this is necessary to avoid
+ * silently corrupting the encryption key... */
memcpy(key, out, keylen);
- free(buff);
}
+#ifdef DEBUG
+ {
+ char buf[IW_ENCODING_TOKEN_MAX * 3];
+ iw_print_key(buf, sizeof(buf), key, keylen, 0);
+ printf("Got key : %d [%s]\n", keylen, buf);
+ }
+#endif
+
return(keylen);
}
memcpy(key, input + 2, keylen);
/* Separate the two strings */
- p = strchr(key, ':');
+ p = strchr((char *) key, ':');
if(p == NULL)
{
fprintf(stderr, "Error: Invalid login format\n");
* Inspired from irdadump...
*/
void
-iw_print_timeval(char * buffer,
- int buflen,
- const struct timeval * time)
+iw_print_timeval(char * buffer,
+ int buflen,
+ const struct timeval * timev,
+ const struct timezone * tz)
{
int s;
- s = (time->tv_sec) % 86400;
- snprintf(buffer, buflen, "%02d:%02d:%02d.%06u ",
+ s = (timev->tv_sec - tz->tz_minuteswest * 60) % 86400;
+ snprintf(buffer, buflen, "%02d:%02d:%02d.%06u",
s / 3600, (s % 3600) / 60,
- s % 60, (u_int32_t) time->tv_usec);
+ s % 60, (u_int32_t) timev->tv_usec);
}
/*********************** ADDRESS SUBROUTINES ************************/
*/
int
iw_check_mac_addr_type(int skfd,
- char * ifname)
+ const char * ifname)
{
struct ifreq ifr;
/* Get the type of hardware address */
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if((ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) ||
- (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER))
+ ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
+ && (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211)))
{
/* Deep trouble... */
fprintf(stderr, "Interface %s doesn't support MAC addresses\n",
}
#ifdef DEBUG
- printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
- iw_ether_ntoa((struct ether_addr *) ifr.ifr_hwaddr.sa_data));
+ {
+ char buf[20];
+ printf("Hardware : %d - %s\n", ifr.ifr_hwaddr.sa_family,
+ iw_saether_ntop(&ifr.ifr_hwaddr, buf));
+ }
#endif
return(0);
*/
int
iw_check_if_addr_type(int skfd,
- char * ifname)
+ const char * ifname)
{
struct ifreq ifr;
}
#endif
+#if 0
/*------------------------------------------------------------------*/
/*
* Ask the kernel for the MAC address of an interface.
*ptype = ifr.ifr_hwaddr.sa_family;
return(ret);
}
+#endif
+
+/*------------------------------------------------------------------*/
+/*
+ * Display an arbitrary length MAC address in readable format.
+ */
+char *
+iw_mac_ntop(const unsigned char * mac,
+ int maclen,
+ char * buf,
+ int buflen)
+{
+ int i;
+
+ /* Overflow check (don't forget '\0') */
+ if(buflen < (maclen * 3 - 1 + 1))
+ return(NULL);
+
+ /* First byte */
+ sprintf(buf, "%02X", mac[0]);
+
+ /* Other bytes */
+ for(i = 1; i < maclen; i++)
+ sprintf(buf + (i * 3) - 1, ":%02X", mac[i]);
+ return(buf);
+}
/*------------------------------------------------------------------*/
/*
* Display an Ethernet address in readable format.
*/
void
-iw_ether_ntop(const struct ether_addr* eth, char* buf)
+iw_ether_ntop(const struct ether_addr * eth,
+ char * buf)
{
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
eth->ether_addr_octet[0], eth->ether_addr_octet[1],
/*------------------------------------------------------------------*/
/*
- * Display an Ethernet address in readable format.
- * Same with a static buffer
+ * Display an Wireless Access Point Socket Address in readable format.
+ * Note : 0x44 is an accident of history, that's what the Orinoco/PrismII
+ * chipset report, and the driver doesn't filter it.
*/
char *
-iw_ether_ntoa(const struct ether_addr* eth)
+iw_sawap_ntop(const struct sockaddr * sap,
+ char * buf)
{
- static char buf[20];
- iw_ether_ntop(eth, buf);
- return buf;
+ const struct ether_addr ether_zero = {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
+ const struct ether_addr ether_bcast = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
+ const struct ether_addr ether_hack = {{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }};
+ const struct ether_addr * ether_wap = (const struct ether_addr *) sap->sa_data;
+
+ if(!iw_ether_cmp(ether_wap, ðer_zero))
+ sprintf(buf, "Not-Associated");
+ else
+ if(!iw_ether_cmp(ether_wap, ðer_bcast))
+ sprintf(buf, "Invalid");
+ else
+ if(!iw_ether_cmp(ether_wap, ðer_hack))
+ sprintf(buf, "None");
+ else
+ iw_ether_ntop(ether_wap, buf);
+ return(buf);
}
/*------------------------------------------------------------------*/
/*
- * Input an Ethernet address and convert to binary.
+ * Input an arbitrary length MAC address and convert to binary.
+ * Return address size.
*/
int
-iw_ether_aton(const char *orig, struct ether_addr *eth)
+iw_mac_aton(const char * orig,
+ unsigned char * mac,
+ int macmax)
{
- const char *bufp;
- int i;
-
- i = 0;
- for(bufp = orig; *bufp != '\0'; ++bufp) {
- unsigned int val;
- unsigned char c = *bufp++;
- if (isdigit(c)) val = c - '0';
- else if (c >= 'a' && c <= 'f') val = c - 'a' + 10;
- else if (c >= 'A' && c <= 'F') val = c - 'A' + 10;
- else break;
-
- val <<= 4;
- c = *bufp++;
- if (isdigit(c)) val |= c - '0';
- else if (c >= 'a' && c <= 'f') val |= c - 'a' + 10;
- else if (c >= 'A' && c <= 'F') val |= c - 'A' + 10;
- else break;
-
- eth->ether_addr_octet[i] = (unsigned char) (val & 0377);
- if(++i == ETH_ALEN) {
- /* That's it. Any trailing junk? */
- if (*bufp != '\0') {
+ const char * p = orig;
+ int maclen = 0;
+
+ /* Loop on all bytes of the string */
+ while(*p != '\0')
+ {
+ int temph;
+ int templ;
+ int count;
+ /* Extract one byte as two chars */
+ count = sscanf(p, "%1X%1X", &temph, &templ);
+ if(count != 2)
+ break; /* Error -> non-hex chars */
+ /* Output two chars as one byte */
+ templ |= temph << 4;
+ mac[maclen++] = (unsigned char) (templ & 0xFF);
+
+ /* Check end of string */
+ p += 2;
+ if(*p == '\0')
+ {
#ifdef DEBUG
- fprintf(stderr, "iw_ether_aton(%s): trailing junk!\n", orig);
- errno = EINVAL;
- return(0);
+ char buf[20];
+ iw_ether_ntop((const struct ether_addr *) mac, buf);
+ fprintf(stderr, "iw_mac_aton(%s): %s\n", orig, buf);
#endif
- }
+ return(maclen); /* Normal exit */
+ }
+
+ /* Check overflow */
+ if(maclen >= macmax)
+ {
#ifdef DEBUG
- fprintf(stderr, "iw_ether_aton(%s): %s\n",
- orig, ether_ntoa(eth));
+ fprintf(stderr, "iw_mac_aton(%s): trailing junk!\n", orig);
#endif
- return(1);
+ errno = E2BIG;
+ return(0); /* Error -> overflow */
}
- if (*bufp != ':')
- break;
- }
+ /* Check separator */
+ if(*p != ':')
+ break;
+ p++;
+ }
+
+ /* Error... */
#ifdef DEBUG
- fprintf(stderr, "iw_ether_aton(%s): invalid ether address!\n", orig);
+ fprintf(stderr, "iw_mac_aton(%s): invalid ether address!\n", orig);
#endif
errno = EINVAL;
return(0);
}
+/*------------------------------------------------------------------*/
+/*
+ * Input an Ethernet address and convert to binary.
+ */
+int
+iw_ether_aton(const char *orig, struct ether_addr *eth)
+{
+ int maclen;
+ maclen = iw_mac_aton(orig, (unsigned char *) eth, ETH_ALEN);
+ if((maclen > 0) && (maclen < ETH_ALEN))
+ {
+ errno = EINVAL;
+ maclen = 0;
+ }
+ return(maclen);
+}
/*------------------------------------------------------------------*/
/*
*/
int
iw_in_addr(int skfd,
- char * ifname,
+ const char * ifname,
char * bufp,
struct sockaddr *sap)
{
sizeof(struct sockaddr));
#ifdef DEBUG
- printf("IP Address %s => Hw Address = %s\n",
- bufp, iw_ether_ntoa((struct ether_addr *) sap->sa_data));
+ {
+ char buf[20];
+ printf("IP Address %s => Hw Address = %s\n",
+ bufp, iw_saether_ntop(sap, buf));
+ }
#endif
}
else /* If it's an hardware address */
}
/* Get the hardware address */
- if(iw_in_ether(bufp, sap) < 0)
+ if(iw_saether_aton(bufp, sap) == 0)
{
fprintf(stderr, "Invalid hardware address %s\n", bufp);
return(-1);
}
#ifdef DEBUG
- printf("Hw Address = %s\n", iw_ether_ntoa((struct ether_addr *) sap->sa_data));
+ {
+ char buf[20];
+ printf("Hw Address = %s\n", iw_saether_ntop(sap, buf));
+ }
#endif
return(0);
* this case.
*/
+/* -------------------------- CONSTANTS -------------------------- */
+
/* Type of headers we know about (basically union iwreq_data) */
#define IW_HEADER_TYPE_NULL 0 /* Not available */
#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
-/* Headers for the various requests */
-static const char standard_ioctl_hdr[] = {
- IW_HEADER_TYPE_NULL, /* SIOCSIWCOMMIT */
- IW_HEADER_TYPE_CHAR, /* SIOCGIWNAME */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWNWID */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWNWID */
- IW_HEADER_TYPE_FREQ, /* SIOCSIWFREQ */
- IW_HEADER_TYPE_FREQ, /* SIOCGIWFREQ */
- IW_HEADER_TYPE_UINT, /* SIOCSIWMODE */
- IW_HEADER_TYPE_UINT, /* SIOCGIWMODE */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWSENS */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWSENS */
- IW_HEADER_TYPE_NULL, /* SIOCSIWRANGE */
- IW_HEADER_TYPE_POINT, /* SIOCGIWRANGE */
- IW_HEADER_TYPE_NULL, /* SIOCSIWPRIV */
- IW_HEADER_TYPE_POINT, /* SIOCGIWPRIV */
- IW_HEADER_TYPE_NULL, /* SIOCSIWSTATS */
- IW_HEADER_TYPE_POINT, /* SIOCGIWSTATS */
- IW_HEADER_TYPE_POINT, /* SIOCSIWSPY */
- IW_HEADER_TYPE_POINT, /* SIOCGIWSPY */
- IW_HEADER_TYPE_POINT, /* SIOCSIWTHRSPY */
- IW_HEADER_TYPE_POINT, /* SIOCGIWTHRSPY */
- IW_HEADER_TYPE_ADDR, /* SIOCSIWAP */
- IW_HEADER_TYPE_ADDR, /* SIOCGIWAP */
- IW_HEADER_TYPE_NULL, /* -- hole -- */
- IW_HEADER_TYPE_POINT, /* SIOCGIWAPLIST */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWSCAN */
- IW_HEADER_TYPE_POINT, /* SIOCGIWSCAN */
- IW_HEADER_TYPE_POINT, /* SIOCSIWESSID */
- IW_HEADER_TYPE_POINT, /* SIOCGIWESSID */
- IW_HEADER_TYPE_POINT, /* SIOCSIWNICKN */
- IW_HEADER_TYPE_POINT, /* SIOCGIWNICKN */
- IW_HEADER_TYPE_NULL, /* -- hole -- */
- IW_HEADER_TYPE_NULL, /* -- hole -- */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWRATE */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWRATE */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWRTS */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWRTS */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWFRAG */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWFRAG */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWTXPOW */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWTXPOW */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWRETRY */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWRETRY */
- IW_HEADER_TYPE_POINT, /* SIOCSIWENCODE */
- IW_HEADER_TYPE_POINT, /* SIOCGIWENCODE */
- IW_HEADER_TYPE_PARAM, /* SIOCSIWPOWER */
- IW_HEADER_TYPE_PARAM, /* SIOCGIWPOWER */
+/* Handling flags */
+/* Most are not implemented. I just use them as a reminder of some
+ * cool features we might need one day ;-) */
+#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
+/* Wrapper level flags */
+#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
+#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
+#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
+ /* SET : Omit payload from generated iwevent */
+#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
+/* Driver level flags */
+#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
+
+/* ---------------------------- TYPES ---------------------------- */
+
+/*
+ * Describe how a standard IOCTL looks like.
+ */
+struct iw_ioctl_description
+{
+ __u8 header_type; /* NULL, iw_point or other */
+ __u8 token_type; /* Future */
+ __u16 token_size; /* Granularity of payload */
+ __u16 min_tokens; /* Min acceptable token number */
+ __u16 max_tokens; /* Max acceptable token number */
+ __u32 flags; /* Special handling of the request */
+};
+
+/* -------------------------- VARIABLES -------------------------- */
+
+/*
+ * Meta-data about all the standard Wireless Extension request we
+ * know about.
+ */
+static const struct iw_ioctl_description standard_ioctl_descr[] = {
+ [SIOCSIWCOMMIT - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_NULL,
+ },
+ [SIOCGIWNAME - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_CHAR,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWNWID - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ .flags = IW_DESCR_FLAG_EVENT,
+ },
+ [SIOCGIWNWID - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWFREQ - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_FREQ,
+ .flags = IW_DESCR_FLAG_EVENT,
+ },
+ [SIOCGIWFREQ - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_FREQ,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWMODE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_UINT,
+ .flags = IW_DESCR_FLAG_EVENT,
+ },
+ [SIOCGIWMODE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_UINT,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWSENS - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWSENS - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWRANGE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_NULL,
+ },
+ [SIOCGIWRANGE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = sizeof(struct iw_range),
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWPRIV - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_NULL,
+ },
+ [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
+ .header_type = IW_HEADER_TYPE_NULL,
+ },
+ [SIOCSIWSTATS - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_NULL,
+ },
+ [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
+ .header_type = IW_HEADER_TYPE_NULL,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWSPY - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = sizeof(struct sockaddr),
+ .max_tokens = IW_MAX_SPY,
+ },
+ [SIOCGIWSPY - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = sizeof(struct sockaddr) +
+ sizeof(struct iw_quality),
+ .max_tokens = IW_MAX_SPY,
+ },
+ [SIOCSIWTHRSPY - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = sizeof(struct iw_thrspy),
+ .min_tokens = 1,
+ .max_tokens = 1,
+ },
+ [SIOCGIWTHRSPY - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = sizeof(struct iw_thrspy),
+ .min_tokens = 1,
+ .max_tokens = 1,
+ },
+ [SIOCSIWAP - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_ADDR,
+ },
+ [SIOCGIWAP - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_ADDR,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWMLME - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .min_tokens = sizeof(struct iw_mlme),
+ .max_tokens = sizeof(struct iw_mlme),
+ },
+ [SIOCGIWAPLIST - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = sizeof(struct sockaddr) +
+ sizeof(struct iw_quality),
+ .max_tokens = IW_MAX_AP,
+ .flags = IW_DESCR_FLAG_NOMAX,
+ },
+ [SIOCSIWSCAN - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .min_tokens = 0,
+ .max_tokens = sizeof(struct iw_scan_req),
+ },
+ [SIOCGIWSCAN - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_SCAN_MAX_DATA,
+ .flags = IW_DESCR_FLAG_NOMAX,
+ },
+ [SIOCSIWESSID - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ .flags = IW_DESCR_FLAG_EVENT,
+ },
+ [SIOCGIWESSID - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ .flags = IW_DESCR_FLAG_DUMP,
+ },
+ [SIOCSIWNICKN - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ },
+ [SIOCGIWNICKN - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ },
+ [SIOCSIWRATE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWRATE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWRTS - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWRTS - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWFRAG - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWFRAG - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWTXPOW - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWTXPOW - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWRETRY - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWRETRY - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWENCODE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_ENCODING_TOKEN_MAX,
+ .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
+ },
+ [SIOCGIWENCODE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_ENCODING_TOKEN_MAX,
+ .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
+ },
+ [SIOCSIWPOWER - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWPOWER - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWGENIE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_GENERIC_IE_MAX,
+ },
+ [SIOCGIWGENIE - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_GENERIC_IE_MAX,
+ },
+ [SIOCSIWAUTH - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCGIWAUTH - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_PARAM,
+ },
+ [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .min_tokens = sizeof(struct iw_encode_ext),
+ .max_tokens = sizeof(struct iw_encode_ext) +
+ IW_ENCODING_TOKEN_MAX,
+ },
+ [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .min_tokens = sizeof(struct iw_encode_ext),
+ .max_tokens = sizeof(struct iw_encode_ext) +
+ IW_ENCODING_TOKEN_MAX,
+ },
+ [SIOCSIWPMKSA - SIOCIWFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .min_tokens = sizeof(struct iw_pmksa),
+ .max_tokens = sizeof(struct iw_pmksa),
+ },
};
-static const unsigned int standard_ioctl_num = sizeof(standard_ioctl_hdr);
+static const unsigned int standard_ioctl_num = (sizeof(standard_ioctl_descr) /
+ sizeof(struct iw_ioctl_description));
/*
* Meta-data about all the additional standard Wireless Extension events
* we know about.
*/
-static const char standard_event_hdr[] = {
- IW_HEADER_TYPE_ADDR, /* IWEVTXDROP */
- IW_HEADER_TYPE_QUAL, /* IWEVQUAL */
- IW_HEADER_TYPE_POINT, /* IWEVCUSTOM */
- IW_HEADER_TYPE_ADDR, /* IWEVREGISTERED */
- IW_HEADER_TYPE_ADDR, /* IWEVEXPIRED */
+static const struct iw_ioctl_description standard_event_descr[] = {
+ [IWEVTXDROP - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_ADDR,
+ },
+ [IWEVQUAL - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_QUAL,
+ },
+ [IWEVCUSTOM - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_CUSTOM_MAX,
+ },
+ [IWEVREGISTERED - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_ADDR,
+ },
+ [IWEVEXPIRED - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_ADDR,
+ },
+ [IWEVGENIE - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_GENERIC_IE_MAX,
+ },
+ [IWEVMICHAELMICFAILURE - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = sizeof(struct iw_michaelmicfailure),
+ },
+ [IWEVASSOCREQIE - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_GENERIC_IE_MAX,
+ },
+ [IWEVASSOCRESPIE - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = IW_GENERIC_IE_MAX,
+ },
+ [IWEVPMKIDCAND - IWEVFIRST] = {
+ .header_type = IW_HEADER_TYPE_POINT,
+ .token_size = 1,
+ .max_tokens = sizeof(struct iw_pmkid_cand),
+ },
};
-static const unsigned int standard_event_num = sizeof(standard_event_hdr);
+static const unsigned int standard_event_num = (sizeof(standard_event_descr) /
+ sizeof(struct iw_ioctl_description));
/* Size (in bytes) of various events */
static const int event_type_size[] = {
IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
};
-/* Forward compatibility with WE-19 */
-#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
- (char *) NULL)
-
/*------------------------------------------------------------------*/
/*
* Initialise the struct stream_descr so that we can extract
struct iw_event * iwe, /* Extracted event */
int we_version)
{
+ const struct iw_ioctl_description * descr = NULL;
int event_type = 0;
unsigned int event_len = 1; /* Invalid */
char * pointer;
if((stream->current + IW_EV_LCP_LEN) > stream->end)
return(0);
-#if 0
+#if DEBUG
printf("DBG - stream->current = %p, stream->value = %p, stream->end = %p\n",
stream->current, stream->value, stream->end);
#endif
* Note : the event may be unaligned, therefore copy... */
memcpy((char *) iwe, stream->current, IW_EV_LCP_LEN);
-#if 0
+#if DEBUG
printf("DBG - iwe->cmd = 0x%X, iwe->len = %d\n",
iwe->cmd, iwe->len);
#endif
{
cmd_index = iwe->cmd - SIOCIWFIRST;
if(cmd_index < standard_ioctl_num)
- event_type = standard_ioctl_hdr[cmd_index];
+ descr = &(standard_ioctl_descr[cmd_index]);
}
else
{
cmd_index = iwe->cmd - IWEVFIRST;
if(cmd_index < standard_event_num)
- event_type = standard_event_hdr[cmd_index];
+ descr = &(standard_event_descr[cmd_index]);
}
+ if(descr != NULL)
+ event_type = descr->header_type;
/* Unknown events -> event_type=0 => IW_EV_LCP_LEN */
event_len = event_type_size[event_type];
- /* Fixup for later version of WE */
- if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
- event_len -= IW_EV_POINT_OFF;
+ /* Fixup for earlier version of WE */
+ if((we_version <= 18) && (event_type == IW_HEADER_TYPE_POINT))
+ event_len += IW_EV_POINT_OFF;
/* Check if we know about this event */
if(event_len <= IW_EV_LCP_LEN)
else
pointer = stream->current + IW_EV_LCP_LEN; /* First value in event */
-#if 0
+#if DEBUG
printf("DBG - event_type = %d, event_len = %d, pointer = %p\n",
event_type, event_len, pointer);
#endif
stream->current += iwe->len;
return(-2);
}
- /* Fixup for later version of WE */
+ /* Fixup for WE-19 and later : pointer no longer in the stream */
if((we_version > 18) && (event_type == IW_HEADER_TYPE_POINT))
memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
pointer, event_len);
if(event_type == IW_HEADER_TYPE_POINT)
{
/* Check the length of the payload */
- if((iwe->len - (event_len + IW_EV_LCP_LEN)) > 0)
- /* Set pointer on variable part (warning : non aligned) */
- iwe->u.data.pointer = pointer;
+ unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_LEN);
+ if(extra_len > 0)
+ {
+ /* Set pointer on variable part (warning : non aligned) */
+ iwe->u.data.pointer = pointer;
+
+ /* Check that we have a descriptor for the command */
+ if(descr == NULL)
+ /* Can't check payload -> unsafe... */
+ iwe->u.data.pointer = NULL; /* Discard paylod */
+ else
+ {
+ /* Those checks are actually pretty hard to trigger,
+ * because of the checks done in the kernel... */
+
+ /* Discard bogus events which advertise more tokens than
+ * what they carry... */
+ unsigned int token_len = iwe->u.data.length * descr->token_size;
+ if(token_len > extra_len)
+ iwe->u.data.pointer = NULL; /* Discard paylod */
+ /* Check that the advertised token size is not going to
+ * produce buffer overflow to our caller... */
+ if((iwe->u.data.length > descr->max_tokens)
+ && !(descr->flags & IW_DESCR_FLAG_NOMAX))
+ iwe->u.data.pointer = NULL; /* Discard paylod */
+ /* Same for underflows... */
+ if(iwe->u.data.length < descr->min_tokens)
+ iwe->u.data.pointer = NULL; /* Discard paylod */
+#if DEBUG
+ printf("DBG - extra_len = %d, token_len = %d, token = %d, max = %d, min = %d\n",
+ extra_len, token_len, iwe->u.data.length, descr->max_tokens, descr->min_tokens);
+#endif
+ }
+ }
else
/* No data */
iwe->u.data.pointer = NULL;
case SIOCGIWESSID:
wscan->b.has_essid = 1;
wscan->b.essid_on = event->u.data.flags;
+ memset(wscan->b.essid, '\0', IW_ESSID_MAX_SIZE+1);
if((event->u.essid.pointer) && (event->u.essid.length))
memcpy(wscan->b.essid, event->u.essid.pointer, event->u.essid.length);
- wscan->b.essid[event->u.essid.length] = '\0';
break;
case SIOCGIWENCODE:
wscan->b.has_key = 1;
case IWEVQUAL:
/* We don't get complete stats, only qual */
wscan->has_stats = 1;
- memcpy(&wscan->stats.qual, &event->u.qual, sizeof(iwstats));
+ memcpy(&wscan->stats.qual, &event->u.qual, sizeof(struct iw_quality));
break;
case SIOCGIWRATE:
/* Scan may return a list of bitrates. Should we really bother with
int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
unsigned char * newbuf;
- /* Don't waste too much time on interfaces (50 * 100 = 5s) */
+ /* Don't waste too much time on interfaces (150 * 100 = 15s) */
context->retry++;
- if(context->retry > 50)
+ if(context->retry > 150)
{
errno = ETIME;
return(-1);
struct stream_descr stream;
struct wireless_scan * wscan = NULL;
int ret;
-#if 0
+#if DEBUG
/* Debugging code. In theory useless, because it's debugged ;-) */
int i;
printf("Scan result [%02X", buffer[0]);
#endif
/* Init */
- iw_init_event_stream(&stream, buffer, wrq.u.data.length);
+ iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
/* This is dangerous, we may leak user data... */
context->result = NULL;