├── iwinfo_nl80211.h ├── Makefile ├── include ├── iwinfo │ ├── lua.h │ └── utils.h └── iwinfo.h ├── api ├── broadcom.h └── madwifi.h ├── iwinfo_wext.h ├── iwinfo_lib.c ├── iwinfo_wext.c ├── iwinfo_wext_scan.c ├── devices.txt ├── iwinfo_utils.c ├── COPYING ├── iwinfo_wl.c ├── iwinfo_lua.c └── iwinfo_cli.c /iwinfo_nl80211.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - NL80211 Headers 3 | * 4 | * Copyright (C) 2010 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #ifndef __IWINFO_NL80211_H_ 20 | #define __IWINFO_NL80211_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "iwinfo.h" 35 | #include "iwinfo/utils.h" 36 | #include "api/nl80211.h" 37 | 38 | struct nl80211_state { 39 | struct nl_sock *nl_sock; 40 | struct nl_cache *nl_cache; 41 | struct genl_family *nl80211; 42 | struct genl_family *nlctrl; 43 | }; 44 | 45 | struct nl80211_msg_conveyor { 46 | struct nl_msg *msg; 47 | struct nl_cb *cb; 48 | }; 49 | 50 | struct nl80211_event_conveyor { 51 | uint32_t wait[(NL80211_CMD_MAX / 32) + !!(NL80211_CMD_MAX % 32)]; 52 | int recv; 53 | }; 54 | 55 | struct nl80211_group_conveyor { 56 | const char *name; 57 | int id; 58 | }; 59 | 60 | struct nl80211_rssi_rate { 61 | int16_t rate; 62 | int rate_samples; 63 | int8_t rssi; 64 | int rssi_samples; 65 | }; 66 | 67 | struct nl80211_array_buf { 68 | void *buf; 69 | int count; 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IWINFO_SOVERSION = $(if $(SOVERSION),$(SOVERSION),0) 2 | 3 | IWINFO_BACKENDS = $(BACKENDS) 4 | IWINFO_CFLAGS = $(CFLAGS) -Wall -std=gnu99 -fstrict-aliasing -Iinclude 5 | IWINFO_LDFLAGS = -luci -lubox -lubus 6 | 7 | IWINFO_LIB = libiwinfo.so 8 | IWINFO_LIB_LDFLAGS = $(LDFLAGS) -shared -Wl,-soname -Wl,$(IWINFO_LIB).$(IWINFO_SOVERSION) 9 | IWINFO_LIB_OBJ = iwinfo_utils.o iwinfo_lib.o 10 | 11 | IWINFO_LUA = iwinfo.so 12 | IWINFO_LUA_LDFLAGS = $(LDFLAGS) -shared -L. -liwinfo -llua 13 | IWINFO_LUA_OBJ = iwinfo_lua.o 14 | 15 | IWINFO_CLI = iwinfo 16 | IWINFO_CLI_LDFLAGS = $(LDFLAGS) -L. -liwinfo 17 | IWINFO_CLI_OBJ = iwinfo_cli.o 18 | 19 | 20 | ifneq ($(filter wl wext madwifi,$(IWINFO_BACKENDS)),) 21 | IWINFO_CFLAGS += -DUSE_WEXT 22 | IWINFO_LIB_OBJ += iwinfo_wext.o iwinfo_wext_scan.o 23 | endif 24 | 25 | ifneq ($(filter wl,$(IWINFO_BACKENDS)),) 26 | IWINFO_CFLAGS += -DUSE_WL 27 | IWINFO_LIB_OBJ += iwinfo_wl.o 28 | endif 29 | 30 | ifneq ($(filter madwifi,$(IWINFO_BACKENDS)),) 31 | IWINFO_CFLAGS += -DUSE_MADWIFI 32 | IWINFO_LIB_OBJ += iwinfo_madwifi.o 33 | endif 34 | 35 | ifneq ($(filter nl80211,$(IWINFO_BACKENDS)),) 36 | IWINFO_CFLAGS += -DUSE_NL80211 37 | IWINFO_CLI_LDFLAGS += -lnl-tiny 38 | IWINFO_LIB_LDFLAGS += -lnl-tiny 39 | IWINFO_LIB_OBJ += iwinfo_nl80211.o 40 | endif 41 | 42 | 43 | compile: clean $(IWINFO_LIB) $(IWINFO_LUA) $(IWINFO_CLI) 44 | 45 | %.o: %.c 46 | $(CC) $(IWINFO_CFLAGS) $(FPIC) -c -o $@ $< 47 | 48 | $(IWINFO_LIB): $(IWINFO_LIB_OBJ) 49 | $(CC) $(IWINFO_LDFLAGS) $(IWINFO_LIB_LDFLAGS) -o $(IWINFO_LIB).$(IWINFO_SOVERSION) $(IWINFO_LIB_OBJ) && \ 50 | ln -sf $(IWINFO_LIB).$(IWINFO_SOVERSION) $(IWINFO_LIB) 51 | 52 | $(IWINFO_LUA): $(IWINFO_LUA_OBJ) 53 | $(CC) $(IWINFO_LDFLAGS) $(IWINFO_LUA_LDFLAGS) -o $(IWINFO_LUA) $(IWINFO_LUA_OBJ) 54 | 55 | $(IWINFO_CLI): $(IWINFO_CLI_OBJ) 56 | $(CC) $(IWINFO_LDFLAGS) $(IWINFO_CLI_LDFLAGS) -o $(IWINFO_CLI) $(IWINFO_CLI_OBJ) 57 | 58 | clean: 59 | rm -f *.o $(IWINFO_LIB) $(IWINFO_LUA) $(IWINFO_CLI) 60 | -------------------------------------------------------------------------------- /include/iwinfo/lua.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Lua Headers 3 | * 4 | * Copyright (C) 2009 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #ifndef __IWINFO_LUALUB_H_ 20 | #define __IWINFO_LUALIB_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "iwinfo.h" 27 | 28 | 29 | #define IWINFO_META "iwinfo" 30 | #define IWINFO_WEXT_META "iwinfo.wext" 31 | 32 | #ifdef USE_WL 33 | #define IWINFO_WL_META "iwinfo.wl" 34 | #endif 35 | 36 | #ifdef USE_MADWIFI 37 | #define IWINFO_MADWIFI_META "iwinfo.madwifi" 38 | #endif 39 | 40 | #ifdef USE_NL80211 41 | #define IWINFO_NL80211_META "iwinfo.nl80211" 42 | #endif 43 | 44 | 45 | #define LUA_REG(type,op) \ 46 | { #op, iwinfo_L_##type##_##op } 47 | 48 | #define LUA_WRAP_INT_OP(type,op) \ 49 | static int iwinfo_L_##type##_##op(lua_State *L) \ 50 | { \ 51 | const char *ifname = luaL_checkstring(L, 1); \ 52 | int rv; \ 53 | if( !type##_ops.op(ifname, &rv) ) \ 54 | lua_pushnumber(L, rv); \ 55 | else \ 56 | lua_pushnil(L); \ 57 | return 1; \ 58 | } 59 | 60 | #define LUA_WRAP_STRING_OP(type,op) \ 61 | static int iwinfo_L_##type##_##op(lua_State *L) \ 62 | { \ 63 | const char *ifname = luaL_checkstring(L, 1); \ 64 | char rv[IWINFO_BUFSIZE]; \ 65 | memset(rv, 0, IWINFO_BUFSIZE); \ 66 | if( !type##_ops.op(ifname, rv) ) \ 67 | lua_pushstring(L, rv); \ 68 | else \ 69 | lua_pushnil(L); \ 70 | return 1; \ 71 | } 72 | 73 | #define LUA_WRAP_STRUCT_OP(type,op) \ 74 | static int iwinfo_L_##type##_##op(lua_State *L) \ 75 | { \ 76 | return iwinfo_L_##op(L, type##_ops.op); \ 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /include/iwinfo/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Utility Headers 3 | * 4 | * Copyright (C) 2010 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #ifndef __IWINFO_UTILS_H_ 20 | #define __IWINFO_UTILS_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "iwinfo.h" 28 | 29 | #ifndef ARRAY_SIZE 30 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 31 | #endif 32 | 33 | #define LOG10_MAGIC 1.25892541179 34 | 35 | extern struct uci_context *uci_ctx; 36 | 37 | int iwinfo_ioctl(int cmd, void *ifr); 38 | 39 | int iwinfo_dbm2mw(int in); 40 | int iwinfo_mw2dbm(int in); 41 | static inline int iwinfo_mbm2dbm(int gain) 42 | { 43 | return gain / 100; 44 | } 45 | 46 | const char * const iwinfo_band_name(int mask); 47 | const char * const iwinfo_htmode_name(int mask); 48 | 49 | uint32_t iwinfo_band2ghz(uint8_t band); 50 | uint8_t iwinfo_ghz2band(uint32_t ghz); 51 | 52 | size_t iwinfo_format_hwmodes(int modes, char *buf, size_t len); 53 | int iwinfo_htmode_is_ht(int htmode); 54 | int iwinfo_htmode_is_vht(int htmode); 55 | int iwinfo_htmode_is_he(int htmode); 56 | int iwinfo_htmode_is_eht(int htmode); 57 | 58 | int iwinfo_ifup(const char *ifname); 59 | int iwinfo_ifdown(const char *ifname); 60 | int iwinfo_ifmac(const char *ifname); 61 | 62 | void iwinfo_close(void); 63 | 64 | struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id); 65 | 66 | int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id); 67 | 68 | void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len, 69 | uint16_t defcipher, uint8_t defauth); 70 | 71 | struct uci_section *iwinfo_uci_get_radio(const char *name, const char *type); 72 | void iwinfo_uci_free(void); 73 | 74 | int iwinfo_ubus_query(const char *ifname, const char *field, 75 | char *buf, size_t len); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /api/broadcom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Custom OID/ioctl definitions for 3 | * Broadcom 802.11abg Networking Device Driver 4 | * 5 | * Definitions subject to change without notice. 6 | * 7 | * Copyright 2006, Broadcom Corporation 8 | * All Rights Reserved. 9 | * 10 | * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 11 | * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 12 | * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 13 | * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 14 | * 15 | */ 16 | 17 | #ifndef _BROADCOM_H 18 | #define _BROADCOM_H 19 | 20 | #define WL_MCSSET_LEN 16 21 | #define WL_MAX_STA_COUNT 32 22 | 23 | #define WL_BSS_RSSI_OFFSET 82 24 | #define WL_BSS_NOISE_OFFSET 84 25 | 26 | #define WLC_IOCTL_MAGIC 0x14e46c77 27 | #define WLC_IOCTL_MAXLEN 8192 28 | 29 | #define WLC_CNTRY_BUF_SZ 4 30 | 31 | #define WLC_GET_MAGIC 0 32 | #define WLC_GET_RATE 12 33 | #define WLC_GET_INFRA 19 34 | #define WLC_GET_AUTH 21 35 | #define WLC_GET_BSSID 23 36 | #define WLC_GET_SSID 25 37 | #define WLC_GET_CHANNEL 29 38 | #define WLC_GET_PHYTYPE 39 39 | #define WLC_GET_PASSIVE 48 40 | #define WLC_GET_COUNTRY 83 41 | #define WLC_GET_REVINFO 98 42 | #define WLC_GET_AP 117 43 | #define WLC_GET_RSSI 127 44 | #define WLC_GET_WSEC 133 45 | #define WLC_GET_PHY_NOISE 135 46 | #define WLC_GET_BSS_INFO 136 47 | #define WLC_GET_BANDLIST 140 48 | #define WLC_GET_ASSOCLIST 159 49 | #define WLC_GET_WPA_AUTH 164 50 | #define WLC_GET_COUNTRY_LIST 261 51 | #define WLC_GET_VAR 262 52 | 53 | #define WLC_PHY_TYPE_A 0 54 | #define WLC_PHY_TYPE_B 1 55 | #define WLC_PHY_TYPE_G 2 56 | #define WLC_PHY_TYPE_N 4 57 | #define WLC_PHY_TYPE_LP 5 58 | #define WLC_PHY_TYPE_HT 7 59 | #define WLC_PHY_TYPE_AC 11 60 | 61 | #define WLC_BAND_5G 1 62 | #define WLC_BAND_2G 2 63 | #define WLC_BAND_ALL 3 64 | 65 | 66 | struct wl_ether_addr { 67 | uint8_t octet[6]; 68 | }; 69 | 70 | struct wl_maclist { 71 | uint count; 72 | struct wl_ether_addr ea[1]; 73 | }; 74 | 75 | typedef struct wl_sta_rssi { 76 | int rssi; 77 | char mac[6]; 78 | uint16_t foo; 79 | } wl_sta_rssi_t; 80 | 81 | #define WL_NUMRATES 255 /* max # of rates in a rateset */ 82 | typedef struct wl_rateset { 83 | uint32_t count; /* # rates in this set */ 84 | uint8_t rates[WL_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */ 85 | } wl_rateset_t; 86 | 87 | typedef struct wl_sta_info { 88 | uint16_t ver; /* version of this struct */ 89 | uint16_t len; /* length in bytes of this structure */ 90 | uint16_t cap; /* sta's advertised capabilities */ 91 | uint32_t flags; /* flags defined below */ 92 | uint32_t idle; /* time since data pkt rx'd from sta */ 93 | unsigned char ea[6]; /* Station address */ 94 | wl_rateset_t rateset; /* rateset in use */ 95 | uint32_t in; /* seconds elapsed since associated */ 96 | uint32_t listen_interval_inms; /* Min Listen interval in ms for this STA */ 97 | uint32_t tx_pkts; /* # of packets transmitted */ 98 | uint32_t tx_failures; /* # of packets failed */ 99 | uint32_t rx_ucast_pkts; /* # of unicast packets received */ 100 | uint32_t rx_mcast_pkts; /* # of multicast packets received */ 101 | uint32_t tx_rate; /* Rate of last successful tx frame */ 102 | uint32_t rx_rate; /* Rate of last successful rx frame */ 103 | } wl_sta_info_t; 104 | 105 | typedef struct wlc_ssid { 106 | uint32_t ssid_len; 107 | unsigned char ssid[32]; 108 | } wlc_ssid_t; 109 | 110 | /* Linux network driver ioctl encoding */ 111 | typedef struct wl_ioctl { 112 | uint32_t cmd; /* common ioctl definition */ 113 | void *buf; /* pointer to user buffer */ 114 | uint32_t len; /* length of user buffer */ 115 | uint8_t set; /* get or set request (optional) */ 116 | uint32_t used; /* bytes read or written (optional) */ 117 | uint32_t needed; /* bytes needed (optional) */ 118 | } wl_ioctl_t; 119 | 120 | /* Revision info */ 121 | typedef struct wlc_rev_info { 122 | uint vendorid; /* PCI vendor id */ 123 | uint deviceid; /* device id of chip */ 124 | uint radiorev; /* radio revision */ 125 | uint chiprev; /* chip revision */ 126 | uint corerev; /* core revision */ 127 | uint boardid; /* board identifier (usu. PCI sub-device id) */ 128 | uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */ 129 | uint boardrev; /* board revision */ 130 | uint driverrev; /* driver version */ 131 | uint ucoderev; /* microcode version */ 132 | uint bus; /* bus type */ 133 | uint chipnum; /* chip number */ 134 | uint phytype; /* phy type */ 135 | uint phyrev; /* phy revision */ 136 | uint anarev; /* anacore rev */ 137 | } wlc_rev_info_t; 138 | 139 | typedef struct wl_country_list { 140 | uint32_t buflen; 141 | uint32_t band_set; 142 | uint32_t band; 143 | uint32_t count; 144 | char country_abbrev[1]; 145 | } wl_country_list_t; 146 | 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /api/madwifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Header bits derived from MadWifi source: 3 | * Copyright (c) 2001 Atsushi Onoe 4 | * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 5 | * All rights reserved. 6 | * 7 | * Distributed under the terms of the GPLv2 license. 8 | * 9 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 10 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 11 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 12 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 13 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 14 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 15 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 16 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 17 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 18 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | */ 20 | 21 | #ifndef _MADWIFI_H 22 | #define _MADWIFI_H 23 | 24 | /* ieee80211.h */ 25 | #define IEEE80211_ADDR_LEN 6 26 | #define IEEE80211_RATE_VAL 0x7f 27 | #define IEEE80211_SEQ_SEQ_MASK 0xfff0 28 | #define IEEE80211_SEQ_SEQ_SHIFT 4 29 | 30 | 31 | /* ieee80211_crypto.h */ 32 | #define IEEE80211_KEYBUF_SIZE 16 33 | #define IEEE80211_MICBUF_SIZE 16 34 | #define IEEE80211_TID_SIZE 17 35 | 36 | #define IEEE80211_CIPHER_WEP 0 37 | #define IEEE80211_CIPHER_TKIP 1 38 | #define IEEE80211_CIPHER_AES_OCB 2 39 | #define IEEE80211_CIPHER_AES_CCM 3 40 | #define IEEE80211_CIPHER_CKIP 5 41 | #define IEEE80211_CIPHER_NONE 6 42 | #define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE + 1) 43 | 44 | 45 | /* ieee80211_ioctl.h */ 46 | #define IEEE80211_KEY_DEFAULT 0x80 47 | #define IEEE80211_CHAN_MAX 255 48 | #define IEEE80211_CHAN_BYTES 32 49 | #define IEEE80211_RATE_MAXSIZE 15 50 | 51 | #define IEEE80211_IOCTL_GETKEY (SIOCDEVPRIVATE+3) 52 | #define IEEE80211_IOCTL_STA_STATS (SIOCDEVPRIVATE+5) 53 | #define IEEE80211_IOCTL_STA_INFO (SIOCDEVPRIVATE+6) 54 | 55 | #define IEEE80211_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1) 56 | #define IEEE80211_IOCTL_GETMODE (SIOCIWFIRSTPRIV+3) 57 | #define IEEE80211_IOCTL_GETCHANLIST (SIOCIWFIRSTPRIV+7) 58 | #define IEEE80211_IOCTL_GETCHANINFO (SIOCIWFIRSTPRIV+13) 59 | 60 | #define SIOC80211IFCREATE (SIOCDEVPRIVATE+7) 61 | #define SIOC80211IFDESTROY (SIOCDEVPRIVATE+8) 62 | 63 | #define IEEE80211_CLONE_BSSID 0x0001 /* allocate unique mac/bssid */ 64 | #define IEEE80211_NO_STABEACONS 0x0002 /* Do not setup the station beacon timers */ 65 | 66 | struct ieee80211_clone_params { 67 | char icp_name[IFNAMSIZ]; /* device name */ 68 | u_int16_t icp_opmode; /* operating mode */ 69 | u_int16_t icp_flags; /* see below */ 70 | }; 71 | 72 | enum ieee80211_opmode { 73 | IEEE80211_M_STA = 1, /* infrastructure station */ 74 | IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ 75 | IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */ 76 | IEEE80211_M_HOSTAP = 6, /* Software Access Point */ 77 | IEEE80211_M_MONITOR = 8, /* Monitor mode */ 78 | IEEE80211_M_WDS = 2, /* WDS link */ 79 | }; 80 | 81 | enum { 82 | IEEE80211_PARAM_AUTHMODE = 3, /* authentication mode */ 83 | IEEE80211_PARAM_MCASTCIPHER = 5, /* multicast/default cipher */ 84 | IEEE80211_PARAM_MCASTKEYLEN = 6, /* multicast key length */ 85 | IEEE80211_PARAM_UCASTCIPHERS = 7, /* unicast cipher suites */ 86 | IEEE80211_PARAM_WPA = 10, /* WPA mode (0,1,2) */ 87 | }; 88 | 89 | /* 90 | * Authentication mode. 91 | */ 92 | enum ieee80211_authmode { 93 | IEEE80211_AUTH_NONE = 0, 94 | IEEE80211_AUTH_OPEN = 1, /* open */ 95 | IEEE80211_AUTH_SHARED = 2, /* shared-key */ 96 | IEEE80211_AUTH_8021X = 3, /* 802.1x */ 97 | IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */ 98 | /* NB: these are used only for ioctls */ 99 | IEEE80211_AUTH_WPA = 5, /* WPA/RSN w/ 802.1x/PSK */ 100 | }; 101 | 102 | struct ieee80211_channel { 103 | u_int16_t ic_freq; /* setting in MHz */ 104 | u_int16_t ic_flags; /* see below */ 105 | u_int8_t ic_ieee; /* IEEE channel number */ 106 | int8_t ic_maxregpower; /* maximum regulatory tx power in dBm */ 107 | int8_t ic_maxpower; /* maximum tx power in dBm */ 108 | int8_t ic_minpower; /* minimum tx power in dBm */ 109 | u_int8_t ic_scanflags; 110 | u_int8_t ic_idletime; /* phy idle time in % */ 111 | }; 112 | 113 | struct ieee80211req_key { 114 | u_int8_t ik_type; /* key/cipher type */ 115 | u_int8_t ik_pad; 116 | u_int16_t ik_keyix; /* key index */ 117 | u_int8_t ik_keylen; /* key length in bytes */ 118 | u_int8_t ik_flags; 119 | u_int8_t ik_macaddr[IEEE80211_ADDR_LEN]; 120 | u_int64_t ik_keyrsc; /* key receive sequence counter */ 121 | u_int64_t ik_keytsc; /* key transmit sequence counter */ 122 | u_int8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE]; 123 | }; 124 | 125 | struct ieee80211req_chanlist { 126 | u_int8_t ic_channels[IEEE80211_CHAN_BYTES]; 127 | }; 128 | 129 | struct ieee80211req_chaninfo { 130 | u_int ic_nchans; 131 | struct ieee80211_channel ic_chans[IEEE80211_CHAN_MAX]; 132 | }; 133 | 134 | struct ieee80211req_sta_info { 135 | u_int16_t isi_len; /* length (mult of 4) */ 136 | u_int16_t isi_freq; /* MHz */ 137 | u_int16_t isi_flags; /* channel flags */ 138 | u_int16_t isi_state; /* state flags */ 139 | u_int8_t isi_authmode; /* authentication algorithm */ 140 | u_int8_t isi_rssi; 141 | int8_t isi_noise; 142 | u_int16_t isi_capinfo; /* capabilities */ 143 | u_int8_t isi_athflags; /* Atheros capabilities */ 144 | u_int8_t isi_erp; /* ERP element */ 145 | u_int8_t isi_macaddr[IEEE80211_ADDR_LEN]; 146 | u_int8_t isi_nrates; /* negotiated rates */ 147 | u_int8_t isi_rates[IEEE80211_RATE_MAXSIZE]; 148 | u_int8_t isi_txrate; /* index to isi_rates[] */ 149 | u_int16_t isi_ie_len; /* IE length */ 150 | u_int16_t isi_associd; /* assoc response */ 151 | u_int16_t isi_txpower; /* current tx power */ 152 | u_int16_t isi_vlan; /* vlan tag */ 153 | u_int16_t isi_txseqs[17]; /* seq to be transmitted */ 154 | u_int16_t isi_rxseqs[17]; /* seq previous for qos frames*/ 155 | u_int16_t isi_inact; /* inactivity timer */ 156 | u_int8_t isi_uapsd; /* UAPSD queues */ 157 | u_int8_t isi_opmode; /* sta operating mode */ 158 | }; 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /iwinfo_wext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Linux Wireless Extension Headers 3 | * 4 | * Copyright (C) 2009-2010 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #ifndef __IWINFO_WEXT_SCAN_H_ 20 | #define __IWINFO_WEXT_SCAN_H_ 21 | 22 | #include 23 | 24 | #include "iwinfo.h" 25 | #include "iwinfo/utils.h" 26 | #include "api/wext.h" 27 | 28 | 29 | typedef struct stream_descr 30 | { 31 | char * end; /* End of the stream */ 32 | char * current; /* Current event in stream of events */ 33 | char * value; /* Current value in event */ 34 | } stream_descr; 35 | 36 | /* 37 | * Describe how a standard IOCTL looks like. 38 | */ 39 | struct iw_ioctl_description 40 | { 41 | uint8_t header_type; /* NULL, iw_point or other */ 42 | uint8_t token_type; /* Future */ 43 | uint16_t token_size; /* Granularity of payload */ 44 | uint16_t min_tokens; /* Min acceptable token number */ 45 | uint16_t max_tokens; /* Max acceptable token number */ 46 | uint32_t flags; /* Special handling of the request */ 47 | }; 48 | 49 | /* Type of headers we know about (basically union iwreq_data) */ 50 | #define IW_HEADER_TYPE_NULL 0 /* Not available */ 51 | #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ 52 | #define IW_HEADER_TYPE_UINT 4 /* __u32 */ 53 | #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ 54 | #define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ 55 | #define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ 56 | #define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ 57 | #define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ 58 | 59 | /* Handling flags */ 60 | /* Most are not implemented. I just use them as a reminder of some 61 | * cool features we might need one day ;-) */ 62 | #define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */ 63 | /* Wrapper level flags */ 64 | #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ 65 | #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ 66 | #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ 67 | /* SET : Omit payload from generated iwevent */ 68 | #define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */ 69 | /* Driver level flags */ 70 | #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ 71 | 72 | 73 | /* 74 | * Meta-data about all the standard Wireless Extension request we 75 | * know about. 76 | */ 77 | static const struct iw_ioctl_description standard_ioctl_descr[] = { 78 | [SIOCSIWCOMMIT - SIOCIWFIRST] = { 79 | .header_type = IW_HEADER_TYPE_NULL, 80 | }, 81 | [SIOCGIWNAME - SIOCIWFIRST] = { 82 | .header_type = IW_HEADER_TYPE_CHAR, 83 | .flags = IW_DESCR_FLAG_DUMP, 84 | }, 85 | [SIOCSIWNWID - SIOCIWFIRST] = { 86 | .header_type = IW_HEADER_TYPE_PARAM, 87 | .flags = IW_DESCR_FLAG_EVENT, 88 | }, 89 | [SIOCGIWNWID - SIOCIWFIRST] = { 90 | .header_type = IW_HEADER_TYPE_PARAM, 91 | .flags = IW_DESCR_FLAG_DUMP, 92 | }, 93 | [SIOCSIWFREQ - SIOCIWFIRST] = { 94 | .header_type = IW_HEADER_TYPE_FREQ, 95 | .flags = IW_DESCR_FLAG_EVENT, 96 | }, 97 | [SIOCGIWFREQ - SIOCIWFIRST] = { 98 | .header_type = IW_HEADER_TYPE_FREQ, 99 | .flags = IW_DESCR_FLAG_DUMP, 100 | }, 101 | [SIOCSIWMODE - SIOCIWFIRST] = { 102 | .header_type = IW_HEADER_TYPE_UINT, 103 | .flags = IW_DESCR_FLAG_EVENT, 104 | }, 105 | [SIOCGIWMODE - SIOCIWFIRST] = { 106 | .header_type = IW_HEADER_TYPE_UINT, 107 | .flags = IW_DESCR_FLAG_DUMP, 108 | }, 109 | [SIOCSIWSENS - SIOCIWFIRST] = { 110 | .header_type = IW_HEADER_TYPE_PARAM, 111 | }, 112 | [SIOCGIWSENS - SIOCIWFIRST] = { 113 | .header_type = IW_HEADER_TYPE_PARAM, 114 | }, 115 | [SIOCSIWRANGE - SIOCIWFIRST] = { 116 | .header_type = IW_HEADER_TYPE_NULL, 117 | }, 118 | [SIOCGIWRANGE - SIOCIWFIRST] = { 119 | .header_type = IW_HEADER_TYPE_POINT, 120 | .token_size = 1, 121 | .max_tokens = sizeof(struct iw_range), 122 | .flags = IW_DESCR_FLAG_DUMP, 123 | }, 124 | [SIOCSIWPRIV - SIOCIWFIRST] = { 125 | .header_type = IW_HEADER_TYPE_NULL, 126 | }, 127 | [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ 128 | .header_type = IW_HEADER_TYPE_NULL, 129 | }, 130 | [SIOCSIWSTATS - SIOCIWFIRST] = { 131 | .header_type = IW_HEADER_TYPE_NULL, 132 | }, 133 | [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ 134 | .header_type = IW_HEADER_TYPE_NULL, 135 | .flags = IW_DESCR_FLAG_DUMP, 136 | }, 137 | [SIOCSIWSPY - SIOCIWFIRST] = { 138 | .header_type = IW_HEADER_TYPE_POINT, 139 | .token_size = sizeof(struct sockaddr), 140 | .max_tokens = IW_MAX_SPY, 141 | }, 142 | [SIOCGIWSPY - SIOCIWFIRST] = { 143 | .header_type = IW_HEADER_TYPE_POINT, 144 | .token_size = sizeof(struct sockaddr) + 145 | sizeof(struct iw_quality), 146 | .max_tokens = IW_MAX_SPY, 147 | }, 148 | [SIOCSIWTHRSPY - SIOCIWFIRST] = { 149 | .header_type = IW_HEADER_TYPE_POINT, 150 | .token_size = sizeof(struct iw_thrspy), 151 | .min_tokens = 1, 152 | .max_tokens = 1, 153 | }, 154 | [SIOCGIWTHRSPY - SIOCIWFIRST] = { 155 | .header_type = IW_HEADER_TYPE_POINT, 156 | .token_size = sizeof(struct iw_thrspy), 157 | .min_tokens = 1, 158 | .max_tokens = 1, 159 | }, 160 | [SIOCSIWAP - SIOCIWFIRST] = { 161 | .header_type = IW_HEADER_TYPE_ADDR, 162 | }, 163 | [SIOCGIWAP - SIOCIWFIRST] = { 164 | .header_type = IW_HEADER_TYPE_ADDR, 165 | .flags = IW_DESCR_FLAG_DUMP, 166 | }, 167 | [SIOCSIWMLME - SIOCIWFIRST] = { 168 | .header_type = IW_HEADER_TYPE_POINT, 169 | .token_size = 1, 170 | .min_tokens = sizeof(struct iw_mlme), 171 | .max_tokens = sizeof(struct iw_mlme), 172 | }, 173 | [SIOCGIWAPLIST - SIOCIWFIRST] = { 174 | .header_type = IW_HEADER_TYPE_POINT, 175 | .token_size = sizeof(struct sockaddr) + 176 | sizeof(struct iw_quality), 177 | .max_tokens = IW_MAX_AP, 178 | .flags = IW_DESCR_FLAG_NOMAX, 179 | }, 180 | [SIOCSIWSCAN - SIOCIWFIRST] = { 181 | .header_type = IW_HEADER_TYPE_POINT, 182 | .token_size = 1, 183 | .min_tokens = 0, 184 | .max_tokens = sizeof(struct iw_scan_req), 185 | }, 186 | [SIOCGIWSCAN - SIOCIWFIRST] = { 187 | .header_type = IW_HEADER_TYPE_POINT, 188 | .token_size = 1, 189 | .max_tokens = IW_SCAN_MAX_DATA, 190 | .flags = IW_DESCR_FLAG_NOMAX, 191 | }, 192 | [SIOCSIWESSID - SIOCIWFIRST] = { 193 | .header_type = IW_HEADER_TYPE_POINT, 194 | .token_size = 1, 195 | .max_tokens = IW_ESSID_MAX_SIZE + 1, 196 | .flags = IW_DESCR_FLAG_EVENT, 197 | }, 198 | [SIOCGIWESSID - SIOCIWFIRST] = { 199 | .header_type = IW_HEADER_TYPE_POINT, 200 | .token_size = 1, 201 | .max_tokens = IW_ESSID_MAX_SIZE + 1, 202 | .flags = IW_DESCR_FLAG_DUMP, 203 | }, 204 | [SIOCSIWNICKN - SIOCIWFIRST] = { 205 | .header_type = IW_HEADER_TYPE_POINT, 206 | .token_size = 1, 207 | .max_tokens = IW_ESSID_MAX_SIZE + 1, 208 | }, 209 | [SIOCGIWNICKN - SIOCIWFIRST] = { 210 | .header_type = IW_HEADER_TYPE_POINT, 211 | .token_size = 1, 212 | .max_tokens = IW_ESSID_MAX_SIZE + 1, 213 | }, 214 | [SIOCSIWRATE - SIOCIWFIRST] = { 215 | .header_type = IW_HEADER_TYPE_PARAM, 216 | }, 217 | [SIOCGIWRATE - SIOCIWFIRST] = { 218 | .header_type = IW_HEADER_TYPE_PARAM, 219 | }, 220 | [SIOCSIWRTS - SIOCIWFIRST] = { 221 | .header_type = IW_HEADER_TYPE_PARAM, 222 | }, 223 | [SIOCGIWRTS - SIOCIWFIRST] = { 224 | .header_type = IW_HEADER_TYPE_PARAM, 225 | }, 226 | [SIOCSIWFRAG - SIOCIWFIRST] = { 227 | .header_type = IW_HEADER_TYPE_PARAM, 228 | }, 229 | [SIOCGIWFRAG - SIOCIWFIRST] = { 230 | .header_type = IW_HEADER_TYPE_PARAM, 231 | }, 232 | [SIOCSIWTXPOW - SIOCIWFIRST] = { 233 | .header_type = IW_HEADER_TYPE_PARAM, 234 | }, 235 | [SIOCGIWTXPOW - SIOCIWFIRST] = { 236 | .header_type = IW_HEADER_TYPE_PARAM, 237 | }, 238 | [SIOCSIWRETRY - SIOCIWFIRST] = { 239 | .header_type = IW_HEADER_TYPE_PARAM, 240 | }, 241 | [SIOCGIWRETRY - SIOCIWFIRST] = { 242 | .header_type = IW_HEADER_TYPE_PARAM, 243 | }, 244 | [SIOCSIWENCODE - SIOCIWFIRST] = { 245 | .header_type = IW_HEADER_TYPE_POINT, 246 | .token_size = 1, 247 | .max_tokens = IW_ENCODING_TOKEN_MAX, 248 | .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, 249 | }, 250 | [SIOCGIWENCODE - SIOCIWFIRST] = { 251 | .header_type = IW_HEADER_TYPE_POINT, 252 | .token_size = 1, 253 | .max_tokens = IW_ENCODING_TOKEN_MAX, 254 | .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, 255 | }, 256 | [SIOCSIWPOWER - SIOCIWFIRST] = { 257 | .header_type = IW_HEADER_TYPE_PARAM, 258 | }, 259 | [SIOCGIWPOWER - SIOCIWFIRST] = { 260 | .header_type = IW_HEADER_TYPE_PARAM, 261 | }, 262 | [SIOCSIWMODUL - SIOCIWFIRST] = { 263 | .header_type = IW_HEADER_TYPE_PARAM, 264 | }, 265 | [SIOCGIWMODUL - SIOCIWFIRST] = { 266 | .header_type = IW_HEADER_TYPE_PARAM, 267 | }, 268 | [SIOCSIWGENIE - SIOCIWFIRST] = { 269 | .header_type = IW_HEADER_TYPE_POINT, 270 | .token_size = 1, 271 | .max_tokens = IW_GENERIC_IE_MAX, 272 | }, 273 | [SIOCGIWGENIE - SIOCIWFIRST] = { 274 | .header_type = IW_HEADER_TYPE_POINT, 275 | .token_size = 1, 276 | .max_tokens = IW_GENERIC_IE_MAX, 277 | }, 278 | [SIOCSIWAUTH - SIOCIWFIRST] = { 279 | .header_type = IW_HEADER_TYPE_PARAM, 280 | }, 281 | [SIOCGIWAUTH - SIOCIWFIRST] = { 282 | .header_type = IW_HEADER_TYPE_PARAM, 283 | }, 284 | [SIOCSIWENCODEEXT - SIOCIWFIRST] = { 285 | .header_type = IW_HEADER_TYPE_POINT, 286 | .token_size = 1, 287 | .min_tokens = sizeof(struct iw_encode_ext), 288 | .max_tokens = sizeof(struct iw_encode_ext) + 289 | IW_ENCODING_TOKEN_MAX, 290 | }, 291 | [SIOCGIWENCODEEXT - SIOCIWFIRST] = { 292 | .header_type = IW_HEADER_TYPE_POINT, 293 | .token_size = 1, 294 | .min_tokens = sizeof(struct iw_encode_ext), 295 | .max_tokens = sizeof(struct iw_encode_ext) + 296 | IW_ENCODING_TOKEN_MAX, 297 | }, 298 | [SIOCSIWPMKSA - SIOCIWFIRST] = { 299 | .header_type = IW_HEADER_TYPE_POINT, 300 | .token_size = 1, 301 | .min_tokens = sizeof(struct iw_pmksa), 302 | .max_tokens = sizeof(struct iw_pmksa), 303 | }, 304 | }; 305 | 306 | /* 307 | * Meta-data about all the additional standard Wireless Extension events 308 | * we know about. 309 | */ 310 | static const struct iw_ioctl_description standard_event_descr[] = { 311 | [IWEVTXDROP - IWEVFIRST] = { 312 | .header_type = IW_HEADER_TYPE_ADDR, 313 | }, 314 | [IWEVQUAL - IWEVFIRST] = { 315 | .header_type = IW_HEADER_TYPE_QUAL, 316 | }, 317 | [IWEVCUSTOM - IWEVFIRST] = { 318 | .header_type = IW_HEADER_TYPE_POINT, 319 | .token_size = 1, 320 | .max_tokens = IW_CUSTOM_MAX, 321 | }, 322 | [IWEVREGISTERED - IWEVFIRST] = { 323 | .header_type = IW_HEADER_TYPE_ADDR, 324 | }, 325 | [IWEVEXPIRED - IWEVFIRST] = { 326 | .header_type = IW_HEADER_TYPE_ADDR, 327 | }, 328 | [IWEVGENIE - IWEVFIRST] = { 329 | .header_type = IW_HEADER_TYPE_POINT, 330 | .token_size = 1, 331 | .max_tokens = IW_GENERIC_IE_MAX, 332 | }, 333 | [IWEVMICHAELMICFAILURE - IWEVFIRST] = { 334 | .header_type = IW_HEADER_TYPE_POINT, 335 | .token_size = 1, 336 | .max_tokens = sizeof(struct iw_michaelmicfailure), 337 | }, 338 | [IWEVASSOCREQIE - IWEVFIRST] = { 339 | .header_type = IW_HEADER_TYPE_POINT, 340 | .token_size = 1, 341 | .max_tokens = IW_GENERIC_IE_MAX, 342 | }, 343 | [IWEVASSOCRESPIE - IWEVFIRST] = { 344 | .header_type = IW_HEADER_TYPE_POINT, 345 | .token_size = 1, 346 | .max_tokens = IW_GENERIC_IE_MAX, 347 | }, 348 | [IWEVPMKIDCAND - IWEVFIRST] = { 349 | .header_type = IW_HEADER_TYPE_POINT, 350 | .token_size = 1, 351 | .max_tokens = sizeof(struct iw_pmkid_cand), 352 | }, 353 | }; 354 | 355 | /* Size (in bytes) of various events */ 356 | static const int event_type_size[] = { 357 | IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */ 358 | 0, 359 | IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */ 360 | 0, 361 | IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */ 362 | IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */ 363 | IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */ 364 | 0, 365 | IW_EV_POINT_PK_LEN, /* Without variable payload */ 366 | IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */ 367 | IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */ 368 | }; 369 | 370 | 371 | static const unsigned int standard_ioctl_num = 372 | (sizeof(standard_ioctl_descr) / sizeof(struct iw_ioctl_description)); 373 | 374 | static const unsigned int standard_event_num = 375 | (sizeof(standard_event_descr) / sizeof(struct iw_ioctl_description)); 376 | 377 | #define IW_IE_CYPHER_NUM 8 378 | #define IW_IE_KEY_MGMT_NUM 3 379 | 380 | int wext_get_scanlist(const char *ifname, char *buf, int *len); 381 | 382 | #endif 383 | -------------------------------------------------------------------------------- /include/iwinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef __IWINFO_H_ 2 | #define __IWINFO_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | #define IWINFO_BUFSIZE 24 * 1024 24 | #define IWINFO_ESSID_MAX_SIZE 32 25 | 26 | enum iwinfo_80211 { 27 | IWINFO_80211_A = 0, 28 | IWINFO_80211_B, 29 | IWINFO_80211_G, 30 | IWINFO_80211_N, 31 | IWINFO_80211_AC, 32 | IWINFO_80211_AD, 33 | IWINFO_80211_AX, 34 | IWINFO_80211_BE, 35 | 36 | /* keep last */ 37 | IWINFO_80211_COUNT 38 | }; 39 | 40 | #define IWINFO_80211_A (1 << IWINFO_80211_A) 41 | #define IWINFO_80211_B (1 << IWINFO_80211_B) 42 | #define IWINFO_80211_G (1 << IWINFO_80211_G) 43 | #define IWINFO_80211_N (1 << IWINFO_80211_N) 44 | #define IWINFO_80211_AC (1 << IWINFO_80211_AC) 45 | #define IWINFO_80211_AD (1 << IWINFO_80211_AD) 46 | #define IWINFO_80211_AX (1 << IWINFO_80211_AX) 47 | #define IWINFO_80211_BE (1 << IWINFO_80211_BE) 48 | 49 | extern const char * const IWINFO_80211_NAMES[IWINFO_80211_COUNT]; 50 | 51 | 52 | enum iwinfo_band { 53 | IWINFO_BAND_24 = 0, 54 | IWINFO_BAND_5, 55 | IWINFO_BAND_6, 56 | IWINFO_BAND_60, 57 | 58 | /* keep last */ 59 | IWINFO_BAND_COUNT 60 | }; 61 | 62 | #define IWINFO_BAND_24 (1 << IWINFO_BAND_24) 63 | #define IWINFO_BAND_5 (1 << IWINFO_BAND_5) 64 | #define IWINFO_BAND_6 (1 << IWINFO_BAND_6) 65 | #define IWINFO_BAND_60 (1 << IWINFO_BAND_60) 66 | 67 | extern const char * const IWINFO_BAND_NAMES[IWINFO_BAND_COUNT]; 68 | 69 | 70 | enum iwinfo_cipher { 71 | IWINFO_CIPHER_NONE = 0, 72 | IWINFO_CIPHER_WEP40, 73 | IWINFO_CIPHER_TKIP, 74 | IWINFO_CIPHER_WRAP, 75 | IWINFO_CIPHER_CCMP, 76 | IWINFO_CIPHER_WEP104, 77 | IWINFO_CIPHER_AESOCB, 78 | IWINFO_CIPHER_CKIP, 79 | IWINFO_CIPHER_GCMP, 80 | IWINFO_CIPHER_CCMP256, 81 | IWINFO_CIPHER_GCMP256, 82 | 83 | /* keep last */ 84 | IWINFO_CIPHER_COUNT 85 | }; 86 | 87 | #define IWINFO_CIPHER_NONE (1 << IWINFO_CIPHER_NONE) 88 | #define IWINFO_CIPHER_WEP40 (1 << IWINFO_CIPHER_WEP40) 89 | #define IWINFO_CIPHER_TKIP (1 << IWINFO_CIPHER_TKIP) 90 | #define IWINFO_CIPHER_WRAP (1 << IWINFO_CIPHER_WRAP) 91 | #define IWINFO_CIPHER_CCMP (1 << IWINFO_CIPHER_CCMP) 92 | #define IWINFO_CIPHER_WEP104 (1 << IWINFO_CIPHER_WEP104) 93 | #define IWINFO_CIPHER_AESOCB (1 << IWINFO_CIPHER_AESOCB) 94 | #define IWINFO_CIPHER_CKIP (1 << IWINFO_CIPHER_CKIP) 95 | #define IWINFO_CIPHER_GCMP (1 << IWINFO_CIPHER_GCMP) 96 | #define IWINFO_CIPHER_CCMP256 (1 << IWINFO_CIPHER_CCMP256) 97 | #define IWINFO_CIPHER_GCMP256 (1 << IWINFO_CIPHER_GCMP256) 98 | 99 | extern const char * const IWINFO_CIPHER_NAMES[IWINFO_CIPHER_COUNT]; 100 | 101 | 102 | enum iwinfo_kmgmt { 103 | IWINFO_KMGMT_NONE = 0, 104 | IWINFO_KMGMT_8021x, 105 | IWINFO_KMGMT_PSK, 106 | IWINFO_KMGMT_SAE, 107 | IWINFO_KMGMT_OWE, 108 | 109 | /* keep last */ 110 | IWINFO_KMGMT_COUNT 111 | }; 112 | 113 | #define IWINFO_KMGMT_NONE (1 << IWINFO_KMGMT_NONE) 114 | #define IWINFO_KMGMT_8021x (1 << IWINFO_KMGMT_8021x) 115 | #define IWINFO_KMGMT_PSK (1 << IWINFO_KMGMT_PSK) 116 | #define IWINFO_KMGMT_SAE (1 << IWINFO_KMGMT_SAE) 117 | #define IWINFO_KMGMT_OWE (1 << IWINFO_KMGMT_OWE) 118 | 119 | extern const char * const IWINFO_KMGMT_NAMES[IWINFO_KMGMT_COUNT]; 120 | 121 | 122 | enum iwinfo_auth { 123 | IWINFO_AUTH_OPEN = 0, 124 | IWINFO_AUTH_SHARED, 125 | 126 | /* keep last */ 127 | IWINFO_AUTH_COUNT 128 | }; 129 | 130 | #define IWINFO_AUTH_OPEN (1 << IWINFO_AUTH_OPEN) 131 | #define IWINFO_AUTH_SHARED (1 << IWINFO_AUTH_SHARED) 132 | 133 | extern const char * const IWINFO_AUTH_NAMES[IWINFO_AUTH_COUNT]; 134 | 135 | 136 | enum iwinfo_freq_flag { 137 | IWINFO_FREQ_NO_10MHZ = 0, 138 | IWINFO_FREQ_NO_20MHZ, 139 | IWINFO_FREQ_NO_HT40PLUS, 140 | IWINFO_FREQ_NO_HT40MINUS, 141 | IWINFO_FREQ_NO_80MHZ, 142 | IWINFO_FREQ_NO_160MHZ, 143 | IWINFO_FREQ_NO_HE, 144 | IWINFO_FREQ_NO_IR, 145 | IWINFO_FREQ_INDOOR_ONLY, 146 | 147 | /* keep last */ 148 | IWINFO_FREQ_FLAG_COUNT, 149 | }; 150 | 151 | #define IWINFO_FREQ_NO_10MHZ (1 << IWINFO_FREQ_NO_10MHZ) 152 | #define IWINFO_FREQ_NO_20MHZ (1 << IWINFO_FREQ_NO_20MHZ) 153 | #define IWINFO_FREQ_NO_HT40PLUS (1 << IWINFO_FREQ_NO_HT40PLUS) 154 | #define IWINFO_FREQ_NO_HT40MINUS (1 << IWINFO_FREQ_NO_HT40MINUS) 155 | #define IWINFO_FREQ_NO_80MHZ (1 << IWINFO_FREQ_NO_80MHZ) 156 | #define IWINFO_FREQ_NO_160MHZ (1 << IWINFO_FREQ_NO_160MHZ) 157 | #define IWINFO_FREQ_NO_HE (1 << IWINFO_FREQ_NO_HE) 158 | #define IWINFO_FREQ_NO_IR (1 << IWINFO_FREQ_NO_IR) 159 | #define IWINFO_FREQ_INDOOR_ONLY (1 << IWINFO_FREQ_INDOOR_ONLY) 160 | 161 | extern const char * const IWINFO_FREQ_FLAG_NAMES[IWINFO_FREQ_FLAG_COUNT]; 162 | 163 | 164 | enum iwinfo_opmode { 165 | IWINFO_OPMODE_UNKNOWN = 0, 166 | IWINFO_OPMODE_MASTER, 167 | IWINFO_OPMODE_ADHOC, 168 | IWINFO_OPMODE_CLIENT, 169 | IWINFO_OPMODE_MONITOR, 170 | IWINFO_OPMODE_AP_VLAN, 171 | IWINFO_OPMODE_WDS, 172 | IWINFO_OPMODE_MESHPOINT, 173 | IWINFO_OPMODE_P2P_CLIENT, 174 | IWINFO_OPMODE_P2P_GO, 175 | 176 | /* keep last */ 177 | IWINFO_OPMODE_COUNT 178 | }; 179 | 180 | extern const char * const IWINFO_OPMODE_NAMES[IWINFO_OPMODE_COUNT]; 181 | 182 | 183 | enum iwinfo_htmode { 184 | IWINFO_HTMODE_HT20 = 0, 185 | IWINFO_HTMODE_HT40, 186 | IWINFO_HTMODE_VHT20, 187 | IWINFO_HTMODE_VHT40, 188 | IWINFO_HTMODE_VHT80, 189 | IWINFO_HTMODE_VHT80_80, 190 | IWINFO_HTMODE_VHT160, 191 | IWINFO_HTMODE_NOHT, 192 | IWINFO_HTMODE_HE20, 193 | IWINFO_HTMODE_HE40, 194 | IWINFO_HTMODE_HE80, 195 | IWINFO_HTMODE_HE80_80, 196 | IWINFO_HTMODE_HE160, 197 | IWINFO_HTMODE_EHT20, 198 | IWINFO_HTMODE_EHT40, 199 | IWINFO_HTMODE_EHT80, 200 | IWINFO_HTMODE_EHT80_80, 201 | IWINFO_HTMODE_EHT160, 202 | IWINFO_HTMODE_EHT320, 203 | 204 | /* keep last */ 205 | IWINFO_HTMODE_COUNT 206 | }; 207 | 208 | #define IWINFO_HTMODE_HT20 (1 << IWINFO_HTMODE_HT20) 209 | #define IWINFO_HTMODE_HT40 (1 << IWINFO_HTMODE_HT40) 210 | #define IWINFO_HTMODE_VHT20 (1 << IWINFO_HTMODE_VHT20) 211 | #define IWINFO_HTMODE_VHT40 (1 << IWINFO_HTMODE_VHT40) 212 | #define IWINFO_HTMODE_VHT80 (1 << IWINFO_HTMODE_VHT80) 213 | #define IWINFO_HTMODE_VHT80_80 (1 << IWINFO_HTMODE_VHT80_80) 214 | #define IWINFO_HTMODE_VHT160 (1 << IWINFO_HTMODE_VHT160) 215 | #define IWINFO_HTMODE_NOHT (1 << IWINFO_HTMODE_NOHT) 216 | #define IWINFO_HTMODE_HE20 (1 << IWINFO_HTMODE_HE20) 217 | #define IWINFO_HTMODE_HE40 (1 << IWINFO_HTMODE_HE40) 218 | #define IWINFO_HTMODE_HE80 (1 << IWINFO_HTMODE_HE80) 219 | #define IWINFO_HTMODE_HE80_80 (1 << IWINFO_HTMODE_HE80_80) 220 | #define IWINFO_HTMODE_HE160 (1 << IWINFO_HTMODE_HE160) 221 | #define IWINFO_HTMODE_EHT20 (1 << IWINFO_HTMODE_EHT20) 222 | #define IWINFO_HTMODE_EHT40 (1 << IWINFO_HTMODE_EHT40) 223 | #define IWINFO_HTMODE_EHT80 (1 << IWINFO_HTMODE_EHT80) 224 | #define IWINFO_HTMODE_EHT80_80 (1 << IWINFO_HTMODE_EHT80_80) 225 | #define IWINFO_HTMODE_EHT160 (1 << IWINFO_HTMODE_EHT160) 226 | #define IWINFO_HTMODE_EHT320 (1 << IWINFO_HTMODE_EHT320) 227 | 228 | extern const char * const IWINFO_HTMODE_NAMES[IWINFO_HTMODE_COUNT]; 229 | 230 | 231 | struct iwinfo_rate_entry { 232 | uint32_t rate; 233 | int8_t mcs; 234 | uint8_t is_40mhz:1; 235 | uint8_t is_short_gi:1; 236 | uint8_t is_ht:1; 237 | uint8_t is_vht:1; 238 | uint8_t is_he:1; 239 | uint8_t is_eht:1; 240 | uint8_t he_gi; 241 | uint8_t he_dcm; 242 | uint8_t mhz; 243 | uint8_t nss; 244 | uint8_t mhz_hi; 245 | uint8_t eht_gi; 246 | }; 247 | 248 | struct iwinfo_assoclist_entry { 249 | uint8_t mac[6]; 250 | int8_t signal; 251 | int8_t signal_avg; 252 | int8_t noise; 253 | uint32_t inactive; 254 | uint32_t connected_time; 255 | uint32_t rx_packets; 256 | uint32_t tx_packets; 257 | uint64_t rx_drop_misc; 258 | struct iwinfo_rate_entry rx_rate; 259 | struct iwinfo_rate_entry tx_rate; 260 | uint64_t rx_bytes; 261 | uint64_t tx_bytes; 262 | uint32_t tx_retries; 263 | uint32_t tx_failed; 264 | uint64_t t_offset; 265 | uint8_t is_authorized:1; 266 | uint8_t is_authenticated:1; 267 | uint8_t is_preamble_short:1; 268 | uint8_t is_wme:1; 269 | uint8_t is_mfp:1; 270 | uint8_t is_tdls:1; 271 | uint32_t thr; 272 | uint16_t llid; 273 | uint16_t plid; 274 | char plink_state[16]; 275 | char local_ps[16]; 276 | char peer_ps[16]; 277 | char nonpeer_ps[16]; 278 | }; 279 | 280 | struct iwinfo_survey_entry { 281 | uint64_t active_time; 282 | uint64_t busy_time; 283 | uint64_t busy_time_ext; 284 | uint64_t rxtime; 285 | uint64_t txtime; 286 | uint32_t mhz; 287 | uint8_t noise; 288 | }; 289 | 290 | struct iwinfo_txpwrlist_entry { 291 | uint8_t dbm; 292 | uint16_t mw; 293 | }; 294 | 295 | struct iwinfo_freqlist_entry { 296 | uint8_t band; 297 | uint8_t channel; 298 | uint32_t mhz; 299 | uint8_t restricted; 300 | uint32_t flags; 301 | }; 302 | 303 | struct iwinfo_crypto_entry { 304 | uint8_t enabled; 305 | uint8_t wpa_version; 306 | uint16_t group_ciphers; 307 | uint16_t pair_ciphers; 308 | uint8_t auth_suites; 309 | uint8_t auth_algs; 310 | }; 311 | 312 | struct iwinfo_scanlist_ht_chan_entry { 313 | uint8_t primary_chan; 314 | uint8_t secondary_chan_off; 315 | uint8_t chan_width; 316 | }; 317 | 318 | struct iwinfo_scanlist_vht_chan_entry { 319 | uint8_t chan_width; 320 | uint8_t center_chan_1; 321 | uint8_t center_chan_2; 322 | }; 323 | 324 | extern const char * const ht_secondary_offset[4]; 325 | /* 0 = 20 MHz 326 | 1 = 40 MHz or higher (refer to vht if supported) */ 327 | extern const uint16_t ht_chan_width[2]; 328 | /* 0 = 40 MHz or lower (refer to ht to a more precise width) 329 | 1 = 80 MHz 330 | 2 = 160 MHz 331 | 3 = 80+80 MHz */ 332 | extern const uint16_t vht_chan_width[4]; 333 | /* 0 = 20 MHz 334 | 1 = 40 MHz 335 | 2 = 80 MHz 336 | 3 = 80+80 or 160 MHz 337 | 4 = 160+160 or 320 MHz */ 338 | extern const uint16_t eht_chan_width[5]; 339 | 340 | struct iwinfo_scanlist_entry { 341 | uint8_t mac[6]; 342 | char ssid[IWINFO_ESSID_MAX_SIZE+1]; 343 | enum iwinfo_opmode mode; 344 | uint8_t band; 345 | uint8_t channel; 346 | uint32_t mhz; 347 | uint8_t signal; 348 | uint8_t quality; 349 | uint8_t quality_max; 350 | struct iwinfo_crypto_entry crypto; 351 | struct iwinfo_scanlist_ht_chan_entry ht_chan_info; 352 | struct iwinfo_scanlist_vht_chan_entry vht_chan_info; 353 | struct iwinfo_scanlist_vht_chan_entry he_chan_info; 354 | struct iwinfo_scanlist_vht_chan_entry eht_chan_info; 355 | }; 356 | 357 | struct iwinfo_country_entry { 358 | uint16_t iso3166; 359 | char ccode[4]; 360 | }; 361 | 362 | struct iwinfo_iso3166_label { 363 | uint16_t iso3166; 364 | const char name[28]; 365 | }; 366 | 367 | struct iwinfo_hardware_id { 368 | uint16_t vendor_id; 369 | uint16_t device_id; 370 | uint16_t subsystem_vendor_id; 371 | uint16_t subsystem_device_id; 372 | char compatible[128]; 373 | }; 374 | 375 | struct iwinfo_hardware_entry { 376 | char vendor_name[64]; 377 | char device_name[64]; 378 | uint16_t vendor_id; 379 | uint16_t device_id; 380 | uint16_t subsystem_vendor_id; 381 | uint16_t subsystem_device_id; 382 | int16_t txpower_offset; 383 | int16_t frequency_offset; 384 | char compatible[128]; 385 | }; 386 | 387 | extern const struct iwinfo_iso3166_label IWINFO_ISO3166_NAMES[]; 388 | 389 | #define IWINFO_HARDWARE_FILE "/usr/share/libiwinfo/devices.txt" 390 | 391 | 392 | struct iwinfo_ops { 393 | const char *name; 394 | 395 | int (*probe)(const char *ifname); 396 | int (*mode)(const char *, int *); 397 | int (*channel)(const char *, int *); 398 | int (*center_chan1)(const char *, int *); 399 | int (*center_chan2)(const char *, int *); 400 | int (*frequency)(const char *, int *); 401 | int (*frequency_offset)(const char *, int *); 402 | int (*txpower)(const char *, int *); 403 | int (*txpower_offset)(const char *, int *); 404 | int (*bitrate)(const char *, int *); 405 | int (*signal)(const char *, int *); 406 | int (*noise)(const char *, int *); 407 | int (*quality)(const char *, int *); 408 | int (*quality_max)(const char *, int *); 409 | int (*mbssid_support)(const char *, int *); 410 | int (*hwmodelist)(const char *, int *); 411 | int (*htmodelist)(const char *, int *); 412 | int (*htmode)(const char *, int *); 413 | int (*ssid)(const char *, char *); 414 | int (*bssid)(const char *, char *); 415 | int (*country)(const char *, char *); 416 | int (*hardware_id)(const char *, char *); 417 | int (*hardware_name)(const char *, char *); 418 | int (*encryption)(const char *, char *); 419 | int (*phyname)(const char *, char *); 420 | int (*assoclist)(const char *, char *, int *); 421 | int (*txpwrlist)(const char *, char *, int *); 422 | int (*scanlist)(const char *, char *, int *); 423 | int (*freqlist)(const char *, char *, int *); 424 | int (*countrylist)(const char *, char *, int *); 425 | int (*survey)(const char *, char *, int *); 426 | int (*lookup_phy)(const char *, char *); 427 | int (*phy_path)(const char *phyname, const char **path); 428 | void (*close)(void); 429 | }; 430 | 431 | const char * iwinfo_type(const char *ifname); 432 | const struct iwinfo_ops * iwinfo_backend(const char *ifname); 433 | const struct iwinfo_ops * iwinfo_backend_by_name(const char *name); 434 | void iwinfo_finish(void); 435 | 436 | extern const struct iwinfo_ops wext_ops; 437 | extern const struct iwinfo_ops madwifi_ops; 438 | extern const struct iwinfo_ops nl80211_ops; 439 | extern const struct iwinfo_ops wl_ops; 440 | 441 | #include "iwinfo/utils.h" 442 | 443 | #endif 444 | -------------------------------------------------------------------------------- /iwinfo_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Lua Bindings 3 | * 4 | * Copyright (C) 2009-2013 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #include "iwinfo.h" 20 | 21 | 22 | /* 23 | * name constants 24 | */ 25 | const char * const IWINFO_80211_NAMES[IWINFO_80211_COUNT] = { 26 | "a", 27 | "b", 28 | "g", 29 | "n", 30 | "ac", 31 | "ad", 32 | "ax", 33 | "be", 34 | }; 35 | 36 | const char * const IWINFO_BAND_NAMES[IWINFO_BAND_COUNT] = { 37 | "2.4 GHz", 38 | "5 GHz", 39 | "6 GHz", 40 | "60 GHz", 41 | }; 42 | 43 | const char * const IWINFO_CIPHER_NAMES[IWINFO_CIPHER_COUNT] = { 44 | "NONE", 45 | "WEP-40", 46 | "TKIP", 47 | "WRAP", 48 | "CCMP", 49 | "WEP-104", 50 | "AES-OCB", 51 | "CKIP", 52 | "GCMP", 53 | "CCMP-256", 54 | "GCMP-256", 55 | }; 56 | 57 | const char * const IWINFO_KMGMT_NAMES[IWINFO_KMGMT_COUNT] = { 58 | "NONE", 59 | "802.1X", 60 | "PSK", 61 | "SAE", 62 | "OWE", 63 | }; 64 | 65 | const char * const IWINFO_AUTH_NAMES[IWINFO_AUTH_COUNT] = { 66 | "OPEN", 67 | "SHARED", 68 | }; 69 | 70 | const char * const IWINFO_OPMODE_NAMES[IWINFO_OPMODE_COUNT] = { 71 | "Unknown", 72 | "Master", 73 | "Ad-Hoc", 74 | "Client", 75 | "Monitor", 76 | "Master (VLAN)", 77 | "WDS", 78 | "Mesh Point", 79 | "P2P Client", 80 | "P2P Go", 81 | }; 82 | 83 | const char * const IWINFO_HTMODE_NAMES[IWINFO_HTMODE_COUNT] = { 84 | "HT20", 85 | "HT40", 86 | "VHT20", 87 | "VHT40", 88 | "VHT80", 89 | "VHT80+80", 90 | "VHT160", 91 | "NOHT", 92 | "HE20", 93 | "HE40", 94 | "HE80", 95 | "HE80+80", 96 | "HE160", 97 | "EHT20", 98 | "EHT40", 99 | "EHT80", 100 | "EHT80+80", 101 | "EHT160", 102 | "EHT320", 103 | }; 104 | 105 | const char * const IWINFO_FREQ_FLAG_NAMES[IWINFO_FREQ_FLAG_COUNT] = { 106 | "NO_10MHZ", 107 | "NO_20MHZ", 108 | "NO_HT40+", 109 | "NO_HT40-", 110 | "NO_80MHZ", 111 | "NO_160MHZ", 112 | "NO_HE", 113 | "NO_IR", 114 | "INDOOR_ONLY", 115 | }; 116 | 117 | const char * const ht_secondary_offset[4] = { 118 | "no secondary", 119 | "above", 120 | "[reserved!]", 121 | "below", 122 | }; 123 | 124 | const uint16_t ht_chan_width[2] = { 125 | 20, 126 | 2040, 127 | }; 128 | 129 | const uint16_t vht_chan_width[4] = { 130 | 40, /* 40 MHz or lower (refer to ht to a more precise width) */ 131 | 80, /* 80 MHz */ 132 | 160, /* 160 MHz */ 133 | 8080, /* 80+80 MHz */ 134 | }; 135 | 136 | const uint16_t eht_chan_width[5] = { 137 | 20, /* 20 MHz */ 138 | 40, /* 40 MHz */ 139 | 80, /* 80 MHz */ 140 | 160, /* 80+80 or 160 MHz */ 141 | 320, /* 160+160 or 320 MHz */ 142 | }; 143 | 144 | /* 145 | * ISO3166 country labels 146 | */ 147 | 148 | const struct iwinfo_iso3166_label IWINFO_ISO3166_NAMES[] = { 149 | { 0x3030 /* 00 */, "World" }, 150 | { 0x4144 /* AD */, "Andorra" }, 151 | { 0x4145 /* AE */, "United Arab Emirates" }, 152 | { 0x4146 /* AF */, "Afghanistan" }, 153 | { 0x4147 /* AG */, "Antigua and Barbuda" }, 154 | { 0x4149 /* AI */, "Anguilla" }, 155 | { 0x414C /* AL */, "Albania" }, 156 | { 0x414D /* AM */, "Armenia" }, 157 | { 0x414E /* AN */, "Netherlands Antilles" }, 158 | { 0x414F /* AO */, "Angola" }, 159 | { 0x4151 /* AQ */, "Antarctica" }, 160 | { 0x4152 /* AR */, "Argentina" }, 161 | { 0x4153 /* AS */, "American Samoa" }, 162 | { 0x4154 /* AT */, "Austria" }, 163 | { 0x4155 /* AU */, "Australia" }, 164 | { 0x4157 /* AW */, "Aruba" }, 165 | { 0x4158 /* AX */, "Aland Islands" }, 166 | { 0x415A /* AZ */, "Azerbaijan" }, 167 | { 0x4241 /* BA */, "Bosnia and Herzegovina" }, 168 | { 0x4242 /* BB */, "Barbados" }, 169 | { 0x4244 /* BD */, "Bangladesh" }, 170 | { 0x4245 /* BE */, "Belgium" }, 171 | { 0x4246 /* BF */, "Burkina Faso" }, 172 | { 0x4247 /* BG */, "Bulgaria" }, 173 | { 0x4248 /* BH */, "Bahrain" }, 174 | { 0x4249 /* BI */, "Burundi" }, 175 | { 0x424A /* BJ */, "Benin" }, 176 | { 0x424C /* BL */, "Saint Barthelemy" }, 177 | { 0x424D /* BM */, "Bermuda" }, 178 | { 0x424E /* BN */, "Brunei Darussalam" }, 179 | { 0x424F /* BO */, "Bolivia" }, 180 | { 0x4252 /* BR */, "Brazil" }, 181 | { 0x4253 /* BS */, "Bahamas" }, 182 | { 0x4254 /* BT */, "Bhutan" }, 183 | { 0x4256 /* BV */, "Bouvet Island" }, 184 | { 0x4257 /* BW */, "Botswana" }, 185 | { 0x4259 /* BY */, "Belarus" }, 186 | { 0x425A /* BZ */, "Belize" }, 187 | { 0x4341 /* CA */, "Canada" }, 188 | { 0x4343 /* CC */, "Cocos (Keeling) Islands" }, 189 | { 0x4344 /* CD */, "Congo" }, 190 | { 0x4346 /* CF */, "Central African Republic" }, 191 | { 0x4347 /* CG */, "Congo" }, 192 | { 0x4348 /* CH */, "Switzerland" }, 193 | { 0x4349 /* CI */, "Cote d'Ivoire" }, 194 | { 0x434B /* CK */, "Cook Islands" }, 195 | { 0x434C /* CL */, "Chile" }, 196 | { 0x434D /* CM */, "Cameroon" }, 197 | { 0x434E /* CN */, "China" }, 198 | { 0x434F /* CO */, "Colombia" }, 199 | { 0x4352 /* CR */, "Costa Rica" }, 200 | { 0x4355 /* CU */, "Cuba" }, 201 | { 0x4356 /* CV */, "Cape Verde" }, 202 | { 0x4358 /* CX */, "Christmas Island" }, 203 | { 0x4359 /* CY */, "Cyprus" }, 204 | { 0x435A /* CZ */, "Czech Republic" }, 205 | { 0x4445 /* DE */, "Germany" }, 206 | { 0x444A /* DJ */, "Djibouti" }, 207 | { 0x444B /* DK */, "Denmark" }, 208 | { 0x444D /* DM */, "Dominica" }, 209 | { 0x444F /* DO */, "Dominican Republic" }, 210 | { 0x445A /* DZ */, "Algeria" }, 211 | { 0x4543 /* EC */, "Ecuador" }, 212 | { 0x4545 /* EE */, "Estonia" }, 213 | { 0x4547 /* EG */, "Egypt" }, 214 | { 0x4548 /* EH */, "Western Sahara" }, 215 | { 0x4552 /* ER */, "Eritrea" }, 216 | { 0x4553 /* ES */, "Spain" }, 217 | { 0x4554 /* ET */, "Ethiopia" }, 218 | { 0x4649 /* FI */, "Finland" }, 219 | { 0x464A /* FJ */, "Fiji" }, 220 | { 0x464B /* FK */, "Falkland Islands" }, 221 | { 0x464D /* FM */, "Micronesia" }, 222 | { 0x464F /* FO */, "Faroe Islands" }, 223 | { 0x4652 /* FR */, "France" }, 224 | { 0x4741 /* GA */, "Gabon" }, 225 | { 0x4742 /* GB */, "United Kingdom" }, 226 | { 0x4744 /* GD */, "Grenada" }, 227 | { 0x4745 /* GE */, "Georgia" }, 228 | { 0x4746 /* GF */, "French Guiana" }, 229 | { 0x4747 /* GG */, "Guernsey" }, 230 | { 0x4748 /* GH */, "Ghana" }, 231 | { 0x4749 /* GI */, "Gibraltar" }, 232 | { 0x474C /* GL */, "Greenland" }, 233 | { 0x474D /* GM */, "Gambia" }, 234 | { 0x474E /* GN */, "Guinea" }, 235 | { 0x4750 /* GP */, "Guadeloupe" }, 236 | { 0x4751 /* GQ */, "Equatorial Guinea" }, 237 | { 0x4752 /* GR */, "Greece" }, 238 | { 0x4753 /* GS */, "South Georgia" }, 239 | { 0x4754 /* GT */, "Guatemala" }, 240 | { 0x4755 /* GU */, "Guam" }, 241 | { 0x4757 /* GW */, "Guinea-Bissau" }, 242 | { 0x4759 /* GY */, "Guyana" }, 243 | { 0x484B /* HK */, "Hong Kong" }, 244 | { 0x484D /* HM */, "Heard and McDonald Islands" }, 245 | { 0x484E /* HN */, "Honduras" }, 246 | { 0x4852 /* HR */, "Croatia" }, 247 | { 0x4854 /* HT */, "Haiti" }, 248 | { 0x4855 /* HU */, "Hungary" }, 249 | { 0x4944 /* ID */, "Indonesia" }, 250 | { 0x4945 /* IE */, "Ireland" }, 251 | { 0x494C /* IL */, "Israel" }, 252 | { 0x494D /* IM */, "Isle of Man" }, 253 | { 0x494E /* IN */, "India" }, 254 | { 0x494F /* IO */, "Chagos Islands" }, 255 | { 0x4951 /* IQ */, "Iraq" }, 256 | { 0x4952 /* IR */, "Iran" }, 257 | { 0x4953 /* IS */, "Iceland" }, 258 | { 0x4954 /* IT */, "Italy" }, 259 | { 0x4A45 /* JE */, "Jersey" }, 260 | { 0x4A4D /* JM */, "Jamaica" }, 261 | { 0x4A4F /* JO */, "Jordan" }, 262 | { 0x4A50 /* JP */, "Japan" }, 263 | { 0x4B45 /* KE */, "Kenya" }, 264 | { 0x4B47 /* KG */, "Kyrgyzstan" }, 265 | { 0x4B48 /* KH */, "Cambodia" }, 266 | { 0x4B49 /* KI */, "Kiribati" }, 267 | { 0x4B4D /* KM */, "Comoros" }, 268 | { 0x4B4E /* KN */, "Saint Kitts and Nevis" }, 269 | { 0x4B50 /* KP */, "North Korea" }, 270 | { 0x4B52 /* KR */, "South Korea" }, 271 | { 0x4B57 /* KW */, "Kuwait" }, 272 | { 0x4B59 /* KY */, "Cayman Islands" }, 273 | { 0x4B5A /* KZ */, "Kazakhstan" }, 274 | { 0x4C41 /* LA */, "Laos" }, 275 | { 0x4C42 /* LB */, "Lebanon" }, 276 | { 0x4C43 /* LC */, "Saint Lucia" }, 277 | { 0x4C49 /* LI */, "Liechtenstein" }, 278 | { 0x4C4B /* LK */, "Sri Lanka" }, 279 | { 0x4C52 /* LR */, "Liberia" }, 280 | { 0x4C53 /* LS */, "Lesotho" }, 281 | { 0x4C54 /* LT */, "Lithuania" }, 282 | { 0x4C55 /* LU */, "Luxembourg" }, 283 | { 0x4C56 /* LV */, "Latvia" }, 284 | { 0x4C59 /* LY */, "Libyan Arab Jamahiriya" }, 285 | { 0x4D41 /* MA */, "Morocco" }, 286 | { 0x4D43 /* MC */, "Monaco" }, 287 | { 0x4D44 /* MD */, "Moldova" }, 288 | { 0x4D45 /* ME */, "Montenegro" }, 289 | { 0x4D46 /* MF */, "Saint Martin (French part)" }, 290 | { 0x4D47 /* MG */, "Madagascar" }, 291 | { 0x4D48 /* MH */, "Marshall Islands" }, 292 | { 0x4D4B /* MK */, "Macedonia" }, 293 | { 0x4D4C /* ML */, "Mali" }, 294 | { 0x4D4D /* MM */, "Myanmar" }, 295 | { 0x4D4E /* MN */, "Mongolia" }, 296 | { 0x4D4F /* MO */, "Macao" }, 297 | { 0x4D50 /* MP */, "Northern Mariana Islands" }, 298 | { 0x4D51 /* MQ */, "Martinique" }, 299 | { 0x4D52 /* MR */, "Mauritania" }, 300 | { 0x4D53 /* MS */, "Montserrat" }, 301 | { 0x4D54 /* MT */, "Malta" }, 302 | { 0x4D55 /* MU */, "Mauritius" }, 303 | { 0x4D56 /* MV */, "Maldives" }, 304 | { 0x4D57 /* MW */, "Malawi" }, 305 | { 0x4D58 /* MX */, "Mexico" }, 306 | { 0x4D59 /* MY */, "Malaysia" }, 307 | { 0x4D5A /* MZ */, "Mozambique" }, 308 | { 0x4E41 /* NA */, "Namibia" }, 309 | { 0x4E43 /* NC */, "New Caledonia" }, 310 | { 0x4E45 /* NE */, "Niger" }, 311 | { 0x4E46 /* NF */, "Norfolk Island" }, 312 | { 0x4E47 /* NG */, "Nigeria" }, 313 | { 0x4E49 /* NI */, "Nicaragua" }, 314 | { 0x4E4C /* NL */, "Netherlands" }, 315 | { 0x4E4F /* NO */, "Norway" }, 316 | { 0x4E50 /* NP */, "Nepal" }, 317 | { 0x4E52 /* NR */, "Nauru" }, 318 | { 0x4E55 /* NU */, "Niue" }, 319 | { 0x4E5A /* NZ */, "New Zealand" }, 320 | { 0x4F4D /* OM */, "Oman" }, 321 | { 0x5041 /* PA */, "Panama" }, 322 | { 0x5045 /* PE */, "Peru" }, 323 | { 0x5046 /* PF */, "French Polynesia" }, 324 | { 0x5047 /* PG */, "Papua New Guinea" }, 325 | { 0x5048 /* PH */, "Philippines" }, 326 | { 0x504B /* PK */, "Pakistan" }, 327 | { 0x504C /* PL */, "Poland" }, 328 | { 0x504D /* PM */, "Saint Pierre and Miquelon" }, 329 | { 0x504E /* PN */, "Pitcairn" }, 330 | { 0x5052 /* PR */, "Puerto Rico" }, 331 | { 0x5053 /* PS */, "Palestinian Territory" }, 332 | { 0x5054 /* PT */, "Portugal" }, 333 | { 0x5057 /* PW */, "Palau" }, 334 | { 0x5059 /* PY */, "Paraguay" }, 335 | { 0x5141 /* QA */, "Qatar" }, 336 | { 0x5245 /* RE */, "Reunion" }, 337 | { 0x524F /* RO */, "Romania" }, 338 | { 0x5253 /* RS */, "Serbia" }, 339 | { 0x5255 /* RU */, "Russian Federation" }, 340 | { 0x5257 /* RW */, "Rwanda" }, 341 | { 0x5341 /* SA */, "Saudi Arabia" }, 342 | { 0x5342 /* SB */, "Solomon Islands" }, 343 | { 0x5343 /* SC */, "Seychelles" }, 344 | { 0x5344 /* SD */, "Sudan" }, 345 | { 0x5345 /* SE */, "Sweden" }, 346 | { 0x5347 /* SG */, "Singapore" }, 347 | { 0x5348 /* SH */, "St. Helena and Dependencies" }, 348 | { 0x5349 /* SI */, "Slovenia" }, 349 | { 0x534A /* SJ */, "Svalbard and Jan Mayen" }, 350 | { 0x534B /* SK */, "Slovakia" }, 351 | { 0x534C /* SL */, "Sierra Leone" }, 352 | { 0x534D /* SM */, "San Marino" }, 353 | { 0x534E /* SN */, "Senegal" }, 354 | { 0x534F /* SO */, "Somalia" }, 355 | { 0x5352 /* SR */, "Suriname" }, 356 | { 0x5354 /* ST */, "Sao Tome and Principe" }, 357 | { 0x5356 /* SV */, "El Salvador" }, 358 | { 0x5359 /* SY */, "Syrian Arab Republic" }, 359 | { 0x535A /* SZ */, "Swaziland" }, 360 | { 0x5443 /* TC */, "Turks and Caicos Islands" }, 361 | { 0x5444 /* TD */, "Chad" }, 362 | { 0x5446 /* TF */, "French Southern Territories" }, 363 | { 0x5447 /* TG */, "Togo" }, 364 | { 0x5448 /* TH */, "Thailand" }, 365 | { 0x544A /* TJ */, "Tajikistan" }, 366 | { 0x544B /* TK */, "Tokelau" }, 367 | { 0x544C /* TL */, "Timor-Leste" }, 368 | { 0x544D /* TM */, "Turkmenistan" }, 369 | { 0x544E /* TN */, "Tunisia" }, 370 | { 0x544F /* TO */, "Tonga" }, 371 | { 0x5452 /* TR */, "Turkey" }, 372 | { 0x5454 /* TT */, "Trinidad and Tobago" }, 373 | { 0x5456 /* TV */, "Tuvalu" }, 374 | { 0x5457 /* TW */, "Taiwan" }, 375 | { 0x545A /* TZ */, "Tanzania" }, 376 | { 0x5541 /* UA */, "Ukraine" }, 377 | { 0x5547 /* UG */, "Uganda" }, 378 | { 0x554D /* UM */, "U.S. Minor Outlying Islands" }, 379 | { 0x5553 /* US */, "United States" }, 380 | { 0x5559 /* UY */, "Uruguay" }, 381 | { 0x555A /* UZ */, "Uzbekistan" }, 382 | { 0x5641 /* VA */, "Vatican City State" }, 383 | { 0x5643 /* VC */, "St. Vincent and Grenadines" }, 384 | { 0x5645 /* VE */, "Venezuela" }, 385 | { 0x5647 /* VG */, "Virgin Islands, British" }, 386 | { 0x5649 /* VI */, "Virgin Islands, U.S." }, 387 | { 0x564E /* VN */, "Viet Nam" }, 388 | { 0x5655 /* VU */, "Vanuatu" }, 389 | { 0x5746 /* WF */, "Wallis and Futuna" }, 390 | { 0x5753 /* WS */, "Samoa" }, 391 | { 0x5945 /* YE */, "Yemen" }, 392 | { 0x5954 /* YT */, "Mayotte" }, 393 | { 0x5A41 /* ZA */, "South Africa" }, 394 | { 0x5A4D /* ZM */, "Zambia" }, 395 | { 0x5A57 /* ZW */, "Zimbabwe" }, 396 | { 0, "" } 397 | }; 398 | 399 | static const struct iwinfo_ops *backends[] = { 400 | #ifdef USE_NL80211 401 | &nl80211_ops, 402 | #endif 403 | #ifdef USE_MADWIFI 404 | &madwifi_ops, 405 | #endif 406 | #ifdef USE_WL 407 | &wl_ops, 408 | #endif 409 | #ifdef USE_WEXT 410 | &wext_ops, 411 | #endif 412 | }; 413 | 414 | const char * iwinfo_type(const char *ifname) 415 | { 416 | const struct iwinfo_ops *ops = iwinfo_backend(ifname); 417 | if (!ops) 418 | return NULL; 419 | 420 | return ops->name; 421 | } 422 | 423 | const struct iwinfo_ops * iwinfo_backend(const char *ifname) 424 | { 425 | int i; 426 | 427 | for (i = 0; i < ARRAY_SIZE(backends); i++) 428 | if (backends[i]->probe(ifname)) 429 | return backends[i]; 430 | 431 | return NULL; 432 | } 433 | 434 | const struct iwinfo_ops * iwinfo_backend_by_name(const char *name) 435 | { 436 | int i; 437 | 438 | for (i = 0; i < ARRAY_SIZE(backends); i++) 439 | if (!strcmp(backends[i]->name, name)) 440 | return backends[i]; 441 | 442 | return NULL; 443 | } 444 | 445 | void iwinfo_finish(void) 446 | { 447 | int i; 448 | 449 | for (i = 0; i < ARRAY_SIZE(backends); i++) 450 | backends[i]->close(); 451 | 452 | iwinfo_close(); 453 | } 454 | -------------------------------------------------------------------------------- /iwinfo_wext.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Linux Wireless Extension Backend 3 | * 4 | * Copyright (C) 2009 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | * 18 | * Parts of this code are derived from the Linux wireless tools, iwlib.c, 19 | * iwlist.c and iwconfig.c in particular. 20 | */ 21 | 22 | #include "iwinfo.h" 23 | #include "iwinfo_wext.h" 24 | 25 | static double wext_freq2float(const struct iw_freq *in) 26 | { 27 | int i; 28 | double res = (double) in->m; 29 | for(i = 0; i < in->e; i++) res *= 10; 30 | return res; 31 | } 32 | 33 | static inline int wext_freq2mhz(const struct iw_freq *in) 34 | { 35 | if( in->e == 6 ) 36 | { 37 | return in->m; 38 | } 39 | else 40 | { 41 | return (int)(wext_freq2float(in) / 1000000); 42 | } 43 | } 44 | 45 | static inline int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq) 46 | { 47 | if( !strncmp(ifname, "mon.", 4) ) 48 | strncpy(wrq->ifr_name, &ifname[4], IFNAMSIZ); 49 | else 50 | strncpy(wrq->ifr_name, ifname, IFNAMSIZ); 51 | 52 | return iwinfo_ioctl(cmd, wrq); 53 | } 54 | 55 | 56 | static int wext_probe(const char *ifname) 57 | { 58 | struct iwreq wrq; 59 | 60 | if(wext_ioctl(ifname, SIOCGIWNAME, &wrq) >= 0) 61 | return 1; 62 | 63 | return 0; 64 | } 65 | 66 | static void wext_close(void) 67 | { 68 | /* Nop */ 69 | } 70 | 71 | static int wext_get_mode(const char *ifname, int *buf) 72 | { 73 | struct iwreq wrq; 74 | 75 | if(wext_ioctl(ifname, SIOCGIWMODE, &wrq) >= 0) 76 | { 77 | switch(wrq.u.mode) 78 | { 79 | case 1: 80 | *buf = IWINFO_OPMODE_ADHOC; 81 | break; 82 | 83 | case 2: 84 | *buf = IWINFO_OPMODE_CLIENT; 85 | break; 86 | 87 | case 3: 88 | *buf = IWINFO_OPMODE_MASTER; 89 | break; 90 | 91 | case 6: 92 | *buf = IWINFO_OPMODE_MONITOR; 93 | break; 94 | 95 | default: 96 | *buf = IWINFO_OPMODE_UNKNOWN; 97 | break; 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | return -1; 104 | } 105 | 106 | static int wext_get_ssid(const char *ifname, char *buf) 107 | { 108 | struct iwreq wrq; 109 | 110 | wrq.u.essid.pointer = (caddr_t) buf; 111 | wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1; 112 | wrq.u.essid.flags = 0; 113 | 114 | if(wext_ioctl(ifname, SIOCGIWESSID, &wrq) >= 0) 115 | return 0; 116 | 117 | return -1; 118 | } 119 | 120 | static int wext_get_bssid(const char *ifname, char *buf) 121 | { 122 | struct iwreq wrq; 123 | 124 | if(wext_ioctl(ifname, SIOCGIWAP, &wrq) >= 0) 125 | { 126 | sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", 127 | (uint8_t)wrq.u.ap_addr.sa_data[0], (uint8_t)wrq.u.ap_addr.sa_data[1], 128 | (uint8_t)wrq.u.ap_addr.sa_data[2], (uint8_t)wrq.u.ap_addr.sa_data[3], 129 | (uint8_t)wrq.u.ap_addr.sa_data[4], (uint8_t)wrq.u.ap_addr.sa_data[5]); 130 | 131 | return 0; 132 | } 133 | 134 | return -1; 135 | } 136 | 137 | static int wext_get_bitrate(const char *ifname, int *buf) 138 | { 139 | struct iwreq wrq; 140 | 141 | if(wext_ioctl(ifname, SIOCGIWRATE, &wrq) >= 0) 142 | { 143 | *buf = (wrq.u.bitrate.value / 1000); 144 | return 0; 145 | } 146 | 147 | return -1; 148 | } 149 | 150 | static int wext_get_channel(const char *ifname, int *buf) 151 | { 152 | struct iwreq wrq; 153 | struct iw_range range; 154 | double freq; 155 | int i; 156 | 157 | if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0) 158 | { 159 | if( wrq.u.freq.m >= 1000 ) 160 | { 161 | freq = wext_freq2float(&wrq.u.freq); 162 | wrq.u.data.pointer = (caddr_t) ⦥ 163 | wrq.u.data.length = sizeof(struct iw_range); 164 | wrq.u.data.flags = 0; 165 | 166 | if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) 167 | { 168 | for(i = 0; i < range.num_frequency; i++) 169 | { 170 | if( wext_freq2float(&range.freq[i]) == freq ) 171 | { 172 | *buf = range.freq[i].i; 173 | return 0; 174 | } 175 | } 176 | } 177 | } 178 | else 179 | { 180 | *buf = wrq.u.freq.m; 181 | return 0; 182 | } 183 | } 184 | 185 | return -1; 186 | } 187 | 188 | static int wext_get_center_chan1(const char *ifname, int *buf) 189 | { 190 | /* Not Supported */ 191 | return -1; 192 | } 193 | 194 | static int wext_get_center_chan2(const char *ifname, int *buf) 195 | { 196 | /* Not Supported */ 197 | return -1; 198 | } 199 | 200 | static int wext_get_frequency(const char *ifname, int *buf) 201 | { 202 | struct iwreq wrq; 203 | struct iw_range range; 204 | int i, channel; 205 | 206 | if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0) 207 | { 208 | /* We got a channel number instead ... */ 209 | if( wrq.u.freq.m < 1000 ) 210 | { 211 | channel = wrq.u.freq.m; 212 | wrq.u.data.pointer = (caddr_t) ⦥ 213 | wrq.u.data.length = sizeof(struct iw_range); 214 | wrq.u.data.flags = 0; 215 | 216 | if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) 217 | { 218 | for(i = 0; i < range.num_frequency; i++) 219 | { 220 | if( range.freq[i].i == channel ) 221 | { 222 | *buf = wext_freq2mhz(&range.freq[i]); 223 | return 0; 224 | } 225 | } 226 | } 227 | } 228 | else 229 | { 230 | *buf = wext_freq2mhz(&wrq.u.freq); 231 | return 0; 232 | } 233 | } 234 | 235 | return -1; 236 | } 237 | 238 | static int wext_get_txpower(const char *ifname, int *buf) 239 | { 240 | struct iwreq wrq; 241 | 242 | wrq.u.txpower.flags = 0; 243 | 244 | if(wext_ioctl(ifname, SIOCGIWTXPOW, &wrq) >= 0) 245 | { 246 | if(wrq.u.txpower.flags & IW_TXPOW_MWATT) 247 | *buf = iwinfo_mw2dbm(wrq.u.txpower.value); 248 | else 249 | *buf = wrq.u.txpower.value; 250 | 251 | return 0; 252 | } 253 | 254 | return -1; 255 | } 256 | 257 | static int wext_get_signal(const char *ifname, int *buf) 258 | { 259 | struct iwreq wrq; 260 | struct iw_statistics stats; 261 | 262 | wrq.u.data.pointer = (caddr_t) &stats; 263 | wrq.u.data.length = sizeof(struct iw_statistics); 264 | wrq.u.data.flags = 1; 265 | 266 | if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0) 267 | { 268 | *buf = (stats.qual.updated & IW_QUAL_DBM) 269 | ? (stats.qual.level - 0x100) : stats.qual.level; 270 | 271 | return 0; 272 | } 273 | 274 | return -1; 275 | } 276 | 277 | static int wext_get_noise(const char *ifname, int *buf) 278 | { 279 | struct iwreq wrq; 280 | struct iw_statistics stats; 281 | 282 | wrq.u.data.pointer = (caddr_t) &stats; 283 | wrq.u.data.length = sizeof(struct iw_statistics); 284 | wrq.u.data.flags = 1; 285 | 286 | if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0) 287 | { 288 | *buf = (stats.qual.updated & IW_QUAL_DBM) 289 | ? (stats.qual.noise - 0x100) : stats.qual.noise; 290 | 291 | return 0; 292 | } 293 | 294 | return -1; 295 | } 296 | 297 | static int wext_get_quality(const char *ifname, int *buf) 298 | { 299 | struct iwreq wrq; 300 | struct iw_statistics stats; 301 | 302 | wrq.u.data.pointer = (caddr_t) &stats; 303 | wrq.u.data.length = sizeof(struct iw_statistics); 304 | wrq.u.data.flags = 1; 305 | 306 | if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0) 307 | { 308 | *buf = stats.qual.qual; 309 | return 0; 310 | } 311 | 312 | return -1; 313 | } 314 | 315 | static int wext_get_quality_max(const char *ifname, int *buf) 316 | { 317 | struct iwreq wrq; 318 | struct iw_range range; 319 | 320 | wrq.u.data.pointer = (caddr_t) ⦥ 321 | wrq.u.data.length = sizeof(struct iw_range); 322 | wrq.u.data.flags = 0; 323 | 324 | if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) 325 | { 326 | *buf = range.max_qual.qual; 327 | return 0; 328 | } 329 | 330 | return -1; 331 | } 332 | 333 | static int wext_get_assoclist(const char *ifname, char *buf, int *len) 334 | { 335 | /* Stub */ 336 | return -1; 337 | } 338 | 339 | static int wext_get_txpwrlist(const char *ifname, char *buf, int *len) 340 | { 341 | struct iwreq wrq; 342 | struct iw_range range; 343 | struct iwinfo_txpwrlist_entry entry; 344 | int i; 345 | 346 | wrq.u.data.pointer = (caddr_t) ⦥ 347 | wrq.u.data.length = sizeof(struct iw_range); 348 | wrq.u.data.flags = 0; 349 | 350 | if( (wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) && 351 | (range.num_txpower > 0) && (range.num_txpower <= IW_MAX_TXPOWER) && 352 | !(range.txpower_capa & IW_TXPOW_RELATIVE) 353 | ) { 354 | for( i = 0; i < range.num_txpower; i++ ) 355 | { 356 | if( range.txpower_capa & IW_TXPOW_MWATT ) 357 | { 358 | entry.dbm = iwinfo_mw2dbm(range.txpower[i]); 359 | entry.mw = range.txpower[i]; 360 | } 361 | 362 | /* Madwifi does neither set mW not dBm caps, also iwlist assumes 363 | * dBm if mW is not set, so don't check here... */ 364 | else /* if( range.txpower_capa & IW_TXPOW_DBM ) */ 365 | { 366 | entry.dbm = range.txpower[i]; 367 | entry.mw = iwinfo_dbm2mw(range.txpower[i]); 368 | } 369 | 370 | memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry)); 371 | } 372 | 373 | *len = i * sizeof(entry); 374 | return 0; 375 | } 376 | 377 | return -1; 378 | } 379 | 380 | static int wext_get_freqlist(const char *ifname, char *buf, int *len) 381 | { 382 | struct iwreq wrq; 383 | struct iw_range range; 384 | struct iwinfo_freqlist_entry entry; 385 | int i, bl; 386 | 387 | wrq.u.data.pointer = (caddr_t) ⦥ 388 | wrq.u.data.length = sizeof(struct iw_range); 389 | wrq.u.data.flags = 0; 390 | 391 | if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) 392 | { 393 | bl = 0; 394 | 395 | for(i = 0; i < range.num_frequency; i++) 396 | { 397 | entry.mhz = wext_freq2mhz(&range.freq[i]); 398 | entry.channel = range.freq[i].i; 399 | entry.restricted = 0; 400 | 401 | memcpy(&buf[bl], &entry, sizeof(struct iwinfo_freqlist_entry)); 402 | bl += sizeof(struct iwinfo_freqlist_entry); 403 | } 404 | 405 | *len = bl; 406 | return 0; 407 | } 408 | 409 | return -1; 410 | } 411 | 412 | static int wext_get_country(const char *ifname, char *buf) 413 | { 414 | sprintf(buf, "00"); 415 | return 0; 416 | } 417 | 418 | static int wext_get_countrylist(const char *ifname, char *buf, int *len) 419 | { 420 | /* Stub */ 421 | return -1; 422 | } 423 | 424 | static int wext_get_hwmodelist(const char *ifname, int *buf) 425 | { 426 | char chans[IWINFO_BUFSIZE] = { 0 }; 427 | struct iwinfo_freqlist_entry *e = NULL; 428 | int len = 0; 429 | 430 | *buf = 0; 431 | 432 | if( !wext_get_freqlist(ifname, chans, &len) ) 433 | { 434 | for( e = (struct iwinfo_freqlist_entry *)chans; e->channel; e++ ) 435 | { 436 | if( e->channel <= 14 ) 437 | { 438 | *buf |= IWINFO_80211_B; 439 | *buf |= IWINFO_80211_G; 440 | } 441 | else 442 | { 443 | *buf |= IWINFO_80211_A; 444 | } 445 | } 446 | 447 | return 0; 448 | } 449 | 450 | return -1; 451 | } 452 | 453 | static int wext_get_htmodelist(const char *ifname, int *buf) 454 | { 455 | /* Stub */ 456 | return -1; 457 | } 458 | 459 | static int wext_get_encryption(const char *ifname, char *buf) 460 | { 461 | /* No reliable crypto info in wext */ 462 | return -1; 463 | } 464 | 465 | static int wext_get_phyname(const char *ifname, char *buf) 466 | { 467 | /* No suitable api in wext */ 468 | strcpy(buf, ifname); 469 | return 0; 470 | } 471 | 472 | static int wext_get_mbssid_support(const char *ifname, int *buf) 473 | { 474 | /* No multi bssid support atm */ 475 | return -1; 476 | } 477 | 478 | static char * wext_sysfs_ifname_file(const char *ifname, const char *path) 479 | { 480 | FILE *f; 481 | static char buf[128]; 482 | char *rv = NULL; 483 | 484 | snprintf(buf, sizeof(buf), "/sys/class/net/%s/%s", ifname, path); 485 | 486 | if ((f = fopen(buf, "r")) != NULL) 487 | { 488 | memset(buf, 0, sizeof(buf)); 489 | 490 | if (fread(buf, 1, sizeof(buf), f)) 491 | rv = buf; 492 | 493 | fclose(f); 494 | } 495 | 496 | return rv; 497 | } 498 | 499 | static int wext_get_hardware_id(const char *ifname, char *buf) 500 | { 501 | char *data; 502 | struct iwinfo_hardware_id *id = (struct iwinfo_hardware_id *)buf; 503 | 504 | memset(id, 0, sizeof(struct iwinfo_hardware_id)); 505 | 506 | data = wext_sysfs_ifname_file(ifname, "device/vendor"); 507 | if (data) 508 | id->vendor_id = strtoul(data, NULL, 16); 509 | 510 | data = wext_sysfs_ifname_file(ifname, "device/device"); 511 | if (data) 512 | id->device_id = strtoul(data, NULL, 16); 513 | 514 | data = wext_sysfs_ifname_file(ifname, "device/subsystem_device"); 515 | if (data) 516 | id->subsystem_device_id = strtoul(data, NULL, 16); 517 | 518 | data = wext_sysfs_ifname_file(ifname, "device/subsystem_vendor"); 519 | if (data) 520 | id->subsystem_vendor_id = strtoul(data, NULL, 16); 521 | 522 | return (id->vendor_id > 0 && id->device_id > 0) ? 0 : -1; 523 | } 524 | 525 | static int wext_get_hardware_name(const char *ifname, char *buf) 526 | { 527 | sprintf(buf, "Generic WEXT"); 528 | return 0; 529 | } 530 | 531 | static int wext_get_txpower_offset(const char *ifname, int *buf) 532 | { 533 | /* Stub */ 534 | *buf = 0; 535 | return -1; 536 | } 537 | 538 | static int wext_get_frequency_offset(const char *ifname, int *buf) 539 | { 540 | /* Stub */ 541 | *buf = 0; 542 | return -1; 543 | } 544 | 545 | const struct iwinfo_ops wext_ops = { 546 | .name = "wext", 547 | .probe = wext_probe, 548 | .channel = wext_get_channel, 549 | .center_chan1 = wext_get_center_chan1, 550 | .center_chan2 = wext_get_center_chan2, 551 | .frequency = wext_get_frequency, 552 | .frequency_offset = wext_get_frequency_offset, 553 | .txpower = wext_get_txpower, 554 | .txpower_offset = wext_get_txpower_offset, 555 | .bitrate = wext_get_bitrate, 556 | .signal = wext_get_signal, 557 | .noise = wext_get_noise, 558 | .quality = wext_get_quality, 559 | .quality_max = wext_get_quality_max, 560 | .mbssid_support = wext_get_mbssid_support, 561 | .hwmodelist = wext_get_hwmodelist, 562 | .htmodelist = wext_get_htmodelist, 563 | .mode = wext_get_mode, 564 | .ssid = wext_get_ssid, 565 | .bssid = wext_get_bssid, 566 | .country = wext_get_country, 567 | .hardware_id = wext_get_hardware_id, 568 | .hardware_name = wext_get_hardware_name, 569 | .encryption = wext_get_encryption, 570 | .phyname = wext_get_phyname, 571 | .assoclist = wext_get_assoclist, 572 | .txpwrlist = wext_get_txpwrlist, 573 | .scanlist = wext_get_scanlist, 574 | .freqlist = wext_get_freqlist, 575 | .countrylist = wext_get_countrylist, 576 | .close = wext_close 577 | }; 578 | -------------------------------------------------------------------------------- /iwinfo_wext_scan.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Linux Wireless Extension Backend 3 | * 4 | * Copyright (C) 2009-2010 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | * 18 | * Parts of this code are derived from the Linux wireless tools, iwlib.c, 19 | * iwlist.c and iwconfig.c in particular. 20 | */ 21 | 22 | #include "iwinfo.h" 23 | #include "iwinfo_wext.h" 24 | 25 | 26 | static int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq) 27 | { 28 | strncpy(wrq->ifr_name, ifname, IFNAMSIZ - 1); 29 | return iwinfo_ioctl(cmd, wrq); 30 | } 31 | 32 | static inline double wext_freq2float(const struct iw_freq *in) 33 | { 34 | int i; 35 | double res = (double) in->m; 36 | for(i = 0; i < in->e; i++) res *= 10; 37 | return res; 38 | } 39 | 40 | static inline int wext_extract_event(struct stream_descr *stream, struct iw_event *iwe, int wev) 41 | { 42 | const struct iw_ioctl_description *descr = NULL; 43 | int event_type = 0; 44 | unsigned int event_len = 1; 45 | char *pointer; 46 | unsigned cmd_index; /* *MUST* be unsigned */ 47 | 48 | /* Check for end of stream */ 49 | if((stream->current + IW_EV_LCP_PK_LEN) > stream->end) 50 | return 0; 51 | 52 | /* Extract the event header (to get the event id). 53 | * Note : the event may be unaligned, therefore copy... */ 54 | memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN); 55 | 56 | /* Check invalid events */ 57 | if(iwe->len <= IW_EV_LCP_PK_LEN) 58 | return -1; 59 | 60 | /* Get the type and length of that event */ 61 | if(iwe->cmd <= SIOCIWLAST) 62 | { 63 | cmd_index = iwe->cmd - SIOCIWFIRST; 64 | if(cmd_index < standard_ioctl_num) 65 | descr = &(standard_ioctl_descr[cmd_index]); 66 | } 67 | else 68 | { 69 | cmd_index = iwe->cmd - IWEVFIRST; 70 | if(cmd_index < standard_event_num) 71 | descr = &(standard_event_descr[cmd_index]); 72 | } 73 | 74 | if(descr != NULL) 75 | event_type = descr->header_type; 76 | 77 | /* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */ 78 | event_len = event_type_size[event_type]; 79 | 80 | /* Fixup for earlier version of WE */ 81 | if((wev <= 18) && (event_type == IW_HEADER_TYPE_POINT)) 82 | event_len += IW_EV_POINT_OFF; 83 | 84 | /* Check if we know about this event */ 85 | if(event_len <= IW_EV_LCP_PK_LEN) 86 | { 87 | /* Skip to next event */ 88 | stream->current += iwe->len; 89 | return 2; 90 | } 91 | 92 | event_len -= IW_EV_LCP_PK_LEN; 93 | 94 | /* Set pointer on data */ 95 | if(stream->value != NULL) 96 | pointer = stream->value; /* Next value in event */ 97 | else 98 | pointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */ 99 | 100 | /* Copy the rest of the event (at least, fixed part) */ 101 | if((pointer + event_len) > stream->end) 102 | { 103 | /* Go to next event */ 104 | stream->current += iwe->len; 105 | return -2; 106 | } 107 | 108 | /* Fixup for WE-19 and later : pointer no longer in the stream */ 109 | /* Beware of alignement. Dest has local alignement, not packed */ 110 | if( (wev > 18) && (event_type == IW_HEADER_TYPE_POINT) ) 111 | memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, pointer, event_len); 112 | else 113 | memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len); 114 | 115 | /* Skip event in the stream */ 116 | pointer += event_len; 117 | 118 | /* Special processing for iw_point events */ 119 | if(event_type == IW_HEADER_TYPE_POINT) 120 | { 121 | /* Check the length of the payload */ 122 | unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN); 123 | if(extra_len > 0) 124 | { 125 | /* Set pointer on variable part (warning : non aligned) */ 126 | iwe->u.data.pointer = pointer; 127 | 128 | /* Check that we have a descriptor for the command */ 129 | if(descr == NULL) 130 | /* Can't check payload -> unsafe... */ 131 | iwe->u.data.pointer = NULL; /* Discard paylod */ 132 | else 133 | { 134 | /* Those checks are actually pretty hard to trigger, 135 | * because of the checks done in the kernel... */ 136 | 137 | unsigned int token_len = iwe->u.data.length * descr->token_size; 138 | 139 | /* Ugly fixup for alignement issues. 140 | * If the kernel is 64 bits and userspace 32 bits, 141 | * we have an extra 4+4 bytes. 142 | * Fixing that in the kernel would break 64 bits userspace. */ 143 | if((token_len != extra_len) && (extra_len >= 4)) 144 | { 145 | uint16_t alt_dlen = *((uint16_t *) pointer); 146 | unsigned int alt_token_len = alt_dlen * descr->token_size; 147 | if((alt_token_len + 8) == extra_len) 148 | { 149 | /* Ok, let's redo everything */ 150 | pointer -= event_len; 151 | pointer += 4; 152 | /* Dest has local alignement, not packed */ 153 | memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, pointer, event_len); 154 | pointer += event_len + 4; 155 | iwe->u.data.pointer = pointer; 156 | token_len = alt_token_len; 157 | } 158 | } 159 | 160 | /* Discard bogus events which advertise more tokens than 161 | * what they carry... */ 162 | if(token_len > extra_len) 163 | iwe->u.data.pointer = NULL; /* Discard paylod */ 164 | 165 | /* Check that the advertised token size is not going to 166 | * produce buffer overflow to our caller... */ 167 | if((iwe->u.data.length > descr->max_tokens) 168 | && !(descr->flags & IW_DESCR_FLAG_NOMAX)) 169 | iwe->u.data.pointer = NULL; /* Discard paylod */ 170 | 171 | /* Same for underflows... */ 172 | if(iwe->u.data.length < descr->min_tokens) 173 | iwe->u.data.pointer = NULL; /* Discard paylod */ 174 | } 175 | } 176 | else 177 | /* No data */ 178 | iwe->u.data.pointer = NULL; 179 | 180 | /* Go to next event */ 181 | stream->current += iwe->len; 182 | } 183 | else 184 | { 185 | /* Ugly fixup for alignement issues. 186 | * If the kernel is 64 bits and userspace 32 bits, 187 | * we have an extra 4 bytes. 188 | * Fixing that in the kernel would break 64 bits userspace. */ 189 | if((stream->value == NULL) 190 | && ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4) 191 | || ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) || 192 | (event_type == IW_HEADER_TYPE_QUAL))) )) 193 | { 194 | pointer -= event_len; 195 | pointer += 4; 196 | /* Beware of alignement. Dest has local alignement, not packed */ 197 | memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len); 198 | pointer += event_len; 199 | } 200 | 201 | /* Is there more value in the event ? */ 202 | if((pointer + event_len) <= (stream->current + iwe->len)) 203 | /* Go to next value */ 204 | stream->value = pointer; 205 | else 206 | { 207 | /* Go to next event */ 208 | stream->value = NULL; 209 | stream->current += iwe->len; 210 | } 211 | } 212 | 213 | return 1; 214 | } 215 | 216 | static inline void wext_fill_wpa(unsigned char *iebuf, int ielen, struct iwinfo_scanlist_entry *e) 217 | { 218 | static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 }; 219 | 220 | while (ielen >= 2 && ielen >= iebuf[1]) 221 | { 222 | switch (iebuf[0]) 223 | { 224 | case 48: /* RSN */ 225 | iwinfo_parse_rsn(&e->crypto, iebuf + 2, iebuf[1], 226 | IWINFO_CIPHER_CCMP, IWINFO_KMGMT_8021x); 227 | break; 228 | 229 | case 221: /* Vendor */ 230 | if (iebuf[1] >= 4 && !memcmp(iebuf + 2, ms_oui, 3) && iebuf[5] == 1) 231 | iwinfo_parse_rsn(&e->crypto, iebuf + 6, iebuf[1] - 4, 232 | IWINFO_CIPHER_TKIP, IWINFO_KMGMT_PSK); 233 | break; 234 | } 235 | 236 | ielen -= iebuf[1] + 2; 237 | iebuf += iebuf[1] + 2; 238 | } 239 | } 240 | 241 | 242 | static inline void wext_fill_entry(struct stream_descr *stream, struct iw_event *event, 243 | struct iw_range *iw_range, int has_range, struct iwinfo_scanlist_entry *e) 244 | { 245 | int i; 246 | double freq; 247 | 248 | /* Now, let's decode the event */ 249 | switch(event->cmd) 250 | { 251 | case SIOCGIWAP: 252 | memcpy(e->mac, &event->u.ap_addr.sa_data, 6); 253 | break; 254 | 255 | case SIOCGIWFREQ: 256 | if( event->u.freq.m >= 1000 ) 257 | { 258 | freq = wext_freq2float(&(event->u.freq)); 259 | 260 | for(i = 0; i < iw_range->num_frequency; i++) 261 | { 262 | if( wext_freq2float(&iw_range->freq[i]) == freq ) 263 | { 264 | e->channel = iw_range->freq[i].i; 265 | break; 266 | } 267 | } 268 | } 269 | else 270 | { 271 | e->channel = event->u.freq.m; 272 | } 273 | 274 | break; 275 | 276 | case SIOCGIWMODE: 277 | switch(event->u.mode) 278 | { 279 | case 1: 280 | e->mode = IWINFO_OPMODE_ADHOC; 281 | break; 282 | 283 | case 2: 284 | case 3: 285 | e->mode = IWINFO_OPMODE_MASTER; 286 | break; 287 | 288 | default: 289 | e->mode = IWINFO_OPMODE_UNKNOWN; 290 | break; 291 | } 292 | 293 | break; 294 | 295 | case SIOCGIWESSID: 296 | if( event->u.essid.pointer && event->u.essid.length && event->u.essid.flags ) 297 | memcpy(e->ssid, event->u.essid.pointer, event->u.essid.length); 298 | 299 | break; 300 | 301 | case SIOCGIWENCODE: 302 | e->crypto.enabled = !(event->u.data.flags & IW_ENCODE_DISABLED); 303 | break; 304 | 305 | case IWEVQUAL: 306 | e->signal = event->u.qual.level; 307 | e->quality = event->u.qual.qual; 308 | e->quality_max = iw_range->max_qual.qual; 309 | break; 310 | #if 0 311 | case SIOCGIWRATE: 312 | if(state->val_index == 0) 313 | { 314 | lua_pushstring(L, "bitrates"); 315 | lua_newtable(L); 316 | } 317 | //iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value); 318 | snprintf(buffer, sizeof(buffer), "%d", event->u.bitrate.value); 319 | lua_pushinteger(L, state->val_index + 1); 320 | lua_pushstring(L, buffer); 321 | lua_settable(L, -3); 322 | 323 | /* Check for termination */ 324 | if(stream->value == NULL) 325 | { 326 | lua_settable(L, -3); 327 | state->val_index = 0; 328 | } else 329 | state->val_index++; 330 | break; 331 | #endif 332 | case IWEVGENIE: 333 | wext_fill_wpa(event->u.data.pointer, event->u.data.length, e); 334 | break; 335 | } 336 | } 337 | 338 | 339 | int wext_get_scanlist(const char *ifname, char *buf, int *len) 340 | { 341 | struct iwreq wrq; 342 | struct iw_scan_req scanopt; /* Options for 'set' */ 343 | unsigned char *buffer = NULL; /* Results */ 344 | int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */ 345 | struct iw_range range; 346 | int has_range = 1; 347 | struct timeval tv; /* Select timeout */ 348 | int timeout = 15000000; /* 15s */ 349 | 350 | int entrylen = 0; 351 | struct iwinfo_scanlist_entry e; 352 | 353 | wrq.u.data.pointer = (caddr_t) ⦥ 354 | wrq.u.data.length = sizeof(struct iw_range); 355 | wrq.u.data.flags = 0; 356 | 357 | if( wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0 ) 358 | { 359 | /* Init timeout value -> 250ms between set and first get */ 360 | tv.tv_sec = 0; 361 | tv.tv_usec = 250000; 362 | 363 | /* Clean up set args */ 364 | memset(&scanopt, 0, sizeof(scanopt)); 365 | 366 | wrq.u.data.pointer = NULL; 367 | wrq.u.data.flags = 0; 368 | wrq.u.data.length = 0; 369 | 370 | /* Initiate Scanning */ 371 | if( wext_ioctl(ifname, SIOCSIWSCAN, &wrq) >= 0 ) 372 | { 373 | timeout -= tv.tv_usec; 374 | 375 | /* Forever */ 376 | while(1) 377 | { 378 | fd_set rfds; /* File descriptors for select */ 379 | int last_fd; /* Last fd */ 380 | int ret; 381 | 382 | /* Guess what ? We must re-generate rfds each time */ 383 | FD_ZERO(&rfds); 384 | last_fd = -1; 385 | /* In here, add the rtnetlink fd in the list */ 386 | 387 | /* Wait until something happens */ 388 | ret = select(last_fd + 1, &rfds, NULL, NULL, &tv); 389 | 390 | /* Check if there was an error */ 391 | if(ret < 0) 392 | { 393 | if(errno == EAGAIN || errno == EINTR) 394 | continue; 395 | 396 | return -1; 397 | } 398 | 399 | /* Check if there was a timeout */ 400 | if(ret == 0) 401 | { 402 | unsigned char *newbuf; 403 | 404 | realloc: 405 | /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */ 406 | newbuf = realloc(buffer, buflen); 407 | if(newbuf == NULL) 408 | { 409 | if(buffer) 410 | free(buffer); 411 | 412 | return -1; 413 | } 414 | 415 | buffer = newbuf; 416 | 417 | /* Try to read the results */ 418 | wrq.u.data.pointer = buffer; 419 | wrq.u.data.flags = 0; 420 | wrq.u.data.length = buflen; 421 | 422 | if( wext_ioctl(ifname, SIOCGIWSCAN, &wrq) ) 423 | { 424 | /* Check if buffer was too small (WE-17 only) */ 425 | if((errno == E2BIG) && (range.we_version_compiled > 16)) 426 | { 427 | /* Some driver may return very large scan results, either 428 | * because there are many cells, or because they have many 429 | * large elements in cells (like IWEVCUSTOM). Most will 430 | * only need the regular sized buffer. We now use a dynamic 431 | * allocation of the buffer to satisfy everybody. Of course, 432 | * as we don't know in advance the size of the array, we try 433 | * various increasing sizes. Jean II */ 434 | 435 | /* Check if the driver gave us any hints. */ 436 | if(wrq.u.data.length > buflen) 437 | buflen = wrq.u.data.length; 438 | else 439 | buflen *= 2; 440 | 441 | /* Try again */ 442 | goto realloc; 443 | } 444 | 445 | /* Check if results not available yet */ 446 | if(errno == EAGAIN) 447 | { 448 | /* Restart timer for only 100ms*/ 449 | tv.tv_sec = 0; 450 | tv.tv_usec = 100000; 451 | timeout -= tv.tv_usec; 452 | 453 | if(timeout > 0) 454 | continue; /* Try again later */ 455 | } 456 | 457 | /* Bad error */ 458 | free(buffer); 459 | return -1; 460 | 461 | } else { 462 | /* We have the results, go to process them */ 463 | break; 464 | } 465 | } 466 | } 467 | 468 | if( wrq.u.data.length ) 469 | { 470 | struct iw_event iwe; 471 | struct stream_descr stream; 472 | int ret; 473 | int first = 1; 474 | 475 | memset(&stream, 0, sizeof(stream)); 476 | stream.current = (char *)buffer; 477 | stream.end = (char *)buffer + wrq.u.data.length; 478 | 479 | do 480 | { 481 | /* Extract an event and print it */ 482 | ret = wext_extract_event(&stream, &iwe, range.we_version_compiled); 483 | 484 | if(ret >= 0) 485 | { 486 | if( (iwe.cmd == SIOCGIWAP) || (ret == 0) ) 487 | { 488 | if( first ) 489 | { 490 | first = 0; 491 | } 492 | else if( (entrylen + sizeof(struct iwinfo_scanlist_entry)) <= IWINFO_BUFSIZE ) 493 | { 494 | /* if encryption is off, clear the crypto strunct */ 495 | if( !e.crypto.enabled ) 496 | memset(&e.crypto, 0, sizeof(struct iwinfo_crypto_entry)); 497 | 498 | memcpy(&buf[entrylen], &e, sizeof(struct iwinfo_scanlist_entry)); 499 | entrylen += sizeof(struct iwinfo_scanlist_entry); 500 | } 501 | else 502 | { 503 | /* we exceed the callers buffer size, abort here ... */ 504 | break; 505 | } 506 | 507 | memset(&e, 0, sizeof(struct iwinfo_scanlist_entry)); 508 | } 509 | 510 | wext_fill_entry(&stream, &iwe, &range, has_range, &e); 511 | } 512 | 513 | } while(ret > 0); 514 | 515 | free(buffer); 516 | *len = entrylen; 517 | return 0; 518 | } 519 | 520 | *len = 0; 521 | free(buffer); 522 | return 0; 523 | } 524 | } 525 | 526 | return -1; 527 | } 528 | -------------------------------------------------------------------------------- /devices.txt: -------------------------------------------------------------------------------- 1 | # libiwinfo hardware database 2 | # vendor id | device id | subsystem vendor id | subsystem device id | 3 | # txpower offset | frequency offset | "vendor name" | "device name" 4 | 0x0777 0x11ac 0x0777 0xe7f9 0 0 "Ubiquiti" "LiteBeam 5AC" 5 | 0xffff 0xffff 0xffff 0xb102 0 0 "Ubiquiti" "PowerStation2 (18V)" 6 | 0xffff 0xffff 0xffff 0xb202 0 0 "Ubiquiti" "PowerStation2 (16D)" 7 | 0xffff 0xffff 0xffff 0xb302 0 0 "Ubiquiti" "PowerStation2 (EXT)" 8 | 0xffff 0xffff 0xffff 0xb105 0 0 "Ubiquiti" "PowerStation5 (22V)" 9 | 0xffff 0xffff 0xffff 0xb305 0 0 "Ubiquiti" "PowerStation5 (EXT)" 10 | 0xffff 0xffff 0xffff 0xc302 0 0 "Ubiquiti" "PicoStation2" 11 | 0xffff 0xffff 0xffff 0xc3a2 10 0 "Ubiquiti" "PicoStation2 HP" 12 | 0xffff 0xffff 0xffff 0xa105 0 0 "Ubiquiti" "WispStation5" 13 | 0xffff 0xffff 0xffff 0xa002 10 0 "Ubiquiti" "LiteStation2" 14 | 0xffff 0xffff 0xffff 0xa005 5 0 "Ubiquiti" "LiteStation5" 15 | 0xffff 0xffff 0xffff 0xc002 10 0 "Ubiquiti" "NanoStation2" 16 | 0xffff 0xffff 0xffff 0xc005 5 0 "Ubiquiti" "NanoStation5" 17 | 0xffff 0xffff 0xffff 0xc102 10 0 "Ubiquiti" "NanoStation Loco2" 18 | 0xffff 0xffff 0xffff 0xc105 5 0 "Ubiquiti" "NanoStation Loco5" 19 | 0xffff 0xffff 0xffff 0xc202 10 0 "Ubiquiti" "Bullet2" 20 | 0xffff 0xffff 0xffff 0xc205 5 0 "Ubiquiti" "Bullet5" 21 | 0x168c 0xffff 0x0777 0xe002 6 0 "Ubiquiti" "airOS XM" 22 | 0x168c 0xffff 0x0777 0xe003 3 0 "Ubiquiti" "airOS XM" 23 | 0x168c 0xffff 0x0777 0xe005 5 0 "Ubiquiti" "NanoStation M5" /* airOS XM */ 24 | 0x168c 0xffff 0x0777 0xe006 5 0 "Ubiquiti" "airOS XM" 25 | 0x168c 0xffff 0x0777 0xe009 6 0 "Ubiquiti" "NanoStation Loco M9" /* airOS XM */ 26 | 0x168c 0xffff 0x0777 0xe012 10 0 "Ubiquiti" "NanoStation M2" /* airOS XM */ 27 | 0x168c 0xffff 0x0777 0xe035 3 0 "Ubiquiti" "NanoStation M3" /* airOS XM */ 28 | 0x168c 0xffff 0x0777 0xe0a2 2 0 "Ubiquiti" "NanoStation Loco M2" /* airOS XM */ 29 | 0x168c 0xffff 0x0777 0xe0a5 1 0 "Ubiquiti" "NanoStation Loco M5" /* airOS XM */ 30 | 0x168c 0xffff 0x0777 0xe102 6 0 "Ubiquiti" "airOS XM" 31 | 0x168c 0xffff 0x0777 0xe105 5 0 "Ubiquiti" "Rocket M5" /* airOS XM */ 32 | 0x168c 0xffff 0x0777 0xe112 10 0 "Ubiquiti" "airOS XM" 33 | 0x168c 0xffff 0x0777 0xe115 3 0 "Ubiquiti" "airOS XM" 34 | 0x168c 0xffff 0x0777 0xe1a3 3 0 "Ubiquiti" "airOS XM" 35 | 0x168c 0xffff 0x0777 0xe1a5 5 0 "Ubiquiti" "PowerBridge M5" /* airOS XM */ 36 | 0x168c 0xffff 0x0777 0xe1b2 10 0 "Ubiquiti" "airOS XM" 37 | 0x168c 0xffff 0x0777 0xe1b3 3 0 "Ubiquiti" "airOS XM" 38 | 0x168c 0xffff 0x0777 0xe1b5 5 0 "Ubiquiti" "Rocket M5" /* airOS XM */ 39 | 0x168c 0xffff 0x0777 0xe1b6 5 0 "Ubiquiti" "airOS XM" 40 | 0x168c 0xffff 0x0777 0xe1b9 6 0 "Ubiquiti" "Rocket M9" /* airOS XM */ 41 | 0x168c 0xffff 0x0777 0xe1c2 10 0 "Ubiquiti" "airOS XM" 42 | 0x168c 0xffff 0x0777 0xe1c3 3 0 "Ubiquiti" "Rocket M3" /* airOS XM */ 43 | 0x168c 0xffff 0x0777 0xe1c5 5 0 "Ubiquiti" "Rocket M5 GPS" /* airOS XM */ 44 | 0x168c 0xffff 0x0777 0xe1c5 5 0 "Ubiquiti" "airOS XM" 45 | 0x168c 0xffff 0x0777 0xe1d2 10 0 "Ubiquiti" "Rocket M2 Titanium" /* airOS XM/XW */ 46 | 0x168c 0xffff 0x0777 0xe1d3 3 0 "Ubiquiti" "airOS XM" 47 | 0x168c 0xffff 0x0777 0xe1d5 5 0 "Ubiquiti" "airOS XM/XW" 48 | 0x168c 0xffff 0x0777 0xe1d9 6 0 "Ubiquiti" "airOS XM" 49 | 0x168c 0xffff 0x0777 0xe1e3 3 0 "Ubiquiti" "airOS XM" 50 | 0x168c 0xffff 0x0777 0xe1e5 5 0 "Ubiquiti" "airOS XM" 51 | 0x168c 0xffff 0x0777 0xe202 12 0 "Ubiquiti" "Bullet M2" /* airOS XM */ 52 | 0x168c 0xffff 0x0777 0xe205 6 0 "Ubiquiti" "Bullet M5" /* airOS XM */ 53 | 0x168c 0xffff 0x0777 0xe212 1 0 "Ubiquiti" "AirGrid M2" /* airOS XM */ 54 | 0x168c 0xffff 0x0777 0xe215 1 0 "Ubiquiti" "AirGrid M5" /* airOS XM */ 55 | 0x168c 0xffff 0x0777 0xe232 2 0 "Ubiquiti" "NanoBridge M2" /* airOS XM */ 56 | 0x168c 0xffff 0x0777 0xe233 3 0 "Ubiquiti" "airOS XM" 57 | 0x168c 0xffff 0x0777 0xe235 1 0 "Ubiquiti" "NanoBridge M5" /* airOS XM */ 58 | 0x168c 0xffff 0x0777 0xe239 6 0 "Ubiquiti" "NanoBridge M9" /* airOS XM */ 59 | 0x168c 0xffff 0x0777 0xe242 9 0 "Ubiquiti" "AirGrid M2 HP" /* airOS XM */ 60 | 0x168c 0xffff 0x0777 0xe243 3 0 "Ubiquiti" "NanoBridge M3" /* airOS XM */ 61 | 0x168c 0xffff 0x0777 0xe245 6 0 "Ubiquiti" "AirGrid M5 HP" /* airOS XM */ 62 | 0x168c 0xffff 0x0777 0xe252 9 0 "Ubiquiti" "AirGrid M2 HP" /* airOS XM */ 63 | 0x168c 0xffff 0x0777 0xe255 6 0 "Ubiquiti" "AirGrid M5 HP" /* airOS XM */ 64 | 0x168c 0xffff 0x0777 0xe2a3 3 0 "Ubiquiti" "airOS XM" 65 | 0x168c 0xffff 0x0777 0xe2a5 5 0 "Ubiquiti" "airOS XM" 66 | 0x168c 0xffff 0x0777 0xe2b2 10 0 "Ubiquiti" "airOS XM" 67 | 0x168c 0xffff 0x0777 0xe2b5 1 0 "Ubiquiti" "NanoBridge M5" /* airOS XM */ 68 | 0x168c 0xffff 0x0777 0xe2b9 6 0 "Ubiquiti" "airOS XM" 69 | 0x168c 0xffff 0x0777 0xe2c2 10 0 "Ubiquiti" "NanoBeam M2 Int" /* airOS XW */ 70 | 0x168c 0xffff 0x0777 0xe2c3 6 0 "Ubiquiti" "Bullet M2 XW" /* airOS XW */ 71 | 0x168c 0xffff 0x0777 0xe2c4 6 0 "Ubiquiti" "airOS XW" 72 | 0x168c 0xffff 0x0777 0xe2d2 12 0 "Ubiquiti" "Bullet M2 Titanium HP" /* airOS XM */ 73 | 0x168c 0xffff 0x0777 0xe2d4 6 0 "Ubiquiti" "airOS XW" 74 | 0x168c 0xffff 0x0777 0xe2d5 6 0 "Ubiquiti" "airOS XM" 75 | 0x168c 0xffff 0x0777 0xe2e5 4 0 "Ubiquiti" "airOS XM" 76 | 0x168c 0xffff 0x0777 0xe302 12 0 "Ubiquiti" "PicoStation M2" /* airOS XM */ 77 | 0x168c 0xffff 0x0777 0xe305 6 0 "Ubiquiti" "airOS XM" 78 | 0x168c 0xffff 0x0777 0xe345 6 0 "Ubiquiti" "WispStation M5" /* airOS XM */ 79 | 0x168c 0xffff 0x0777 0xe3a5 5 0 "Ubiquiti" "airOS XM" 80 | 0x168c 0xffff 0x0777 0xe3b5 6 0 "Ubiquiti" "airOS XM/XW" 81 | 0x168c 0xffff 0x0777 0xe3e5 4 0 "Ubiquiti" "PowerBeam M5 300" /* airOS XW */ 82 | 0x168c 0xffff 0x0777 0xe402 10 0 "Ubiquiti" "airOS XM" 83 | 0x168c 0xffff 0x0777 0xe405 1 0 "Ubiquiti" "airOS XM" 84 | 0x168c 0xffff 0x0777 0xe4a2 1 0 "Ubiquiti" "AirRouter" /* airOS XM */ 85 | 0x168c 0xffff 0x0777 0xe4a5 1 0 "Ubiquiti" "airOS XM" 86 | 0x168c 0xffff 0x0777 0xe4b2 9 0 "Ubiquiti" "AirRouter HP" /* airOS XM */ 87 | 0x168c 0xffff 0x0777 0xe4d5 5 0 "Ubiquiti" "Rocket M5 Titanium" /* airOS XW */ 88 | 0x168c 0xffff 0x0777 0xe4e5 4 0 "Ubiquiti" "PowerBeam M5 400" /* airOS XW */ 89 | 0x168c 0xffff 0x0777 0xe5e5 4 0 "Ubiquiti" "airOS XW" 90 | 0x168c 0xffff 0x0777 0xe6a2 1 0 "Ubiquiti" "airOS XM" 91 | 0x168c 0xffff 0x0777 0xe6b2 1 0 "Ubiquiti" "airOS XM" 92 | 0x168c 0xffff 0x0777 0xe6b5 5 0 "Ubiquiti" "Rocket M5 XW" /* airOS XW */ 93 | 0x168c 0xffff 0x0777 0xe6c2 6 0 "Ubiquiti" "airOS XM" 94 | 0x168c 0xffff 0x0777 0xe6e5 4 0 "Ubiquiti" "PowerBeam M5 400 ISO" /* airOS XW */ 95 | 0x168c 0xffff 0x0777 0xe7f8 2 0 "Ubiquiti" "airOS XW" 96 | 0x168c 0xffff 0x0777 0xe805 5 0 "Ubiquiti" "airOS XM" /* e.g. NanoStation M5, Bullet M5 */ 97 | 0x168c 0xffff 0x0777 0xe812 6 0 "Ubiquiti" "NanoBeam M2 13" /* airOS XW */ 98 | 0x168c 0xffff 0x0777 0xe815 4 0 "Ubiquiti" "NanoBeam M5 16" /* airOS XW */ 99 | 0x168c 0xffff 0x0777 0xe825 4 0 "Ubiquiti" "NanoBeam M5 19" /* airOS XW */ 100 | 0x168c 0xffff 0x0777 0xe835 6 0 "Ubiquiti" "AirGrid M5 XW" /* airOS XW */ 101 | 0x168c 0xffff 0x0777 0xe845 1 0 "Ubiquiti" "NanoStation Loco M5 XW" /* airOS XW */ 102 | 0x168c 0xffff 0x0777 0xe855 5 0 "Ubiquiti" "NanoStation M5 XW" /* airOS XW */ 103 | 0x168c 0xffff 0x0777 0xe865 6 0 "Ubiquiti" "LiteBeam M5" /* airOS XW */ 104 | 0x168c 0xffff 0x0777 0xe866 6 0 "Ubiquiti" "NanoStation M2 XW" /* airOS XW */ 105 | 0x168c 0xffff 0x0777 0xe867 2 0 "Ubiquiti" "NanoStation Loco M2 XW" /* airOS XW */ 106 | 0x168c 0xffff 0x0777 0xe868 7 0 "Ubiquiti" "Rocket M2 XW" /* airOS XW */ 107 | 0x168c 0xffff 0x0777 0xe869 2 0 "Ubiquiti" "airOS XW" 108 | 0x168c 0xffff 0x0777 0xe875 4 0 "Ubiquiti" "airOS XW" 109 | 0x168c 0xffff 0x0777 0xe879 2 0 "Ubiquiti" "airOS XW" 110 | 0x168c 0xffff 0x0777 0xe885 4 0 "Ubiquiti" "PowerBeam M5 620 XW" /* airOS XW */ 111 | 0x168c 0xffff 0x0777 0xe895 4 0 "Ubiquiti" "airOS XW" 112 | 0x168c 0xffff 0x0777 0xe8a5 1 0 "Ubiquiti" "NanoStation Loco M5" /* airOS XM */ 113 | 0x168c 0xffff 0x0777 0xe8b5 5 0 "Ubiquiti" "airOS XM" 114 | 0x168c 0x001b 0x0777 0x3002 10 0 "Ubiquiti" "XR2" 115 | 0x168c 0x001b 0x7777 0x3002 10 0 "Ubiquiti" "XR2" 116 | 0x168c 0x001b 0x0777 0x3b02 10 0 "Ubiquiti" "XR2.3" 117 | 0x168c 0x001b 0x0777 0x3c02 10 0 "Ubiquiti" "XR2.6" 118 | 0x168c 0x001b 0x0777 0x3b03 10 0 "Ubiquiti" "XR3-2.8" 119 | 0x168c 0x001b 0x0777 0x3c03 10 0 "Ubiquiti" "XR3-3.6" 120 | 0x168c 0x001b 0x0777 0x3003 10 0 "Ubiquiti" "XR3" 121 | 0x168c 0x001b 0x0777 0x3004 10 0 "Ubiquiti" "XR4" 122 | 0x168c 0x001b 0x0777 0x3005 10 0 "Ubiquiti" "XR5" 123 | 0x168c 0x001b 0x7777 0x3005 10 0 "Ubiquiti" "XR5" 124 | 0x168c 0x001b 0x0777 0x3007 10 0 "Ubiquiti" "XR7" 125 | 0x168c 0x001b 0x0777 0x3009 10 -1520 "Ubiquiti" "XR9" 126 | 0x168c 0x001b 0x168c 0x2063 0 0 "Atheros" "AR5413" 127 | 0x168c 0x0013 0x168c 0x1042 1 0 "Ubiquiti" "SRC" 128 | 0x168c 0x0013 0x0777 0x2041 10 0 "Ubiquiti" "SR2" 129 | 0x168c 0x0013 0x0777 0x2004 6 0 "Ubiquiti" "SR4" 130 | 0x168c 0x0013 0x7777 0x2004 6 0 "Ubiquiti" "SR4" 131 | 0x168c 0x0013 0x0777 0x1004 6 0 "Ubiquiti" "SR4C" 132 | 0x168c 0x0013 0x7777 0x1004 6 0 "Ubiquiti" "SR4C" 133 | 0x168c 0x0013 0x168c 0x2042 7 0 "Ubiquiti" "SR5" 134 | 0x168c 0x0013 0x7777 0x2009 12 -1500 "Ubiquiti" "SR9" 135 | 0x168c 0x0027 0x168c 0x2082 7 0 "Ubiquiti" "SR71A" 136 | 0x168c 0x0027 0x0777 0x4082 7 0 "Ubiquiti" "SR71" 137 | 0x168c 0x0029 0x0777 0x4005 7 0 "Ubiquiti" "SR71-15" 138 | 0x168c 0x002a 0x0777 0xe302 12 0 "Ubiquiti" "PicoStation M2" /* ToDo: confirm offset - Correct! */ 139 | 0x168c 0x002a 0x0777 0xe012 12 0 "Ubiquiti" "NanoStation M2" /* ToDo: confirm offset - Wrong! */ 140 | 0x168c 0x002a 0x0777 0xe005 5 0 "Ubiquiti" "NanoStation M5" /* ToDo: confirm offset - Correct! */ 141 | 0x168c 0x002a 0x0777 0xe202 12 0 "Ubiquiti" "Bullet M2" 142 | 0x168c 0x002a 0x0777 0xe805 5 0 "Ubiquiti" "Bullet M5" 143 | 0x168c 0x002a 0x0777 0xe345 0 0 "Ubiquiti" "WispStation M5" /* ToDo: confirm offset - Wrong! */ 144 | 0x168c 0x0029 0x168c 0xa094 0 0 "Atheros" "AR9220" 145 | 0x168c 0x0029 0x168c 0xa095 0 0 "Atheros" "AR9223" 146 | 0x168c 0x002a 0x168c 0xa093 0 0 "Atheros" "AR9280" 147 | 0x168c 0x002b 0x168c 0xa091 0 0 "Atheros" "AR9285" 148 | 0x168c 0x002d 0x168c 0x209a 0 0 "Atheros" "AR9287" 149 | 0x168c 0x002e 0x1a3b 0x1121 0 0 "Atheros" "AR9287" 150 | 0x168c 0x002e 0x0777 0xe0a2 8 0 "Ubiquiti" "NanoStation Loco M2 (XM)" /* wrong offset! */ 151 | 0x168c 0x002e 0x168c 0x30a4 0 0 "Atheros" "AR9287" 152 | 0x168c 0x002e 0x168c 0xa199 0 0 "Atheros" "AR9287" 153 | 0x168c 0x0030 0x168c 0x3112 0 0 "Atheros" "AR9380" 154 | 0x168c 0x0030 0x168c 0x3114 0 0 "Atheros" "AR9390" 155 | 0x168c 0x0033 0x168c 0xa120 0 0 "Atheros" "AR9580" 156 | 0x168c 0x0033 0x168c 0xa136 0 0 "Atheros" "AR9580" 157 | 0x168c 0x0033 0x168c 0x3123 0 0 "Atheros" "AR9590" 158 | 0x168c 0x0033 0x19b6 0xd014 0 0 "MikroTik" "R11e-5HnD" 159 | 0x168c 0x0033 0x19b6 0xd057 0 0 "MikroTik" "R11e-5HnDr2" 160 | 0x168c 0x0033 0x19b6 0xd016 0 0 "MikroTik" "R11e-2HPnD" 161 | 0x168c 0x0034 0x17aa 0x3214 0 0 "Atheros" "AR9462" 162 | 0x168c 0x003c 0x0000 0x0000 0 0 "Qualcomm Atheros" "QCA9880" 163 | 0x168c 0x003c 0x168c 0x3223 0 0 "Qualcomm Atheros" "QCA9880" 164 | 0x168c 0x003c 0x1a56 0x1420 0 0 "Qualcomm Atheros" "QCA9862" 165 | 0x168c 0x003c 0x19b6 0xd03c 0 0 "Mikrotik" "R11e-5HacT" 166 | 0x168c 0x003c 0x19b6 0xd075 0 0 "Mikrotik" "R11e-5HacD" 167 | 0x168c 0x003e 0x168c 0x3361 0 0 "Qualcomm Atheros" "QCA6174" 168 | 0x168c 0x0040 0x168c 0x0002 0 0 "Qualcomm Atheros" "QCA9990" 169 | 0x168c 0x0046 0x168c 0xcafe 0 0 "Qualcomm Atheros" "QCA9984" 170 | 0x168c 0x0050 0x0000 0x0000 0 0 "Qualcomm Atheros" "QCA9887" 171 | 0x168c 0x0056 0x0000 0x0000 0 0 "Qualcomm Atheros" "QCA9886" 172 | 0x17cb 0x1104 0x17cb 0x1104 0 0 "Qualcomm Atheros" "QCN6024/9024/9074" 173 | 0x1814 0x3051 0x1814 0x0007 0 0 "Ralink" "Rt3051" /* needs fixing */ 174 | 0x1814 0x3052 0x1814 0x0008 0 0 "Ralink" "Rt3052" /* needs fixing */ 175 | 0x1814 0x3091 0x1814 0x3091 0 0 "Ralink" "RT5592" 176 | 0x1814 0x3350 0x1814 0x000b 0 0 "Ralink" "Rt3350" /* needs fixing */ 177 | 0x1814 0x3662 0x1814 0x000d 0 0 "Ralink" "Rt3662" /* needs fixing */ 178 | 0x11ab 0x2a55 0x11ab 0x0000 0 0 "Marvell" "88W8864" 179 | 0x02df 0x9135 0x0000 0x0000 0 0 "Marvell" "88W8887" 180 | 0x11ab 0x2b40 0x11ab 0x0000 0 0 "Marvell" "88W8964" 181 | 0x02df 0x9141 0x0000 0x0000 0 0 "Marvell" "88W8997" 182 | 0x14c3 0x0608 0x14c3 0x0608 0 0 "AMD" "RZ608" 183 | 0x14c3 0x7603 0x14c3 0x7603 0 0 "MediaTek" "MT7603E" 184 | 0x14c3 0x7610 0x14c3 0x7610 0 0 "MediaTek" "MT7610E" 185 | 0x14c3 0x7612 0x14c3 0x7612 0 0 "MediaTek" "MT7612E" 186 | 0x14c3 0x7663 0x14c3 0x7663 0 0 "MediaTek" "MT7613BE" 187 | 0x14c3 0x7615 0x7615 0x14c3 0 0 "MediaTek" "MT7615E" 188 | 0x14c3 0x7628 0x14c3 0x0004 0 0 "MediaTek" "MT76x8" 189 | 0x14c3 0x7650 0x14c3 0x7650 0 0 "MediaTek" "MT7610E" 190 | 0x14c3 0x7662 0x14c3 0x7662 0 0 "MediaTek" "MT76x2E" 191 | 0x14c3 0x7915 0x14c3 0x7915 0 0 "MediaTek" "MT7915E" 192 | 0x14c3 0x7906 0x14c3 0x7906 0 0 "MediaTek" "MT7916AN" 193 | 0x14c3 0x7925 0x1a3b 0x6002 0 0 "MediaTek" "MT7925E" 194 | 0x14c3 0x7990 0x14C3 0x6639 0 0 "MediaTek" "MT7996E" 195 | 0x14c3 0x7992 0x14c3 0x7992 0 0 "MediaTek" "MT7992E" 196 | 0x14e4 0xaa52 0x14e4 0xaa52 0 0 "Broadcom" "BCM43602" 197 | 0x02d0 0xa9a6 0x0000 0x0000 0 0 "Cypress" "CYW43455" 198 | 0x02d0 0x4345 0x0000 0x0000 0 0 "Cypress" "CYW43455" 199 | 0x1ae9 0x0310 0x1ae9 0x0000 0 0 "Wilocity" "Wil6210" 200 | 201 | # USB devices 202 | # 0x0000 | 0x0000 | vendor id | product id | ... 203 | # mt7601u/usb.c 204 | 0x0000 0x0000 0x148f 0x7601 0 0 "MediaTek" "MT7601U" 205 | # mt7921/usb.c 206 | 0x0000 0x0000 0x0e8d 0x7961 0 0 "MediaTek" "MT7921AU" 207 | # mt76x2/usb.c 208 | 0x0000 0x0000 0x0b05 0x1833 0 0 "ASUS" "USB-AC54" 209 | 0x0000 0x0000 0x0b05 0x17eb 0 0 "ASUS" "USB-AC55" 210 | 0x0000 0x0000 0x0b05 0x180b 0 0 "ASUS" "USB-N53 B1" 211 | 0x0000 0x0000 0x0e8d 0x7612 0 0 "Aukey" "USBAC1200" /* Alfa AWUS036ACM */ 212 | 0x0000 0x0000 0x057c 0x8503 0 0 "AVM" "FRITZ!WLAN AC860" 213 | 0x0000 0x0000 0x7392 0xb711 0 0 "Edimax" "EW-7722UAC" 214 | 0x0000 0x0000 0x0e8d 0x7632 0 0 "High Cloud" "HC-M7662BU1" 215 | 0x0000 0x0000 0x2c4e 0x0103 0 0 "Mercury" "UD13" 216 | 0x0000 0x0000 0x0846 0x9053 0 0 "Netgear" "A6210" 217 | 0x0000 0x0000 0x045e 0x02e6 0 0 "Microsoft" "XBox One Wireless Adapter" 218 | 0x0000 0x0000 0x045e 0x02fe 0 0 "Microsoft" "XBox One Wireless Adapter" 219 | # mt76x0/usb.c 220 | 0x0000 0x0000 0x148f 0x7610 0 0 "MediaTek" "MT7610U" 221 | 0x0000 0x0000 0x13b1 0x003e 0 0 "Linksys" "AE6000" 222 | 0x0000 0x0000 0x0e8d 0x7610 0 0 "Sabrent" "NTWLAC" 223 | 0x0000 0x0000 0x7392 0xa711 0 0 "Edimax" "7711MAC" 224 | 0x0000 0x0000 0x148f 0x761a 0 0 "TP-Link" "TL-WDN5200" 225 | 0x0000 0x0000 0x0b05 0x17d1 0 0 "ASUS" "USB-AC51" 226 | 0x0000 0x0000 0x0b05 0x17db 0 0 "ASUS" "USB-AC50" 227 | 0x0000 0x0000 0x0df6 0x0075 0 0 "Sitecom" "WLA-3100" 228 | 0x0000 0x0000 0x2019 0xab31 0 0 "Planex" "GW-450D" 229 | 0x0000 0x0000 0x2001 0x3d02 0 0 "D-Link" "DWA-171 rev B1" 230 | 0x0000 0x0000 0x0586 0x3425 0 0 "Zyxel" "NWD6505" 231 | 0x0000 0x0000 0x07b8 0x7610 0 0 "AboCom" "AU7212" 232 | 0x0000 0x0000 0x04bb 0x0951 0 0 "I-O DATA" "WN-AC433UK" 233 | 0x0000 0x0000 0x057c 0x8502 0 0 "AVM" "FRITZ!WLAN AC430" 234 | 0x0000 0x0000 0x293c 0x5702 0 0 "Comcast" "Xfinity KXW02AAA" 235 | 0x0000 0x0000 0x20f4 0x806b 0 0 "TRENDnet" "TEW-806UBH" 236 | 0x0000 0x0000 0x7392 0xc711 0 0 "Devolo" "WiFi Stick ac" 237 | 0x0000 0x0000 0x0df6 0x0079 0 0 "Sitecom" "WL-356" 238 | 0x0000 0x0000 0x2357 0x0123 0 0 "TP-Link" "T2UHP US v1" 239 | 0x0000 0x0000 0x2357 0x010b 0 0 "TP-Link" "T2UHP UN v1" 240 | 0x0000 0x0000 0x2357 0x0105 0 0 "TP-Link" "Archer T1U" 241 | 0x0000 0x0000 0x0e8d 0x7630 0 0 "MediaTek" "MT7630U" 242 | 0x0000 0x0000 0x0e8d 0x7650 0 0 "MediaTek" "MT7650U" 243 | # mt7615/usb.c 244 | 0x0000 0x0000 0x0e8d 0x7663 0 0 "MediaTek" "MT7663U" 245 | 0x0000 0x0000 0x043e 0x310c 0 0 "LG" "LGSBWAC02" 246 | # rtl8xxxu/rtl8xxxu_core.c 247 | 0x0000 0x0000 0x0bda 0x8176 0 0 "Realtek" "RTL8188CU" 248 | 0x0000 0x0000 0x0bda 0xf179 0 0 "Realtek" "RTL8188FTV" 249 | 250 | # FDT compatible strings 251 | # "compatible" | txpower offset | frequency offset | ... 252 | "qca,ar9130-wmac" 0 0 "Atheros" "AR9130" 253 | "qca,ar9330-wmac" 0 0 "Atheros" "AR9330" 254 | "qca,ar9340-wmac" 0 0 "Atheros" "AR9340" 255 | "qca,qca9530-wmac" 0 0 "Qualcomm Atheros" "QCA9530" 256 | "qca,qca9550-wmac" 0 0 "Qualcomm Atheros" "QCA9550" 257 | "qca,qca9560-wmac" 0 0 "Qualcomm Atheros" "QCA9560" 258 | "qcom,ipq4019-wifi" 0 0 "Qualcomm Atheros" "IPQ4019" 259 | "qcom,ipq5018-wifi" 0 0 "Qualcomm Atheros" "IPQ5018" 260 | "qcom,ipq6018-wifi" 0 0 "Qualcomm Atheros" "IPQ6018" 261 | "qcom,ipq8074-wifi" 0 0 "Qualcomm Atheros" "IPQ8074" 262 | "qcom,qcn6122-wifi" 0 0 "Qualcomm Atheros" "QCN6102/QCN6122" 263 | "mediatek,mt7622-wmac" 0 0 "MediaTek" "MT7622" 264 | "mediatek,mt7628-wmac" 0 0 "MediaTek" "MT7628" 265 | "mediatek,mt7981-wmac" 0 0 "MediaTek" "MT7981" 266 | "mediatek,mt7986-wmac" 0 0 "MediaTek" "MT7986" 267 | "ralink,rt2880-wmac" 0 0 "Ralink" "Rt2880" 268 | "ralink,rt3050-wmac" 0 0 "Ralink" "Rt3050" 269 | "ralink,rt3352-wmac" 0 0 "Ralink" "Rt3352" 270 | "ralink,rt3883-wmac" 0 0 "Ralink" "Rt3883" 271 | "ralink,rt5350-wmac" 0 0 "Ralink" "Rt5350" 272 | "ralink,rt7620-wmac" 0 0 "MediaTek" "MT7620" 273 | -------------------------------------------------------------------------------- /iwinfo_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Shared utility routines 3 | * 4 | * Copyright (C) 2010 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | * 18 | * The signal handling code is derived from the official madwifi tools, 19 | * wlanconfig.c in particular. The encryption property handling was 20 | * inspired by the hostapd madwifi driver. 21 | */ 22 | 23 | #include "iwinfo/utils.h" 24 | 25 | 26 | static int ioctl_socket = -1; 27 | struct uci_context *uci_ctx = NULL; 28 | 29 | static int iwinfo_ioctl_socket(void) 30 | { 31 | /* Prepare socket */ 32 | if (ioctl_socket == -1) 33 | { 34 | ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0); 35 | fcntl(ioctl_socket, F_SETFD, fcntl(ioctl_socket, F_GETFD) | FD_CLOEXEC); 36 | } 37 | 38 | return ioctl_socket; 39 | } 40 | 41 | int iwinfo_ioctl(int cmd, void *ifr) 42 | { 43 | int s = iwinfo_ioctl_socket(); 44 | return ioctl(s, cmd, ifr); 45 | } 46 | 47 | int iwinfo_dbm2mw(int in) 48 | { 49 | double res = 1.0; 50 | int ip = in / 10; 51 | int fp = in % 10; 52 | int k; 53 | 54 | for(k = 0; k < ip; k++) res *= 10; 55 | for(k = 0; k < fp; k++) res *= LOG10_MAGIC; 56 | 57 | return (int)res; 58 | } 59 | 60 | int iwinfo_mw2dbm(int in) 61 | { 62 | double fin = (double) in; 63 | int res = 0; 64 | 65 | while(fin > 10.0) 66 | { 67 | res += 10; 68 | fin /= 10.0; 69 | } 70 | 71 | while(fin > 1.000001) 72 | { 73 | res += 1; 74 | fin /= LOG10_MAGIC; 75 | } 76 | 77 | return (int)res; 78 | } 79 | 80 | static int iwinfo_bit(int value, int max) 81 | { 82 | int i; 83 | 84 | if (max > 31 || !(value & ((1 << max) - 1))) 85 | return -1; 86 | 87 | for (i = 0; i < max; i++) 88 | { 89 | if (value & 1) 90 | break; 91 | 92 | value >>= 1; 93 | } 94 | 95 | return i; 96 | } 97 | 98 | static const char * const iwinfo_name(int mask, int max, const char * const names[]) 99 | { 100 | int index = iwinfo_bit(mask, max); 101 | 102 | if (index < 0) 103 | return NULL; 104 | 105 | return names[index]; 106 | } 107 | 108 | const char * const iwinfo_band_name(int mask) 109 | { 110 | return iwinfo_name(mask, IWINFO_BAND_COUNT, IWINFO_BAND_NAMES); 111 | } 112 | 113 | const char * const iwinfo_htmode_name(int mask) 114 | { 115 | return iwinfo_name(mask, IWINFO_HTMODE_COUNT, IWINFO_HTMODE_NAMES); 116 | } 117 | 118 | uint32_t iwinfo_band2ghz(uint8_t band) 119 | { 120 | switch (band) 121 | { 122 | case IWINFO_BAND_24: 123 | return 2; 124 | case IWINFO_BAND_5: 125 | return 5; 126 | case IWINFO_BAND_6: 127 | return 6; 128 | case IWINFO_BAND_60: 129 | return 60; 130 | } 131 | 132 | return 0; 133 | } 134 | 135 | uint8_t iwinfo_ghz2band(uint32_t ghz) 136 | { 137 | switch (ghz) 138 | { 139 | case 2: 140 | return IWINFO_BAND_24; 141 | case 5: 142 | return IWINFO_BAND_5; 143 | case 6: 144 | return IWINFO_BAND_6; 145 | case 60: 146 | return IWINFO_BAND_60; 147 | } 148 | 149 | return 0; 150 | } 151 | 152 | size_t iwinfo_format_hwmodes(int modes, char *buf, size_t len) 153 | { 154 | // bit numbers as per IWINFO_80211_*: ad ac ax a b be g n 155 | const int order[IWINFO_80211_COUNT] = { 5, 4, 6, 0, 1, 7, 2, 3 }; 156 | size_t res = 0; 157 | int i; 158 | 159 | *buf = 0; 160 | 161 | if (!(modes & ((1 << IWINFO_80211_COUNT) - 1))) 162 | return 0; 163 | 164 | for (i = 0; i < IWINFO_80211_COUNT; i++) 165 | if (modes & 1 << order[i]) 166 | res += snprintf(buf + res, len - res, "%s/", IWINFO_80211_NAMES[order[i]]); 167 | 168 | if (res > 0) 169 | { 170 | res--; 171 | buf[res] = 0; 172 | } 173 | 174 | return res; 175 | } 176 | 177 | int iwinfo_htmode_is_ht(int htmode) 178 | { 179 | switch (htmode) 180 | { 181 | case IWINFO_HTMODE_HT20: 182 | case IWINFO_HTMODE_HT40: 183 | return 1; 184 | } 185 | 186 | return 0; 187 | } 188 | 189 | int iwinfo_htmode_is_vht(int htmode) 190 | { 191 | switch (htmode) 192 | { 193 | case IWINFO_HTMODE_VHT20: 194 | case IWINFO_HTMODE_VHT40: 195 | case IWINFO_HTMODE_VHT80: 196 | case IWINFO_HTMODE_VHT80_80: 197 | case IWINFO_HTMODE_VHT160: 198 | return 1; 199 | } 200 | 201 | return 0; 202 | } 203 | 204 | int iwinfo_htmode_is_he(int htmode) 205 | { 206 | switch (htmode) 207 | { 208 | case IWINFO_HTMODE_HE20: 209 | case IWINFO_HTMODE_HE40: 210 | case IWINFO_HTMODE_HE80: 211 | case IWINFO_HTMODE_HE80_80: 212 | case IWINFO_HTMODE_HE160: 213 | return 1; 214 | } 215 | 216 | return 0; 217 | } 218 | 219 | int iwinfo_htmode_is_eht(int htmode) 220 | { 221 | switch (htmode) 222 | { 223 | case IWINFO_HTMODE_EHT20: 224 | case IWINFO_HTMODE_EHT40: 225 | case IWINFO_HTMODE_EHT80: 226 | case IWINFO_HTMODE_EHT80_80: 227 | case IWINFO_HTMODE_EHT160: 228 | case IWINFO_HTMODE_EHT320: 229 | return 1; 230 | } 231 | 232 | return 0; 233 | } 234 | 235 | int iwinfo_ifup(const char *ifname) 236 | { 237 | struct ifreq ifr; 238 | 239 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 240 | 241 | if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 242 | return 0; 243 | 244 | ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); 245 | 246 | return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 247 | } 248 | 249 | int iwinfo_ifdown(const char *ifname) 250 | { 251 | struct ifreq ifr; 252 | 253 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 254 | 255 | if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr)) 256 | return 0; 257 | 258 | ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING); 259 | 260 | return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr); 261 | } 262 | 263 | int iwinfo_ifmac(const char *ifname) 264 | { 265 | struct ifreq ifr; 266 | 267 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); 268 | 269 | if (iwinfo_ioctl(SIOCGIFHWADDR, &ifr)) 270 | return 0; 271 | 272 | ifr.ifr_hwaddr.sa_data[0] |= 0x02; 273 | ifr.ifr_hwaddr.sa_data[1]++; 274 | ifr.ifr_hwaddr.sa_data[2]++; 275 | 276 | return !iwinfo_ioctl(SIOCSIFHWADDR, &ifr); 277 | } 278 | 279 | void iwinfo_close(void) 280 | { 281 | if (ioctl_socket > -1) 282 | close(ioctl_socket); 283 | 284 | ioctl_socket = -1; 285 | } 286 | 287 | struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id) 288 | { 289 | FILE *db; 290 | char buf[256] = { 0 }; 291 | static struct iwinfo_hardware_entry e; 292 | struct iwinfo_hardware_entry *rv = NULL; 293 | 294 | if (!(db = fopen(IWINFO_HARDWARE_FILE, "r"))) 295 | return NULL; 296 | 297 | while (fgets(buf, sizeof(buf) - 1, db) != NULL) 298 | { 299 | if (buf[0] == '#') 300 | continue; 301 | 302 | memset(&e, 0, sizeof(e)); 303 | 304 | if (sscanf(buf, "%hx %hx %hx %hx %hd %hd \"%63[^\"]\" \"%63[^\"]\"", 305 | &e.vendor_id, &e.device_id, 306 | &e.subsystem_vendor_id, &e.subsystem_device_id, 307 | &e.txpower_offset, &e.frequency_offset, 308 | e.vendor_name, e.device_name) != 8 && 309 | sscanf(buf, "\"%127[^\"]\" %hd %hd \"%63[^\"]\" \"%63[^\"]\"", 310 | e.compatible, &e.txpower_offset, &e.frequency_offset, 311 | e.vendor_name, e.device_name) != 5) 312 | continue; 313 | 314 | if ((e.vendor_id != 0xffff) && (e.vendor_id != id->vendor_id)) 315 | continue; 316 | 317 | if ((e.device_id != 0xffff) && (e.device_id != id->device_id)) 318 | continue; 319 | 320 | if ((e.subsystem_vendor_id != 0xffff) && 321 | (e.subsystem_vendor_id != id->subsystem_vendor_id)) 322 | continue; 323 | 324 | if ((e.subsystem_device_id != 0xffff) && 325 | (e.subsystem_device_id != id->subsystem_device_id)) 326 | continue; 327 | 328 | if (strcmp(e.compatible, id->compatible)) 329 | continue; 330 | 331 | rv = &e; 332 | break; 333 | } 334 | 335 | fclose(db); 336 | return rv; 337 | } 338 | 339 | int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id) 340 | { 341 | FILE *mtd; 342 | uint16_t *bc; 343 | 344 | int fd, off; 345 | unsigned int len; 346 | char buf[128]; 347 | 348 | if (!(mtd = fopen("/proc/mtd", "r"))) 349 | return -1; 350 | 351 | while (fgets(buf, sizeof(buf), mtd) != NULL) 352 | { 353 | if (fscanf(mtd, "mtd%d: %x %*x %127s", &off, &len, buf) < 3 || 354 | (strcmp(buf, "\"boardconfig\"") && strcmp(buf, "\"EEPROM\"") && 355 | strcmp(buf, "\"factory\""))) 356 | { 357 | off = -1; 358 | continue; 359 | } 360 | 361 | break; 362 | } 363 | 364 | fclose(mtd); 365 | 366 | if (off < 0) 367 | return -1; 368 | 369 | snprintf(buf, sizeof(buf), "/dev/mtdblock%d", off); 370 | 371 | if ((fd = open(buf, O_RDONLY)) < 0) 372 | return -1; 373 | 374 | bc = mmap(NULL, len, PROT_READ, MAP_PRIVATE|MAP_LOCKED, fd, 0); 375 | 376 | if ((void *)bc != MAP_FAILED) 377 | { 378 | id->vendor_id = 0; 379 | id->device_id = 0; 380 | 381 | for (off = len / 2 - 0x800; off >= 0; off -= 0x800) 382 | { 383 | /* AR531X board data magic */ 384 | if ((bc[off] == 0x3533) && (bc[off + 1] == 0x3131)) 385 | { 386 | id->vendor_id = bc[off + 0x7d]; 387 | id->device_id = bc[off + 0x7c]; 388 | id->subsystem_vendor_id = bc[off + 0x84]; 389 | id->subsystem_device_id = bc[off + 0x83]; 390 | break; 391 | } 392 | 393 | /* AR5416 EEPROM magic */ 394 | else if ((bc[off] == 0xA55A) || (bc[off] == 0x5AA5)) 395 | { 396 | id->vendor_id = bc[off + 0x0D]; 397 | id->device_id = bc[off + 0x0E]; 398 | id->subsystem_vendor_id = bc[off + 0x13]; 399 | id->subsystem_device_id = bc[off + 0x14]; 400 | break; 401 | } 402 | 403 | /* Rt3xxx SoC */ 404 | else if ((bc[off] == 0x3050) || (bc[off] == 0x5030) || 405 | (bc[off] == 0x3051) || (bc[off] == 0x5130) || 406 | (bc[off] == 0x3052) || (bc[off] == 0x5230) || 407 | (bc[off] == 0x3350) || (bc[off] == 0x5033) || 408 | (bc[off] == 0x3352) || (bc[off] == 0x5233) || 409 | (bc[off] == 0x3662) || (bc[off] == 0x6236) || 410 | (bc[off] == 0x3883) || (bc[off] == 0x8338) || 411 | (bc[off] == 0x5350) || (bc[off] == 0x5053)) 412 | { 413 | /* vendor: RaLink */ 414 | id->vendor_id = 0x1814; 415 | id->subsystem_vendor_id = 0x1814; 416 | 417 | /* device */ 418 | if (((bc[off] & 0xf0) == 0x30) || 419 | ((bc[off] & 0xff) == 0x53)) 420 | id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 421 | else 422 | id->device_id = bc[off]; 423 | 424 | /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 425 | id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 426 | } else if ((bc[off] == 0x7620) || (bc[off] == 0x2076) || 427 | (bc[off] == 0x7628) || (bc[off] == 0x2876) || 428 | (bc[off] == 0x7688) || (bc[off] == 0x8876)) { 429 | /* vendor: MediaTek */ 430 | id->vendor_id = 0x14c3; 431 | id->subsystem_vendor_id = 0x14c3; 432 | 433 | /* device */ 434 | if ((bc[off] & 0xff) == 0x76) 435 | id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8; 436 | else 437 | id->device_id = bc[off]; 438 | 439 | /* subsystem from EEPROM_NIC_CONF0_RF_TYPE */ 440 | id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8; 441 | } 442 | } 443 | 444 | munmap(bc, len); 445 | } 446 | 447 | close(fd); 448 | 449 | return (id->vendor_id && id->device_id) ? 0 : -1; 450 | } 451 | 452 | static void iwinfo_parse_rsn_cipher(uint8_t idx, uint16_t *ciphers) 453 | { 454 | switch (idx) 455 | { 456 | case 0: 457 | *ciphers |= IWINFO_CIPHER_NONE; 458 | break; 459 | 460 | case 1: 461 | *ciphers |= IWINFO_CIPHER_WEP40; 462 | break; 463 | 464 | case 2: 465 | *ciphers |= IWINFO_CIPHER_TKIP; 466 | break; 467 | 468 | case 3: /* WRAP */ 469 | break; 470 | 471 | case 4: 472 | *ciphers |= IWINFO_CIPHER_CCMP; 473 | break; 474 | 475 | case 5: 476 | *ciphers |= IWINFO_CIPHER_WEP104; 477 | break; 478 | 479 | case 8: 480 | *ciphers |= IWINFO_CIPHER_GCMP; 481 | break; 482 | 483 | case 9: 484 | *ciphers |= IWINFO_CIPHER_GCMP256; 485 | break; 486 | 487 | case 10: 488 | *ciphers |= IWINFO_CIPHER_CCMP256; 489 | break; 490 | 491 | case 6: /* AES-128-CMAC */ 492 | case 7: /* No group addressed */ 493 | case 11: /* BIP-GMAC-128 */ 494 | case 12: /* BIP-GMAC-256 */ 495 | case 13: /* BIP-CMAC-256 */ 496 | break; 497 | } 498 | } 499 | 500 | void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len, 501 | uint16_t defcipher, uint8_t defauth) 502 | { 503 | uint16_t i, count; 504 | uint8_t wpa_version = 0; 505 | 506 | static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 }; 507 | static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac }; 508 | 509 | data += 2; 510 | len -= 2; 511 | 512 | if (!memcmp(data, ms_oui, 3)) 513 | wpa_version |= 1; 514 | else if (!memcmp(data, ieee80211_oui, 3)) 515 | wpa_version |= 2; 516 | 517 | if (len < 4) 518 | { 519 | c->group_ciphers |= defcipher; 520 | c->pair_ciphers |= defcipher; 521 | c->auth_suites |= defauth; 522 | return; 523 | } 524 | 525 | if (!memcmp(data, ms_oui, 3) || !memcmp(data, ieee80211_oui, 3)) 526 | iwinfo_parse_rsn_cipher(data[3], &c->group_ciphers); 527 | 528 | data += 4; 529 | len -= 4; 530 | 531 | if (len < 2) 532 | { 533 | c->pair_ciphers |= defcipher; 534 | c->auth_suites |= defauth; 535 | return; 536 | } 537 | 538 | count = data[0] | (data[1] << 8); 539 | if (2 + (count * 4) > len) 540 | return; 541 | 542 | for (i = 0; i < count; i++) 543 | if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 544 | !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 545 | iwinfo_parse_rsn_cipher(data[2 + (i * 4) + 3], &c->pair_ciphers); 546 | 547 | data += 2 + (count * 4); 548 | len -= 2 + (count * 4); 549 | 550 | if (len < 2) 551 | { 552 | c->auth_suites |= defauth; 553 | return; 554 | } 555 | 556 | count = data[0] | (data[1] << 8); 557 | if (2 + (count * 4) > len) 558 | return; 559 | 560 | for (i = 0; i < count; i++) 561 | { 562 | if (!memcmp(data + 2 + (i * 4), ms_oui, 3) || 563 | !memcmp(data + 2 + (i * 4), ieee80211_oui, 3)) 564 | { 565 | switch (data[2 + (i * 4) + 3]) 566 | { 567 | case 1: /* IEEE 802.1x */ 568 | c->wpa_version |= wpa_version; 569 | c->auth_suites |= IWINFO_KMGMT_8021x; 570 | break; 571 | 572 | case 2: /* PSK */ 573 | c->wpa_version |= wpa_version; 574 | c->auth_suites |= IWINFO_KMGMT_PSK; 575 | break; 576 | 577 | case 3: /* FT/IEEE 802.1X */ 578 | case 4: /* FT/PSK */ 579 | case 5: /* IEEE 802.1X/SHA-256 */ 580 | case 6: /* PSK/SHA-256 */ 581 | case 7: /* TPK Handshake */ 582 | break; 583 | 584 | case 8: /* SAE */ 585 | c->wpa_version |= 4; 586 | c->auth_suites |= IWINFO_KMGMT_SAE; 587 | break; 588 | 589 | case 9: /* FT/SAE */ 590 | case 10: /* undefined */ 591 | break; 592 | 593 | case 11: /* 802.1x Suite-B */ 594 | case 12: /* 802.1x Suite-B-192 */ 595 | case 13: /* FT/802.1x SHA-384 */ 596 | c->wpa_version |= 4; 597 | c->auth_suites |= IWINFO_KMGMT_8021x; 598 | break; 599 | 600 | case 14: /* FILS SHA-256 */ 601 | case 15: /* FILS SHA-384 */ 602 | case 16: /* FT/FILS SHA-256 */ 603 | case 17: /* FT/FILS SHA-384 */ 604 | break; 605 | 606 | case 18: /* OWE */ 607 | c->wpa_version |= 4; 608 | c->auth_suites |= IWINFO_KMGMT_OWE; 609 | break; 610 | } 611 | } 612 | } 613 | 614 | data += 2 + (count * 4); 615 | len -= 2 + (count * 4); 616 | } 617 | 618 | struct uci_section *iwinfo_uci_get_radio(const char *name, const char *type) 619 | { 620 | struct uci_ptr ptr = { 621 | .package = "wireless", 622 | .section = name, 623 | .flags = (name && *name == '@') ? UCI_LOOKUP_EXTENDED : 0, 624 | }; 625 | const char *opt; 626 | 627 | if (!uci_ctx) { 628 | uci_ctx = uci_alloc_context(); 629 | if (!uci_ctx) 630 | return NULL; 631 | } 632 | 633 | if (uci_lookup_ptr(uci_ctx, &ptr, NULL, true)) 634 | return NULL; 635 | 636 | if (!ptr.s || strcmp(ptr.s->type, "wifi-device") != 0) 637 | return NULL; 638 | 639 | opt = uci_lookup_option_string(uci_ctx, ptr.s, "type"); 640 | if (!opt || strcmp(opt, type) != 0) 641 | return NULL; 642 | 643 | return ptr.s; 644 | } 645 | 646 | void iwinfo_uci_free(void) 647 | { 648 | if (!uci_ctx) 649 | return; 650 | 651 | uci_free_context(uci_ctx); 652 | uci_ctx = NULL; 653 | } 654 | 655 | 656 | struct iwinfo_ubus_query_state { 657 | const char *ifname; 658 | const char *field; 659 | size_t len; 660 | char *buf; 661 | }; 662 | 663 | static void iwinfo_ubus_query_cb(struct ubus_request *req, int type, 664 | struct blob_attr *msg) 665 | { 666 | struct iwinfo_ubus_query_state *st = req->priv; 667 | 668 | struct blobmsg_policy pol1[2] = { 669 | { "ifname", BLOBMSG_TYPE_STRING }, 670 | { "config", BLOBMSG_TYPE_TABLE } 671 | }; 672 | 673 | struct blobmsg_policy pol2 = { st->field, BLOBMSG_TYPE_STRING }; 674 | struct blob_attr *cur, *cur2, *cur3, *cfg[2], *res; 675 | int rem, rem2, rem3; 676 | 677 | blobmsg_for_each_attr(cur, msg, rem) { 678 | if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) 679 | continue; 680 | 681 | blobmsg_for_each_attr(cur2, cur, rem2) { 682 | if (blobmsg_type(cur2) != BLOBMSG_TYPE_ARRAY) 683 | continue; 684 | 685 | if (strcmp(blobmsg_name(cur2), "interfaces")) 686 | continue; 687 | 688 | blobmsg_for_each_attr(cur3, cur2, rem3) { 689 | blobmsg_parse(pol1, sizeof(pol1) / sizeof(pol1[0]), cfg, 690 | blobmsg_data(cur3), blobmsg_len(cur3)); 691 | 692 | if (!cfg[0] || !cfg[1] || 693 | strcmp(blobmsg_get_string(cfg[0]), st->ifname)) 694 | continue; 695 | 696 | blobmsg_parse(&pol2, 1, &res, 697 | blobmsg_data(cfg[1]), blobmsg_len(cfg[1])); 698 | 699 | if (!res) 700 | continue; 701 | 702 | strncpy(st->buf, blobmsg_get_string(res), st->len); 703 | return; 704 | } 705 | } 706 | } 707 | } 708 | 709 | int iwinfo_ubus_query(const char *ifname, const char *field, 710 | char *buf, size_t len) 711 | { 712 | struct iwinfo_ubus_query_state st = { 713 | .ifname = ifname, 714 | .field = field, 715 | .buf = buf, 716 | .len = len 717 | }; 718 | 719 | struct ubus_context *ctx = NULL; 720 | struct blob_buf b = { }; 721 | int rv = -1; 722 | uint32_t id; 723 | 724 | blob_buf_init(&b, 0); 725 | 726 | ctx = ubus_connect(NULL); 727 | 728 | if (!ctx) 729 | goto out; 730 | 731 | if (ubus_lookup_id(ctx, "network.wireless", &id)) 732 | goto out; 733 | 734 | if (ubus_invoke(ctx, id, "status", b.head, iwinfo_ubus_query_cb, &st, 250)) 735 | goto out; 736 | 737 | rv = 0; 738 | 739 | out: 740 | if (ctx) 741 | ubus_free(ctx); 742 | 743 | blob_buf_free(&b); 744 | 745 | return rv; 746 | } 747 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /iwinfo_wl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Broadcom wl.o Backend 3 | * 4 | * Copyright (C) 2009 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | * 18 | * This code is based on the wlc.c utility published by OpenWrt.org . 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #include "iwinfo.h" 25 | #include "api/broadcom.h" 26 | 27 | static int wl_ioctl(const char *name, int cmd, void *buf, int len) 28 | { 29 | struct ifreq ifr; 30 | wl_ioctl_t ioc; 31 | 32 | /* do it */ 33 | ioc.cmd = cmd; 34 | ioc.buf = buf; 35 | ioc.len = len; 36 | 37 | strncpy(ifr.ifr_name, name, IFNAMSIZ); 38 | ifr.ifr_data = (caddr_t) &ioc; 39 | 40 | return iwinfo_ioctl(SIOCDEVPRIVATE, &ifr); 41 | } 42 | 43 | static int wl_iovar(const char *name, const char *cmd, const char *arg, 44 | int arglen, void *buf, int buflen) 45 | { 46 | int cmdlen = strlen(cmd) + 1; 47 | 48 | memcpy(buf, cmd, cmdlen); 49 | 50 | if (arg && arglen > 0) 51 | memcpy(buf + cmdlen, arg, arglen); 52 | 53 | return wl_ioctl(name, WLC_GET_VAR, buf, buflen); 54 | } 55 | 56 | static struct wl_maclist * wl_read_assoclist(const char *ifname) 57 | { 58 | struct wl_maclist *macs; 59 | int maclen = 4 + WL_MAX_STA_COUNT * 6; 60 | 61 | if (strstr(ifname, "wds")) 62 | return NULL; 63 | 64 | if ((macs = (struct wl_maclist *) malloc(maclen)) != NULL) 65 | { 66 | memset(macs, 0, maclen); 67 | macs->count = WL_MAX_STA_COUNT; 68 | 69 | if (!wl_ioctl(ifname, WLC_GET_ASSOCLIST, macs, maclen)) 70 | return macs; 71 | 72 | free(macs); 73 | } 74 | 75 | return NULL; 76 | } 77 | 78 | 79 | static int wl_probe(const char *ifname) 80 | { 81 | int magic; 82 | return (!wl_ioctl(ifname, WLC_GET_MAGIC, &magic, sizeof(magic)) && 83 | (magic == WLC_IOCTL_MAGIC)); 84 | } 85 | 86 | static void wl_close(void) 87 | { 88 | /* Nop */ 89 | } 90 | 91 | static int wl_get_mode(const char *ifname, int *buf) 92 | { 93 | int ret = -1; 94 | int ap, infra, passive; 95 | 96 | if ((ret = wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)))) 97 | return ret; 98 | 99 | if ((ret = wl_ioctl(ifname, WLC_GET_INFRA, &infra, sizeof(infra)))) 100 | return ret; 101 | 102 | if ((ret = wl_ioctl(ifname, WLC_GET_PASSIVE, &passive, sizeof(passive)))) 103 | return ret; 104 | 105 | if (passive) 106 | *buf = IWINFO_OPMODE_MONITOR; 107 | else if (!infra) 108 | *buf = IWINFO_OPMODE_ADHOC; 109 | else if (ap) 110 | *buf = IWINFO_OPMODE_MASTER; 111 | else 112 | *buf = IWINFO_OPMODE_CLIENT; 113 | 114 | return 0; 115 | } 116 | 117 | static int wl_get_ssid(const char *ifname, char *buf) 118 | { 119 | int ret = -1; 120 | wlc_ssid_t ssid; 121 | 122 | if (!(ret = wl_ioctl(ifname, WLC_GET_SSID, &ssid, sizeof(ssid)))) 123 | memcpy(buf, ssid.ssid, ssid.ssid_len); 124 | 125 | return ret; 126 | } 127 | 128 | static int wl_get_bssid(const char *ifname, char *buf) 129 | { 130 | int ret = -1; 131 | char bssid[6]; 132 | 133 | if (!(ret = wl_ioctl(ifname, WLC_GET_BSSID, bssid, 6))) 134 | sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", 135 | (uint8_t)bssid[0], (uint8_t)bssid[1], (uint8_t)bssid[2], 136 | (uint8_t)bssid[3], (uint8_t)bssid[4], (uint8_t)bssid[5] 137 | ); 138 | 139 | return ret; 140 | } 141 | 142 | static int wl_get_channel(const char *ifname, int *buf) 143 | { 144 | return wl_ioctl(ifname, WLC_GET_CHANNEL, buf, sizeof(buf)); 145 | } 146 | 147 | static int wl_get_center_chan1(const char *ifname, int *buf) 148 | { 149 | /* Not Supported */ 150 | return -1; 151 | } 152 | 153 | static int wl_get_center_chan2(const char *ifname, int *buf) 154 | { 155 | /* Not Supported */ 156 | return -1; 157 | } 158 | 159 | static int wl_get_frequency(const char *ifname, int *buf) 160 | { 161 | return wext_ops.frequency(ifname, buf); 162 | } 163 | 164 | static int wl_get_txpower(const char *ifname, int *buf) 165 | { 166 | /* WLC_GET_VAR "qtxpower" */ 167 | return wext_ops.txpower(ifname, buf); 168 | } 169 | 170 | static int wl_get_bitrate(const char *ifname, int *buf) 171 | { 172 | int ret = -1; 173 | int rate = 0; 174 | 175 | if( !(ret = wl_ioctl(ifname, WLC_GET_RATE, &rate, sizeof(rate))) && (rate > 0)) 176 | *buf = ((rate / 2) * 1000) + ((rate & 1) ? 500 : 0); 177 | 178 | return ret; 179 | } 180 | 181 | static int wl_get_signal(const char *ifname, int *buf) 182 | { 183 | unsigned int ap, rssi, i, rssi_count; 184 | int ioctl_req_version = 0x2000; 185 | char tmp[WLC_IOCTL_MAXLEN]; 186 | struct wl_maclist *macs = NULL; 187 | wl_sta_rssi_t starssi; 188 | 189 | memset(tmp, 0, WLC_IOCTL_MAXLEN); 190 | memcpy(tmp, &ioctl_req_version, sizeof(ioctl_req_version)); 191 | 192 | wl_ioctl(ifname, WLC_GET_BSS_INFO, tmp, WLC_IOCTL_MAXLEN); 193 | 194 | if (!wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)) && !ap) 195 | { 196 | *buf = tmp[WL_BSS_RSSI_OFFSET]; 197 | } 198 | else 199 | { 200 | rssi = rssi_count = 0; 201 | 202 | /* Calculate average rssi from conntected stations */ 203 | if ((macs = wl_read_assoclist(ifname)) != NULL) 204 | { 205 | for (i = 0; i < macs->count; i++) 206 | { 207 | memcpy(starssi.mac, &macs->ea[i], 6); 208 | 209 | if (!wl_ioctl(ifname, WLC_GET_RSSI, &starssi, 12)) 210 | { 211 | rssi -= starssi.rssi; 212 | rssi_count++; 213 | } 214 | } 215 | 216 | free(macs); 217 | } 218 | 219 | *buf = (rssi == 0 || rssi_count == 0) ? 1 : -(rssi / rssi_count); 220 | } 221 | 222 | return 0; 223 | } 224 | 225 | static int wl_get_noise(const char *ifname, int *buf) 226 | { 227 | unsigned int ap, noise; 228 | int ioctl_req_version = 0x2000; 229 | char tmp[WLC_IOCTL_MAXLEN]; 230 | 231 | memset(tmp, 0, WLC_IOCTL_MAXLEN); 232 | memcpy(tmp, &ioctl_req_version, sizeof(ioctl_req_version)); 233 | 234 | wl_ioctl(ifname, WLC_GET_BSS_INFO, tmp, WLC_IOCTL_MAXLEN); 235 | 236 | if ((wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)) < 0) || ap) 237 | { 238 | if (wl_ioctl(ifname, WLC_GET_PHY_NOISE, &noise, sizeof(noise)) < 0) 239 | noise = 0; 240 | } 241 | else 242 | { 243 | noise = tmp[WL_BSS_NOISE_OFFSET]; 244 | } 245 | 246 | *buf = noise; 247 | 248 | return 0; 249 | } 250 | 251 | static int wl_get_quality(const char *ifname, int *buf) 252 | { 253 | return wext_ops.quality(ifname, buf); 254 | } 255 | 256 | static int wl_get_quality_max(const char *ifname, int *buf) 257 | { 258 | return wext_ops.quality_max(ifname, buf); 259 | } 260 | 261 | static int wl_get_encryption(const char *ifname, char *buf) 262 | { 263 | uint32_t wsec, wauth, wpa; 264 | struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf; 265 | 266 | if( wl_ioctl(ifname, WLC_GET_WPA_AUTH, &wpa, sizeof(uint32_t)) || 267 | wl_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(uint32_t)) || 268 | wl_ioctl(ifname, WLC_GET_AUTH, &wauth, sizeof(uint32_t)) ) 269 | return -1; 270 | 271 | switch(wsec) 272 | { 273 | case 2: 274 | c->pair_ciphers |= IWINFO_CIPHER_TKIP; 275 | break; 276 | 277 | case 4: 278 | c->pair_ciphers |= IWINFO_CIPHER_CCMP; 279 | break; 280 | 281 | case 6: 282 | c->pair_ciphers |= IWINFO_CIPHER_TKIP; 283 | c->pair_ciphers |= IWINFO_CIPHER_CCMP; 284 | break; 285 | } 286 | 287 | switch(wpa) 288 | { 289 | case 0: 290 | if (wsec && !wauth) 291 | c->auth_algs |= IWINFO_AUTH_OPEN; 292 | 293 | else if (wsec && wauth) 294 | c->auth_algs |= IWINFO_AUTH_SHARED; 295 | 296 | /* ToDo: evaluate WEP key lengths */ 297 | c->pair_ciphers = IWINFO_CIPHER_WEP40 | IWINFO_CIPHER_WEP104; 298 | c->auth_suites |= IWINFO_KMGMT_NONE; 299 | break; 300 | 301 | case 2: 302 | c->wpa_version = 1; 303 | c->auth_suites |= IWINFO_KMGMT_8021x; 304 | break; 305 | 306 | case 4: 307 | c->wpa_version = 1; 308 | c->auth_suites |= IWINFO_KMGMT_PSK; 309 | break; 310 | 311 | case 32: 312 | case 64: 313 | c->wpa_version = 2; 314 | c->auth_suites |= IWINFO_KMGMT_8021x; 315 | break; 316 | 317 | case 66: 318 | c->wpa_version = 3; 319 | c->auth_suites |= IWINFO_KMGMT_8021x; 320 | break; 321 | 322 | case 128: 323 | c->wpa_version = 2; 324 | c->auth_suites |= IWINFO_KMGMT_PSK; 325 | break; 326 | 327 | case 132: 328 | c->wpa_version = 3; 329 | c->auth_suites |= IWINFO_KMGMT_PSK; 330 | break; 331 | 332 | default: 333 | break; 334 | } 335 | 336 | c->enabled = (c->wpa_version || c->auth_algs) ? 1 : 0; 337 | c->group_ciphers = c->pair_ciphers; 338 | 339 | return 0; 340 | } 341 | 342 | static int wl_get_phyname(const char *ifname, char *buf) 343 | { 344 | char *p; 345 | 346 | strcpy(buf, ifname); 347 | 348 | if ((p = strchr(buf, '.')) != NULL) 349 | *p = 0; 350 | 351 | return 0; 352 | } 353 | 354 | static int wl_get_enctype(const char *ifname, char *buf) 355 | { 356 | uint32_t wsec, wpa; 357 | char algo[11]; 358 | 359 | if( wl_ioctl(ifname, WLC_GET_WPA_AUTH, &wpa, sizeof(uint32_t)) || 360 | wl_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(uint32_t)) ) 361 | return -1; 362 | 363 | switch(wsec) 364 | { 365 | case 2: 366 | sprintf(algo, "TKIP"); 367 | break; 368 | 369 | case 4: 370 | sprintf(algo, "CCMP"); 371 | break; 372 | 373 | case 6: 374 | sprintf(algo, "TKIP, CCMP"); 375 | break; 376 | } 377 | 378 | switch(wpa) 379 | { 380 | case 0: 381 | sprintf(buf, "%s", wsec ? "WEP" : "None"); 382 | break; 383 | 384 | case 2: 385 | sprintf(buf, "WPA 802.1X (%s)", algo); 386 | break; 387 | 388 | case 4: 389 | sprintf(buf, "WPA PSK (%s)", algo); 390 | break; 391 | 392 | case 32: 393 | sprintf(buf, "802.1X (%s)", algo); 394 | break; 395 | 396 | case 64: 397 | sprintf(buf, "WPA2 802.1X (%s)", algo); 398 | break; 399 | 400 | case 66: 401 | sprintf(buf, "mixed WPA/WPA2 802.1X (%s)", algo); 402 | break; 403 | 404 | case 128: 405 | sprintf(buf, "WPA2 PSK (%s)", algo); 406 | break; 407 | 408 | case 132: 409 | sprintf(buf, "mixed WPA/WPA2 PSK (%s)", algo); 410 | break; 411 | 412 | default: 413 | sprintf(buf, "Unknown"); 414 | } 415 | 416 | return 0; 417 | } 418 | 419 | static void wl_get_assoclist_cb(const char *ifname, 420 | struct iwinfo_assoclist_entry *e) 421 | { 422 | wl_sta_info_t sta = { 0 }; 423 | 424 | if (!wl_iovar(ifname, "sta_info", e->mac, 6, &sta, sizeof(sta)) && 425 | (sta.ver >= 2)) 426 | { 427 | e->inactive = sta.idle * 1000; 428 | e->rx_packets = sta.rx_ucast_pkts; 429 | e->tx_packets = sta.tx_pkts; 430 | e->rx_rate.rate = sta.rx_rate; 431 | e->tx_rate.rate = sta.tx_rate; 432 | 433 | /* ToDo: 11n */ 434 | e->rx_rate.mcs = -1; 435 | e->tx_rate.mcs = -1; 436 | } 437 | } 438 | 439 | static int wl_get_assoclist(const char *ifname, char *buf, int *len) 440 | { 441 | int i, j, noise; 442 | int ap, infra, passive; 443 | char line[128]; 444 | char macstr[18]; 445 | char devstr[IFNAMSIZ]; 446 | struct wl_maclist *macs; 447 | struct wl_sta_rssi rssi; 448 | struct iwinfo_assoclist_entry entry; 449 | FILE *arp; 450 | 451 | ap = infra = passive = 0; 452 | 453 | wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)); 454 | wl_ioctl(ifname, WLC_GET_INFRA, &infra, sizeof(infra)); 455 | wl_ioctl(ifname, WLC_GET_PASSIVE, &passive, sizeof(passive)); 456 | 457 | if (wl_get_noise(ifname, &noise)) 458 | noise = 0; 459 | 460 | if ((ap || infra || passive) && ((macs = wl_read_assoclist(ifname)) != NULL)) 461 | { 462 | for (i = 0, j = 0; i < macs->count; i++, j += sizeof(struct iwinfo_assoclist_entry)) 463 | { 464 | memset(&entry, 0, sizeof(entry)); 465 | memcpy(rssi.mac, &macs->ea[i], 6); 466 | 467 | if (!wl_ioctl(ifname, WLC_GET_RSSI, &rssi, sizeof(struct wl_sta_rssi))) 468 | entry.signal = (rssi.rssi - 0x100); 469 | else 470 | entry.signal = 0; 471 | 472 | entry.noise = noise; 473 | memcpy(entry.mac, &macs->ea[i], 6); 474 | wl_get_assoclist_cb(ifname, &entry); 475 | 476 | memcpy(&buf[j], &entry, sizeof(entry)); 477 | } 478 | 479 | *len = j; 480 | free(macs); 481 | return 0; 482 | } 483 | else if ((arp = fopen("/proc/net/arp", "r")) != NULL) 484 | { 485 | j = 0; 486 | 487 | while (fgets(line, sizeof(line), arp) != NULL) 488 | { 489 | if (sscanf(line, "%*s 0x%*d 0x%*d %17s %*s %s", macstr, devstr) && !strcmp(devstr, ifname)) 490 | { 491 | rssi.mac[0] = strtol(&macstr[0], NULL, 16); 492 | rssi.mac[1] = strtol(&macstr[3], NULL, 16); 493 | rssi.mac[2] = strtol(&macstr[6], NULL, 16); 494 | rssi.mac[3] = strtol(&macstr[9], NULL, 16); 495 | rssi.mac[4] = strtol(&macstr[12], NULL, 16); 496 | rssi.mac[5] = strtol(&macstr[15], NULL, 16); 497 | 498 | if (!wl_ioctl(ifname, WLC_GET_RSSI, &rssi, sizeof(struct wl_sta_rssi))) 499 | entry.signal = (rssi.rssi - 0x100); 500 | else 501 | entry.signal = 0; 502 | 503 | entry.noise = noise; 504 | memcpy(entry.mac, rssi.mac, 6); 505 | memcpy(&buf[j], &entry, sizeof(entry)); 506 | 507 | j += sizeof(entry); 508 | } 509 | } 510 | 511 | *len = j; 512 | (void) fclose(arp); 513 | return 0; 514 | } 515 | 516 | return -1; 517 | } 518 | 519 | static int wl_get_txpwrlist(const char *ifname, char *buf, int *len) 520 | { 521 | struct iwinfo_txpwrlist_entry entry; 522 | uint8_t dbm[11] = { 0, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 }; 523 | uint8_t mw[11] = { 1, 3, 6, 10, 15, 25, 39, 63, 100, 158, 251 }; 524 | int i; 525 | 526 | for (i = 0; i < 11; i++) 527 | { 528 | entry.dbm = dbm[i]; 529 | entry.mw = mw[i]; 530 | memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry)); 531 | } 532 | 533 | *len = 11 * sizeof(entry); 534 | return 0; 535 | } 536 | 537 | static int wl_get_scanlist(const char *ifname, char *buf, int *len) 538 | { 539 | return wext_ops.scanlist(ifname, buf, len); 540 | } 541 | 542 | static int wl_get_freqlist(const char *ifname, char *buf, int *len) 543 | { 544 | return wext_ops.freqlist(ifname, buf, len); 545 | } 546 | 547 | static int wl_get_country(const char *ifname, char *buf) 548 | { 549 | char ccode[WLC_CNTRY_BUF_SZ]; 550 | 551 | if (!wl_ioctl(ifname, WLC_GET_COUNTRY, ccode, WLC_CNTRY_BUF_SZ)) 552 | { 553 | /* IL0 -> World */ 554 | if (!strcmp(ccode, "IL0")) 555 | sprintf(buf, "00"); 556 | 557 | /* YU -> RS */ 558 | else if (!strcmp(ccode, "YU")) 559 | sprintf(buf, "RS"); 560 | 561 | else 562 | memcpy(buf, ccode, 2); 563 | 564 | return 0; 565 | } 566 | 567 | return -1; 568 | } 569 | 570 | static int wl_get_countrylist(const char *ifname, char *buf, int *len) 571 | { 572 | int i, count; 573 | char cdata[WLC_IOCTL_MAXLEN]; 574 | struct iwinfo_country_entry *c = (struct iwinfo_country_entry *)buf; 575 | wl_country_list_t *cl = (wl_country_list_t *)cdata; 576 | 577 | cl->buflen = sizeof(cdata); 578 | 579 | if (!wl_ioctl(ifname, WLC_GET_COUNTRY_LIST, cl, cl->buflen)) 580 | { 581 | for (i = 0, count = 0; i < cl->count; i++, c++) 582 | { 583 | snprintf(c->ccode, sizeof(c->ccode), "%s", &cl->country_abbrev[i * WLC_CNTRY_BUF_SZ]); 584 | c->iso3166 = c->ccode[0] * 256 + c->ccode[1]; 585 | 586 | /* IL0 -> World */ 587 | if (!strcmp(c->ccode, "IL0")) 588 | c->iso3166 = 0x3030; 589 | 590 | /* YU -> RS */ 591 | else if (!strcmp(c->ccode, "YU")) 592 | c->iso3166 = 0x5253; 593 | } 594 | 595 | *len = (i * sizeof(struct iwinfo_country_entry)); 596 | return 0; 597 | } 598 | 599 | return -1; 600 | } 601 | 602 | static int wl_get_hwmodelist(const char *ifname, int *buf) 603 | { 604 | int phytype; 605 | uint i, band[WLC_BAND_ALL], bands; 606 | 607 | if (!wl_ioctl(ifname, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)) && 608 | !wl_ioctl(ifname, WLC_GET_BANDLIST, band, sizeof(band))) 609 | { 610 | *buf = 0; 611 | switch (phytype) 612 | { 613 | case WLC_PHY_TYPE_A: 614 | *buf = IWINFO_80211_A; 615 | break; 616 | case WLC_PHY_TYPE_B: 617 | *buf = IWINFO_80211_B; 618 | break; 619 | case WLC_PHY_TYPE_AC: 620 | *buf |= IWINFO_80211_AC; 621 | case WLC_PHY_TYPE_HT: 622 | case WLC_PHY_TYPE_N: 623 | *buf |= IWINFO_80211_N; 624 | case WLC_PHY_TYPE_LP: 625 | case WLC_PHY_TYPE_G: 626 | bands = 0; 627 | for (i = 1; i <= band[0]; i++) 628 | { 629 | bands |= band[i]; 630 | } 631 | if (bands & WLC_BAND_5G) 632 | *buf |= IWINFO_80211_A; 633 | if (bands & WLC_BAND_2G) 634 | { 635 | *buf |= IWINFO_80211_B; 636 | *buf |= IWINFO_80211_G; 637 | } 638 | break; 639 | default: 640 | return -1; 641 | break; 642 | } 643 | return 0; 644 | } 645 | return -1; 646 | } 647 | 648 | static int wl_get_htmodelist(const char *ifname, int *buf) 649 | { 650 | int modes; 651 | 652 | if (!wl_get_hwmodelist(ifname, &modes)) 653 | { 654 | *buf = 0; 655 | 656 | /* FIXME: determine real capabilities */ 657 | 658 | if (modes & IWINFO_80211_N) 659 | *buf |= IWINFO_HTMODE_HT20 | IWINFO_HTMODE_HT40; 660 | 661 | if (modes & IWINFO_80211_AC) 662 | *buf |= IWINFO_HTMODE_VHT20 | IWINFO_HTMODE_VHT40 | 663 | IWINFO_HTMODE_VHT80; 664 | 665 | return 0; 666 | } 667 | 668 | return -1; 669 | } 670 | 671 | static int wl_get_mbssid_support(const char *ifname, int *buf) 672 | { 673 | wlc_rev_info_t revinfo; 674 | 675 | /* Multi bssid support only works on corerev >= 9 */ 676 | if (!wl_ioctl(ifname, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) 677 | { 678 | if (revinfo.corerev >= 9) 679 | { 680 | *buf = 1; 681 | return 0; 682 | } 683 | } 684 | 685 | return -1; 686 | } 687 | 688 | static int wl_get_hardware_id(const char *ifname, char *buf) 689 | { 690 | wlc_rev_info_t revinfo; 691 | struct iwinfo_hardware_id *ids = (struct iwinfo_hardware_id *)buf; 692 | 693 | if (wl_ioctl(ifname, WLC_GET_REVINFO, &revinfo, sizeof(revinfo))) 694 | return -1; 695 | 696 | ids->vendor_id = revinfo.vendorid; 697 | ids->device_id = revinfo.deviceid; 698 | ids->subsystem_vendor_id = revinfo.boardvendor; 699 | ids->subsystem_device_id = revinfo.boardid; 700 | 701 | return 0; 702 | } 703 | 704 | static int wl_get_hardware_name(const char *ifname, char *buf) 705 | { 706 | struct iwinfo_hardware_id ids; 707 | 708 | if (wl_get_hardware_id(ifname, (char *)&ids)) 709 | return -1; 710 | 711 | sprintf(buf, "Broadcom BCM%04X", ids.device_id); 712 | 713 | return 0; 714 | } 715 | 716 | static int wl_get_txpower_offset(const char *ifname, int *buf) 717 | { 718 | FILE *p; 719 | char off[8]; 720 | struct stat s; 721 | 722 | *buf = 0; 723 | 724 | if (!stat("/usr/sbin/nvram", &s) && (s.st_mode & S_IXUSR)) 725 | { 726 | if ((p = popen("/usr/sbin/nvram get opo", "r")) != NULL) 727 | { 728 | if (fread(off, 1, sizeof(off), p)) 729 | *buf = strtoul(off, NULL, 16); 730 | 731 | pclose(p); 732 | } 733 | } 734 | 735 | return 0; 736 | } 737 | 738 | static int wl_get_frequency_offset(const char *ifname, int *buf) 739 | { 740 | /* Stub */ 741 | *buf = 0; 742 | return -1; 743 | } 744 | 745 | const struct iwinfo_ops wl_ops = { 746 | .name = "wl", 747 | .probe = wl_probe, 748 | .channel = wl_get_channel, 749 | .center_chan1 = wl_get_center_chan1, 750 | .center_chan2 = wl_get_center_chan2, 751 | .frequency = wl_get_frequency, 752 | .frequency_offset = wl_get_frequency_offset, 753 | .txpower = wl_get_txpower, 754 | .txpower_offset = wl_get_txpower_offset, 755 | .bitrate = wl_get_bitrate, 756 | .signal = wl_get_signal, 757 | .noise = wl_get_noise, 758 | .quality = wl_get_quality, 759 | .quality_max = wl_get_quality_max, 760 | .mbssid_support = wl_get_mbssid_support, 761 | .hwmodelist = wl_get_hwmodelist, 762 | .htmodelist = wl_get_htmodelist, 763 | .mode = wl_get_mode, 764 | .ssid = wl_get_ssid, 765 | .bssid = wl_get_bssid, 766 | .country = wl_get_country, 767 | .hardware_id = wl_get_hardware_id, 768 | .hardware_name = wl_get_hardware_name, 769 | .encryption = wl_get_encryption, 770 | .phyname = wl_get_phyname, 771 | .assoclist = wl_get_assoclist, 772 | .txpwrlist = wl_get_txpwrlist, 773 | .scanlist = wl_get_scanlist, 774 | .freqlist = wl_get_freqlist, 775 | .countrylist = wl_get_countrylist, 776 | .close = wl_close 777 | }; 778 | -------------------------------------------------------------------------------- /iwinfo_lua.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Lua Bindings 3 | * 4 | * Copyright (C) 2009 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #include "iwinfo/lua.h" 20 | 21 | 22 | /* Determine type */ 23 | static int iwinfo_L_type(lua_State *L) 24 | { 25 | const char *ifname = luaL_checkstring(L, 1); 26 | const char *type = iwinfo_type(ifname); 27 | 28 | if (type) 29 | lua_pushstring(L, type); 30 | else 31 | lua_pushnil(L); 32 | 33 | return 1; 34 | } 35 | 36 | /* Shutdown backends */ 37 | static int iwinfo_L__gc(lua_State *L) 38 | { 39 | iwinfo_finish(); 40 | return 0; 41 | } 42 | 43 | /* 44 | * Build a short textual description of the crypto info 45 | */ 46 | 47 | static char * iwinfo_crypto_print_ciphers(int ciphers) 48 | { 49 | static char str[128] = { 0 }; 50 | char *pos = str; 51 | 52 | if (ciphers & IWINFO_CIPHER_WEP40) 53 | pos += sprintf(pos, "WEP-40, "); 54 | 55 | if (ciphers & IWINFO_CIPHER_WEP104) 56 | pos += sprintf(pos, "WEP-104, "); 57 | 58 | if (ciphers & IWINFO_CIPHER_TKIP) 59 | pos += sprintf(pos, "TKIP, "); 60 | 61 | if (ciphers & IWINFO_CIPHER_CCMP) 62 | pos += sprintf(pos, "CCMP, "); 63 | 64 | if (ciphers & IWINFO_CIPHER_CCMP256) 65 | pos += sprintf(pos, "CCMP-256, "); 66 | 67 | if (ciphers & IWINFO_CIPHER_GCMP) 68 | pos += sprintf(pos, "GCMP, "); 69 | 70 | if (ciphers & IWINFO_CIPHER_GCMP256) 71 | pos += sprintf(pos, "GCMP-256, "); 72 | 73 | if (ciphers & IWINFO_CIPHER_WRAP) 74 | pos += sprintf(pos, "WRAP, "); 75 | 76 | if (ciphers & IWINFO_CIPHER_AESOCB) 77 | pos += sprintf(pos, "AES-OCB, "); 78 | 79 | if (ciphers & IWINFO_CIPHER_CKIP) 80 | pos += sprintf(pos, "CKIP, "); 81 | 82 | if (!ciphers || (ciphers & IWINFO_CIPHER_NONE)) 83 | pos += sprintf(pos, "NONE, "); 84 | 85 | *(pos - 2) = 0; 86 | 87 | return str; 88 | } 89 | 90 | static char * iwinfo_crypto_print_suites(int suites) 91 | { 92 | static char str[64] = { 0 }; 93 | char *pos = str; 94 | 95 | if (suites & IWINFO_KMGMT_PSK) 96 | pos += sprintf(pos, "PSK/"); 97 | 98 | if (suites & IWINFO_KMGMT_8021x) 99 | pos += sprintf(pos, "802.1X/"); 100 | 101 | if (suites & IWINFO_KMGMT_SAE) 102 | pos += sprintf(pos, "SAE/"); 103 | 104 | if (suites & IWINFO_KMGMT_OWE) 105 | pos += sprintf(pos, "OWE/"); 106 | 107 | if (!suites || (suites & IWINFO_KMGMT_NONE)) 108 | pos += sprintf(pos, "NONE/"); 109 | 110 | *(pos - 1) = 0; 111 | 112 | return str; 113 | } 114 | 115 | static char * iwinfo_crypto_desc(struct iwinfo_crypto_entry *c) 116 | { 117 | static char desc[512] = { 0 }; 118 | char *pos = desc; 119 | int i, n; 120 | 121 | if (c) 122 | { 123 | if (c->enabled) 124 | { 125 | /* WEP */ 126 | if (c->auth_algs && !c->wpa_version) 127 | { 128 | if ((c->auth_algs & IWINFO_AUTH_OPEN) && 129 | (c->auth_algs & IWINFO_AUTH_SHARED)) 130 | { 131 | sprintf(desc, "WEP Open/Shared (%s)", 132 | iwinfo_crypto_print_ciphers(c->pair_ciphers)); 133 | } 134 | else if (c->auth_algs & IWINFO_AUTH_OPEN) 135 | { 136 | sprintf(desc, "WEP Open System (%s)", 137 | iwinfo_crypto_print_ciphers(c->pair_ciphers)); 138 | } 139 | else if (c->auth_algs & IWINFO_AUTH_SHARED) 140 | { 141 | sprintf(desc, "WEP Shared Auth (%s)", 142 | iwinfo_crypto_print_ciphers(c->pair_ciphers)); 143 | } 144 | } 145 | 146 | /* WPA */ 147 | else if (c->wpa_version) 148 | { 149 | for (i = 0, n = 0; i < 3; i++) 150 | if (c->wpa_version & (1 << i)) 151 | n++; 152 | 153 | if (n > 1) 154 | pos += sprintf(pos, "mixed "); 155 | 156 | for (i = 0; i < 3; i++) 157 | if (c->wpa_version & (1 << i)) 158 | { 159 | if (i) 160 | pos += sprintf(pos, "WPA%d/", i + 1); 161 | else 162 | pos += sprintf(pos, "WPA/"); 163 | } 164 | 165 | pos--; 166 | 167 | sprintf(pos, " %s (%s)", 168 | iwinfo_crypto_print_suites(c->auth_suites), 169 | iwinfo_crypto_print_ciphers( 170 | c->pair_ciphers | c->group_ciphers)); 171 | } 172 | else 173 | { 174 | sprintf(desc, "None"); 175 | } 176 | } 177 | else 178 | { 179 | sprintf(desc, "None"); 180 | } 181 | } 182 | else 183 | { 184 | sprintf(desc, "Unknown"); 185 | } 186 | 187 | return desc; 188 | } 189 | 190 | /* Build Lua table from crypto data */ 191 | static void iwinfo_L_cryptotable(lua_State *L, struct iwinfo_crypto_entry *c) 192 | { 193 | int i, j; 194 | 195 | lua_newtable(L); 196 | 197 | lua_pushboolean(L, c->enabled); 198 | lua_setfield(L, -2, "enabled"); 199 | 200 | lua_pushstring(L, iwinfo_crypto_desc(c)); 201 | lua_setfield(L, -2, "description"); 202 | 203 | lua_pushboolean(L, (c->enabled && !c->wpa_version)); 204 | lua_setfield(L, -2, "wep"); 205 | 206 | lua_pushinteger(L, c->wpa_version); 207 | lua_setfield(L, -2, "wpa"); 208 | 209 | lua_newtable(L); 210 | for (i = 0, j = 1; i < ARRAY_SIZE(IWINFO_CIPHER_NAMES); i++) 211 | { 212 | if (c->pair_ciphers & (1 << i)) 213 | { 214 | lua_pushstring(L, IWINFO_CIPHER_NAMES[i]); 215 | lua_rawseti(L, -2, j++); 216 | } 217 | } 218 | lua_setfield(L, -2, "pair_ciphers"); 219 | 220 | lua_newtable(L); 221 | for (i = 0, j = 1; i < ARRAY_SIZE(IWINFO_CIPHER_NAMES); i++) 222 | { 223 | if (c->group_ciphers & (1 << i)) 224 | { 225 | lua_pushstring(L, IWINFO_CIPHER_NAMES[i]); 226 | lua_rawseti(L, -2, j++); 227 | } 228 | } 229 | lua_setfield(L, -2, "group_ciphers"); 230 | 231 | lua_newtable(L); 232 | for (i = 0, j = 1; i < ARRAY_SIZE(IWINFO_KMGMT_NAMES); i++) 233 | { 234 | if (c->auth_suites & (1 << i)) 235 | { 236 | lua_pushstring(L, IWINFO_KMGMT_NAMES[i]); 237 | lua_rawseti(L, -2, j++); 238 | } 239 | } 240 | lua_setfield(L, -2, "auth_suites"); 241 | 242 | lua_newtable(L); 243 | for (i = 0, j = 1; i < ARRAY_SIZE(IWINFO_AUTH_NAMES); i++) 244 | { 245 | if (c->auth_algs & (1 << i)) 246 | { 247 | lua_pushstring(L, IWINFO_AUTH_NAMES[i]); 248 | lua_rawseti(L, -2, j++); 249 | } 250 | } 251 | lua_setfield(L, -2, "auth_algs"); 252 | } 253 | 254 | 255 | /* Wrapper for mode */ 256 | static int iwinfo_L_mode(lua_State *L, int (*func)(const char *, int *)) 257 | { 258 | int mode; 259 | const char *ifname = luaL_checkstring(L, 1); 260 | 261 | if ((*func)(ifname, &mode)) 262 | mode = IWINFO_OPMODE_UNKNOWN; 263 | 264 | lua_pushstring(L, IWINFO_OPMODE_NAMES[mode]); 265 | return 1; 266 | } 267 | 268 | static void set_rateinfo(lua_State *L, struct iwinfo_rate_entry *r, bool rx) 269 | { 270 | lua_pushnumber(L, r->rate); 271 | lua_setfield(L, -2, rx ? "rx_rate" : "tx_rate"); 272 | 273 | lua_pushboolean(L, r->is_ht); 274 | lua_setfield(L, -2, rx ? "rx_ht" : "tx_ht"); 275 | 276 | lua_pushboolean(L, r->is_vht); 277 | lua_setfield(L, -2, rx ? "rx_vht" : "tx_vht"); 278 | 279 | lua_pushboolean(L, r->is_he); 280 | lua_setfield(L, -2, rx ? "rx_he" : "tx_he"); 281 | 282 | lua_pushboolean(L, r->is_eht); 283 | lua_setfield(L, -2, rx ? "rx_eht" : "tx_eht"); 284 | 285 | lua_pushnumber(L, r->mhz_hi * 256 + r->mhz); 286 | lua_setfield(L, -2, rx ? "rx_mhz" : "tx_mhz"); 287 | 288 | if (r->is_ht) 289 | { 290 | lua_pushboolean(L, r->is_40mhz); 291 | lua_setfield(L, -2, rx ? "rx_40mhz" : "tx_40mhz"); 292 | 293 | lua_pushnumber(L, r->mcs); 294 | lua_setfield(L, -2, rx ? "rx_mcs" : "tx_mcs"); 295 | 296 | lua_pushboolean(L, r->is_short_gi); 297 | lua_setfield(L, -2, rx ? "rx_short_gi" : "tx_short_gi"); 298 | } 299 | else if (r->is_vht || r->is_he | r->is_eht) 300 | { 301 | lua_pushnumber(L, r->mcs); 302 | lua_setfield(L, -2, rx ? "rx_mcs" : "tx_mcs"); 303 | 304 | lua_pushnumber(L, r->nss); 305 | lua_setfield(L, -2, rx ? "rx_nss" : "tx_nss"); 306 | 307 | if (r->is_he) { 308 | lua_pushnumber(L, r->he_gi); 309 | lua_setfield(L, -2, rx ? "rx_he_gi" : "tx_he_gi"); 310 | 311 | lua_pushnumber(L, r->he_dcm); 312 | lua_setfield(L, -2, rx ? "rx_he_dcm" : "tx_he_dcm"); 313 | } 314 | 315 | if (r->is_eht) { 316 | lua_pushnumber(L, r->eht_gi); 317 | lua_setfield(L, -2, rx ? "rx_eht_gi" : "tx_eht_gi"); 318 | } 319 | 320 | if (r->is_vht) { 321 | lua_pushboolean(L, r->is_short_gi); 322 | lua_setfield(L, -2, rx ? "rx_short_gi" : "tx_short_gi"); 323 | } 324 | } 325 | } 326 | 327 | /* Wrapper for assoclist */ 328 | static int iwinfo_L_assoclist(lua_State *L, int (*func)(const char *, char *, int *)) 329 | { 330 | int i, len; 331 | char rv[IWINFO_BUFSIZE]; 332 | char macstr[18]; 333 | const char *ifname = luaL_checkstring(L, 1); 334 | struct iwinfo_assoclist_entry *e; 335 | 336 | lua_newtable(L); 337 | memset(rv, 0, sizeof(rv)); 338 | 339 | if (!(*func)(ifname, rv, &len)) 340 | { 341 | for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) 342 | { 343 | e = (struct iwinfo_assoclist_entry *) &rv[i]; 344 | 345 | sprintf(macstr, "%02X:%02X:%02X:%02X:%02X:%02X", 346 | e->mac[0], e->mac[1], e->mac[2], 347 | e->mac[3], e->mac[4], e->mac[5]); 348 | 349 | lua_newtable(L); 350 | 351 | lua_pushnumber(L, e->signal); 352 | lua_setfield(L, -2, "signal"); 353 | 354 | lua_pushnumber(L, e->noise); 355 | lua_setfield(L, -2, "noise"); 356 | 357 | lua_pushnumber(L, e->inactive); 358 | lua_setfield(L, -2, "inactive"); 359 | 360 | lua_pushnumber(L, e->rx_packets); 361 | lua_setfield(L, -2, "rx_packets"); 362 | 363 | lua_pushnumber(L, e->tx_packets); 364 | lua_setfield(L, -2, "tx_packets"); 365 | 366 | set_rateinfo(L, &e->rx_rate, true); 367 | set_rateinfo(L, &e->tx_rate, false); 368 | 369 | if (e->thr) { 370 | lua_pushnumber(L, e->thr); 371 | lua_setfield(L, -2, "expected_throughput"); 372 | } 373 | 374 | lua_setfield(L, -2, macstr); 375 | } 376 | } 377 | 378 | return 1; 379 | } 380 | 381 | /* Wrapper for tx power list */ 382 | static int iwinfo_L_txpwrlist(lua_State *L, int (*func)(const char *, char *, int *)) 383 | { 384 | int i, x, len; 385 | char rv[IWINFO_BUFSIZE]; 386 | const char *ifname = luaL_checkstring(L, 1); 387 | struct iwinfo_txpwrlist_entry *e; 388 | 389 | memset(rv, 0, sizeof(rv)); 390 | 391 | if (!(*func)(ifname, rv, &len)) 392 | { 393 | lua_newtable(L); 394 | 395 | for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_txpwrlist_entry), x++) 396 | { 397 | e = (struct iwinfo_txpwrlist_entry *) &rv[i]; 398 | 399 | lua_newtable(L); 400 | 401 | lua_pushnumber(L, e->mw); 402 | lua_setfield(L, -2, "mw"); 403 | 404 | lua_pushnumber(L, e->dbm); 405 | lua_setfield(L, -2, "dbm"); 406 | 407 | lua_rawseti(L, -2, x); 408 | } 409 | 410 | return 1; 411 | } 412 | 413 | return 0; 414 | } 415 | 416 | /* Wrapper for scan list */ 417 | static int iwinfo_L_scanlist(lua_State *L, int (*func)(const char *, char *, int *)) 418 | { 419 | int i, x, len = 0; 420 | char rv[IWINFO_BUFSIZE]; 421 | char macstr[18]; 422 | const char *ifname = luaL_checkstring(L, 1); 423 | struct iwinfo_scanlist_entry *e; 424 | 425 | lua_newtable(L); 426 | memset(rv, 0, sizeof(rv)); 427 | 428 | if (!(*func)(ifname, rv, &len)) 429 | { 430 | for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_scanlist_entry), x++) 431 | { 432 | e = (struct iwinfo_scanlist_entry *) &rv[i]; 433 | 434 | lua_newtable(L); 435 | 436 | /* BSSID */ 437 | sprintf(macstr, "%02X:%02X:%02X:%02X:%02X:%02X", 438 | e->mac[0], e->mac[1], e->mac[2], 439 | e->mac[3], e->mac[4], e->mac[5]); 440 | 441 | lua_pushstring(L, macstr); 442 | lua_setfield(L, -2, "bssid"); 443 | 444 | /* ESSID */ 445 | if (e->ssid[0]) 446 | { 447 | lua_pushstring(L, (char *) e->ssid); 448 | lua_setfield(L, -2, "ssid"); 449 | } 450 | 451 | /* Channel */ 452 | lua_pushinteger(L, e->channel); 453 | lua_setfield(L, -2, "channel"); 454 | 455 | /* Mode */ 456 | lua_pushstring(L, IWINFO_OPMODE_NAMES[e->mode]); 457 | lua_setfield(L, -2, "mode"); 458 | 459 | /* Quality, Signal */ 460 | lua_pushinteger(L, e->quality); 461 | lua_setfield(L, -2, "quality"); 462 | 463 | lua_pushinteger(L, e->quality_max); 464 | lua_setfield(L, -2, "quality_max"); 465 | 466 | lua_pushnumber(L, (e->signal - 0x100)); 467 | lua_setfield(L, -2, "signal"); 468 | 469 | /* Crypto */ 470 | iwinfo_L_cryptotable(L, &e->crypto); 471 | lua_setfield(L, -2, "encryption"); 472 | 473 | lua_rawseti(L, -2, x); 474 | } 475 | } 476 | 477 | return 1; 478 | } 479 | 480 | /* Wrapper for frequency list */ 481 | static int iwinfo_L_freqlist(lua_State *L, int (*func)(const char *, char *, int *)) 482 | { 483 | int i, x, len; 484 | char rv[IWINFO_BUFSIZE]; 485 | const char *ifname = luaL_checkstring(L, 1); 486 | struct iwinfo_freqlist_entry *e; 487 | 488 | lua_newtable(L); 489 | memset(rv, 0, sizeof(rv)); 490 | 491 | if (!(*func)(ifname, rv, &len)) 492 | { 493 | for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_freqlist_entry), x++) 494 | { 495 | e = (struct iwinfo_freqlist_entry *) &rv[i]; 496 | 497 | lua_newtable(L); 498 | 499 | /* MHz */ 500 | lua_pushinteger(L, e->mhz); 501 | lua_setfield(L, -2, "mhz"); 502 | 503 | /* Channel */ 504 | lua_pushinteger(L, e->channel); 505 | lua_setfield(L, -2, "channel"); 506 | 507 | /* Restricted (DFS/TPC/Radar) */ 508 | lua_pushboolean(L, e->restricted); 509 | lua_setfield(L, -2, "restricted"); 510 | 511 | lua_rawseti(L, -2, x); 512 | } 513 | } 514 | 515 | return 1; 516 | } 517 | 518 | /* Wrapper for crypto settings */ 519 | static int iwinfo_L_encryption(lua_State *L, int (*func)(const char *, char *)) 520 | { 521 | const char *ifname = luaL_checkstring(L, 1); 522 | struct iwinfo_crypto_entry c = { 0 }; 523 | 524 | if (!(*func)(ifname, (char *)&c)) 525 | { 526 | iwinfo_L_cryptotable(L, &c); 527 | return 1; 528 | } 529 | 530 | lua_pushnil(L); 531 | return 1; 532 | } 533 | 534 | /* Wrapper for hwmode list */ 535 | static int iwinfo_L_hwmodelist(lua_State *L, int (*func)(const char *, int *)) 536 | { 537 | const char *ifname = luaL_checkstring(L, 1); 538 | int hwmodes = 0; 539 | 540 | if (!(*func)(ifname, &hwmodes)) 541 | { 542 | lua_newtable(L); 543 | 544 | lua_pushboolean(L, hwmodes & IWINFO_80211_A); 545 | lua_setfield(L, -2, "a"); 546 | 547 | lua_pushboolean(L, hwmodes & IWINFO_80211_B); 548 | lua_setfield(L, -2, "b"); 549 | 550 | lua_pushboolean(L, hwmodes & IWINFO_80211_G); 551 | lua_setfield(L, -2, "g"); 552 | 553 | lua_pushboolean(L, hwmodes & IWINFO_80211_N); 554 | lua_setfield(L, -2, "n"); 555 | 556 | lua_pushboolean(L, hwmodes & IWINFO_80211_AC); 557 | lua_setfield(L, -2, "ac"); 558 | 559 | lua_pushboolean(L, hwmodes & IWINFO_80211_AD); 560 | lua_setfield(L, -2, "ad"); 561 | 562 | lua_pushboolean(L, hwmodes & IWINFO_80211_AX); 563 | lua_setfield(L, -2, "ax"); 564 | 565 | lua_pushboolean(L, hwmodes & IWINFO_80211_BE); 566 | lua_setfield(L, -2, "be"); 567 | 568 | return 1; 569 | } 570 | 571 | lua_pushnil(L); 572 | return 1; 573 | } 574 | 575 | /* Wrapper for htmode list */ 576 | static int iwinfo_L_htmodelist(lua_State *L, int (*func)(const char *, int *)) 577 | { 578 | const char *ifname = luaL_checkstring(L, 1); 579 | int i, htmodes = 0; 580 | 581 | if (!(*func)(ifname, &htmodes)) 582 | { 583 | lua_newtable(L); 584 | 585 | for (i = 0; i < ARRAY_SIZE(IWINFO_HTMODE_NAMES); i++) 586 | { 587 | lua_pushboolean(L, htmodes & (1 << i)); 588 | lua_setfield(L, -2, IWINFO_HTMODE_NAMES[i]); 589 | } 590 | 591 | return 1; 592 | } 593 | 594 | lua_pushnil(L); 595 | return 1; 596 | } 597 | 598 | /* Wrapper for mbssid_support */ 599 | static int iwinfo_L_mbssid_support(lua_State *L, int (*func)(const char *, int *)) 600 | { 601 | const char *ifname = luaL_checkstring(L, 1); 602 | int support = 0; 603 | 604 | if (!(*func)(ifname, &support)) 605 | { 606 | lua_pushboolean(L, support); 607 | return 1; 608 | } 609 | 610 | lua_pushnil(L); 611 | return 1; 612 | } 613 | 614 | /* Wrapper for hardware_id */ 615 | static int iwinfo_L_hardware_id(lua_State *L, int (*func)(const char *, char *)) 616 | { 617 | const char *ifname = luaL_checkstring(L, 1); 618 | struct iwinfo_hardware_id ids; 619 | 620 | if (!(*func)(ifname, (char *)&ids)) 621 | { 622 | lua_newtable(L); 623 | 624 | lua_pushnumber(L, ids.vendor_id); 625 | lua_setfield(L, -2, "vendor_id"); 626 | 627 | lua_pushnumber(L, ids.device_id); 628 | lua_setfield(L, -2, "device_id"); 629 | 630 | lua_pushnumber(L, ids.subsystem_vendor_id); 631 | lua_setfield(L, -2, "subsystem_vendor_id"); 632 | 633 | lua_pushnumber(L, ids.subsystem_device_id); 634 | lua_setfield(L, -2, "subsystem_device_id"); 635 | } 636 | else 637 | { 638 | lua_pushnil(L); 639 | } 640 | 641 | return 1; 642 | } 643 | 644 | /* Wrapper for country list */ 645 | static char * iwinfo_L_country_lookup(char *buf, int len, int iso3166) 646 | { 647 | int i; 648 | struct iwinfo_country_entry *c; 649 | 650 | for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry)) 651 | { 652 | c = (struct iwinfo_country_entry *) &buf[i]; 653 | 654 | if (c->iso3166 == iso3166) 655 | return c->ccode; 656 | } 657 | 658 | return NULL; 659 | } 660 | 661 | static int iwinfo_L_countrylist(lua_State *L, int (*func)(const char *, char *, int *)) 662 | { 663 | int len, i; 664 | char rv[IWINFO_BUFSIZE], alpha2[3]; 665 | char *ccode; 666 | const char *ifname = luaL_checkstring(L, 1); 667 | const struct iwinfo_iso3166_label *l; 668 | 669 | lua_newtable(L); 670 | memset(rv, 0, sizeof(rv)); 671 | 672 | if (!(*func)(ifname, rv, &len)) 673 | { 674 | for (l = IWINFO_ISO3166_NAMES, i = 1; l->iso3166; l++) 675 | { 676 | if ((ccode = iwinfo_L_country_lookup(rv, len, l->iso3166)) != NULL) 677 | { 678 | sprintf(alpha2, "%c%c", 679 | (l->iso3166 / 256), (l->iso3166 % 256)); 680 | 681 | lua_newtable(L); 682 | 683 | lua_pushstring(L, alpha2); 684 | lua_setfield(L, -2, "alpha2"); 685 | 686 | lua_pushstring(L, ccode); 687 | lua_setfield(L, -2, "ccode"); 688 | 689 | lua_pushstring(L, l->name); 690 | lua_setfield(L, -2, "name"); 691 | 692 | lua_rawseti(L, -2, i++); 693 | } 694 | } 695 | } 696 | 697 | return 1; 698 | } 699 | 700 | 701 | #ifdef USE_WL 702 | /* Broadcom */ 703 | LUA_WRAP_INT_OP(wl,channel) 704 | LUA_WRAP_INT_OP(wl,frequency) 705 | LUA_WRAP_INT_OP(wl,frequency_offset) 706 | LUA_WRAP_INT_OP(wl,txpower) 707 | LUA_WRAP_INT_OP(wl,txpower_offset) 708 | LUA_WRAP_INT_OP(wl,bitrate) 709 | LUA_WRAP_INT_OP(wl,signal) 710 | LUA_WRAP_INT_OP(wl,noise) 711 | LUA_WRAP_INT_OP(wl,quality) 712 | LUA_WRAP_INT_OP(wl,quality_max) 713 | LUA_WRAP_STRING_OP(wl,ssid) 714 | LUA_WRAP_STRING_OP(wl,bssid) 715 | LUA_WRAP_STRING_OP(wl,country) 716 | LUA_WRAP_STRING_OP(wl,hardware_name) 717 | LUA_WRAP_STRING_OP(wl,phyname) 718 | LUA_WRAP_STRUCT_OP(wl,mode) 719 | LUA_WRAP_STRUCT_OP(wl,assoclist) 720 | LUA_WRAP_STRUCT_OP(wl,txpwrlist) 721 | LUA_WRAP_STRUCT_OP(wl,scanlist) 722 | LUA_WRAP_STRUCT_OP(wl,freqlist) 723 | LUA_WRAP_STRUCT_OP(wl,countrylist) 724 | LUA_WRAP_STRUCT_OP(wl,hwmodelist) 725 | LUA_WRAP_STRUCT_OP(wl,htmodelist) 726 | LUA_WRAP_STRUCT_OP(wl,encryption) 727 | LUA_WRAP_STRUCT_OP(wl,mbssid_support) 728 | LUA_WRAP_STRUCT_OP(wl,hardware_id) 729 | #endif 730 | 731 | #ifdef USE_MADWIFI 732 | /* Madwifi */ 733 | LUA_WRAP_INT_OP(madwifi,channel) 734 | LUA_WRAP_INT_OP(madwifi,frequency) 735 | LUA_WRAP_INT_OP(madwifi,frequency_offset) 736 | LUA_WRAP_INT_OP(madwifi,txpower) 737 | LUA_WRAP_INT_OP(madwifi,txpower_offset) 738 | LUA_WRAP_INT_OP(madwifi,bitrate) 739 | LUA_WRAP_INT_OP(madwifi,signal) 740 | LUA_WRAP_INT_OP(madwifi,noise) 741 | LUA_WRAP_INT_OP(madwifi,quality) 742 | LUA_WRAP_INT_OP(madwifi,quality_max) 743 | LUA_WRAP_STRING_OP(madwifi,ssid) 744 | LUA_WRAP_STRING_OP(madwifi,bssid) 745 | LUA_WRAP_STRING_OP(madwifi,country) 746 | LUA_WRAP_STRING_OP(madwifi,hardware_name) 747 | LUA_WRAP_STRING_OP(madwifi,phyname) 748 | LUA_WRAP_STRUCT_OP(madwifi,mode) 749 | LUA_WRAP_STRUCT_OP(madwifi,assoclist) 750 | LUA_WRAP_STRUCT_OP(madwifi,txpwrlist) 751 | LUA_WRAP_STRUCT_OP(madwifi,scanlist) 752 | LUA_WRAP_STRUCT_OP(madwifi,freqlist) 753 | LUA_WRAP_STRUCT_OP(madwifi,countrylist) 754 | LUA_WRAP_STRUCT_OP(madwifi,hwmodelist) 755 | LUA_WRAP_STRUCT_OP(madwifi,htmodelist) 756 | LUA_WRAP_STRUCT_OP(madwifi,encryption) 757 | LUA_WRAP_STRUCT_OP(madwifi,mbssid_support) 758 | LUA_WRAP_STRUCT_OP(madwifi,hardware_id) 759 | #endif 760 | 761 | #ifdef USE_NL80211 762 | /* NL80211 */ 763 | LUA_WRAP_INT_OP(nl80211,channel) 764 | LUA_WRAP_INT_OP(nl80211,frequency) 765 | LUA_WRAP_INT_OP(nl80211,frequency_offset) 766 | LUA_WRAP_INT_OP(nl80211,txpower) 767 | LUA_WRAP_INT_OP(nl80211,txpower_offset) 768 | LUA_WRAP_INT_OP(nl80211,bitrate) 769 | LUA_WRAP_INT_OP(nl80211,signal) 770 | LUA_WRAP_INT_OP(nl80211,noise) 771 | LUA_WRAP_INT_OP(nl80211,quality) 772 | LUA_WRAP_INT_OP(nl80211,quality_max) 773 | LUA_WRAP_STRING_OP(nl80211,ssid) 774 | LUA_WRAP_STRING_OP(nl80211,bssid) 775 | LUA_WRAP_STRING_OP(nl80211,country) 776 | LUA_WRAP_STRING_OP(nl80211,hardware_name) 777 | LUA_WRAP_STRING_OP(nl80211,phyname) 778 | LUA_WRAP_STRUCT_OP(nl80211,mode) 779 | LUA_WRAP_STRUCT_OP(nl80211,assoclist) 780 | LUA_WRAP_STRUCT_OP(nl80211,txpwrlist) 781 | LUA_WRAP_STRUCT_OP(nl80211,scanlist) 782 | LUA_WRAP_STRUCT_OP(nl80211,freqlist) 783 | LUA_WRAP_STRUCT_OP(nl80211,countrylist) 784 | LUA_WRAP_STRUCT_OP(nl80211,hwmodelist) 785 | LUA_WRAP_STRUCT_OP(nl80211,htmodelist) 786 | LUA_WRAP_STRUCT_OP(nl80211,encryption) 787 | LUA_WRAP_STRUCT_OP(nl80211,mbssid_support) 788 | LUA_WRAP_STRUCT_OP(nl80211,hardware_id) 789 | #endif 790 | 791 | /* Wext */ 792 | #ifdef USE_WEXT 793 | LUA_WRAP_INT_OP(wext,channel) 794 | LUA_WRAP_INT_OP(wext,frequency) 795 | LUA_WRAP_INT_OP(wext,frequency_offset) 796 | LUA_WRAP_INT_OP(wext,txpower) 797 | LUA_WRAP_INT_OP(wext,txpower_offset) 798 | LUA_WRAP_INT_OP(wext,bitrate) 799 | LUA_WRAP_INT_OP(wext,signal) 800 | LUA_WRAP_INT_OP(wext,noise) 801 | LUA_WRAP_INT_OP(wext,quality) 802 | LUA_WRAP_INT_OP(wext,quality_max) 803 | LUA_WRAP_STRING_OP(wext,ssid) 804 | LUA_WRAP_STRING_OP(wext,bssid) 805 | LUA_WRAP_STRING_OP(wext,country) 806 | LUA_WRAP_STRING_OP(wext,hardware_name) 807 | LUA_WRAP_STRING_OP(wext,phyname) 808 | LUA_WRAP_STRUCT_OP(wext,mode) 809 | LUA_WRAP_STRUCT_OP(wext,assoclist) 810 | LUA_WRAP_STRUCT_OP(wext,txpwrlist) 811 | LUA_WRAP_STRUCT_OP(wext,scanlist) 812 | LUA_WRAP_STRUCT_OP(wext,freqlist) 813 | LUA_WRAP_STRUCT_OP(wext,countrylist) 814 | LUA_WRAP_STRUCT_OP(wext,hwmodelist) 815 | LUA_WRAP_STRUCT_OP(wext,htmodelist) 816 | LUA_WRAP_STRUCT_OP(wext,encryption) 817 | LUA_WRAP_STRUCT_OP(wext,mbssid_support) 818 | LUA_WRAP_STRUCT_OP(wext,hardware_id) 819 | #endif 820 | 821 | #ifdef USE_WL 822 | /* Broadcom table */ 823 | static const luaL_reg R_wl[] = { 824 | LUA_REG(wl,channel), 825 | LUA_REG(wl,frequency), 826 | LUA_REG(wl,frequency_offset), 827 | LUA_REG(wl,txpower), 828 | LUA_REG(wl,txpower_offset), 829 | LUA_REG(wl,bitrate), 830 | LUA_REG(wl,signal), 831 | LUA_REG(wl,noise), 832 | LUA_REG(wl,quality), 833 | LUA_REG(wl,quality_max), 834 | LUA_REG(wl,mode), 835 | LUA_REG(wl,ssid), 836 | LUA_REG(wl,bssid), 837 | LUA_REG(wl,country), 838 | LUA_REG(wl,assoclist), 839 | LUA_REG(wl,txpwrlist), 840 | LUA_REG(wl,scanlist), 841 | LUA_REG(wl,freqlist), 842 | LUA_REG(wl,countrylist), 843 | LUA_REG(wl,hwmodelist), 844 | LUA_REG(wl,htmodelist), 845 | LUA_REG(wl,encryption), 846 | LUA_REG(wl,mbssid_support), 847 | LUA_REG(wl,hardware_id), 848 | LUA_REG(wl,hardware_name), 849 | LUA_REG(wl,phyname), 850 | { NULL, NULL } 851 | }; 852 | #endif 853 | 854 | #ifdef USE_MADWIFI 855 | /* Madwifi table */ 856 | static const luaL_reg R_madwifi[] = { 857 | LUA_REG(madwifi,channel), 858 | LUA_REG(madwifi,frequency), 859 | LUA_REG(madwifi,frequency_offset), 860 | LUA_REG(madwifi,txpower), 861 | LUA_REG(madwifi,txpower_offset), 862 | LUA_REG(madwifi,bitrate), 863 | LUA_REG(madwifi,signal), 864 | LUA_REG(madwifi,noise), 865 | LUA_REG(madwifi,quality), 866 | LUA_REG(madwifi,quality_max), 867 | LUA_REG(madwifi,mode), 868 | LUA_REG(madwifi,ssid), 869 | LUA_REG(madwifi,bssid), 870 | LUA_REG(madwifi,country), 871 | LUA_REG(madwifi,assoclist), 872 | LUA_REG(madwifi,txpwrlist), 873 | LUA_REG(madwifi,scanlist), 874 | LUA_REG(madwifi,freqlist), 875 | LUA_REG(madwifi,countrylist), 876 | LUA_REG(madwifi,hwmodelist), 877 | LUA_REG(madwifi,htmodelist), 878 | LUA_REG(madwifi,encryption), 879 | LUA_REG(madwifi,mbssid_support), 880 | LUA_REG(madwifi,hardware_id), 881 | LUA_REG(madwifi,hardware_name), 882 | LUA_REG(madwifi,phyname), 883 | { NULL, NULL } 884 | }; 885 | #endif 886 | 887 | #ifdef USE_NL80211 888 | /* NL80211 table */ 889 | static const luaL_reg R_nl80211[] = { 890 | LUA_REG(nl80211,channel), 891 | LUA_REG(nl80211,frequency), 892 | LUA_REG(nl80211,frequency_offset), 893 | LUA_REG(nl80211,txpower), 894 | LUA_REG(nl80211,txpower_offset), 895 | LUA_REG(nl80211,bitrate), 896 | LUA_REG(nl80211,signal), 897 | LUA_REG(nl80211,noise), 898 | LUA_REG(nl80211,quality), 899 | LUA_REG(nl80211,quality_max), 900 | LUA_REG(nl80211,mode), 901 | LUA_REG(nl80211,ssid), 902 | LUA_REG(nl80211,bssid), 903 | LUA_REG(nl80211,country), 904 | LUA_REG(nl80211,assoclist), 905 | LUA_REG(nl80211,txpwrlist), 906 | LUA_REG(nl80211,scanlist), 907 | LUA_REG(nl80211,freqlist), 908 | LUA_REG(nl80211,countrylist), 909 | LUA_REG(nl80211,hwmodelist), 910 | LUA_REG(nl80211,htmodelist), 911 | LUA_REG(nl80211,encryption), 912 | LUA_REG(nl80211,mbssid_support), 913 | LUA_REG(nl80211,hardware_id), 914 | LUA_REG(nl80211,hardware_name), 915 | LUA_REG(nl80211,phyname), 916 | { NULL, NULL } 917 | }; 918 | #endif 919 | 920 | /* Wext table */ 921 | #ifdef USE_WEXT 922 | static const luaL_reg R_wext[] = { 923 | LUA_REG(wext,channel), 924 | LUA_REG(wext,frequency), 925 | LUA_REG(wext,frequency_offset), 926 | LUA_REG(wext,txpower), 927 | LUA_REG(wext,txpower_offset), 928 | LUA_REG(wext,bitrate), 929 | LUA_REG(wext,signal), 930 | LUA_REG(wext,noise), 931 | LUA_REG(wext,quality), 932 | LUA_REG(wext,quality_max), 933 | LUA_REG(wext,mode), 934 | LUA_REG(wext,ssid), 935 | LUA_REG(wext,bssid), 936 | LUA_REG(wext,country), 937 | LUA_REG(wext,assoclist), 938 | LUA_REG(wext,txpwrlist), 939 | LUA_REG(wext,scanlist), 940 | LUA_REG(wext,freqlist), 941 | LUA_REG(wext,countrylist), 942 | LUA_REG(wext,hwmodelist), 943 | LUA_REG(wext,htmodelist), 944 | LUA_REG(wext,encryption), 945 | LUA_REG(wext,mbssid_support), 946 | LUA_REG(wext,hardware_id), 947 | LUA_REG(wext,hardware_name), 948 | LUA_REG(wext,phyname), 949 | { NULL, NULL } 950 | }; 951 | #endif 952 | 953 | /* Common */ 954 | static const luaL_reg R_common[] = { 955 | { "type", iwinfo_L_type }, 956 | { "__gc", iwinfo_L__gc }, 957 | { NULL, NULL } 958 | }; 959 | 960 | 961 | LUALIB_API int luaopen_iwinfo(lua_State *L) { 962 | luaL_register(L, IWINFO_META, R_common); 963 | 964 | #ifdef USE_WL 965 | luaL_newmetatable(L, IWINFO_WL_META); 966 | luaL_register(L, NULL, R_common); 967 | luaL_register(L, NULL, R_wl); 968 | lua_pushvalue(L, -1); 969 | lua_setfield(L, -2, "__index"); 970 | lua_setfield(L, -2, "wl"); 971 | #endif 972 | 973 | #ifdef USE_MADWIFI 974 | luaL_newmetatable(L, IWINFO_MADWIFI_META); 975 | luaL_register(L, NULL, R_common); 976 | luaL_register(L, NULL, R_madwifi); 977 | lua_pushvalue(L, -1); 978 | lua_setfield(L, -2, "__index"); 979 | lua_setfield(L, -2, "madwifi"); 980 | #endif 981 | 982 | #ifdef USE_NL80211 983 | luaL_newmetatable(L, IWINFO_NL80211_META); 984 | luaL_register(L, NULL, R_common); 985 | luaL_register(L, NULL, R_nl80211); 986 | lua_pushvalue(L, -1); 987 | lua_setfield(L, -2, "__index"); 988 | lua_setfield(L, -2, "nl80211"); 989 | #endif 990 | 991 | #ifdef USE_WEXT 992 | luaL_newmetatable(L, IWINFO_WEXT_META); 993 | luaL_register(L, NULL, R_common); 994 | luaL_register(L, NULL, R_wext); 995 | lua_pushvalue(L, -1); 996 | lua_setfield(L, -2, "__index"); 997 | lua_setfield(L, -2, "wext"); 998 | #endif 999 | 1000 | return 1; 1001 | } 1002 | -------------------------------------------------------------------------------- /iwinfo_cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iwinfo - Wireless Information Library - Command line frontend 3 | * 4 | * Copyright (C) 2011 Jo-Philipp Wich 5 | * 6 | * The iwinfo library is free software: you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License version 2 8 | * as published by the Free Software Foundation. 9 | * 10 | * The iwinfo library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | * See the GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with the iwinfo library. If not, see http://www.gnu.org/licenses/. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "iwinfo.h" 23 | 24 | 25 | static char * format_bssid(unsigned char *mac) 26 | { 27 | static char buf[18]; 28 | 29 | snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X", 30 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 31 | 32 | return buf; 33 | } 34 | 35 | static char * format_ssid(char *ssid) 36 | { 37 | static char buf[IWINFO_ESSID_MAX_SIZE+3]; 38 | 39 | if (ssid && ssid[0]) 40 | snprintf(buf, sizeof(buf), "\"%s\"", ssid); 41 | else 42 | snprintf(buf, sizeof(buf), "unknown"); 43 | 44 | return buf; 45 | } 46 | 47 | static const char *format_band(int band) 48 | { 49 | const char *name; 50 | 51 | name = iwinfo_band_name(band); 52 | if (name) 53 | return name; 54 | 55 | return "unknown"; 56 | } 57 | 58 | static char * format_channel(int ch) 59 | { 60 | static char buf[16]; 61 | 62 | if (ch <= 0) 63 | snprintf(buf, sizeof(buf), "unknown"); 64 | else 65 | snprintf(buf, sizeof(buf), "%d", ch); 66 | 67 | return buf; 68 | } 69 | 70 | static char * format_frequency(int freq) 71 | { 72 | static char buf[11]; 73 | 74 | if (freq <= 0) 75 | snprintf(buf, sizeof(buf), "unknown"); 76 | else 77 | snprintf(buf, sizeof(buf), "%.3f GHz", ((float)freq / 1000.0)); 78 | 79 | return buf; 80 | } 81 | 82 | static char * format_freqflags(uint32_t flags) 83 | { 84 | static char str[512] = "["; 85 | char *pos = str + 1; 86 | int i; 87 | 88 | if (!flags) 89 | return ""; 90 | 91 | for (i = 0; i < IWINFO_FREQ_FLAG_COUNT; i++) 92 | if (flags & (1 << i)) 93 | pos += sprintf(pos, "%s, ", IWINFO_FREQ_FLAG_NAMES[i]); 94 | 95 | *(pos - 2) = ']'; 96 | *(pos - 1) = 0; 97 | 98 | return str; 99 | } 100 | 101 | static char * format_txpower(int pwr) 102 | { 103 | static char buf[16]; 104 | 105 | if (pwr < 0) 106 | snprintf(buf, sizeof(buf), "unknown"); 107 | else 108 | snprintf(buf, sizeof(buf), "%d dBm", pwr); 109 | 110 | return buf; 111 | } 112 | 113 | static char * format_quality(int qual) 114 | { 115 | static char buf[16]; 116 | 117 | if (qual < 0) 118 | snprintf(buf, sizeof(buf), "unknown"); 119 | else 120 | snprintf(buf, sizeof(buf), "%d", qual); 121 | 122 | return buf; 123 | } 124 | 125 | static char * format_quality_max(int qmax) 126 | { 127 | static char buf[16]; 128 | 129 | if (qmax < 0) 130 | snprintf(buf, sizeof(buf), "unknown"); 131 | else 132 | snprintf(buf, sizeof(buf), "%d", qmax); 133 | 134 | return buf; 135 | } 136 | 137 | static char * format_signal(int sig) 138 | { 139 | static char buf[10]; 140 | 141 | if (!sig) 142 | snprintf(buf, sizeof(buf), "unknown"); 143 | else 144 | snprintf(buf, sizeof(buf), "%d dBm", sig); 145 | 146 | return buf; 147 | } 148 | 149 | static char * format_noise(int noise) 150 | { 151 | static char buf[10]; 152 | 153 | if (!noise) 154 | snprintf(buf, sizeof(buf), "unknown"); 155 | else 156 | snprintf(buf, sizeof(buf), "%d dBm", noise); 157 | 158 | return buf; 159 | } 160 | 161 | static char * format_rate(int rate) 162 | { 163 | static char buf[18]; 164 | 165 | if (rate <= 0) 166 | snprintf(buf, sizeof(buf), "unknown"); 167 | else 168 | snprintf(buf, sizeof(buf), "%d.%d MBit/s", 169 | rate / 1000, (rate % 1000) / 100); 170 | 171 | return buf; 172 | } 173 | 174 | static char * format_enc_ciphers(int ciphers) 175 | { 176 | static char str[128] = { 0 }; 177 | char *pos = str; 178 | int i; 179 | 180 | for (i = 0; i < IWINFO_CIPHER_COUNT; i++) 181 | if (ciphers & (1 << i)) 182 | pos += sprintf(pos, "%s, ", IWINFO_CIPHER_NAMES[i]); 183 | 184 | *(pos - 2) = 0; 185 | 186 | return str; 187 | } 188 | 189 | static char * format_enc_suites(int suites) 190 | { 191 | static char str[64] = { 0 }; 192 | char *pos = str; 193 | int i; 194 | 195 | for (i = 0; i < IWINFO_KMGMT_COUNT; i++) 196 | if (suites & (1 << i)) 197 | pos += sprintf(pos, "%s/", IWINFO_KMGMT_NAMES[i]); 198 | 199 | *(pos - 1) = 0; 200 | 201 | return str; 202 | } 203 | 204 | static char * format_encryption(struct iwinfo_crypto_entry *c) 205 | { 206 | static char buf[512]; 207 | char *pos = buf; 208 | int i, n; 209 | 210 | if (!c) 211 | { 212 | snprintf(buf, sizeof(buf), "unknown"); 213 | } 214 | else if (c->enabled) 215 | { 216 | /* WEP */ 217 | if (c->auth_algs && !c->wpa_version) 218 | { 219 | if ((c->auth_algs & IWINFO_AUTH_OPEN) && 220 | (c->auth_algs & IWINFO_AUTH_SHARED)) 221 | { 222 | snprintf(buf, sizeof(buf), "WEP Open/Shared (%s)", 223 | format_enc_ciphers(c->pair_ciphers)); 224 | } 225 | else if (c->auth_algs & IWINFO_AUTH_OPEN) 226 | { 227 | snprintf(buf, sizeof(buf), "WEP Open System (%s)", 228 | format_enc_ciphers(c->pair_ciphers)); 229 | } 230 | else if (c->auth_algs & IWINFO_AUTH_SHARED) 231 | { 232 | snprintf(buf, sizeof(buf), "WEP Shared Auth (%s)", 233 | format_enc_ciphers(c->pair_ciphers)); 234 | } 235 | } 236 | 237 | /* WPA */ 238 | else if (c->wpa_version) 239 | { 240 | for (i = 0, n = 0; i < 3; i++) 241 | if (c->wpa_version & (1 << i)) 242 | n++; 243 | 244 | if (n > 1) 245 | pos += sprintf(pos, "mixed "); 246 | 247 | for (i = 0; i < 3; i++) 248 | if (c->wpa_version & (1 << i)) 249 | { 250 | if (i) 251 | pos += sprintf(pos, "WPA%d/", i + 1); 252 | else 253 | pos += sprintf(pos, "WPA/"); 254 | } 255 | 256 | pos--; 257 | 258 | sprintf(pos, " %s (%s)", 259 | format_enc_suites(c->auth_suites), 260 | format_enc_ciphers(c->pair_ciphers | c->group_ciphers)); 261 | } 262 | else 263 | { 264 | snprintf(buf, sizeof(buf), "none"); 265 | } 266 | } 267 | else 268 | { 269 | snprintf(buf, sizeof(buf), "none"); 270 | } 271 | 272 | return buf; 273 | } 274 | 275 | static char * format_hwmodes(int modes) 276 | { 277 | static char buf[32] = "802.11"; 278 | 279 | if (iwinfo_format_hwmodes(modes, buf + 6, sizeof(buf) - 6) < 1) 280 | snprintf(buf, sizeof(buf), "unknown"); 281 | 282 | return buf; 283 | } 284 | 285 | static char * format_assocrate(struct iwinfo_rate_entry *r) 286 | { 287 | static char buf[80]; 288 | char *p = buf; 289 | int l = sizeof(buf); 290 | 291 | if (r->rate <= 0) 292 | { 293 | snprintf(buf, sizeof(buf), "unknown"); 294 | } 295 | else 296 | { 297 | p += snprintf(p, l, "%s", format_rate(r->rate)); 298 | l = sizeof(buf) - (p - buf); 299 | 300 | if (r->is_ht) 301 | { 302 | p += snprintf(p, l, ", MCS %d, %dMHz", r->mcs, r->mhz); 303 | l = sizeof(buf) - (p - buf); 304 | } 305 | else if (r->is_vht) 306 | { 307 | p += snprintf(p, l, ", VHT-MCS %d, %dMHz", r->mcs, r->mhz); 308 | l = sizeof(buf) - (p - buf); 309 | 310 | if (r->nss) 311 | { 312 | p += snprintf(p, l, ", VHT-NSS %d", r->nss); 313 | l = sizeof(buf) - (p - buf); 314 | } 315 | } 316 | else if (r->is_he) 317 | { 318 | p += snprintf(p, l, ", HE-MCS %d, %dMHz", r->mcs, r->mhz); 319 | l = sizeof(buf) - (p - buf); 320 | 321 | p += snprintf(p, l, ", HE-NSS %d", r->nss); 322 | l = sizeof(buf) - (p - buf); 323 | 324 | p += snprintf(p, l, ", HE-GI %d", r->he_gi); 325 | l = sizeof(buf) - (p - buf); 326 | 327 | p += snprintf(p, l, ", HE-DCM %d", r->he_dcm); 328 | l = sizeof(buf) - (p - buf); 329 | } 330 | else if (r->is_eht) 331 | { 332 | p += snprintf(p, l, ", EHT-MCS %d, %dMHz", r->mcs, r->mhz_hi * 256 + r->mhz); 333 | l = sizeof(buf) - (p - buf); 334 | 335 | p += snprintf(p, l, ", EHT-NSS %d", r->nss); 336 | l = sizeof(buf) - (p - buf); 337 | 338 | p += snprintf(p, l, ", EHT-GI %d", r->eht_gi); 339 | l = sizeof(buf) - (p - buf); 340 | } 341 | } 342 | 343 | return buf; 344 | } 345 | 346 | static const char* format_chan_width(bool vht, uint8_t width) 347 | { 348 | if (!vht && width < ARRAY_SIZE(ht_chan_width)) 349 | switch (ht_chan_width[width]) { 350 | case 20: return "20 MHz"; 351 | case 2040: return "40 MHz or higher"; 352 | } 353 | 354 | if (vht && width < ARRAY_SIZE(vht_chan_width)) 355 | switch (vht_chan_width[width]) { 356 | case 40: return "20 or 40 MHz"; 357 | case 80: return "80 MHz"; 358 | case 8080: return "80+80 MHz"; 359 | case 160: return "160 MHz"; 360 | } 361 | 362 | return "unknown"; 363 | } 364 | 365 | static const char* format_6ghz_chan_width(uint8_t width) 366 | { 367 | if (width < ARRAY_SIZE(eht_chan_width)) 368 | switch (eht_chan_width[width]) { 369 | case 20: return "20 MHz"; 370 | case 40: return "40 MHz"; 371 | case 80: return "80 MHz"; 372 | case 160: return "160 MHz"; 373 | case 320: return "320 MHz"; 374 | } 375 | 376 | return "unknown"; 377 | } 378 | 379 | static const char * print_type(const struct iwinfo_ops *iw, const char *ifname) 380 | { 381 | const char *type = iwinfo_type(ifname); 382 | return type ? type : "unknown"; 383 | } 384 | 385 | static char * print_hardware_id(const struct iwinfo_ops *iw, const char *ifname) 386 | { 387 | static char buf[20]; 388 | struct iwinfo_hardware_id ids; 389 | 390 | if (!iw->hardware_id(ifname, (char *)&ids)) 391 | { 392 | if (strlen(ids.compatible) > 0) 393 | snprintf(buf, sizeof(buf), "embedded"); 394 | else if (ids.vendor_id == 0 && ids.device_id == 0 && 395 | ids.subsystem_vendor_id != 0 && ids.subsystem_device_id != 0) 396 | snprintf(buf, sizeof(buf), "USB %04X:%04X", 397 | ids.subsystem_vendor_id, ids.subsystem_device_id); 398 | else 399 | snprintf(buf, sizeof(buf), "%04X:%04X %04X:%04X", 400 | ids.vendor_id, ids.device_id, 401 | ids.subsystem_vendor_id, ids.subsystem_device_id); 402 | } 403 | else 404 | { 405 | snprintf(buf, sizeof(buf), "unknown"); 406 | } 407 | 408 | return buf; 409 | } 410 | 411 | static char * print_hardware_name(const struct iwinfo_ops *iw, const char *ifname) 412 | { 413 | static char buf[128]; 414 | 415 | if (iw->hardware_name(ifname, buf)) 416 | snprintf(buf, sizeof(buf), "unknown"); 417 | 418 | return buf; 419 | } 420 | 421 | static char * print_txpower_offset(const struct iwinfo_ops *iw, const char *ifname) 422 | { 423 | int off; 424 | static char buf[12]; 425 | 426 | if (iw->txpower_offset(ifname, &off)) 427 | snprintf(buf, sizeof(buf), "unknown"); 428 | else if (off != 0) 429 | snprintf(buf, sizeof(buf), "%d dB", off); 430 | else 431 | snprintf(buf, sizeof(buf), "none"); 432 | 433 | return buf; 434 | } 435 | 436 | static char * print_frequency_offset(const struct iwinfo_ops *iw, const char *ifname) 437 | { 438 | int off; 439 | static char buf[12]; 440 | 441 | if (iw->frequency_offset(ifname, &off)) 442 | snprintf(buf, sizeof(buf), "unknown"); 443 | else if (off != 0) 444 | snprintf(buf, sizeof(buf), "%.3f GHz", ((float)off / 1000.0)); 445 | else 446 | snprintf(buf, sizeof(buf), "none"); 447 | 448 | return buf; 449 | } 450 | 451 | static char * print_ssid(const struct iwinfo_ops *iw, const char *ifname) 452 | { 453 | char buf[IWINFO_ESSID_MAX_SIZE+1] = { 0 }; 454 | 455 | if (iw->ssid(ifname, buf)) 456 | memset(buf, 0, sizeof(buf)); 457 | 458 | return format_ssid(buf); 459 | } 460 | 461 | static char * print_bssid(const struct iwinfo_ops *iw, const char *ifname) 462 | { 463 | static char buf[18] = { 0 }; 464 | 465 | if (iw->bssid(ifname, buf)) 466 | snprintf(buf, sizeof(buf), "00:00:00:00:00:00"); 467 | 468 | return buf; 469 | } 470 | 471 | static char * print_mode(const struct iwinfo_ops *iw, const char *ifname) 472 | { 473 | int mode; 474 | static char buf[128]; 475 | 476 | if (iw->mode(ifname, &mode)) 477 | mode = IWINFO_OPMODE_UNKNOWN; 478 | 479 | snprintf(buf, sizeof(buf), "%s", IWINFO_OPMODE_NAMES[mode]); 480 | 481 | return buf; 482 | } 483 | 484 | static char * print_channel(const struct iwinfo_ops *iw, const char *ifname) 485 | { 486 | int ch; 487 | if (iw->channel(ifname, &ch)) 488 | ch = -1; 489 | 490 | return format_channel(ch); 491 | } 492 | 493 | static char * print_center_chan1(const struct iwinfo_ops *iw, const char *ifname) 494 | { 495 | int ch; 496 | if (iw->center_chan1(ifname, &ch)) 497 | ch = -1; 498 | 499 | return format_channel(ch); 500 | } 501 | 502 | static char * print_center_chan2(const struct iwinfo_ops *iw, const char *ifname) 503 | { 504 | int ch; 505 | if (iw->center_chan2(ifname, &ch)) 506 | ch = -1; 507 | 508 | return format_channel(ch); 509 | } 510 | 511 | static char * print_frequency(const struct iwinfo_ops *iw, const char *ifname) 512 | { 513 | int freq; 514 | if (iw->frequency(ifname, &freq)) 515 | freq = -1; 516 | 517 | return format_frequency(freq); 518 | } 519 | 520 | static char * print_txpower(const struct iwinfo_ops *iw, const char *ifname) 521 | { 522 | int pwr, off; 523 | if (iw->txpower_offset(ifname, &off)) 524 | off = 0; 525 | 526 | if (iw->txpower(ifname, &pwr)) 527 | pwr = -1; 528 | else 529 | pwr += off; 530 | 531 | return format_txpower(pwr); 532 | } 533 | 534 | static char * print_quality(const struct iwinfo_ops *iw, const char *ifname) 535 | { 536 | int qual; 537 | if (iw->quality(ifname, &qual)) 538 | qual = -1; 539 | 540 | return format_quality(qual); 541 | } 542 | 543 | static char * print_quality_max(const struct iwinfo_ops *iw, const char *ifname) 544 | { 545 | int qmax; 546 | if (iw->quality_max(ifname, &qmax)) 547 | qmax = -1; 548 | 549 | return format_quality_max(qmax); 550 | } 551 | 552 | static char * print_signal(const struct iwinfo_ops *iw, const char *ifname) 553 | { 554 | int sig; 555 | if (iw->signal(ifname, &sig)) 556 | sig = 0; 557 | 558 | return format_signal(sig); 559 | } 560 | 561 | static char * print_noise(const struct iwinfo_ops *iw, const char *ifname) 562 | { 563 | int noise; 564 | if (iw->noise(ifname, &noise)) 565 | noise = 0; 566 | 567 | return format_noise(noise); 568 | } 569 | 570 | static char * print_rate(const struct iwinfo_ops *iw, const char *ifname) 571 | { 572 | int rate; 573 | if (iw->bitrate(ifname, &rate)) 574 | rate = -1; 575 | 576 | return format_rate(rate); 577 | } 578 | 579 | static char * print_encryption(const struct iwinfo_ops *iw, const char *ifname) 580 | { 581 | struct iwinfo_crypto_entry c = { 0 }; 582 | if (iw->encryption(ifname, (char *)&c)) 583 | return format_encryption(NULL); 584 | 585 | return format_encryption(&c); 586 | } 587 | 588 | static char * print_hwmodes(const struct iwinfo_ops *iw, const char *ifname) 589 | { 590 | int modes; 591 | if (iw->hwmodelist(ifname, &modes)) 592 | modes = -1; 593 | 594 | return format_hwmodes(modes); 595 | } 596 | 597 | static const char *print_htmode(const struct iwinfo_ops *iw, const char *ifname) 598 | { 599 | int mode; 600 | const char *name; 601 | if (iw->htmode(ifname, &mode)) 602 | mode = -1; 603 | 604 | name = iwinfo_htmode_name(mode); 605 | if (name) 606 | return name; 607 | 608 | return "unknown"; 609 | } 610 | 611 | static char * print_mbssid_supp(const struct iwinfo_ops *iw, const char *ifname) 612 | { 613 | int supp; 614 | static char buf[4]; 615 | 616 | if (iw->mbssid_support(ifname, &supp)) 617 | snprintf(buf, sizeof(buf), "no"); 618 | else 619 | snprintf(buf, sizeof(buf), "%s", supp ? "yes" : "no"); 620 | 621 | return buf; 622 | } 623 | 624 | static char * print_phyname(const struct iwinfo_ops *iw, const char *ifname) 625 | { 626 | static char buf[32]; 627 | 628 | if (!iw->phyname(ifname, buf)) 629 | return buf; 630 | 631 | return "?"; 632 | } 633 | 634 | 635 | static void print_info(const struct iwinfo_ops *iw, const char *ifname) 636 | { 637 | printf("%-9s ESSID: %s\n", 638 | ifname, 639 | print_ssid(iw, ifname)); 640 | printf(" Access Point: %s\n", 641 | print_bssid(iw, ifname)); 642 | printf(" Mode: %s Channel: %s (%s) HT Mode: %s\n", 643 | print_mode(iw, ifname), 644 | print_channel(iw, ifname), 645 | print_frequency(iw, ifname), 646 | print_htmode(iw, ifname)); 647 | if (iw->center_chan1 != NULL) { 648 | printf(" Center Channel 1: %s", 649 | print_center_chan1(iw, ifname)); 650 | printf(" 2: %s\n", print_center_chan2(iw, ifname)); 651 | } 652 | printf(" Tx-Power: %s Link Quality: %s/%s\n", 653 | print_txpower(iw, ifname), 654 | print_quality(iw, ifname), 655 | print_quality_max(iw, ifname)); 656 | printf(" Signal: %s Noise: %s\n", 657 | print_signal(iw, ifname), 658 | print_noise(iw, ifname)); 659 | printf(" Bit Rate: %s\n", 660 | print_rate(iw, ifname)); 661 | printf(" Encryption: %s\n", 662 | print_encryption(iw, ifname)); 663 | printf(" Type: %s HW Mode(s): %s\n", 664 | print_type(iw, ifname), 665 | print_hwmodes(iw, ifname)); 666 | printf(" Hardware: %s [%s]\n", 667 | print_hardware_id(iw, ifname), 668 | print_hardware_name(iw, ifname)); 669 | printf(" TX power offset: %s\n", 670 | print_txpower_offset(iw, ifname)); 671 | printf(" Frequency offset: %s\n", 672 | print_frequency_offset(iw, ifname)); 673 | printf(" Supports VAPs: %s PHY name: %s\n", 674 | print_mbssid_supp(iw, ifname), 675 | print_phyname(iw, ifname)); 676 | } 677 | 678 | 679 | static void print_scanlist(const struct iwinfo_ops *iw, const char *ifname) 680 | { 681 | int i, x, len; 682 | char buf[IWINFO_BUFSIZE]; 683 | struct iwinfo_scanlist_entry *e; 684 | 685 | if (iw->scanlist(ifname, buf, &len)) 686 | { 687 | printf("Scanning not possible\n\n"); 688 | return; 689 | } 690 | else if (len <= 0) 691 | { 692 | printf("No scan results\n\n"); 693 | return; 694 | } 695 | 696 | for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_scanlist_entry), x++) 697 | { 698 | e = (struct iwinfo_scanlist_entry *) &buf[i]; 699 | 700 | printf("Cell %02d - Address: %s\n", 701 | x, 702 | format_bssid(e->mac)); 703 | printf(" ESSID: %s\n", 704 | format_ssid(e->ssid)); 705 | printf(" Mode: %s Frequency: %s Band: %s Channel: %s\n", 706 | IWINFO_OPMODE_NAMES[e->mode], 707 | format_frequency(e->mhz), 708 | format_band(e->band), 709 | format_channel(e->channel)); 710 | printf(" Signal: %s Quality: %s/%s\n", 711 | format_signal(e->signal - 0x100), 712 | format_quality(e->quality), 713 | format_quality_max(e->quality_max)); 714 | printf(" Encryption: %s\n", 715 | format_encryption(&e->crypto)); 716 | if (e->ht_chan_info.primary_chan) { 717 | printf(" HT Operation:\n"); 718 | printf(" Primary Channel: %d\n", 719 | e->ht_chan_info.primary_chan); 720 | printf(" Secondary Channel Offset: %s\n", 721 | ht_secondary_offset[e->ht_chan_info.secondary_chan_off]); 722 | printf(" Channel Width: %s\n", 723 | format_chan_width(false, e->ht_chan_info.chan_width)); 724 | } 725 | 726 | if (e->vht_chan_info.center_chan_1) { 727 | printf(" VHT Operation:\n"); 728 | printf(" Center Frequency 1: %d\n", 729 | e->vht_chan_info.center_chan_1); 730 | printf(" Center Frequency 2: %d\n", 731 | e->vht_chan_info.center_chan_2); 732 | printf(" Channel Width: %s\n", 733 | format_chan_width(true, e->vht_chan_info.chan_width)); 734 | } 735 | 736 | if (e->he_chan_info.center_chan_1) { 737 | printf(" HE Operation:\n"); 738 | printf(" Center Frequency 1: %d\n", 739 | e->he_chan_info.center_chan_1); 740 | printf(" Center Frequency 2: %d\n", 741 | e->he_chan_info.center_chan_2); 742 | printf(" Channel Width: %s\n", 743 | format_6ghz_chan_width(e->he_chan_info.chan_width)); 744 | } 745 | 746 | if (e->eht_chan_info.center_chan_1) { 747 | printf(" EHT Operation:\n"); 748 | printf(" Center Frequency 1: %d\n", 749 | e->eht_chan_info.center_chan_1); 750 | printf(" Center Frequency 2: %d\n", 751 | e->eht_chan_info.center_chan_2); 752 | printf(" Channel Width: %s\n", 753 | format_6ghz_chan_width(e->eht_chan_info.chan_width)); 754 | } 755 | 756 | printf("\n"); 757 | } 758 | } 759 | 760 | 761 | static void print_txpwrlist(const struct iwinfo_ops *iw, const char *ifname) 762 | { 763 | int len, pwr, off, i; 764 | char buf[IWINFO_BUFSIZE]; 765 | struct iwinfo_txpwrlist_entry *e; 766 | 767 | if (iw->txpwrlist(ifname, buf, &len) || len <= 0) 768 | { 769 | printf("No TX power information available\n"); 770 | return; 771 | } 772 | 773 | if (iw->txpower(ifname, &pwr)) 774 | pwr = -1; 775 | 776 | if (iw->txpower_offset(ifname, &off)) 777 | off = 0; 778 | 779 | for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry)) 780 | { 781 | e = (struct iwinfo_txpwrlist_entry *) &buf[i]; 782 | 783 | printf("%s%3d dBm (%4d mW)\n", 784 | (pwr == e->dbm) ? "*" : " ", 785 | e->dbm + off, 786 | iwinfo_dbm2mw(e->dbm + off)); 787 | } 788 | } 789 | 790 | 791 | static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname) 792 | { 793 | int i, len, freq; 794 | char buf[IWINFO_BUFSIZE]; 795 | struct iwinfo_freqlist_entry *e; 796 | 797 | if (iw->freqlist(ifname, buf, &len) || len <= 0) 798 | { 799 | printf("No frequency information available\n"); 800 | return; 801 | } 802 | 803 | if (iw->frequency(ifname, &freq)) 804 | freq = -1; 805 | 806 | for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry)) 807 | { 808 | e = (struct iwinfo_freqlist_entry *) &buf[i]; 809 | 810 | printf("%s %s (Band: %s, Channel %s) %s\n", 811 | (freq == e->mhz) ? "*" : " ", 812 | format_frequency(e->mhz), 813 | format_band(e->band), 814 | format_channel(e->channel), 815 | format_freqflags(e->flags)); 816 | } 817 | } 818 | 819 | 820 | static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname) 821 | { 822 | int i, len; 823 | char buf[IWINFO_BUFSIZE]; 824 | struct iwinfo_assoclist_entry *e; 825 | 826 | if (iw->assoclist(ifname, buf, &len)) 827 | { 828 | printf("No information available\n"); 829 | return; 830 | } 831 | else if (len <= 0) 832 | { 833 | printf("No station connected\n"); 834 | return; 835 | } 836 | 837 | for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) 838 | { 839 | e = (struct iwinfo_assoclist_entry *) &buf[i]; 840 | 841 | printf("%s %s / %s (SNR %d) %d ms ago\n", 842 | format_bssid(e->mac), 843 | format_signal(e->signal), 844 | format_noise(e->noise), 845 | (e->signal - e->noise), 846 | e->inactive); 847 | 848 | printf(" RX: %-38s %8d Pkts.\n", 849 | format_assocrate(&e->rx_rate), 850 | e->rx_packets 851 | ); 852 | 853 | printf(" TX: %-38s %8d Pkts.\n", 854 | format_assocrate(&e->tx_rate), 855 | e->tx_packets 856 | ); 857 | 858 | printf(" expected throughput: %s\n\n", 859 | format_rate(e->thr)); 860 | } 861 | } 862 | 863 | 864 | static char * lookup_country(char *buf, int len, int iso3166) 865 | { 866 | int i; 867 | struct iwinfo_country_entry *c; 868 | 869 | for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry)) 870 | { 871 | c = (struct iwinfo_country_entry *) &buf[i]; 872 | 873 | if (c->iso3166 == iso3166) 874 | return c->ccode; 875 | } 876 | 877 | return NULL; 878 | } 879 | 880 | static void print_countrylist(const struct iwinfo_ops *iw, const char *ifname) 881 | { 882 | int len; 883 | char buf[IWINFO_BUFSIZE]; 884 | char *ccode; 885 | char curcode[3]; 886 | const struct iwinfo_iso3166_label *l; 887 | 888 | if (iw->countrylist(ifname, buf, &len)) 889 | { 890 | printf("No country code information available\n"); 891 | return; 892 | } 893 | 894 | if (iw->country(ifname, curcode)) 895 | memset(curcode, 0, sizeof(curcode)); 896 | 897 | for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++) 898 | { 899 | if ((ccode = lookup_country(buf, len, l->iso3166)) != NULL) 900 | { 901 | printf("%s %4s %c%c\n", 902 | strncmp(ccode, curcode, 2) ? " " : "*", 903 | ccode, (l->iso3166 / 256), (l->iso3166 % 256)); 904 | } 905 | } 906 | } 907 | 908 | static void print_htmodelist(const struct iwinfo_ops *iw, const char *ifname) 909 | { 910 | int i, htmodes = 0; 911 | 912 | if (iw->htmodelist(ifname, &htmodes)) 913 | { 914 | printf("No HT mode information available\n"); 915 | return; 916 | } 917 | 918 | for (i = 0; i < IWINFO_HTMODE_COUNT; i++) 919 | if (htmodes & (1 << i)) 920 | printf("%s ", IWINFO_HTMODE_NAMES[i]); 921 | 922 | printf("\n"); 923 | } 924 | 925 | static void lookup_phy(const struct iwinfo_ops *iw, const char *section) 926 | { 927 | char buf[IWINFO_BUFSIZE]; 928 | 929 | if (!iw->lookup_phy) 930 | { 931 | fprintf(stderr, "Not supported\n"); 932 | return; 933 | } 934 | 935 | if (iw->lookup_phy(section, buf)) 936 | { 937 | fprintf(stderr, "Phy not found\n"); 938 | return; 939 | } 940 | 941 | printf("%s\n", buf); 942 | } 943 | 944 | 945 | static void lookup_path(const struct iwinfo_ops *iw, const char *phy) 946 | { 947 | const char *path; 948 | 949 | if (!iw->phy_path || iw->phy_path(phy, &path) || !path) 950 | return; 951 | 952 | printf("%s\n", path); 953 | } 954 | 955 | int main(int argc, char **argv) 956 | { 957 | int i, rv = 0; 958 | char *p; 959 | const struct iwinfo_ops *iw; 960 | glob_t globbuf; 961 | 962 | if (argc > 1 && argc < 3) 963 | { 964 | fprintf(stderr, 965 | "Usage:\n" 966 | " iwinfo info\n" 967 | " iwinfo scan\n" 968 | " iwinfo txpowerlist\n" 969 | " iwinfo freqlist\n" 970 | " iwinfo assoclist\n" 971 | " iwinfo countrylist\n" 972 | " iwinfo htmodelist\n" 973 | " iwinfo phyname
\n" 974 | ); 975 | 976 | return 1; 977 | } 978 | 979 | if (argc == 1) 980 | { 981 | glob("/sys/class/net/*", 0, NULL, &globbuf); 982 | 983 | for (i = 0; i < globbuf.gl_pathc; i++) 984 | { 985 | p = strrchr(globbuf.gl_pathv[i], '/'); 986 | 987 | if (!p) 988 | continue; 989 | 990 | iw = iwinfo_backend(++p); 991 | 992 | if (!iw) 993 | continue; 994 | 995 | print_info(iw, p); 996 | printf("\n"); 997 | } 998 | 999 | globfree(&globbuf); 1000 | return 0; 1001 | } 1002 | 1003 | if (argc > 3) 1004 | { 1005 | iw = iwinfo_backend_by_name(argv[1]); 1006 | 1007 | if (!iw) 1008 | { 1009 | fprintf(stderr, "No such wireless backend: %s\n", argv[1]); 1010 | rv = 1; 1011 | } 1012 | else 1013 | { 1014 | if (!strcmp(argv[2], "path")) { 1015 | lookup_path(iw, argv[3]); 1016 | return 0; 1017 | } 1018 | switch (argv[2][0]) 1019 | { 1020 | case 'p': 1021 | lookup_phy(iw, argv[3]); 1022 | break; 1023 | 1024 | default: 1025 | fprintf(stderr, "Unknown command: %s\n", argv[2]); 1026 | rv = 1; 1027 | } 1028 | } 1029 | } 1030 | else 1031 | { 1032 | iw = iwinfo_backend(argv[1]); 1033 | 1034 | if (!iw) 1035 | { 1036 | fprintf(stderr, "No such wireless device: %s\n", argv[1]); 1037 | rv = 1; 1038 | } 1039 | else 1040 | { 1041 | for (i = 2; i < argc; i++) 1042 | { 1043 | switch(argv[i][0]) 1044 | { 1045 | case 'i': 1046 | print_info(iw, argv[1]); 1047 | break; 1048 | 1049 | case 's': 1050 | print_scanlist(iw, argv[1]); 1051 | break; 1052 | 1053 | case 't': 1054 | print_txpwrlist(iw, argv[1]); 1055 | break; 1056 | 1057 | case 'f': 1058 | print_freqlist(iw, argv[1]); 1059 | break; 1060 | 1061 | case 'a': 1062 | print_assoclist(iw, argv[1]); 1063 | break; 1064 | 1065 | case 'c': 1066 | print_countrylist(iw, argv[1]); 1067 | break; 1068 | 1069 | case 'h': 1070 | print_htmodelist(iw, argv[1]); 1071 | break; 1072 | 1073 | default: 1074 | fprintf(stderr, "Unknown command: %s\n", argv[i]); 1075 | rv = 1; 1076 | } 1077 | } 1078 | } 1079 | } 1080 | 1081 | iwinfo_finish(); 1082 | 1083 | return rv; 1084 | } 1085 | --------------------------------------------------------------------------------