libs/iwinfo: implement wifi scans
authorJo-Philipp Wich <jow@openwrt.org>
Mon, 24 Aug 2009 05:54:38 +0000 (05:54 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Mon, 24 Aug 2009 05:54:38 +0000 (05:54 +0000)
12 files changed:
libs/iwinfo/Makefile
libs/iwinfo/src/iwinfo.h
libs/iwinfo/src/iwinfo_lualib.c
libs/iwinfo/src/iwinfo_lualib.h
libs/iwinfo/src/iwinfo_madwifi.c
libs/iwinfo/src/iwinfo_madwifi.h
libs/iwinfo/src/iwinfo_wext.c
libs/iwinfo/src/iwinfo_wext.h
libs/iwinfo/src/iwinfo_wext_scan.c [new file with mode: 0644]
libs/iwinfo/src/iwinfo_wext_scan.h [new file with mode: 0644]
libs/iwinfo/src/iwinfo_wl.c
libs/iwinfo/src/iwinfo_wl.h

index 2d775230db121e580ceccf30bf14eb56c99ecbfb..573dcae5a512e0bbdca402bc52090ae546d0f1c8 100644 (file)
@@ -10,7 +10,8 @@ IWINFO_LDFLAGS    =
 IWINFO_CFLAGS     = -fstrict-aliasing
 IWINFO_SO         = iwinfo.so
 IWINFO_LUA        = iwinfo.lua
-IWINFO_OBJ        = src/iwinfo_wl.o src/iwinfo_madwifi.o src/iwinfo_wext.o src/iwinfo_lualib.o
+IWINFO_OBJ        = src/iwinfo_wl.o src/iwinfo_madwifi.o \
+       src/iwinfo_wext.o src/iwinfo_wext_scan.o src/iwinfo_lualib.o
 
 %.o: %.c
        $(COMPILE) $(IWINFO_CFLAGS) $(LUA_CFLAGS) $(FPIC) -c -o $@ $< 
index be7c1ece0afbf687e90b752518c1adf347bf46d1..29398831cc91f619e8bf122ce786aa5e69ba2a60 100644 (file)
@@ -34,5 +34,21 @@ struct iwinfo_txpwrlist_entry {
        uint8_t mw;
 };
 
+struct iwinfo_crypto_entry {
+       uint8_t enabled;
+       uint8_t wpa_version;
+       uint8_t group_ciphers[8];
+       uint8_t pair_ciphers[8];
+       uint8_t auth_suites[8];
+};
+
+struct iwinfo_scanlist_entry {
+       uint8_t mac[6];
+       uint8_t ssid[IW_ESSID_MAX_SIZE+1];
+       uint8_t mode[8];
+       uint8_t channel;
+       struct iwinfo_crypto_entry crypto;
+};
+
 #endif
 
index e63eeabd4d9e2bf8e6a5827812bea746823dc785..1a0d71b99a6fd4c5e24165180aa6f1a7a7ffe3c8 100644 (file)
@@ -107,6 +107,100 @@ static int iwinfo_L_txpwrlist(lua_State *L, int (*func)(const char *, char *, in
        return 1;
 }
 
+/* Wrapper for scan list */
+static int iwinfo_L_scanlist(lua_State *L, int (*func)(const char *, char *, int *))
+{
+       int i, j, x, y, len;
+       char rv[IWINFO_BUFSIZE];
+       char macstr[18];
+       const char *ifname = luaL_checkstring(L, 1);
+       struct iwinfo_scanlist_entry *e;
+
+       lua_newtable(L);
+       memset(rv, 0, sizeof(rv));
+
+       if( !(*func)(ifname, rv, &len) )
+       {
+               for( i = 0, x = 1; i < len; i += sizeof(struct iwinfo_scanlist_entry), x++ )
+               {
+                       e = (struct iwinfo_scanlist_entry *) &rv[i];
+
+                       lua_newtable(L);
+
+                       /* BSSID */
+                       sprintf(macstr, "%02X:%02X:%02X:%02X:%02X:%02X",
+                               e->mac[0], e->mac[1], e->mac[2],
+                               e->mac[3], e->mac[4], e->mac[5]);
+
+                       lua_pushstring(L, macstr);
+                       lua_setfield(L, -2, "mac");
+
+                       /* ESSID */
+                       if( e->ssid[0] )
+                       {
+                               lua_pushstring(L, (char *) e->ssid);
+                               lua_setfield(L, -2, "ssid");
+                       }
+
+                       /* Channel */
+                       lua_pushinteger(L, e->channel);
+                       lua_setfield(L, -2, "channel");
+
+                       /* Mode */
+                       lua_pushstring(L, (char *) e->mode);
+                       lua_setfield(L, -2, "mode");
+
+                       /* Crypto */
+                       lua_pushinteger(L, e->crypto.wpa_version);
+                       lua_setfield(L, -2, "wpa_version");
+
+                       lua_newtable(L);
+                       for( j = 0, y = 1; j < sizeof(e->crypto.group_ciphers); j++ )
+                       {
+                               if( e->crypto.group_ciphers[j] )
+                               {
+                                       lua_pushstring(L, (j < IW_IE_CYPHER_NUM)
+                                               ? iw_ie_cypher_name[j] : "Proprietary");
+
+                                       lua_rawseti(L, -2, y++);
+                               }
+                       }
+                       lua_setfield(L, -2, "group_ciphers");
+
+                       lua_newtable(L);
+                       for( j = 0, y = 1; j < sizeof(e->crypto.pair_ciphers); j++ )
+                       {
+                               if( e->crypto.pair_ciphers[j] )
+                               {
+                                       lua_pushstring(L, (j < IW_IE_CYPHER_NUM)
+                                               ? iw_ie_cypher_name[j] : "Proprietary");
+
+                                       lua_rawseti(L, -2, y++);
+                               }
+                       }
+                       lua_setfield(L, -2, "pair_ciphers");
+
+                       lua_newtable(L);
+                       for( j = 0, y = 1; j < sizeof(e->crypto.auth_suites); j++ )
+                       {
+                               if( e->crypto.auth_suites[j] )
+                               {
+                                       lua_pushstring(L, (j < IW_IE_KEY_MGMT_NUM)
+                                               ? iw_ie_key_mgmt_name[j] : "Proprietary");
+
+                                       lua_rawseti(L, -2, y++);
+                               }
+                       }
+                       lua_setfield(L, -2, "auth_suites");
+
+                       lua_rawseti(L, -2, x);
+               }
+       }
+
+       return 1;
+}
+
+
 /* Broadcom */
 LUA_WRAP_INT(wl,channel)
 LUA_WRAP_INT(wl,frequency)
@@ -122,6 +216,7 @@ LUA_WRAP_STRING(wl,bssid)
 LUA_WRAP_STRING(wl,enctype)
 LUA_WRAP_LIST(wl,assoclist)
 LUA_WRAP_LIST(wl,txpwrlist)
+LUA_WRAP_LIST(wl,scanlist)
 
 /* Madwifi */
 LUA_WRAP_INT(madwifi,channel)
@@ -138,6 +233,7 @@ LUA_WRAP_STRING(madwifi,bssid)
 LUA_WRAP_STRING(madwifi,enctype)
 LUA_WRAP_LIST(madwifi,assoclist)
 LUA_WRAP_LIST(madwifi,txpwrlist)
+LUA_WRAP_LIST(madwifi,scanlist)
 
 /* Wext */
 LUA_WRAP_INT(wext,channel)
@@ -154,6 +250,7 @@ LUA_WRAP_STRING(wext,bssid)
 LUA_WRAP_STRING(wext,enctype)
 LUA_WRAP_LIST(wext,assoclist)
 LUA_WRAP_LIST(wext,txpwrlist)
+LUA_WRAP_LIST(wext,scanlist)
 
 /* Broadcom table */
 static const luaL_reg R_wl[] = {
@@ -170,6 +267,7 @@ static const luaL_reg R_wl[] = {
        LUA_REG(wl,enctype),
        LUA_REG(wl,assoclist),
        LUA_REG(wl,txpwrlist),
+       LUA_REG(wl,scanlist),
        LUA_REG(wl,mbssid_support),
        { NULL, NULL }
 };
@@ -189,6 +287,7 @@ static const luaL_reg R_madwifi[] = {
        LUA_REG(madwifi,enctype),
        LUA_REG(madwifi,assoclist),
        LUA_REG(madwifi,txpwrlist),
+       LUA_REG(madwifi,scanlist),
        LUA_REG(madwifi,mbssid_support),
        { NULL, NULL }
 };
@@ -208,6 +307,7 @@ static const luaL_reg R_wext[] = {
        LUA_REG(wext,enctype),
        LUA_REG(wext,assoclist),
        LUA_REG(wext,txpwrlist),
+       LUA_REG(wext,scanlist),
        LUA_REG(wext,mbssid_support),
        { NULL, NULL }
 };
index f7eba149d1e020a2e203d2cc84b9e7ef0ec6accb..bf7568a653560216d4a42911367a9c33610aee2d 100644 (file)
@@ -24,6 +24,7 @@
 #include <lauxlib.h>
 
 #include "iwinfo.h"
+#include "iwinfo_wext_scan.h"
 
 
 #define IWINFO_META                    "iwinfo"
index 11650129c1aa83751b1f8df12cc673f84147f961..e09d49b1ebb42ffa91cae597cf1c62087e44615c 100644 (file)
@@ -403,6 +403,11 @@ int madwifi_get_txpwrlist(const char *ifname, char *buf, int *len)
        return wext_get_txpwrlist(ifname, buf, len);
 }
 
+int madwifi_get_scanlist(const char *ifname, char *buf, int *len)
+{
+       return wext_get_scanlist(ifname, buf, len);
+}
+
 int madwifi_get_mbssid_support(const char *ifname, int *buf)
 {
        /* We assume that multi bssid is always possible */
index 24573f3b856a72a0348af6487c54cc69d8cece0f..9c5b7fa5896a3a12961845dbde706574e9adde0a 100644 (file)
@@ -36,6 +36,7 @@ int madwifi_get_quality_max(const char *ifname, int *buf);
 int madwifi_get_enctype(const char *ifname, char *buf);
 int madwifi_get_assoclist(const char *ifname, char *buf, int *len);
 int madwifi_get_txpwrlist(const char *ifname, char *buf, int *len);
+int madwifi_get_scanlist(const char *ifname, char *buf, int *len);
 int madwifi_get_mbssid_support(const char *ifname, int *buf);
 
 #endif
index 24be10fa9d6ccf006ec636eba78826315b49ec15..311fd8ebbe628c3edd46a81b2ecf97819cc6e459 100644 (file)
@@ -189,7 +189,7 @@ int wext_get_bitrate(const char *ifname, int *buf)
 
        if(wext_ioctl(ifname, SIOCGIWRATE, &wrq) >= 0)
        {
-               *buf = wrq.u.bitrate.value;
+               *buf = (wrq.u.bitrate.value / 1000000);
                return 0;
        }
 
@@ -199,12 +199,36 @@ int wext_get_bitrate(const char *ifname, int *buf)
 int wext_get_channel(const char *ifname, int *buf)
 {
        struct iwreq wrq;
+       struct iw_range range;
+       double freq;
+       int i;
 
        if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
        {
-               /* FIXME: iwlib has some strange workarounds here, maybe we need them as well... */
-               *buf = (int) wext_freq2float(&wrq.u.freq);
-               return 0;
+               if( wrq.u.freq.m >= 1000 )
+               {
+                       freq = wext_freq2float(&wrq.u.freq);
+                       wrq.u.data.pointer = (caddr_t) &range;
+                       wrq.u.data.length  = sizeof(struct iw_range);
+                       wrq.u.data.flags   = 0;
+
+                       if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
+                       {
+                               for(i = 0; i < range.num_frequency; i++)
+                               {
+                                       if( wext_freq2float(&range.freq[i]) == freq )
+                                       {
+                                               *buf = range.freq[i].i;
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       *buf = wrq.u.freq.m;
+                       return 0;
+               }
        }
 
        return -1;      
index 906b9324db2348840428b139e7c19ed7c73432da..dd1922fc8c144692ec847c8957a33c1c714da9f5 100644 (file)
@@ -22,6 +22,7 @@
 #include "iwinfo.h"
 #include "include/wext.h"
 
+
 int wext_probe(const char *ifname);
 int wext_get_mode(const char *ifname, char *buf);
 int wext_get_ssid(const char *ifname, char *buf);
@@ -36,6 +37,7 @@ int wext_get_quality_max(const char *ifname, int *buf);
 int wext_get_enctype(const char *ifname, char *buf);
 int wext_get_assoclist(const char *ifname, char *buf, int *len);
 int wext_get_txpwrlist(const char *ifname, char *buf, int *len);
+int wext_get_scanlist(const char *ifname, char *buf, int *len);
 int wext_get_mbssid_support(const char *ifname, int *buf);
 
 #endif
diff --git a/libs/iwinfo/src/iwinfo_wext_scan.c b/libs/iwinfo/src/iwinfo_wext_scan.c
new file mode 100644 (file)
index 0000000..63231b8
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * iwinfo - Wireless Information Library - Linux Wireless Extension Backend
+ *
+ *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * The iwinfo library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * The iwinfo library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
+ *
+ * Parts of this code are derived from the Linux wireless tools, iwlib.c,
+ * iwlist.c and iwconfig.c in particular.
+ */
+
+#include "iwinfo.h"
+#include "iwinfo_wext_scan.h"
+
+
+static int ioctl_socket = -1;
+
+static int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq)
+{
+       /* prepare socket */
+       if( ioctl_socket == -1 )
+               ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0);
+
+       strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
+       return ioctl(ioctl_socket, cmd, wrq);
+}
+
+static double wext_freq2float(const struct iw_freq *in)
+{
+       int             i;
+       double  res = (double) in->m;
+       for(i = 0; i < in->e; i++) res *= 10;
+       return res;
+}
+
+static int wext_extract_event(struct stream_descr *stream, struct iw_event *iwe)
+{
+       const struct iw_ioctl_description *descr = NULL;
+       int event_type = 0;
+       unsigned int event_len = 1;
+       char *pointer;
+       unsigned cmd_index;             /* *MUST* be unsigned */
+
+       /* Check for end of stream */
+       if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
+               return 0;
+
+       /* Extract the event header (to get the event id).
+        * Note : the event may be unaligned, therefore copy... */
+       memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
+
+       /* Check invalid events */
+       if(iwe->len <= IW_EV_LCP_PK_LEN)
+               return -1;
+
+       /* Get the type and length of that event */
+       if(iwe->cmd <= SIOCIWLAST)
+       {
+               cmd_index = iwe->cmd - SIOCIWFIRST;
+               if(cmd_index < standard_ioctl_num)
+                       descr = &(standard_ioctl_descr[cmd_index]);
+       }
+       else
+       {
+               cmd_index = iwe->cmd - IWEVFIRST;
+               if(cmd_index < standard_event_num)
+                       descr = &(standard_event_descr[cmd_index]);
+       }
+
+       if(descr != NULL)
+               event_type = descr->header_type;
+
+       /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
+       event_len = event_type_size[event_type];
+
+       /* Check if we know about this event */
+       if(event_len <= IW_EV_LCP_PK_LEN)
+       {
+               /* Skip to next event */
+               stream->current += iwe->len;
+               return 2;
+       }
+
+       event_len -= IW_EV_LCP_PK_LEN;
+
+       /* Set pointer on data */
+       if(stream->value != NULL)
+               pointer = stream->value;                        /* Next value in event */
+       else
+               pointer = stream->current + IW_EV_LCP_PK_LEN;   /* First value in event */
+
+       /* Copy the rest of the event (at least, fixed part) */
+       if((pointer + event_len) > stream->end)
+       {
+               /* Go to next event */
+               stream->current += iwe->len;
+               return -2;
+       }
+
+       /* Fixup for WE-19 and later : pointer no longer in the stream */
+       /* Beware of alignement. Dest has local alignement, not packed */
+       if( event_type == IW_HEADER_TYPE_POINT )
+               memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, pointer, event_len);
+       else
+               memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
+
+       /* Skip event in the stream */
+       pointer += event_len;
+
+       /* Special processing for iw_point events */
+       if(event_type == IW_HEADER_TYPE_POINT)
+       {
+               /* Check the length of the payload */
+               unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_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... */
+
+                               unsigned int    token_len = iwe->u.data.length * descr->token_size;
+
+                               /* Ugly fixup for alignement issues.
+                               * If the kernel is 64 bits and userspace 32 bits,
+                               * we have an extra 4+4 bytes.
+                               * Fixing that in the kernel would break 64 bits userspace. */
+                               if((token_len != extra_len) && (extra_len >= 4))
+                               {
+                                       uint16_t alt_dlen = *((uint16_t *) pointer);
+                                       unsigned int alt_token_len = alt_dlen * descr->token_size;
+                                       if((alt_token_len + 8) == extra_len)
+                                       {
+                                               /* Ok, let's redo everything */
+                                               pointer -= event_len;
+                                               pointer += 4;
+                                               /* Dest has local alignement, not packed */
+                                               memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, pointer, event_len);
+                                               pointer += event_len + 4;
+                                               iwe->u.data.pointer = pointer;
+                                               token_len = alt_token_len;
+                                       }
+                               }
+
+                               /* Discard bogus events which advertise more tokens than
+                               * what they carry... */
+                               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 */
+                       }
+               }
+               else
+                       /* No data */
+                       iwe->u.data.pointer = NULL;
+
+               /* Go to next event */
+               stream->current += iwe->len;
+       }
+       else
+       {
+               /* Ugly fixup for alignement issues.
+               * If the kernel is 64 bits and userspace 32 bits,
+               * we have an extra 4 bytes.
+               * Fixing that in the kernel would break 64 bits userspace. */
+               if((stream->value == NULL)
+               && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
+               || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
+               (event_type == IW_HEADER_TYPE_QUAL))) ))
+               {
+                       pointer -= event_len;
+                       pointer += 4;
+                       /* Beware of alignement. Dest has local alignement, not packed */
+                       memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
+                       pointer += event_len;
+               }
+
+               /* Is there more value in the event ? */
+               if((pointer + event_len) <= (stream->current + iwe->len))
+                       /* Go to next value */
+                       stream->value = pointer;
+               else
+               {
+                       /* Go to next event */
+                       stream->value = NULL;
+                       stream->current += iwe->len;
+               }
+       }
+
+       return 1;
+}
+
+static inline void wext_fill_wpa(unsigned char *iebuf, int buflen, struct iwinfo_scanlist_entry *e)
+{
+       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;
+       int wpa1 = 0, wpa2 = 0;
+       char buf[256];
+
+       struct iwinfo_crypto_entry *ce = &e->crypto;
+
+       if( !ce->enabled )
+               return;
+
+       //memset(&e->crypto, 0, sizeof(struct iwinfo_crypto_entry));
+
+       if(ielen > buflen)
+               ielen = buflen;
+
+       switch(iebuf[0])
+       {
+               case 0x30:      /* WPA2 */
+                       /* Check if we have enough data */
+                       if(ielen < 4)
+                               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. */
+                       if((ielen < 8) || ((memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+                               && (iebuf[offset+3] == 0x01)))
+                                       return;
+
+                       offset += 4;
+                       break;
+
+               default:
+                       return;
+       }
+
+       /* Pick version number (little endian) */
+       ver = iebuf[offset] | (iebuf[offset + 1] << 8);
+       offset += 2;
+
+       if(iebuf[0] == 0xdd)
+               wpa1 = 1;
+
+       if(iebuf[0] == 0x30)
+               wpa2 = 1;
+
+       if( wpa1 && (ce->wpa_version == 2) )
+               ce->wpa_version = 3;
+       else if( wpa2 && (ce->wpa_version == 1) )
+               ce->wpa_version = 3;
+       else if( wpa1 && !ce->wpa_version )
+               ce->wpa_version = 1;
+       else if( wpa2 && !ce->wpa_version )
+               ce->wpa_version = 2;
+
+       if(ielen < (offset + 4))
+       {
+               ce->group_ciphers[2] = 1; /* TKIP */
+               return;
+       }
+
+       if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+               ce->group_ciphers[7] = 1; /* Proprietary */
+       else
+               ce->group_ciphers[iebuf[offset+3]] = 1;
+
+       offset += 4;
+
+       if(ielen < (offset + 2))
+       {
+               ce->pair_ciphers[2] = 1; /* TKIP */
+               return;
+       }
+
+       /* Otherwise, we have some number of pairwise ciphers. */
+       cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
+       offset += 2;
+
+       if(ielen < (offset + 4*cnt))
+               return;
+
+       *buf = '\0';
+       for(i = 0; i < cnt; i++)
+       {
+               if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+                       ce->pair_ciphers[7] = 1; /* Proprietary */
+               else if(iebuf[offset+3] <= IW_IE_CYPHER_NUM)
+                       ce->pair_ciphers[iebuf[offset+3]] = 1;
+               //else
+               //      ce->pair_ciphers[ce->pair_cipher_num++] = 255; /* Unknown */
+
+               offset += 4;
+       }
+
+       /* Check if we are done */
+       if(ielen < (offset + 2))
+               return;
+
+       /* Now, we have authentication suites. */
+       cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
+       offset += 2;
+       *buf = '\0';
+
+       if(ielen < (offset + 4*cnt))
+               return;
+
+       for(i = 0; i < cnt; i++)
+       {
+               if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
+                       ce->auth_suites[7] = 1; /* Proprietary */
+               else if(iebuf[offset+3] <= IW_IE_KEY_MGMT_NUM)
+                       ce->auth_suites[iebuf[offset+3]] = 1;
+               //else
+               //      ce->auth_suites[ce->auth_suite_num++] = 255; /* Unknown */
+
+               offset += 4;
+       }
+}
+
+
+static inline int wext_fill_entry(struct stream_descr *stream, struct iw_event *event,
+       struct iw_range *iw_range, int has_range, struct iwinfo_scanlist_entry *e)
+{
+       int i;
+       double freq;
+
+       /* Now, let's decode the event */
+       switch(event->cmd)
+       {
+               case SIOCGIWAP:
+                       memcpy(e->mac, &event->u.ap_addr.sa_data, 6);
+                       break;
+
+               case SIOCGIWFREQ:
+                       if( event->u.freq.m >= 1000 )
+                       {
+                               freq = wext_freq2float(&(event->u.freq));
+
+                               for(i = 0; i < iw_range->num_frequency; i++)
+                               {
+                                       if( wext_freq2float(&iw_range->freq[i]) == freq )
+                                       {
+                                               e->channel = iw_range->freq[i].i;
+                                               break;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               e->channel = event->u.freq.m;
+                       }
+
+                       break;
+
+               case SIOCGIWMODE:
+                       switch(event->u.mode)
+                       {
+                               case 1:
+                                       sprintf((char *) e->mode, "Ad-Hoc");
+                                       break;
+
+                               case 3:
+                                       sprintf((char *) e->mode, "Master");
+                                       break;
+
+                               default:
+                                       sprintf((char *) e->mode, "Unknown");
+                       }
+
+                       break;
+
+               case SIOCGIWESSID:
+                       if( event->u.essid.pointer && event->u.essid.length && event->u.essid.flags )
+                               memcpy(e->ssid, event->u.essid.pointer, event->u.essid.length);
+
+                       break;
+
+               case SIOCGIWENCODE:
+                       e->crypto.enabled = !(event->u.data.flags & IW_ENCODE_DISABLED);
+                       break;
+
+#if 0
+               case SIOCGIWRATE:
+                       if(state->val_index == 0)
+                       {
+                               lua_pushstring(L, "bitrates");
+                               lua_newtable(L);
+                       }
+                       //iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
+                       snprintf(buffer, sizeof(buffer), "%d", event->u.bitrate.value);
+                       lua_pushinteger(L, state->val_index + 1);
+                       lua_pushstring(L, buffer);
+                       lua_settable(L, -3);
+
+                       /* Check for termination */
+                       if(stream->value == NULL)
+                       {
+                               lua_settable(L, -3);
+                               state->val_index = 0;
+                       } else
+                               state->val_index++;
+                       break;
+#endif
+                case IWEVGENIE:
+                       i = 0;
+
+                       while(i <= (event->u.data.length - 2))
+                       {
+                               switch(((unsigned char *)event->u.data.pointer)[i])
+                               {
+                                       case 0xdd:  /* WPA1 (and other) */
+                                       case 0x30:  /* WPA2 */
+                                               wext_fill_wpa((unsigned char *)event->u.data.pointer + i,
+                                                       event->u.data.length, e);
+
+                                               break;
+                               }
+
+                               i += ((unsigned char *)event->u.data.pointer)[i+1] + 2;
+                       }
+
+                       break;
+       }
+
+       return 0;
+}
+
+
+int wext_get_scanlist(const char *ifname, char *buf, int *len)
+{
+       struct iwreq wrq;
+       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 = 1;
+       struct timeval tv;             /* Select timeout */
+       int timeout = 15000000;     /* 15s */
+
+       int _len = 0;
+       struct iwinfo_scanlist_entry e;
+
+       //IWINFO_BUFSIZE
+       wrq.u.data.pointer = (caddr_t) &range;
+       wrq.u.data.length  = sizeof(struct iw_range);
+       wrq.u.data.flags   = 0; 
+
+       if( wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0 )
+       {
+               /* Init timeout value -> 250ms between set and first get */
+               tv.tv_sec  = 0;
+               tv.tv_usec = 250000;
+
+               /* Clean up set args */
+               memset(&scanopt, 0, sizeof(scanopt));
+
+               wrq.u.data.pointer = NULL;
+               wrq.u.data.flags   = 0;
+               wrq.u.data.length  = 0;
+
+               /* Initiate Scanning */
+               if( wext_ioctl(ifname, SIOCSIWSCAN, &wrq) >= 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;
+
+                                       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);
+
+                                               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( wext_ioctl(ifname, SIOCGIWSCAN, &wrq) )
+                                       {
+                                               /* Check if buffer was too small (WE-17 only) */
+                                               if((errno == E2BIG) && (range.we_version_compiled > 16))
+                                               {
+                                                       /* 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;
+
+                                                       /* 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);
+                                               return -1;
+
+                                       } else {
+                                               /* We have the results, go to process them */
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if( wrq.u.data.length )
+                       {
+                               struct iw_event       iwe;
+                               struct stream_descr   stream;
+                               int ret;
+                               int first = 1;
+
+                               memset(&stream, 0, sizeof(stream));
+                               stream.current = (char *)buffer;
+                               stream.end     = (char *)buffer + wrq.u.data.length;
+
+                               do
+                               {
+                                       /* Extract an event and print it */
+                                       ret = wext_extract_event(&stream, &iwe);
+
+                                       if(ret >= 0)
+                                       {
+                                               if( (iwe.cmd == SIOCGIWAP) || (ret == 0) )
+                                               {
+                                                       if( first )
+                                                       {
+                                                               first = 0;
+                                                       }
+                                                       else if( (_len + sizeof(struct iwinfo_scanlist_entry)) <= IWINFO_BUFSIZE )
+                                                       {
+                                                               memcpy(&buf[_len], &e, sizeof(struct iwinfo_scanlist_entry));
+                                                               _len += sizeof(struct iwinfo_scanlist_entry);
+                                                       }
+                                                       else
+                                                       {
+                                                               /* we exceed the callers buffer size, abort here ... */
+                                                               break;
+                                                       }
+
+                                                       memset(&e, 0, sizeof(struct iwinfo_scanlist_entry));
+                                               }
+
+                                               wext_fill_entry(&stream, &iwe, &range, has_range, &e);
+                                       }
+
+                               } while(ret > 0);
+
+                               free(buffer);
+                               *len = _len;
+                               return 0;
+                       }
+
+                       free(buffer);
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
diff --git a/libs/iwinfo/src/iwinfo_wext_scan.h b/libs/iwinfo/src/iwinfo_wext_scan.h
new file mode 100644 (file)
index 0000000..a85f563
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * iwinfo - Wireless Information Library - Linux Wireless Extension Headers
+ *
+ *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
+ *
+ * The iwinfo library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * The iwinfo library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
+ */
+
+#ifndef __IWINFO_WEXT_SCAN_H_
+#define __IWINFO_WEXT_SCAN_H_
+
+#include "iwinfo.h"
+#include "include/wext.h"
+
+
+typedef struct stream_descr
+{
+  char *        end;            /* End of the stream */
+  char *        current;        /* Current event in stream of events */
+  char *        value;          /* Current value in event */
+} stream_descr;
+
+/*
+ * Describe how a standard IOCTL looks like.
+ */
+struct iw_ioctl_description
+{
+       uint8_t header_type;            /* NULL, iw_point or other */
+       uint8_t token_type;             /* Future */
+       uint16_t        token_size;             /* Granularity of payload */
+       uint16_t        min_tokens;             /* Min acceptable token number */
+       uint16_t        max_tokens;             /* Max acceptable token number */
+       uint32_t        flags;                  /* Special handling of the request */
+};
+
+/* 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_UINT    4       /* __u32 */
+#define IW_HEADER_TYPE_FREQ    5       /* struct iw_freq */
+#define IW_HEADER_TYPE_ADDR    6       /* struct sockaddr */
+#define IW_HEADER_TYPE_POINT   8       /* struct iw_point */
+#define IW_HEADER_TYPE_PARAM   9       /* struct iw_param */
+#define IW_HEADER_TYPE_QUAL    10      /* struct iw_quality */
+
+/* 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 */
+
+
+/*
+ * 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,
+       },
+       [SIOCSIWMODUL   - SIOCIWFIRST] = {
+               .header_type    = IW_HEADER_TYPE_PARAM,
+       },
+       [SIOCGIWMODUL   - 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),
+       },
+};
+
+/*
+ * Meta-data about all the additional standard Wireless Extension events
+ * we know about.
+ */
+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),
+       },
+};
+
+/* Size (in bytes) of various events */
+static const int event_type_size[] = {
+       IW_EV_LCP_PK_LEN,       /* IW_HEADER_TYPE_NULL */
+       0,
+       IW_EV_CHAR_PK_LEN,      /* IW_HEADER_TYPE_CHAR */
+       0,
+       IW_EV_UINT_PK_LEN,      /* IW_HEADER_TYPE_UINT */
+       IW_EV_FREQ_PK_LEN,      /* IW_HEADER_TYPE_FREQ */
+       IW_EV_ADDR_PK_LEN,      /* IW_HEADER_TYPE_ADDR */
+       0,
+       IW_EV_POINT_PK_LEN,     /* Without variable payload */
+       IW_EV_PARAM_PK_LEN,     /* IW_HEADER_TYPE_PARAM */
+       IW_EV_QUAL_PK_LEN,      /* IW_HEADER_TYPE_QUAL */
+};
+
+
+static const unsigned int standard_ioctl_num =
+       (sizeof(standard_ioctl_descr) / sizeof(struct iw_ioctl_description));
+
+static const unsigned int standard_event_num =
+       (sizeof(standard_event_descr) / sizeof(struct iw_ioctl_description));
+
+static const char *iw_ie_cypher_name[] = {
+       "none",
+       "WEP-40",
+       "TKIP",
+       "WRAP",
+       "CCMP",
+       "WEP-104",
+};
+
+#define IW_ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
+#define        IW_IE_CYPHER_NUM        IW_ARRAY_LEN(iw_ie_cypher_name)
+
+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
index 2c3126a8393efe27261df917157329a2dcbc22bb..8387b9f4c85411fc841b109d94bff380fd06625d 100644 (file)
@@ -384,6 +384,11 @@ int wl_get_txpwrlist(const char *ifname, char *buf, int *len)
        return 0;
 }
 
+int wl_get_scanlist(const char *ifname, char *buf, int *len)
+{
+       return wext_get_scanlist(ifname, buf, len);
+}
+
 int wl_get_mbssid_support(const char *ifname, int *buf)
 {
        wlc_rev_info_t revinfo;
index 1bee4f95093a53875d4960ec85d761bf442d9c6d..31832d985edbb029324ec8a99d82e1dcd4beb824 100644 (file)
@@ -36,6 +36,7 @@ int wl_get_quality_max(const char *ifname, int *buf);
 int wl_get_enctype(const char *ifname, char *buf);
 int wl_get_assoclist(const char *ifname, char *buf, int *len);
 int wl_get_txpwrlist(const char *ifname, char *buf, int *len);
+int wl_get_scanlist(const char *ifname, char *buf, int *len);
 int wl_get_mbssid_support(const char *ifname, int *buf);
 
 #endif