Initial commit

Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
This commit is contained in:
Jo-Philipp Wich 2014-10-05 19:56:27 +02:00
commit 8ae758db52
21 changed files with 14737 additions and 0 deletions

339
COPYING Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

44
Makefile Normal file
View file

@ -0,0 +1,44 @@
IWINFO_BACKENDS = $(BACKENDS)
IWINFO_CFLAGS = $(CFLAGS) -std=gnu99 -fstrict-aliasing -Iinclude
IWINFO_LIB = libiwinfo.so
IWINFO_LIB_LDFLAGS = $(LDFLAGS) -shared
IWINFO_LIB_OBJ = iwinfo_utils.o iwinfo_wext.o iwinfo_wext_scan.o iwinfo_lib.o
IWINFO_LUA = iwinfo.so
IWINFO_LUA_LDFLAGS = $(LDFLAGS) -shared -L. -liwinfo -llua
IWINFO_LUA_OBJ = iwinfo_lua.o
IWINFO_CLI = iwinfo
IWINFO_CLI_LDFLAGS = $(LDFLAGS) -L. -liwinfo
IWINFO_CLI_OBJ = iwinfo_cli.o
ifneq ($(filter wl,$(IWINFO_BACKENDS)),)
IWINFO_CFLAGS += -DUSE_WL
IWINFO_LIB_OBJ += iwinfo_wl.o
endif
ifneq ($(filter madwifi,$(IWINFO_BACKENDS)),)
IWINFO_CFLAGS += -DUSE_MADWIFI
IWINFO_LIB_OBJ += iwinfo_madwifi.o
endif
ifneq ($(filter nl80211,$(IWINFO_BACKENDS)),)
IWINFO_CFLAGS += -DUSE_NL80211
IWINFO_CLI_LDFLAGS += -lnl-tiny
IWINFO_LIB_LDFLAGS += -lnl-tiny
IWINFO_LIB_OBJ += iwinfo_nl80211.o
endif
%.o: %.c
$(CC) $(IWINFO_CFLAGS) $(FPIC) -c -o $@ $<
compile: clean $(IWINFO_LIB_OBJ) $(IWINFO_LUA_OBJ) $(IWINFO_CLI_OBJ)
$(CC) $(IWINFO_LIB_LDFLAGS) -o $(IWINFO_LIB) $(IWINFO_LIB_OBJ)
$(CC) $(IWINFO_LUA_LDFLAGS) -o $(IWINFO_LUA) $(IWINFO_LUA_OBJ)
$(CC) $(IWINFO_CLI_LDFLAGS) -o $(IWINFO_CLI) $(IWINFO_CLI_OBJ)
clean:
rm -f *.o $(IWINFO_LIB) $(IWINFO_LUA) $(IWINFO_CLI)

146
api/broadcom.h Normal file
View file

@ -0,0 +1,146 @@
/*
* Custom OID/ioctl definitions for
* Broadcom 802.11abg Networking Device Driver
*
* Definitions subject to change without notice.
*
* Copyright 2006, Broadcom Corporation
* All Rights Reserved.
*
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
*
*/
#ifndef _BROADCOM_H
#define _BROADCOM_H
#define WL_MCSSET_LEN 16
#define WL_MAX_STA_COUNT 32
#define WL_BSS_RSSI_OFFSET 82
#define WL_BSS_NOISE_OFFSET 84
#define WLC_IOCTL_MAGIC 0x14e46c77
#define WLC_IOCTL_MAXLEN 8192
#define WLC_CNTRY_BUF_SZ 4
#define WLC_GET_MAGIC 0
#define WLC_GET_RATE 12
#define WLC_GET_INFRA 19
#define WLC_GET_AUTH 21
#define WLC_GET_BSSID 23
#define WLC_GET_SSID 25
#define WLC_GET_CHANNEL 29
#define WLC_GET_PHYTYPE 39
#define WLC_GET_PASSIVE 48
#define WLC_GET_COUNTRY 83
#define WLC_GET_REVINFO 98
#define WLC_GET_AP 117
#define WLC_GET_RSSI 127
#define WLC_GET_WSEC 133
#define WLC_GET_PHY_NOISE 135
#define WLC_GET_BSS_INFO 136
#define WLC_GET_BANDLIST 140
#define WLC_GET_ASSOCLIST 159
#define WLC_GET_WPA_AUTH 164
#define WLC_GET_COUNTRY_LIST 261
#define WLC_GET_VAR 262
#define WLC_PHY_TYPE_A 0
#define WLC_PHY_TYPE_B 1
#define WLC_PHY_TYPE_G 2
#define WLC_PHY_TYPE_N 4
#define WLC_PHY_TYPE_LP 5
#define WLC_BAND_5G 1
#define WLC_BAND_2G 2
#define WLC_BAND_ALL 3
struct wl_ether_addr {
uint8_t octet[6];
};
struct wl_maclist {
uint count;
struct wl_ether_addr ea[1];
};
typedef struct wl_sta_rssi {
int rssi;
char mac[6];
uint16_t foo;
} wl_sta_rssi_t;
#define WL_NUMRATES 255 /* max # of rates in a rateset */
typedef struct wl_rateset {
uint32_t count; /* # rates in this set */
uint8_t rates[WL_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */
} wl_rateset_t;
typedef struct wl_sta_info {
uint16_t ver; /* version of this struct */
uint16_t len; /* length in bytes of this structure */
uint16_t cap; /* sta's advertised capabilities */
uint32_t flags; /* flags defined below */
uint32_t idle; /* time since data pkt rx'd from sta */
unsigned char ea[6]; /* Station address */
wl_rateset_t rateset; /* rateset in use */
uint32_t in; /* seconds elapsed since associated */
uint32_t listen_interval_inms; /* Min Listen interval in ms for this STA */
uint32_t tx_pkts; /* # of packets transmitted */
uint32_t tx_failures; /* # of packets failed */
uint32_t rx_ucast_pkts; /* # of unicast packets received */
uint32_t rx_mcast_pkts; /* # of multicast packets received */
uint32_t tx_rate; /* Rate of last successful tx frame */
uint32_t rx_rate; /* Rate of last successful rx frame */
} wl_sta_info_t;
typedef struct wlc_ssid {
uint32_t ssid_len;
unsigned char ssid[32];
} wlc_ssid_t;
/* Linux network driver ioctl encoding */
typedef struct wl_ioctl {
uint32_t cmd; /* common ioctl definition */
void *buf; /* pointer to user buffer */
uint32_t len; /* length of user buffer */
uint8_t set; /* get or set request (optional) */
uint32_t used; /* bytes read or written (optional) */
uint32_t needed; /* bytes needed (optional) */
} wl_ioctl_t;
/* Revision info */
typedef struct wlc_rev_info {
uint vendorid; /* PCI vendor id */
uint deviceid; /* device id of chip */
uint radiorev; /* radio revision */
uint chiprev; /* chip revision */
uint corerev; /* core revision */
uint boardid; /* board identifier (usu. PCI sub-device id) */
uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */
uint boardrev; /* board revision */
uint driverrev; /* driver version */
uint ucoderev; /* microcode version */
uint bus; /* bus type */
uint chipnum; /* chip number */
uint phytype; /* phy type */
uint phyrev; /* phy revision */
uint anarev; /* anacore rev */
} wlc_rev_info_t;
typedef struct wl_country_list {
uint32_t buflen;
uint32_t band_set;
uint32_t band;
uint32_t count;
char country_abbrev[1];
} wl_country_list_t;
#endif

160
api/madwifi.h Normal file
View file

@ -0,0 +1,160 @@
/*
* Header bits derived from MadWifi source:
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Distributed under the terms of the GPLv2 license.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MADWIFI_H
#define _MADWIFI_H
/* ieee80211.h */
#define IEEE80211_ADDR_LEN 6
#define IEEE80211_RATE_VAL 0x7f
#define IEEE80211_SEQ_SEQ_MASK 0xfff0
#define IEEE80211_SEQ_SEQ_SHIFT 4
/* ieee80211_crypto.h */
#define IEEE80211_KEYBUF_SIZE 16
#define IEEE80211_MICBUF_SIZE 16
#define IEEE80211_TID_SIZE 17
#define IEEE80211_CIPHER_WEP 0
#define IEEE80211_CIPHER_TKIP 1
#define IEEE80211_CIPHER_AES_OCB 2
#define IEEE80211_CIPHER_AES_CCM 3
#define IEEE80211_CIPHER_CKIP 5
#define IEEE80211_CIPHER_NONE 6
#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE + 1)
/* ieee80211_ioctl.h */
#define IEEE80211_KEY_DEFAULT 0x80
#define IEEE80211_CHAN_MAX 255
#define IEEE80211_CHAN_BYTES 32
#define IEEE80211_RATE_MAXSIZE 15
#define IEEE80211_IOCTL_GETKEY (SIOCDEVPRIVATE+3)
#define IEEE80211_IOCTL_STA_STATS (SIOCDEVPRIVATE+5)
#define IEEE80211_IOCTL_STA_INFO (SIOCDEVPRIVATE+6)
#define IEEE80211_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1)
#define IEEE80211_IOCTL_GETMODE (SIOCIWFIRSTPRIV+3)
#define IEEE80211_IOCTL_GETCHANLIST (SIOCIWFIRSTPRIV+7)
#define IEEE80211_IOCTL_GETCHANINFO (SIOCIWFIRSTPRIV+13)
#define SIOC80211IFCREATE (SIOCDEVPRIVATE+7)
#define SIOC80211IFDESTROY (SIOCDEVPRIVATE+8)
#define IEEE80211_CLONE_BSSID 0x0001 /* allocate unique mac/bssid */
#define IEEE80211_NO_STABEACONS 0x0002 /* Do not setup the station beacon timers */
struct ieee80211_clone_params {
char icp_name[IFNAMSIZ]; /* device name */
u_int16_t icp_opmode; /* operating mode */
u_int16_t icp_flags; /* see below */
};
enum ieee80211_opmode {
IEEE80211_M_STA = 1, /* infrastructure station */
IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */
IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */
IEEE80211_M_HOSTAP = 6, /* Software Access Point */
IEEE80211_M_MONITOR = 8, /* Monitor mode */
IEEE80211_M_WDS = 2, /* WDS link */
};
enum {
IEEE80211_PARAM_AUTHMODE = 3, /* authentication mode */
IEEE80211_PARAM_MCASTCIPHER = 5, /* multicast/default cipher */
IEEE80211_PARAM_MCASTKEYLEN = 6, /* multicast key length */
IEEE80211_PARAM_UCASTCIPHERS = 7, /* unicast cipher suites */
IEEE80211_PARAM_WPA = 10, /* WPA mode (0,1,2) */
};
/*
* Authentication mode.
*/
enum ieee80211_authmode {
IEEE80211_AUTH_NONE = 0,
IEEE80211_AUTH_OPEN = 1, /* open */
IEEE80211_AUTH_SHARED = 2, /* shared-key */
IEEE80211_AUTH_8021X = 3, /* 802.1x */
IEEE80211_AUTH_AUTO = 4, /* auto-select/accept */
/* NB: these are used only for ioctls */
IEEE80211_AUTH_WPA = 5, /* WPA/RSN w/ 802.1x/PSK */
};
struct ieee80211_channel {
u_int16_t ic_freq; /* setting in MHz */
u_int16_t ic_flags; /* see below */
u_int8_t ic_ieee; /* IEEE channel number */
int8_t ic_maxregpower; /* maximum regulatory tx power in dBm */
int8_t ic_maxpower; /* maximum tx power in dBm */
int8_t ic_minpower; /* minimum tx power in dBm */
u_int8_t ic_scanflags;
u_int8_t ic_idletime; /* phy idle time in % */
};
struct ieee80211req_key {
u_int8_t ik_type; /* key/cipher type */
u_int8_t ik_pad;
u_int16_t ik_keyix; /* key index */
u_int8_t ik_keylen; /* key length in bytes */
u_int8_t ik_flags;
u_int8_t ik_macaddr[IEEE80211_ADDR_LEN];
u_int64_t ik_keyrsc; /* key receive sequence counter */
u_int64_t ik_keytsc; /* key transmit sequence counter */
u_int8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
};
struct ieee80211req_chanlist {
u_int8_t ic_channels[IEEE80211_CHAN_BYTES];
};
struct ieee80211req_chaninfo {
u_int ic_nchans;
struct ieee80211_channel ic_chans[IEEE80211_CHAN_MAX];
};
struct ieee80211req_sta_info {
u_int16_t isi_len; /* length (mult of 4) */
u_int16_t isi_freq; /* MHz */
u_int16_t isi_flags; /* channel flags */
u_int16_t isi_state; /* state flags */
u_int8_t isi_authmode; /* authentication algorithm */
u_int8_t isi_rssi;
int8_t isi_noise;
u_int16_t isi_capinfo; /* capabilities */
u_int8_t isi_athflags; /* Atheros capabilities */
u_int8_t isi_erp; /* ERP element */
u_int8_t isi_macaddr[IEEE80211_ADDR_LEN];
u_int8_t isi_nrates; /* negotiated rates */
u_int8_t isi_rates[IEEE80211_RATE_MAXSIZE];
u_int8_t isi_txrate; /* index to isi_rates[] */
u_int16_t isi_ie_len; /* IE length */
u_int16_t isi_associd; /* assoc response */
u_int16_t isi_txpower; /* current tx power */
u_int16_t isi_vlan; /* vlan tag */
u_int16_t isi_txseqs[17]; /* seq to be transmitted */
u_int16_t isi_rxseqs[17]; /* seq previous for qos frames*/
u_int16_t isi_inact; /* inactivity timer */
u_int8_t isi_uapsd; /* UAPSD queues */
u_int8_t isi_opmode; /* sta operating mode */
};
#endif

4172
api/nl80211.h Normal file

File diff suppressed because it is too large Load diff

1139
api/wext.h Normal file

File diff suppressed because it is too large Load diff

57
hardware.txt Normal file
View file

@ -0,0 +1,57 @@
# libiwinfo hardware database
# vendor id | device id | subsystem vendor id | subsystem device id |
# txpower offset | frequency offset | "vendor name" | "device name"
0xffff 0xffff 0xffff 0xb102 0 0 "Ubiquiti" "PowerStation2 (18V)"
0xffff 0xffff 0xffff 0xb202 0 0 "Ubiquiti" "PowerStation2 (16D)"
0xffff 0xffff 0xffff 0xb302 0 0 "Ubiquiti" "PowerStation2 (EXT)"
0xffff 0xffff 0xffff 0xb105 0 0 "Ubiquiti" "PowerStation5 (22V)"
0xffff 0xffff 0xffff 0xb305 0 0 "Ubiquiti" "PowerStation5 (EXT)"
0xffff 0xffff 0xffff 0xc302 0 0 "Ubiquiti" "PicoStation2"
0xffff 0xffff 0xffff 0xc3a2 10 0 "Ubiquiti" "PicoStation2 HP"
0xffff 0xffff 0xffff 0xa105 0 0 "Ubiquiti" "WispStation5"
0xffff 0xffff 0xffff 0xa002 10 0 "Ubiquiti" "LiteStation2"
0xffff 0xffff 0xffff 0xa005 5 0 "Ubiquiti" "LiteStation5"
0xffff 0xffff 0xffff 0xc002 10 0 "Ubiquiti" "NanoStation2"
0xffff 0xffff 0xffff 0xc005 5 0 "Ubiquiti" "NanoStation5"
0xffff 0xffff 0xffff 0xc102 10 0 "Ubiquiti" "NanoStation Loco2"
0xffff 0xffff 0xffff 0xc105 5 0 "Ubiquiti" "NanoStation Loco5"
0xffff 0xffff 0xffff 0xc202 10 0 "Ubiquiti" "Bullet2"
0xffff 0xffff 0xffff 0xc205 5 0 "Ubiquiti" "Bullet5"
0x168c 0x001b 0x0777 0x3002 10 0 "Ubiquiti" "XR2"
0x168c 0x001b 0x7777 0x3002 10 0 "Ubiquiti" "XR2"
0x168c 0x001b 0x0777 0x3b02 10 0 "Ubiquiti" "XR2.3"
0x168c 0x001b 0x0777 0x3c02 10 0 "Ubiquiti" "XR2.6"
0x168c 0x001b 0x0777 0x3b03 10 0 "Ubiquiti" "XR3-2.8"
0x168c 0x001b 0x0777 0x3c03 10 0 "Ubiquiti" "XR3-3.6"
0x168c 0x001b 0x0777 0x3003 10 0 "Ubiquiti" "XR3"
0x168c 0x001b 0x0777 0x3004 10 0 "Ubiquiti" "XR4"
0x168c 0x001b 0x0777 0x3005 10 0 "Ubiquiti" "XR5"
0x168c 0x001b 0x7777 0x3005 10 0 "Ubiquiti" "XR5"
0x168c 0x001b 0x0777 0x3007 10 0 "Ubiquiti" "XR7"
0x168c 0x001b 0x0777 0x3009 10 -1520 "Ubiquiti" "XR9"
0x168c 0x001b 0x168c 0x2063 0 0 "Atheros" "AR5413"
0x168c 0x0013 0x168c 0x1042 1 0 "Ubiquiti" "SRC"
0x168c 0x0013 0x0777 0x2041 10 0 "Ubiquiti" "SR2"
0x168c 0x0013 0x0777 0x2004 6 0 "Ubiquiti" "SR4"
0x168c 0x0013 0x7777 0x2004 6 0 "Ubiquiti" "SR4"
0x168c 0x0013 0x0777 0x1004 6 0 "Ubiquiti" "SR4C"
0x168c 0x0013 0x7777 0x1004 6 0 "Ubiquiti" "SR4C"
0x168c 0x0013 0x168c 0x2042 7 0 "Ubiquiti" "SR5"
0x168c 0x0013 0x7777 0x2009 12 -1500 "Ubiquiti" "SR9"
0x168c 0x0027 0x168c 0x2082 7 0 "Ubiquiti" "SR71A"
0x168c 0x0027 0x0777 0x4082 7 0 "Ubiquiti" "SR71"
0x168c 0x0029 0x0777 0x4005 7 0 "Ubiquiti" "SR71-15"
0x168c 0x002a 0x0777 0xe302 12 0 "Ubiquiti" "PicoStation M2" /* ToDo: confirm offset */
0x168c 0x002a 0x0777 0xe012 12 0 "Ubiquiti" "NanoStation M2" /* ToDo: confirm offset */
0x168c 0x002a 0x0777 0xe005 5 0 "Ubiquiti" "NanoStation M5" /* ToDo: confirm offset */
0x168c 0x002a 0x0777 0xe202 12 0 "Ubiquiti" "Bullet M2"
0x168c 0x002a 0x0777 0xe805 5 0 "Ubiquiti" "Bullet M5"
0x168c 0x002a 0x0777 0xe345 0 0 "Ubiquiti" "WispStation M5" /* ToDo: confirm offset */
0x168c 0x0029 0x168c 0xa094 0 0 "Atheros" "AR9220"
0x168c 0x0029 0x168c 0xa095 0 0 "Atheros" "AR9223"
0x168c 0x002a 0x168c 0xa093 0 0 "Atheros" "AR9280"
0x168c 0x002b 0x168c 0xa091 0 0 "Atheros" "AR9285"
0x168c 0x0033 0x168c 0xa120 0 0 "Atheros" "AR9580"
0x1814 0x3050 0x1814 0x0005 0 0 "RaLink" "Rt3050"
0x1814 0x3052 0x1814 0x0008 0 0 "RaLink" "Rt3052"
0x1814 0x3352 0x1814 0x000c 0 0 "RaLink" "Rt3352"

194
include/iwinfo.h Normal file
View file

@ -0,0 +1,194 @@
#ifndef __IWINFO_H_
#define __IWINFO_H_
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <glob.h>
#include <ctype.h>
#include <dirent.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <net/if.h>
#include <errno.h>
#define IWINFO_BUFSIZE 24 * 1024
#define IWINFO_ESSID_MAX_SIZE 32
#define IWINFO_80211_A (1 << 0)
#define IWINFO_80211_B (1 << 1)
#define IWINFO_80211_G (1 << 2)
#define IWINFO_80211_N (1 << 3)
#define IWINFO_80211_AC (1 << 4)
#define IWINFO_CIPHER_NONE (1 << 0)
#define IWINFO_CIPHER_WEP40 (1 << 1)
#define IWINFO_CIPHER_TKIP (1 << 2)
#define IWINFO_CIPHER_WRAP (1 << 3)
#define IWINFO_CIPHER_CCMP (1 << 4)
#define IWINFO_CIPHER_WEP104 (1 << 5)
#define IWINFO_CIPHER_AESOCB (1 << 6)
#define IWINFO_CIPHER_CKIP (1 << 7)
#define IWINFO_KMGMT_NONE (1 << 0)
#define IWINFO_KMGMT_8021x (1 << 1)
#define IWINFO_KMGMT_PSK (1 << 2)
#define IWINFO_AUTH_OPEN (1 << 0)
#define IWINFO_AUTH_SHARED (1 << 1)
extern const char *IWINFO_CIPHER_NAMES[];
extern const char *IWINFO_KMGMT_NAMES[];
extern const char *IWINFO_AUTH_NAMES[];
enum iwinfo_opmode {
IWINFO_OPMODE_UNKNOWN = 0,
IWINFO_OPMODE_MASTER = 1,
IWINFO_OPMODE_ADHOC = 2,
IWINFO_OPMODE_CLIENT = 3,
IWINFO_OPMODE_MONITOR = 4,
IWINFO_OPMODE_AP_VLAN = 5,
IWINFO_OPMODE_WDS = 6,
IWINFO_OPMODE_MESHPOINT = 7,
IWINFO_OPMODE_P2P_CLIENT = 8,
IWINFO_OPMODE_P2P_GO = 9,
};
extern const char *IWINFO_OPMODE_NAMES[];
struct iwinfo_rate_entry {
uint32_t rate;
int8_t mcs;
uint8_t is_40mhz:1;
uint8_t is_short_gi:1;
};
struct iwinfo_assoclist_entry {
uint8_t mac[6];
int8_t signal;
int8_t noise;
uint32_t inactive;
uint32_t rx_packets;
uint32_t tx_packets;
struct iwinfo_rate_entry rx_rate;
struct iwinfo_rate_entry tx_rate;
};
struct iwinfo_txpwrlist_entry {
uint8_t dbm;
uint16_t mw;
};
struct iwinfo_freqlist_entry {
uint8_t channel;
uint32_t mhz;
uint8_t restricted;
};
struct iwinfo_crypto_entry {
uint8_t enabled;
uint8_t wpa_version;
uint8_t group_ciphers;
uint8_t pair_ciphers;
uint8_t auth_suites;
uint8_t auth_algs;
};
struct iwinfo_scanlist_entry {
uint8_t mac[6];
uint8_t ssid[IWINFO_ESSID_MAX_SIZE+1];
enum iwinfo_opmode mode;
uint8_t channel;
uint8_t signal;
uint8_t quality;
uint8_t quality_max;
struct iwinfo_crypto_entry crypto;
};
struct iwinfo_country_entry {
uint16_t iso3166;
uint8_t ccode[4];
};
struct iwinfo_iso3166_label {
uint16_t iso3166;
uint8_t name[28];
};
struct iwinfo_hardware_id {
uint16_t vendor_id;
uint16_t device_id;
uint16_t subsystem_vendor_id;
uint16_t subsystem_device_id;
};
struct iwinfo_hardware_entry {
char vendor_name[64];
char device_name[64];
uint16_t vendor_id;
uint16_t device_id;
uint16_t subsystem_vendor_id;
uint16_t subsystem_device_id;
int16_t txpower_offset;
int16_t frequency_offset;
};
extern const struct iwinfo_iso3166_label IWINFO_ISO3166_NAMES[];
#define IWINFO_HARDWARE_FILE "/usr/share/libiwinfo/hardware.txt"
struct iwinfo_ops {
const char *name;
int (*probe)(const char *ifname);
int (*mode)(const char *, int *);
int (*channel)(const char *, int *);
int (*frequency)(const char *, int *);
int (*frequency_offset)(const char *, int *);
int (*txpower)(const char *, int *);
int (*txpower_offset)(const char *, int *);
int (*bitrate)(const char *, int *);
int (*signal)(const char *, int *);
int (*noise)(const char *, int *);
int (*quality)(const char *, int *);
int (*quality_max)(const char *, int *);
int (*mbssid_support)(const char *, int *);
int (*hwmodelist)(const char *, int *);
int (*ssid)(const char *, char *);
int (*bssid)(const char *, char *);
int (*country)(const char *, char *);
int (*hardware_id)(const char *, char *);
int (*hardware_name)(const char *, char *);
int (*encryption)(const char *, char *);
int (*phyname)(const char *, char *);
int (*assoclist)(const char *, char *, int *);
int (*txpwrlist)(const char *, char *, int *);
int (*scanlist)(const char *, char *, int *);
int (*freqlist)(const char *, char *, int *);
int (*countrylist)(const char *, char *, int *);
void (*close)(void);
};
const char * iwinfo_type(const char *ifname);
const struct iwinfo_ops * iwinfo_backend(const char *ifname);
void iwinfo_finish(void);
extern const struct iwinfo_ops wext_ops;
extern const struct iwinfo_ops madwifi_ops;
extern const struct iwinfo_ops nl80211_ops;
extern const struct iwinfo_ops wl_ops;
#include "iwinfo/utils.h"
#endif

79
include/iwinfo/lua.h Normal file
View file

@ -0,0 +1,79 @@
/*
* iwinfo - Wireless Information Library - Lua Headers
*
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*/
#ifndef __IWINFO_LUALUB_H_
#define __IWINFO_LUALIB_H_
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "iwinfo.h"
#define IWINFO_META "iwinfo"
#define IWINFO_WEXT_META "iwinfo.wext"
#ifdef USE_WL
#define IWINFO_WL_META "iwinfo.wl"
#endif
#ifdef USE_MADWIFI
#define IWINFO_MADWIFI_META "iwinfo.madwifi"
#endif
#ifdef USE_NL80211
#define IWINFO_NL80211_META "iwinfo.nl80211"
#endif
#define LUA_REG(type,op) \
{ #op, iwinfo_L_##type##_##op }
#define LUA_WRAP_INT_OP(type,op) \
static int iwinfo_L_##type##_##op(lua_State *L) \
{ \
const char *ifname = luaL_checkstring(L, 1); \
int rv; \
if( !type##_ops.op(ifname, &rv) ) \
lua_pushnumber(L, rv); \
else \
lua_pushnil(L); \
return 1; \
}
#define LUA_WRAP_STRING_OP(type,op) \
static int iwinfo_L_##type##_##op(lua_State *L) \
{ \
const char *ifname = luaL_checkstring(L, 1); \
char rv[IWINFO_BUFSIZE]; \
memset(rv, 0, IWINFO_BUFSIZE); \
if( !type##_ops.op(ifname, rv) ) \
lua_pushstring(L, rv); \
else \
lua_pushnil(L); \
return 1; \
}
#define LUA_WRAP_STRUCT_OP(type,op) \
static int iwinfo_L_##type##_##op(lua_State *L) \
{ \
return iwinfo_L_##op(L, type##_ops.op); \
}
#endif

47
include/iwinfo/utils.h Normal file
View file

@ -0,0 +1,47 @@
/*
* iwinfo - Wireless Information Library - Utility Headers
*
* Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*/
#ifndef __IWINFO_UTILS_H_
#define __IWINFO_UTILS_H_
#include <sys/socket.h>
#include <net/if.h>
#include "iwinfo.h"
#define LOG10_MAGIC 1.25892541179
int iwinfo_ioctl(int cmd, void *ifr);
int iwinfo_dbm2mw(int in);
int iwinfo_mw2dbm(int in);
int iwinfo_ifup(const char *ifname);
int iwinfo_ifdown(const char *ifname);
int iwinfo_ifmac(const char *ifname);
void iwinfo_close(void);
struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id);
int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id);
void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len,
uint8_t defcipher, uint8_t defauth);
#endif

839
iwinfo_cli.c Normal file
View file

@ -0,0 +1,839 @@
/*
* iwinfo - Wireless Information Library - Command line frontend
*
* Copyright (C) 2011 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*/
#include <stdio.h>
#include <glob.h>
#include "iwinfo.h"
static char * format_bssid(unsigned char *mac)
{
static char buf[18];
snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return buf;
}
static char * format_ssid(char *ssid)
{
static char buf[IWINFO_ESSID_MAX_SIZE+3];
if (ssid && ssid[0])
snprintf(buf, sizeof(buf), "\"%s\"", ssid);
else
snprintf(buf, sizeof(buf), "unknown");
return buf;
}
static char * format_channel(int ch)
{
static char buf[8];
if (ch <= 0)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%d", ch);
return buf;
}
static char * format_frequency(int freq)
{
static char buf[10];
if (freq <= 0)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%.3f GHz", ((float)freq / 1000.0));
return buf;
}
static char * format_txpower(int pwr)
{
static char buf[10];
if (pwr < 0)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%d dBm", pwr);
return buf;
}
static char * format_quality(int qual)
{
static char buf[8];
if (qual < 0)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%d", qual);
return buf;
}
static char * format_quality_max(int qmax)
{
static char buf[8];
if (qmax < 0)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%d", qmax);
return buf;
}
static char * format_signal(int sig)
{
static char buf[10];
if (!sig)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%d dBm", sig);
return buf;
}
static char * format_noise(int noise)
{
static char buf[10];
if (!noise)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%d dBm", noise);
return buf;
}
static char * format_rate(int rate)
{
static char buf[14];
if (rate <= 0)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "%d.%d MBit/s",
rate / 1000, (rate % 1000) / 100);
return buf;
}
static char * format_enc_ciphers(int ciphers)
{
static char str[128] = { 0 };
char *pos = str;
if (ciphers & IWINFO_CIPHER_WEP40)
pos += sprintf(pos, "WEP-40, ");
if (ciphers & IWINFO_CIPHER_WEP104)
pos += sprintf(pos, "WEP-104, ");
if (ciphers & IWINFO_CIPHER_TKIP)
pos += sprintf(pos, "TKIP, ");
if (ciphers & IWINFO_CIPHER_CCMP)
pos += sprintf(pos, "CCMP, ");
if (ciphers & IWINFO_CIPHER_WRAP)
pos += sprintf(pos, "WRAP, ");
if (ciphers & IWINFO_CIPHER_AESOCB)
pos += sprintf(pos, "AES-OCB, ");
if (ciphers & IWINFO_CIPHER_CKIP)
pos += sprintf(pos, "CKIP, ");
if (!ciphers || (ciphers & IWINFO_CIPHER_NONE))
pos += sprintf(pos, "NONE, ");
*(pos - 2) = 0;
return str;
}
static char * format_enc_suites(int suites)
{
static char str[64] = { 0 };
char *pos = str;
if (suites & IWINFO_KMGMT_PSK)
pos += sprintf(pos, "PSK/");
if (suites & IWINFO_KMGMT_8021x)
pos += sprintf(pos, "802.1X/");
if (!suites || (suites & IWINFO_KMGMT_NONE))
pos += sprintf(pos, "NONE/");
*(pos - 1) = 0;
return str;
}
static char * format_encryption(struct iwinfo_crypto_entry *c)
{
static char buf[512];
if (!c)
{
snprintf(buf, sizeof(buf), "unknown");
}
else if (c->enabled)
{
/* WEP */
if (c->auth_algs && !c->wpa_version)
{
if ((c->auth_algs & IWINFO_AUTH_OPEN) &&
(c->auth_algs & IWINFO_AUTH_SHARED))
{
snprintf(buf, sizeof(buf), "WEP Open/Shared (%s)",
format_enc_ciphers(c->pair_ciphers));
}
else if (c->auth_algs & IWINFO_AUTH_OPEN)
{
snprintf(buf, sizeof(buf), "WEP Open System (%s)",
format_enc_ciphers(c->pair_ciphers));
}
else if (c->auth_algs & IWINFO_AUTH_SHARED)
{
snprintf(buf, sizeof(buf), "WEP Shared Auth (%s)",
format_enc_ciphers(c->pair_ciphers));
}
}
/* WPA */
else if (c->wpa_version)
{
switch (c->wpa_version) {
case 3:
snprintf(buf, sizeof(buf), "mixed WPA/WPA2 %s (%s)",
format_enc_suites(c->auth_suites),
format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
break;
case 2:
snprintf(buf, sizeof(buf), "WPA2 %s (%s)",
format_enc_suites(c->auth_suites),
format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
break;
case 1:
snprintf(buf, sizeof(buf), "WPA %s (%s)",
format_enc_suites(c->auth_suites),
format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
break;
}
}
else
{
snprintf(buf, sizeof(buf), "none");
}
}
else
{
snprintf(buf, sizeof(buf), "none");
}
return buf;
}
static char * format_hwmodes(int modes)
{
static char buf[12];
if (modes <= 0)
snprintf(buf, sizeof(buf), "unknown");
else
snprintf(buf, sizeof(buf), "802.11%s%s%s%s%s",
(modes & IWINFO_80211_A) ? "a" : "",
(modes & IWINFO_80211_B) ? "b" : "",
(modes & IWINFO_80211_G) ? "g" : "",
(modes & IWINFO_80211_N) ? "n" : "",
(modes & IWINFO_80211_AC) ? "ac" : "");
return buf;
}
static char * format_assocrate(struct iwinfo_rate_entry *r)
{
static char buf[40];
char *p = buf;
int l = sizeof(buf);
if (r->rate <= 0)
{
snprintf(buf, sizeof(buf), "unknown");
}
else
{
p += snprintf(p, l, "%s", format_rate(r->rate));
l = sizeof(buf) - (p - buf);
if (r->mcs >= 0)
{
p += snprintf(p, l, ", MCS %d, %dMHz", r->mcs, 20 + r->is_40mhz*20);
l = sizeof(buf) - (p - buf);
if (r->is_short_gi)
p += snprintf(p, l, ", short GI");
}
}
return buf;
}
static const char * print_type(const struct iwinfo_ops *iw, const char *ifname)
{
const char *type = iwinfo_type(ifname);
return type ? type : "unknown";
}
static char * print_hardware_id(const struct iwinfo_ops *iw, const char *ifname)
{
static char buf[20];
struct iwinfo_hardware_id ids;
if (!iw->hardware_id(ifname, (char *)&ids))
{
snprintf(buf, sizeof(buf), "%04X:%04X %04X:%04X",
ids.vendor_id, ids.device_id,
ids.subsystem_vendor_id, ids.subsystem_device_id);
}
else
{
snprintf(buf, sizeof(buf), "unknown");
}
return buf;
}
static char * print_hardware_name(const struct iwinfo_ops *iw, const char *ifname)
{
static char buf[128];
if (iw->hardware_name(ifname, buf))
snprintf(buf, sizeof(buf), "unknown");
return buf;
}
static char * print_txpower_offset(const struct iwinfo_ops *iw, const char *ifname)
{
int off;
static char buf[12];
if (iw->txpower_offset(ifname, &off))
snprintf(buf, sizeof(buf), "unknown");
else if (off != 0)
snprintf(buf, sizeof(buf), "%d dB", off);
else
snprintf(buf, sizeof(buf), "none");
return buf;
}
static char * print_frequency_offset(const struct iwinfo_ops *iw, const char *ifname)
{
int off;
static char buf[12];
if (iw->frequency_offset(ifname, &off))
snprintf(buf, sizeof(buf), "unknown");
else if (off != 0)
snprintf(buf, sizeof(buf), "%.3f GHz", ((float)off / 1000.0));
else
snprintf(buf, sizeof(buf), "none");
return buf;
}
static char * print_ssid(const struct iwinfo_ops *iw, const char *ifname)
{
char buf[IWINFO_ESSID_MAX_SIZE+1] = { 0 };
if (iw->ssid(ifname, buf))
memset(buf, 0, sizeof(buf));
return format_ssid(buf);
}
static char * print_bssid(const struct iwinfo_ops *iw, const char *ifname)
{
static char buf[18] = { 0 };
if (iw->bssid(ifname, buf))
snprintf(buf, sizeof(buf), "00:00:00:00:00:00");
return buf;
}
static char * print_mode(const struct iwinfo_ops *iw, const char *ifname)
{
int mode;
static char buf[128];
if (iw->mode(ifname, &mode))
mode = IWINFO_OPMODE_UNKNOWN;
snprintf(buf, sizeof(buf), "%s", IWINFO_OPMODE_NAMES[mode]);
return buf;
}
static char * print_channel(const struct iwinfo_ops *iw, const char *ifname)
{
int ch;
if (iw->channel(ifname, &ch))
ch = -1;
return format_channel(ch);
}
static char * print_frequency(const struct iwinfo_ops *iw, const char *ifname)
{
int freq;
if (iw->frequency(ifname, &freq))
freq = -1;
return format_frequency(freq);
}
static char * print_txpower(const struct iwinfo_ops *iw, const char *ifname)
{
int pwr, off;
if (iw->txpower_offset(ifname, &off))
off = 0;
if (iw->txpower(ifname, &pwr))
pwr = -1;
else
pwr += off;
return format_txpower(pwr);
}
static char * print_quality(const struct iwinfo_ops *iw, const char *ifname)
{
int qual;
if (iw->quality(ifname, &qual))
qual = -1;
return format_quality(qual);
}
static char * print_quality_max(const struct iwinfo_ops *iw, const char *ifname)
{
int qmax;
if (iw->quality_max(ifname, &qmax))
qmax = -1;
return format_quality_max(qmax);
}
static char * print_signal(const struct iwinfo_ops *iw, const char *ifname)
{
int sig;
if (iw->signal(ifname, &sig))
sig = 0;
return format_signal(sig);
}
static char * print_noise(const struct iwinfo_ops *iw, const char *ifname)
{
int noise;
if (iw->noise(ifname, &noise))
noise = 0;
return format_noise(noise);
}
static char * print_rate(const struct iwinfo_ops *iw, const char *ifname)
{
int rate;
if (iw->bitrate(ifname, &rate))
rate = -1;
return format_rate(rate);
}
static char * print_encryption(const struct iwinfo_ops *iw, const char *ifname)
{
struct iwinfo_crypto_entry c = { 0 };
if (iw->encryption(ifname, (char *)&c))
return format_encryption(NULL);
return format_encryption(&c);
}
static char * print_hwmodes(const struct iwinfo_ops *iw, const char *ifname)
{
int modes;
if (iw->hwmodelist(ifname, &modes))
modes = -1;
return format_hwmodes(modes);
}
static char * print_mbssid_supp(const struct iwinfo_ops *iw, const char *ifname)
{
int supp;
static char buf[4];
if (iw->mbssid_support(ifname, &supp))
snprintf(buf, sizeof(buf), "no");
else
snprintf(buf, sizeof(buf), "%s", supp ? "yes" : "no");
return buf;
}
static char * print_phyname(const struct iwinfo_ops *iw, const char *ifname)
{
static char buf[32];
if (!iw->phyname(ifname, buf))
return buf;
return "?";
}
static void print_info(const struct iwinfo_ops *iw, const char *ifname)
{
printf("%-9s ESSID: %s\n",
ifname,
print_ssid(iw, ifname));
printf(" Access Point: %s\n",
print_bssid(iw, ifname));
printf(" Mode: %s Channel: %s (%s)\n",
print_mode(iw, ifname),
print_channel(iw, ifname),
print_frequency(iw, ifname));
printf(" Tx-Power: %s Link Quality: %s/%s\n",
print_txpower(iw, ifname),
print_quality(iw, ifname),
print_quality_max(iw, ifname));
printf(" Signal: %s Noise: %s\n",
print_signal(iw, ifname),
print_noise(iw, ifname));
printf(" Bit Rate: %s\n",
print_rate(iw, ifname));
printf(" Encryption: %s\n",
print_encryption(iw, ifname));
printf(" Type: %s HW Mode(s): %s\n",
print_type(iw, ifname),
print_hwmodes(iw, ifname));
printf(" Hardware: %s [%s]\n",
print_hardware_id(iw, ifname),
print_hardware_name(iw, ifname));
printf(" TX power offset: %s\n",
print_txpower_offset(iw, ifname));
printf(" Frequency offset: %s\n",
print_frequency_offset(iw, ifname));
printf(" Supports VAPs: %s PHY name: %s\n",
print_mbssid_supp(iw, ifname),
print_phyname(iw, ifname));
}
static void print_scanlist(const struct iwinfo_ops *iw, const char *ifname)
{
int i, x, len;
char buf[IWINFO_BUFSIZE];
struct iwinfo_scanlist_entry *e;
if (iw->scanlist(ifname, buf, &len))
{
printf("Scanning not possible\n\n");
return;
}
else if (len <= 0)
{
printf("No scan results\n\n");
return;
}
for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_scanlist_entry), x++)
{
e = (struct iwinfo_scanlist_entry *) &buf[i];
printf("Cell %02d - Address: %s\n",
x,
format_bssid(e->mac));
printf(" ESSID: %s\n",
format_ssid(e->ssid));
printf(" Mode: %s Channel: %s\n",
IWINFO_OPMODE_NAMES[e->mode],
format_channel(e->channel));
printf(" Signal: %s Quality: %s/%s\n",
format_signal(e->signal - 0x100),
format_quality(e->quality),
format_quality_max(e->quality_max));
printf(" Encryption: %s\n\n",
format_encryption(&e->crypto));
}
}
static void print_txpwrlist(const struct iwinfo_ops *iw, const char *ifname)
{
int len, pwr, off, i;
char buf[IWINFO_BUFSIZE];
struct iwinfo_txpwrlist_entry *e;
if (iw->txpwrlist(ifname, buf, &len) || len <= 0)
{
printf("No TX power information available\n");
return;
}
if (iw->txpower(ifname, &pwr))
pwr = -1;
if (iw->txpower_offset(ifname, &off))
off = 0;
for (i = 0; i < len; i += sizeof(struct iwinfo_txpwrlist_entry))
{
e = (struct iwinfo_txpwrlist_entry *) &buf[i];
printf("%s%3d dBm (%4d mW)\n",
(pwr == e->dbm) ? "*" : " ",
e->dbm + off,
iwinfo_dbm2mw(e->dbm + off));
}
}
static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname)
{
int i, len, ch;
char buf[IWINFO_BUFSIZE];
struct iwinfo_freqlist_entry *e;
if (iw->freqlist(ifname, buf, &len) || len <= 0)
{
printf("No frequency information available\n");
return;
}
if (iw->channel(ifname, &ch))
ch = -1;
for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry))
{
e = (struct iwinfo_freqlist_entry *) &buf[i];
printf("%s %s (Channel %s)%s\n",
(ch == e->channel) ? "*" : " ",
format_frequency(e->mhz),
format_channel(e->channel),
e->restricted ? " [restricted]" : "");
}
}
static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname)
{
int i, len;
char buf[IWINFO_BUFSIZE];
struct iwinfo_assoclist_entry *e;
if (iw->assoclist(ifname, buf, &len))
{
printf("No information available\n");
return;
}
else if (len <= 0)
{
printf("No station connected\n");
return;
}
for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry))
{
e = (struct iwinfo_assoclist_entry *) &buf[i];
printf("%s %s / %s (SNR %d) %d ms ago\n",
format_bssid(e->mac),
format_signal(e->signal),
format_noise(e->noise),
(e->signal - e->noise),
e->inactive);
printf(" RX: %-38s %8d Pkts.\n",
format_assocrate(&e->rx_rate),
e->rx_packets
);
printf(" TX: %-38s %8d Pkts.\n\n",
format_assocrate(&e->tx_rate),
e->tx_packets
);
}
}
static char * lookup_country(char *buf, int len, int iso3166)
{
int i;
struct iwinfo_country_entry *c;
for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry))
{
c = (struct iwinfo_country_entry *) &buf[i];
if (c->iso3166 == iso3166)
return c->ccode;
}
return NULL;
}
static void print_countrylist(const struct iwinfo_ops *iw, const char *ifname)
{
int len;
char buf[IWINFO_BUFSIZE];
char *ccode;
char curcode[3];
const struct iwinfo_iso3166_label *l;
if (iw->countrylist(ifname, buf, &len))
{
printf("No country code information available\n");
return;
}
if (iw->country(ifname, curcode))
memset(curcode, 0, sizeof(curcode));
for (l = IWINFO_ISO3166_NAMES; l->iso3166; l++)
{
if ((ccode = lookup_country(buf, len, l->iso3166)) != NULL)
{
printf("%s %4s %c%c\n",
strncmp(ccode, curcode, 2) ? " " : "*",
ccode, (l->iso3166 / 256), (l->iso3166 % 256));
}
}
}
int main(int argc, char **argv)
{
int i;
char *p;
const struct iwinfo_ops *iw;
glob_t globbuf;
if (argc > 1 && argc < 3)
{
fprintf(stderr,
"Usage:\n"
" iwinfo <device> info\n"
" iwinfo <device> scan\n"
" iwinfo <device> txpowerlist\n"
" iwinfo <device> freqlist\n"
" iwinfo <device> assoclist\n"
" iwinfo <device> countrylist\n"
);
return 1;
}
if (argc == 1)
{
glob("/sys/class/net/*", 0, NULL, &globbuf);
for (i = 0; i < globbuf.gl_pathc; i++)
{
p = strrchr(globbuf.gl_pathv[i], '/');
if (!p)
continue;
iw = iwinfo_backend(++p);
if (!iw)
continue;
print_info(iw, p);
printf("\n");
}
globfree(&globbuf);
return 0;
}
iw = iwinfo_backend(argv[1]);
if (!iw)
{
fprintf(stderr, "No such wireless device: %s\n", argv[1]);
return 1;
}
for (i = 2; i < argc; i++)
{
switch(argv[i][0])
{
case 'i':
print_info(iw, argv[1]);
break;
case 's':
print_scanlist(iw, argv[1]);
break;
case 't':
print_txpwrlist(iw, argv[1]);
break;
case 'f':
print_freqlist(iw, argv[1]);
break;
case 'a':
print_assoclist(iw, argv[1]);
break;
case 'c':
print_countrylist(iw, argv[1]);
break;
default:
fprintf(stderr, "Unknown command: %s\n", argv[i]);
return 1;
}
}
iwinfo_finish();
return 0;
}

361
iwinfo_lib.c Normal file
View file

@ -0,0 +1,361 @@
/*
* iwinfo - Wireless Information Library - Lua Bindings
*
* Copyright (C) 2009-2013 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*/
#include "iwinfo.h"
/*
* name constants
*/
const char *IWINFO_CIPHER_NAMES[] = {
"NONE",
"WEP40",
"TKIP",
"WRAP",
"CCMP",
"WEP104",
"AES-OCB",
"CKIP",
};
const char *IWINFO_KMGMT_NAMES[] = {
"NONE",
"802.1X",
"PSK",
};
const char *IWINFO_AUTH_NAMES[] = {
"OPEN",
"SHARED",
};
const char *IWINFO_OPMODE_NAMES[] = {
"Unknown",
"Master",
"Ad-Hoc",
"Client",
"Monitor",
"Master (VLAN)",
"WDS",
"Mesh Point",
"P2P Client",
"P2P Go",
};
/*
* ISO3166 country labels
*/
const struct iwinfo_iso3166_label IWINFO_ISO3166_NAMES[] = {
{ 0x3030 /* 00 */, "World" },
{ 0x4144 /* AD */, "Andorra" },
{ 0x4145 /* AE */, "United Arab Emirates" },
{ 0x4146 /* AF */, "Afghanistan" },
{ 0x4147 /* AG */, "Antigua and Barbuda" },
{ 0x4149 /* AI */, "Anguilla" },
{ 0x414C /* AL */, "Albania" },
{ 0x414D /* AM */, "Armenia" },
{ 0x414E /* AN */, "Netherlands Antilles" },
{ 0x414F /* AO */, "Angola" },
{ 0x4151 /* AQ */, "Antarctica" },
{ 0x4152 /* AR */, "Argentina" },
{ 0x4153 /* AS */, "American Samoa" },
{ 0x4154 /* AT */, "Austria" },
{ 0x4155 /* AU */, "Australia" },
{ 0x4157 /* AW */, "Aruba" },
{ 0x4158 /* AX */, "Aland Islands" },
{ 0x415A /* AZ */, "Azerbaijan" },
{ 0x4241 /* BA */, "Bosnia and Herzegovina" },
{ 0x4242 /* BB */, "Barbados" },
{ 0x4244 /* BD */, "Bangladesh" },
{ 0x4245 /* BE */, "Belgium" },
{ 0x4246 /* BF */, "Burkina Faso" },
{ 0x4247 /* BG */, "Bulgaria" },
{ 0x4248 /* BH */, "Bahrain" },
{ 0x4249 /* BI */, "Burundi" },
{ 0x424A /* BJ */, "Benin" },
{ 0x424C /* BL */, "Saint Barthelemy" },
{ 0x424D /* BM */, "Bermuda" },
{ 0x424E /* BN */, "Brunei Darussalam" },
{ 0x424F /* BO */, "Bolivia" },
{ 0x4252 /* BR */, "Brazil" },
{ 0x4253 /* BS */, "Bahamas" },
{ 0x4254 /* BT */, "Bhutan" },
{ 0x4256 /* BV */, "Bouvet Island" },
{ 0x4257 /* BW */, "Botswana" },
{ 0x4259 /* BY */, "Belarus" },
{ 0x425A /* BZ */, "Belize" },
{ 0x4341 /* CA */, "Canada" },
{ 0x4343 /* CC */, "Cocos (Keeling) Islands" },
{ 0x4344 /* CD */, "Congo" },
{ 0x4346 /* CF */, "Central African Republic" },
{ 0x4347 /* CG */, "Congo" },
{ 0x4348 /* CH */, "Switzerland" },
{ 0x4349 /* CI */, "Cote d'Ivoire" },
{ 0x434B /* CK */, "Cook Islands" },
{ 0x434C /* CL */, "Chile" },
{ 0x434D /* CM */, "Cameroon" },
{ 0x434E /* CN */, "China" },
{ 0x434F /* CO */, "Colombia" },
{ 0x4352 /* CR */, "Costa Rica" },
{ 0x4355 /* CU */, "Cuba" },
{ 0x4356 /* CV */, "Cape Verde" },
{ 0x4358 /* CX */, "Christmas Island" },
{ 0x4359 /* CY */, "Cyprus" },
{ 0x435A /* CZ */, "Czech Republic" },
{ 0x4445 /* DE */, "Germany" },
{ 0x444A /* DJ */, "Djibouti" },
{ 0x444B /* DK */, "Denmark" },
{ 0x444D /* DM */, "Dominica" },
{ 0x444F /* DO */, "Dominican Republic" },
{ 0x445A /* DZ */, "Algeria" },
{ 0x4543 /* EC */, "Ecuador" },
{ 0x4545 /* EE */, "Estonia" },
{ 0x4547 /* EG */, "Egypt" },
{ 0x4548 /* EH */, "Western Sahara" },
{ 0x4552 /* ER */, "Eritrea" },
{ 0x4553 /* ES */, "Spain" },
{ 0x4554 /* ET */, "Ethiopia" },
{ 0x4649 /* FI */, "Finland" },
{ 0x464A /* FJ */, "Fiji" },
{ 0x464B /* FK */, "Falkland Islands" },
{ 0x464D /* FM */, "Micronesia" },
{ 0x464F /* FO */, "Faroe Islands" },
{ 0x4652 /* FR */, "France" },
{ 0x4741 /* GA */, "Gabon" },
{ 0x4742 /* GB */, "United Kingdom" },
{ 0x4744 /* GD */, "Grenada" },
{ 0x4745 /* GE */, "Georgia" },
{ 0x4746 /* GF */, "French Guiana" },
{ 0x4747 /* GG */, "Guernsey" },
{ 0x4748 /* GH */, "Ghana" },
{ 0x4749 /* GI */, "Gibraltar" },
{ 0x474C /* GL */, "Greenland" },
{ 0x474D /* GM */, "Gambia" },
{ 0x474E /* GN */, "Guinea" },
{ 0x4750 /* GP */, "Guadeloupe" },
{ 0x4751 /* GQ */, "Equatorial Guinea" },
{ 0x4752 /* GR */, "Greece" },
{ 0x4753 /* GS */, "South Georgia" },
{ 0x4754 /* GT */, "Guatemala" },
{ 0x4755 /* GU */, "Guam" },
{ 0x4757 /* GW */, "Guinea-Bissau" },
{ 0x4759 /* GY */, "Guyana" },
{ 0x484B /* HK */, "Hong Kong" },
{ 0x484D /* HM */, "Heard and McDonald Islands" },
{ 0x484E /* HN */, "Honduras" },
{ 0x4852 /* HR */, "Croatia" },
{ 0x4854 /* HT */, "Haiti" },
{ 0x4855 /* HU */, "Hungary" },
{ 0x4944 /* ID */, "Indonesia" },
{ 0x4945 /* IE */, "Ireland" },
{ 0x494C /* IL */, "Israel" },
{ 0x494D /* IM */, "Isle of Man" },
{ 0x494E /* IN */, "India" },
{ 0x494F /* IO */, "Chagos Islands" },
{ 0x4951 /* IQ */, "Iraq" },
{ 0x4952 /* IR */, "Iran" },
{ 0x4953 /* IS */, "Iceland" },
{ 0x4954 /* IT */, "Italy" },
{ 0x4A45 /* JE */, "Jersey" },
{ 0x4A4D /* JM */, "Jamaica" },
{ 0x4A4F /* JO */, "Jordan" },
{ 0x4A50 /* JP */, "Japan" },
{ 0x4B45 /* KE */, "Kenya" },
{ 0x4B47 /* KG */, "Kyrgyzstan" },
{ 0x4B48 /* KH */, "Cambodia" },
{ 0x4B49 /* KI */, "Kiribati" },
{ 0x4B4D /* KM */, "Comoros" },
{ 0x4B4E /* KN */, "Saint Kitts and Nevis" },
{ 0x4B50 /* KP */, "North Korea" },
{ 0x4B52 /* KR */, "South Korea" },
{ 0x4B57 /* KW */, "Kuwait" },
{ 0x4B59 /* KY */, "Cayman Islands" },
{ 0x4B5A /* KZ */, "Kazakhstan" },
{ 0x4C41 /* LA */, "Laos" },
{ 0x4C42 /* LB */, "Lebanon" },
{ 0x4C43 /* LC */, "Saint Lucia" },
{ 0x4C49 /* LI */, "Liechtenstein" },
{ 0x4C4B /* LK */, "Sri Lanka" },
{ 0x4C52 /* LR */, "Liberia" },
{ 0x4C53 /* LS */, "Lesotho" },
{ 0x4C54 /* LT */, "Lithuania" },
{ 0x4C55 /* LU */, "Luxembourg" },
{ 0x4C56 /* LV */, "Latvia" },
{ 0x4C59 /* LY */, "Libyan Arab Jamahiriya" },
{ 0x4D41 /* MA */, "Morocco" },
{ 0x4D43 /* MC */, "Monaco" },
{ 0x4D44 /* MD */, "Moldova" },
{ 0x4D45 /* ME */, "Montenegro" },
{ 0x4D46 /* MF */, "Saint Martin (French part)" },
{ 0x4D47 /* MG */, "Madagascar" },
{ 0x4D48 /* MH */, "Marshall Islands" },
{ 0x4D4B /* MK */, "Macedonia" },
{ 0x4D4C /* ML */, "Mali" },
{ 0x4D4D /* MM */, "Myanmar" },
{ 0x4D4E /* MN */, "Mongolia" },
{ 0x4D4F /* MO */, "Macao" },
{ 0x4D50 /* MP */, "Northern Mariana Islands" },
{ 0x4D51 /* MQ */, "Martinique" },
{ 0x4D52 /* MR */, "Mauritania" },
{ 0x4D53 /* MS */, "Montserrat" },
{ 0x4D54 /* MT */, "Malta" },
{ 0x4D55 /* MU */, "Mauritius" },
{ 0x4D56 /* MV */, "Maldives" },
{ 0x4D57 /* MW */, "Malawi" },
{ 0x4D58 /* MX */, "Mexico" },
{ 0x4D59 /* MY */, "Malaysia" },
{ 0x4D5A /* MZ */, "Mozambique" },
{ 0x4E41 /* NA */, "Namibia" },
{ 0x4E43 /* NC */, "New Caledonia" },
{ 0x4E45 /* NE */, "Niger" },
{ 0x4E46 /* NF */, "Norfolk Island" },
{ 0x4E47 /* NG */, "Nigeria" },
{ 0x4E49 /* NI */, "Nicaragua" },
{ 0x4E4C /* NL */, "Netherlands" },
{ 0x4E4F /* NO */, "Norway" },
{ 0x4E50 /* NP */, "Nepal" },
{ 0x4E52 /* NR */, "Nauru" },
{ 0x4E55 /* NU */, "Niue" },
{ 0x4E5A /* NZ */, "New Zealand" },
{ 0x4F4D /* OM */, "Oman" },
{ 0x5041 /* PA */, "Panama" },
{ 0x5045 /* PE */, "Peru" },
{ 0x5046 /* PF */, "French Polynesia" },
{ 0x5047 /* PG */, "Papua New Guinea" },
{ 0x5048 /* PH */, "Philippines" },
{ 0x504B /* PK */, "Pakistan" },
{ 0x504C /* PL */, "Poland" },
{ 0x504D /* PM */, "Saint Pierre and Miquelon" },
{ 0x504E /* PN */, "Pitcairn" },
{ 0x5052 /* PR */, "Puerto Rico" },
{ 0x5053 /* PS */, "Palestinian Territory" },
{ 0x5054 /* PT */, "Portugal" },
{ 0x5057 /* PW */, "Palau" },
{ 0x5059 /* PY */, "Paraguay" },
{ 0x5141 /* QA */, "Qatar" },
{ 0x5245 /* RE */, "Reunion" },
{ 0x524F /* RO */, "Romania" },
{ 0x5253 /* RS */, "Serbia" },
{ 0x5255 /* RU */, "Russian Federation" },
{ 0x5257 /* RW */, "Rwanda" },
{ 0x5341 /* SA */, "Saudi Arabia" },
{ 0x5342 /* SB */, "Solomon Islands" },
{ 0x5343 /* SC */, "Seychelles" },
{ 0x5344 /* SD */, "Sudan" },
{ 0x5345 /* SE */, "Sweden" },
{ 0x5347 /* SG */, "Singapore" },
{ 0x5348 /* SH */, "St. Helena and Dependencies" },
{ 0x5349 /* SI */, "Slovenia" },
{ 0x534A /* SJ */, "Svalbard and Jan Mayen" },
{ 0x534B /* SK */, "Slovakia" },
{ 0x534C /* SL */, "Sierra Leone" },
{ 0x534D /* SM */, "San Marino" },
{ 0x534E /* SN */, "Senegal" },
{ 0x534F /* SO */, "Somalia" },
{ 0x5352 /* SR */, "Suriname" },
{ 0x5354 /* ST */, "Sao Tome and Principe" },
{ 0x5356 /* SV */, "El Salvador" },
{ 0x5359 /* SY */, "Syrian Arab Republic" },
{ 0x535A /* SZ */, "Swaziland" },
{ 0x5443 /* TC */, "Turks and Caicos Islands" },
{ 0x5444 /* TD */, "Chad" },
{ 0x5446 /* TF */, "French Southern Territories" },
{ 0x5447 /* TG */, "Togo" },
{ 0x5448 /* TH */, "Thailand" },
{ 0x544A /* TJ */, "Tajikistan" },
{ 0x544B /* TK */, "Tokelau" },
{ 0x544C /* TL */, "Timor-Leste" },
{ 0x544D /* TM */, "Turkmenistan" },
{ 0x544E /* TN */, "Tunisia" },
{ 0x544F /* TO */, "Tonga" },
{ 0x5452 /* TR */, "Turkey" },
{ 0x5454 /* TT */, "Trinidad and Tobago" },
{ 0x5456 /* TV */, "Tuvalu" },
{ 0x5457 /* TW */, "Taiwan" },
{ 0x545A /* TZ */, "Tanzania" },
{ 0x5541 /* UA */, "Ukraine" },
{ 0x5547 /* UG */, "Uganda" },
{ 0x554D /* UM */, "U.S. Minor Outlying Islands" },
{ 0x5553 /* US */, "United States" },
{ 0x5559 /* UY */, "Uruguay" },
{ 0x555A /* UZ */, "Uzbekistan" },
{ 0x5641 /* VA */, "Vatican City State" },
{ 0x5643 /* VC */, "St. Vincent and Grenadines" },
{ 0x5645 /* VE */, "Venezuela" },
{ 0x5647 /* VG */, "Virgin Islands, British" },
{ 0x5649 /* VI */, "Virgin Islands, U.S." },
{ 0x564E /* VN */, "Viet Nam" },
{ 0x5655 /* VU */, "Vanuatu" },
{ 0x5746 /* WF */, "Wallis and Futuna" },
{ 0x5753 /* WS */, "Samoa" },
{ 0x5945 /* YE */, "Yemen" },
{ 0x5954 /* YT */, "Mayotte" },
{ 0x5A41 /* ZA */, "South Africa" },
{ 0x5A4D /* ZM */, "Zambia" },
{ 0x5A57 /* ZW */, "Zimbabwe" },
{ 0, "" }
};
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif
static const struct iwinfo_ops *backends[] = {
#ifdef USE_NL80211
&nl80211_ops,
#endif
#ifdef USE_MADWIFI
&madwifi_ops,
#endif
#ifdef USE_WL
&wl_ops,
#endif
&wext_ops,
};
const char * iwinfo_type(const char *ifname)
{
const struct iwinfo_ops *ops = iwinfo_backend(ifname);
if (!ops)
return NULL;
return ops->name;
}
const struct iwinfo_ops * iwinfo_backend(const char *ifname)
{
int i;
for (i = 0; i < ARRAY_SIZE(backends); i++)
if (backends[i]->probe(ifname))
return backends[i];
return NULL;
}
void iwinfo_finish(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(backends); i++)
backends[i]->close();
iwinfo_close();
}

901
iwinfo_lua.c Normal file
View file

@ -0,0 +1,901 @@
/*
* iwinfo - Wireless Information Library - Lua Bindings
*
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*/
#include "iwinfo/lua.h"
/* Determine type */
static int iwinfo_L_type(lua_State *L)
{
const char *ifname = luaL_checkstring(L, 1);
const char *type = iwinfo_type(ifname);
if (type)
lua_pushstring(L, type);
else
lua_pushnil(L);
return 1;
}
/* Shutdown backends */
static int iwinfo_L__gc(lua_State *L)
{
iwinfo_finish();
return 0;
}
/*
* Build a short textual description of the crypto info
*/
static char * iwinfo_crypto_print_ciphers(int ciphers)
{
static char str[128] = { 0 };
char *pos = str;
if (ciphers & IWINFO_CIPHER_WEP40)
pos += sprintf(pos, "WEP-40, ");
if (ciphers & IWINFO_CIPHER_WEP104)
pos += sprintf(pos, "WEP-104, ");
if (ciphers & IWINFO_CIPHER_TKIP)
pos += sprintf(pos, "TKIP, ");
if (ciphers & IWINFO_CIPHER_CCMP)
pos += sprintf(pos, "CCMP, ");
if (ciphers & IWINFO_CIPHER_WRAP)
pos += sprintf(pos, "WRAP, ");
if (ciphers & IWINFO_CIPHER_AESOCB)
pos += sprintf(pos, "AES-OCB, ");
if (ciphers & IWINFO_CIPHER_CKIP)
pos += sprintf(pos, "CKIP, ");
if (!ciphers || (ciphers & IWINFO_CIPHER_NONE))
pos += sprintf(pos, "NONE, ");
*(pos - 2) = 0;
return str;
}
static char * iwinfo_crypto_print_suites(int suites)
{
static char str[64] = { 0 };
char *pos = str;
if (suites & IWINFO_KMGMT_PSK)
pos += sprintf(pos, "PSK/");
if (suites & IWINFO_KMGMT_8021x)
pos += sprintf(pos, "802.1X/");
if (!suites || (suites & IWINFO_KMGMT_NONE))
pos += sprintf(pos, "NONE/");
*(pos - 1) = 0;
return str;
}
static char * iwinfo_crypto_desc(struct iwinfo_crypto_entry *c)
{
static char desc[512] = { 0 };
if (c)
{
if (c->enabled)
{
/* WEP */
if (c->auth_algs && !c->wpa_version)
{
if ((c->auth_algs & IWINFO_AUTH_OPEN) &&
(c->auth_algs & IWINFO_AUTH_SHARED))
{
sprintf(desc, "WEP Open/Shared (%s)",
iwinfo_crypto_print_ciphers(c->pair_ciphers));
}
else if (c->auth_algs & IWINFO_AUTH_OPEN)
{
sprintf(desc, "WEP Open System (%s)",
iwinfo_crypto_print_ciphers(c->pair_ciphers));
}
else if (c->auth_algs & IWINFO_AUTH_SHARED)
{
sprintf(desc, "WEP Shared Auth (%s)",
iwinfo_crypto_print_ciphers(c->pair_ciphers));
}
}
/* WPA */
else if (c->wpa_version)
{
switch (c->wpa_version) {
case 3:
sprintf(desc, "mixed WPA/WPA2 %s (%s)",
iwinfo_crypto_print_suites(c->auth_suites),
iwinfo_crypto_print_ciphers(
c->pair_ciphers & c->group_ciphers));
break;
case 2:
sprintf(desc, "WPA2 %s (%s)",
iwinfo_crypto_print_suites(c->auth_suites),
iwinfo_crypto_print_ciphers(
c->pair_ciphers & c->group_ciphers));
break;
case 1:
sprintf(desc, "WPA %s (%s)",
iwinfo_crypto_print_suites(c->auth_suites),
iwinfo_crypto_print_ciphers(
c->pair_ciphers & c->group_ciphers));
break;
}
}
else
{
sprintf(desc, "None");
}
}
else
{
sprintf(desc, "None");
}
}
else
{
sprintf(desc, "Unknown");
}
return desc;
}
/* Build Lua table from crypto data */
static void iwinfo_L_cryptotable(lua_State *L, struct iwinfo_crypto_entry *c)
{
int i, j;
lua_newtable(L);
lua_pushboolean(L, c->enabled);
lua_setfield(L, -2, "enabled");
lua_pushstring(L, iwinfo_crypto_desc(c));
lua_setfield(L, -2, "description");
lua_pushboolean(L, (c->enabled && !c->wpa_version));
lua_setfield(L, -2, "wep");
lua_pushinteger(L, c->wpa_version);
lua_setfield(L, -2, "wpa");
lua_newtable(L);
for (i = 0, j = 1; i < 8; i++)
{
if (c->pair_ciphers & (1 << i))
{
lua_pushstring(L, IWINFO_CIPHER_NAMES[i]);
lua_rawseti(L, -2, j++);
}
}
lua_setfield(L, -2, "pair_ciphers");
lua_newtable(L);
for (i = 0, j = 1; i < 8; i++)
{
if (c->group_ciphers & (1 << i))
{
lua_pushstring(L, IWINFO_CIPHER_NAMES[i]);
lua_rawseti(L, -2, j++);
}
}
lua_setfield(L, -2, "group_ciphers");
lua_newtable(L);
for (i = 0, j = 1; i < 8; i++)
{
if (c->auth_suites & (1 << i))
{
lua_pushstring(L, IWINFO_KMGMT_NAMES[i]);
lua_rawseti(L, -2, j++);
}
}
lua_setfield(L, -2, "auth_suites");
lua_newtable(L);
for (i = 0, j = 1; i < 8; i++)
{
if (c->auth_algs & (1 << i))
{
lua_pushstring(L, IWINFO_AUTH_NAMES[i]);
lua_rawseti(L, -2, j++);
}
}
lua_setfield(L, -2, "auth_algs");
}
/* Wrapper for mode */
static int iwinfo_L_mode(lua_State *L, int (*func)(const char *, int *))
{
int mode;
const char *ifname = luaL_checkstring(L, 1);
if ((*func)(ifname, &mode))
mode = IWINFO_OPMODE_UNKNOWN;
lua_pushstring(L, IWINFO_OPMODE_NAMES[mode]);
return 1;
}
/* Wrapper for assoclist */
static int iwinfo_L_assoclist(lua_State *L, int (*func)(const char *, char *, int *))
{
int i, len;
char rv[IWINFO_BUFSIZE];
char macstr[18];
const char *ifname = luaL_checkstring(L, 1);
struct iwinfo_assoclist_entry *e;
lua_newtable(L);
memset(rv, 0, sizeof(rv));
if (!(*func)(ifname, rv, &len))
{
for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry))
{
e = (struct iwinfo_assoclist_entry *) &rv[i];
sprintf(macstr, "%02X:%02X:%02X:%02X:%02X:%02X",
e->mac[0], e->mac[1], e->mac[2],
e->mac[3], e->mac[4], e->mac[5]);
lua_newtable(L);
lua_pushnumber(L, e->signal);
lua_setfield(L, -2, "signal");
lua_pushnumber(L, e->noise);
lua_setfield(L, -2, "noise");
lua_pushnumber(L, e->inactive);
lua_setfield(L, -2, "inactive");
lua_pushnumber(L, e->rx_packets);
lua_setfield(L, -2, "rx_packets");
lua_pushnumber(L, e->tx_packets);
lua_setfield(L, -2, "tx_packets");
lua_pushnumber(L, e->rx_rate.rate);
lua_setfield(L, -2, "rx_rate");
lua_pushnumber(L, e->tx_rate.rate);
lua_setfield(L, -2, "tx_rate");
if (e->rx_rate.mcs >= 0)
{
lua_pushnumber(L, e->rx_rate.mcs);
lua_setfield(L, -2, "rx_mcs");
lua_pushboolean(L, e->rx_rate.is_40mhz);
lua_setfield(L, -2, "rx_40mhz");
lua_pushboolean(L, e->rx_rate.is_short_gi);
lua_setfield(L, -2, "rx_short_gi");
}
if (e->tx_rate.mcs >= 0)
{
lua_pushnumber(L, e->tx_rate.mcs);
lua_setfield(L, -2, "tx_mcs");
lua_pushboolean(L, e->tx_rate.is_40mhz);
lua_setfield(L, -2, "tx_40mhz");
lua_pushboolean(L, e->tx_rate.is_short_gi);
lua_setfield(L, -2, "tx_short_gi");
}
lua_setfield(L, -2, macstr);
}
}
return 1;
}
/* Wrapper for tx power list */
static int iwinfo_L_txpwrlist(lua_State *L, int (*func)(const char *, char *, int *))
{
int i, x, len;
char rv[IWINFO_BUFSIZE];
const char *ifname = luaL_checkstring(L, 1);
struct iwinfo_txpwrlist_entry *e;
memset(rv, 0, sizeof(rv));
if (!(*func)(ifname, rv, &len))
{
lua_newtable(L);
for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_txpwrlist_entry), x++)
{
e = (struct iwinfo_txpwrlist_entry *) &rv[i];
lua_newtable(L);
lua_pushnumber(L, e->mw);
lua_setfield(L, -2, "mw");
lua_pushnumber(L, e->dbm);
lua_setfield(L, -2, "dbm");
lua_rawseti(L, -2, x);
}
return 1;
}
return 0;
}
/* Wrapper for scan list */
static int iwinfo_L_scanlist(lua_State *L, int (*func)(const char *, char *, int *))
{
int i, x, len = 0;
char rv[IWINFO_BUFSIZE];
char macstr[18];
const char *ifname = luaL_checkstring(L, 1);
struct iwinfo_scanlist_entry *e;
lua_newtable(L);
memset(rv, 0, sizeof(rv));
if (!(*func)(ifname, rv, &len))
{
for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_scanlist_entry), x++)
{
e = (struct iwinfo_scanlist_entry *) &rv[i];
lua_newtable(L);
/* BSSID */
sprintf(macstr, "%02X:%02X:%02X:%02X:%02X:%02X",
e->mac[0], e->mac[1], e->mac[2],
e->mac[3], e->mac[4], e->mac[5]);
lua_pushstring(L, macstr);
lua_setfield(L, -2, "bssid");
/* ESSID */
if (e->ssid[0])
{
lua_pushstring(L, (char *) e->ssid);
lua_setfield(L, -2, "ssid");
}
/* Channel */
lua_pushinteger(L, e->channel);
lua_setfield(L, -2, "channel");
/* Mode */
lua_pushstring(L, IWINFO_OPMODE_NAMES[e->mode]);
lua_setfield(L, -2, "mode");
/* Quality, Signal */
lua_pushinteger(L, e->quality);
lua_setfield(L, -2, "quality");
lua_pushinteger(L, e->quality_max);
lua_setfield(L, -2, "quality_max");
lua_pushnumber(L, (e->signal - 0x100));
lua_setfield(L, -2, "signal");
/* Crypto */
iwinfo_L_cryptotable(L, &e->crypto);
lua_setfield(L, -2, "encryption");
lua_rawseti(L, -2, x);
}
}
return 1;
}
/* Wrapper for frequency list */
static int iwinfo_L_freqlist(lua_State *L, int (*func)(const char *, char *, int *))
{
int i, x, len;
char rv[IWINFO_BUFSIZE];
const char *ifname = luaL_checkstring(L, 1);
struct iwinfo_freqlist_entry *e;
lua_newtable(L);
memset(rv, 0, sizeof(rv));
if (!(*func)(ifname, rv, &len))
{
for (i = 0, x = 1; i < len; i += sizeof(struct iwinfo_freqlist_entry), x++)
{
e = (struct iwinfo_freqlist_entry *) &rv[i];
lua_newtable(L);
/* MHz */
lua_pushinteger(L, e->mhz);
lua_setfield(L, -2, "mhz");
/* Channel */
lua_pushinteger(L, e->channel);
lua_setfield(L, -2, "channel");
/* Restricted (DFS/TPC/Radar) */
lua_pushboolean(L, e->restricted);
lua_setfield(L, -2, "restricted");
lua_rawseti(L, -2, x);
}
}
return 1;
}
/* Wrapper for crypto settings */
static int iwinfo_L_encryption(lua_State *L, int (*func)(const char *, char *))
{
const char *ifname = luaL_checkstring(L, 1);
struct iwinfo_crypto_entry c = { 0 };
if (!(*func)(ifname, (char *)&c))
{
iwinfo_L_cryptotable(L, &c);
return 1;
}
lua_pushnil(L);
return 1;
}
/* Wrapper for hwmode list */
static int iwinfo_L_hwmodelist(lua_State *L, int (*func)(const char *, int *))
{
const char *ifname = luaL_checkstring(L, 1);
int hwmodes = 0;
if (!(*func)(ifname, &hwmodes))
{
lua_newtable(L);
lua_pushboolean(L, hwmodes & IWINFO_80211_A);
lua_setfield(L, -2, "a");
lua_pushboolean(L, hwmodes & IWINFO_80211_B);
lua_setfield(L, -2, "b");
lua_pushboolean(L, hwmodes & IWINFO_80211_G);
lua_setfield(L, -2, "g");
lua_pushboolean(L, hwmodes & IWINFO_80211_N);
lua_setfield(L, -2, "n");
lua_pushboolean(L, hwmodes & IWINFO_80211_AC);
lua_setfield(L, -2, "ac");
return 1;
}
lua_pushnil(L);
return 1;
}
/* Wrapper for mbssid_support */
static int iwinfo_L_mbssid_support(lua_State *L, int (*func)(const char *, int *))
{
const char *ifname = luaL_checkstring(L, 1);
int support = 0;
if (!(*func)(ifname, &support))
{
lua_pushboolean(L, support);
return 1;
}
lua_pushnil(L);
return 1;
}
/* Wrapper for hardware_id */
static int iwinfo_L_hardware_id(lua_State *L, int (*func)(const char *, char *))
{
const char *ifname = luaL_checkstring(L, 1);
struct iwinfo_hardware_id ids;
if (!(*func)(ifname, (char *)&ids))
{
lua_newtable(L);
lua_pushnumber(L, ids.vendor_id);
lua_setfield(L, -2, "vendor_id");
lua_pushnumber(L, ids.device_id);
lua_setfield(L, -2, "device_id");
lua_pushnumber(L, ids.subsystem_vendor_id);
lua_setfield(L, -2, "subsystem_vendor_id");
lua_pushnumber(L, ids.subsystem_device_id);
lua_setfield(L, -2, "subsystem_device_id");
}
else
{
lua_pushnil(L);
}
return 1;
}
/* Wrapper for country list */
static char * iwinfo_L_country_lookup(char *buf, int len, int iso3166)
{
int i;
struct iwinfo_country_entry *c;
for (i = 0; i < len; i += sizeof(struct iwinfo_country_entry))
{
c = (struct iwinfo_country_entry *) &buf[i];
if (c->iso3166 == iso3166)
return c->ccode;
}
return NULL;
}
static int iwinfo_L_countrylist(lua_State *L, int (*func)(const char *, char *, int *))
{
int len, i, j;
char rv[IWINFO_BUFSIZE], alpha2[3];
char *ccode;
const char *ifname = luaL_checkstring(L, 1);
const struct iwinfo_iso3166_label *l;
lua_newtable(L);
memset(rv, 0, sizeof(rv));
if (!(*func)(ifname, rv, &len))
{
for (l = IWINFO_ISO3166_NAMES, j = 1; l->iso3166; l++)
{
if ((ccode = iwinfo_L_country_lookup(rv, len, l->iso3166)) != NULL)
{
sprintf(alpha2, "%c%c",
(l->iso3166 / 256), (l->iso3166 % 256));
lua_newtable(L);
lua_pushstring(L, alpha2);
lua_setfield(L, -2, "alpha2");
lua_pushstring(L, ccode);
lua_setfield(L, -2, "ccode");
lua_pushstring(L, l->name);
lua_setfield(L, -2, "name");
lua_rawseti(L, -2, j++);
}
}
}
return 1;
}
#ifdef USE_WL
/* Broadcom */
LUA_WRAP_INT_OP(wl,channel)
LUA_WRAP_INT_OP(wl,frequency)
LUA_WRAP_INT_OP(wl,frequency_offset)
LUA_WRAP_INT_OP(wl,txpower)
LUA_WRAP_INT_OP(wl,txpower_offset)
LUA_WRAP_INT_OP(wl,bitrate)
LUA_WRAP_INT_OP(wl,signal)
LUA_WRAP_INT_OP(wl,noise)
LUA_WRAP_INT_OP(wl,quality)
LUA_WRAP_INT_OP(wl,quality_max)
LUA_WRAP_STRING_OP(wl,ssid)
LUA_WRAP_STRING_OP(wl,bssid)
LUA_WRAP_STRING_OP(wl,country)
LUA_WRAP_STRING_OP(wl,hardware_name)
LUA_WRAP_STRING_OP(wl,phyname)
LUA_WRAP_STRUCT_OP(wl,mode)
LUA_WRAP_STRUCT_OP(wl,assoclist)
LUA_WRAP_STRUCT_OP(wl,txpwrlist)
LUA_WRAP_STRUCT_OP(wl,scanlist)
LUA_WRAP_STRUCT_OP(wl,freqlist)
LUA_WRAP_STRUCT_OP(wl,countrylist)
LUA_WRAP_STRUCT_OP(wl,hwmodelist)
LUA_WRAP_STRUCT_OP(wl,encryption)
LUA_WRAP_STRUCT_OP(wl,mbssid_support)
LUA_WRAP_STRUCT_OP(wl,hardware_id)
#endif
#ifdef USE_MADWIFI
/* Madwifi */
LUA_WRAP_INT_OP(madwifi,channel)
LUA_WRAP_INT_OP(madwifi,frequency)
LUA_WRAP_INT_OP(madwifi,frequency_offset)
LUA_WRAP_INT_OP(madwifi,txpower)
LUA_WRAP_INT_OP(madwifi,txpower_offset)
LUA_WRAP_INT_OP(madwifi,bitrate)
LUA_WRAP_INT_OP(madwifi,signal)
LUA_WRAP_INT_OP(madwifi,noise)
LUA_WRAP_INT_OP(madwifi,quality)
LUA_WRAP_INT_OP(madwifi,quality_max)
LUA_WRAP_STRING_OP(madwifi,ssid)
LUA_WRAP_STRING_OP(madwifi,bssid)
LUA_WRAP_STRING_OP(madwifi,country)
LUA_WRAP_STRING_OP(madwifi,hardware_name)
LUA_WRAP_STRING_OP(madwifi,phyname)
LUA_WRAP_STRUCT_OP(madwifi,mode)
LUA_WRAP_STRUCT_OP(madwifi,assoclist)
LUA_WRAP_STRUCT_OP(madwifi,txpwrlist)
LUA_WRAP_STRUCT_OP(madwifi,scanlist)
LUA_WRAP_STRUCT_OP(madwifi,freqlist)
LUA_WRAP_STRUCT_OP(madwifi,countrylist)
LUA_WRAP_STRUCT_OP(madwifi,hwmodelist)
LUA_WRAP_STRUCT_OP(madwifi,encryption)
LUA_WRAP_STRUCT_OP(madwifi,mbssid_support)
LUA_WRAP_STRUCT_OP(madwifi,hardware_id)
#endif
#ifdef USE_NL80211
/* NL80211 */
LUA_WRAP_INT_OP(nl80211,channel)
LUA_WRAP_INT_OP(nl80211,frequency)
LUA_WRAP_INT_OP(nl80211,frequency_offset)
LUA_WRAP_INT_OP(nl80211,txpower)
LUA_WRAP_INT_OP(nl80211,txpower_offset)
LUA_WRAP_INT_OP(nl80211,bitrate)
LUA_WRAP_INT_OP(nl80211,signal)
LUA_WRAP_INT_OP(nl80211,noise)
LUA_WRAP_INT_OP(nl80211,quality)
LUA_WRAP_INT_OP(nl80211,quality_max)
LUA_WRAP_STRING_OP(nl80211,ssid)
LUA_WRAP_STRING_OP(nl80211,bssid)
LUA_WRAP_STRING_OP(nl80211,country)
LUA_WRAP_STRING_OP(nl80211,hardware_name)
LUA_WRAP_STRING_OP(nl80211,phyname)
LUA_WRAP_STRUCT_OP(nl80211,mode)
LUA_WRAP_STRUCT_OP(nl80211,assoclist)
LUA_WRAP_STRUCT_OP(nl80211,txpwrlist)
LUA_WRAP_STRUCT_OP(nl80211,scanlist)
LUA_WRAP_STRUCT_OP(nl80211,freqlist)
LUA_WRAP_STRUCT_OP(nl80211,countrylist)
LUA_WRAP_STRUCT_OP(nl80211,hwmodelist)
LUA_WRAP_STRUCT_OP(nl80211,encryption)
LUA_WRAP_STRUCT_OP(nl80211,mbssid_support)
LUA_WRAP_STRUCT_OP(nl80211,hardware_id)
#endif
/* Wext */
LUA_WRAP_INT_OP(wext,channel)
LUA_WRAP_INT_OP(wext,frequency)
LUA_WRAP_INT_OP(wext,frequency_offset)
LUA_WRAP_INT_OP(wext,txpower)
LUA_WRAP_INT_OP(wext,txpower_offset)
LUA_WRAP_INT_OP(wext,bitrate)
LUA_WRAP_INT_OP(wext,signal)
LUA_WRAP_INT_OP(wext,noise)
LUA_WRAP_INT_OP(wext,quality)
LUA_WRAP_INT_OP(wext,quality_max)
LUA_WRAP_STRING_OP(wext,ssid)
LUA_WRAP_STRING_OP(wext,bssid)
LUA_WRAP_STRING_OP(wext,country)
LUA_WRAP_STRING_OP(wext,hardware_name)
LUA_WRAP_STRING_OP(wext,phyname)
LUA_WRAP_STRUCT_OP(wext,mode)
LUA_WRAP_STRUCT_OP(wext,assoclist)
LUA_WRAP_STRUCT_OP(wext,txpwrlist)
LUA_WRAP_STRUCT_OP(wext,scanlist)
LUA_WRAP_STRUCT_OP(wext,freqlist)
LUA_WRAP_STRUCT_OP(wext,countrylist)
LUA_WRAP_STRUCT_OP(wext,hwmodelist)
LUA_WRAP_STRUCT_OP(wext,encryption)
LUA_WRAP_STRUCT_OP(wext,mbssid_support)
LUA_WRAP_STRUCT_OP(wext,hardware_id)
#ifdef USE_WL
/* Broadcom table */
static const luaL_reg R_wl[] = {
LUA_REG(wl,channel),
LUA_REG(wl,frequency),
LUA_REG(wl,frequency_offset),
LUA_REG(wl,txpower),
LUA_REG(wl,txpower_offset),
LUA_REG(wl,bitrate),
LUA_REG(wl,signal),
LUA_REG(wl,noise),
LUA_REG(wl,quality),
LUA_REG(wl,quality_max),
LUA_REG(wl,mode),
LUA_REG(wl,ssid),
LUA_REG(wl,bssid),
LUA_REG(wl,country),
LUA_REG(wl,assoclist),
LUA_REG(wl,txpwrlist),
LUA_REG(wl,scanlist),
LUA_REG(wl,freqlist),
LUA_REG(wl,countrylist),
LUA_REG(wl,hwmodelist),
LUA_REG(wl,encryption),
LUA_REG(wl,mbssid_support),
LUA_REG(wl,hardware_id),
LUA_REG(wl,hardware_name),
LUA_REG(wl,phyname),
{ NULL, NULL }
};
#endif
#ifdef USE_MADWIFI
/* Madwifi table */
static const luaL_reg R_madwifi[] = {
LUA_REG(madwifi,channel),
LUA_REG(madwifi,frequency),
LUA_REG(madwifi,frequency_offset),
LUA_REG(madwifi,txpower),
LUA_REG(madwifi,txpower_offset),
LUA_REG(madwifi,bitrate),
LUA_REG(madwifi,signal),
LUA_REG(madwifi,noise),
LUA_REG(madwifi,quality),
LUA_REG(madwifi,quality_max),
LUA_REG(madwifi,mode),
LUA_REG(madwifi,ssid),
LUA_REG(madwifi,bssid),
LUA_REG(madwifi,country),
LUA_REG(madwifi,assoclist),
LUA_REG(madwifi,txpwrlist),
LUA_REG(madwifi,scanlist),
LUA_REG(madwifi,freqlist),
LUA_REG(madwifi,countrylist),
LUA_REG(madwifi,hwmodelist),
LUA_REG(madwifi,encryption),
LUA_REG(madwifi,mbssid_support),
LUA_REG(madwifi,hardware_id),
LUA_REG(madwifi,hardware_name),
LUA_REG(madwifi,phyname),
{ NULL, NULL }
};
#endif
#ifdef USE_NL80211
/* NL80211 table */
static const luaL_reg R_nl80211[] = {
LUA_REG(nl80211,channel),
LUA_REG(nl80211,frequency),
LUA_REG(nl80211,frequency_offset),
LUA_REG(nl80211,txpower),
LUA_REG(nl80211,txpower_offset),
LUA_REG(nl80211,bitrate),
LUA_REG(nl80211,signal),
LUA_REG(nl80211,noise),
LUA_REG(nl80211,quality),
LUA_REG(nl80211,quality_max),
LUA_REG(nl80211,mode),
LUA_REG(nl80211,ssid),
LUA_REG(nl80211,bssid),
LUA_REG(nl80211,country),
LUA_REG(nl80211,assoclist),
LUA_REG(nl80211,txpwrlist),
LUA_REG(nl80211,scanlist),
LUA_REG(nl80211,freqlist),
LUA_REG(nl80211,countrylist),
LUA_REG(nl80211,hwmodelist),
LUA_REG(nl80211,encryption),
LUA_REG(nl80211,mbssid_support),
LUA_REG(nl80211,hardware_id),
LUA_REG(nl80211,hardware_name),
LUA_REG(nl80211,phyname),
{ NULL, NULL }
};
#endif
/* Wext table */
static const luaL_reg R_wext[] = {
LUA_REG(wext,channel),
LUA_REG(wext,frequency),
LUA_REG(wext,frequency_offset),
LUA_REG(wext,txpower),
LUA_REG(wext,txpower_offset),
LUA_REG(wext,bitrate),
LUA_REG(wext,signal),
LUA_REG(wext,noise),
LUA_REG(wext,quality),
LUA_REG(wext,quality_max),
LUA_REG(wext,mode),
LUA_REG(wext,ssid),
LUA_REG(wext,bssid),
LUA_REG(wext,country),
LUA_REG(wext,assoclist),
LUA_REG(wext,txpwrlist),
LUA_REG(wext,scanlist),
LUA_REG(wext,freqlist),
LUA_REG(wext,countrylist),
LUA_REG(wext,hwmodelist),
LUA_REG(wext,encryption),
LUA_REG(wext,mbssid_support),
LUA_REG(wext,hardware_id),
LUA_REG(wext,hardware_name),
LUA_REG(wext,phyname),
{ NULL, NULL }
};
/* Common */
static const luaL_reg R_common[] = {
{ "type", iwinfo_L_type },
{ "__gc", iwinfo_L__gc },
{ NULL, NULL }
};
LUALIB_API int luaopen_iwinfo(lua_State *L) {
luaL_register(L, IWINFO_META, R_common);
#ifdef USE_WL
luaL_newmetatable(L, IWINFO_WL_META);
luaL_register(L, NULL, R_common);
luaL_register(L, NULL, R_wl);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_setfield(L, -2, "wl");
#endif
#ifdef USE_MADWIFI
luaL_newmetatable(L, IWINFO_MADWIFI_META);
luaL_register(L, NULL, R_common);
luaL_register(L, NULL, R_madwifi);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_setfield(L, -2, "madwifi");
#endif
#ifdef USE_NL80211
luaL_newmetatable(L, IWINFO_NL80211_META);
luaL_register(L, NULL, R_common);
luaL_register(L, NULL, R_nl80211);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_setfield(L, -2, "nl80211");
#endif
luaL_newmetatable(L, IWINFO_WEXT_META);
luaL_register(L, NULL, R_common);
luaL_register(L, NULL, R_wext);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_setfield(L, -2, "wext");
return 1;
}

1133
iwinfo_madwifi.c Normal file

File diff suppressed because it is too large Load diff

2492
iwinfo_nl80211.c Normal file

File diff suppressed because it is too large Load diff

70
iwinfo_nl80211.h Normal file
View file

@ -0,0 +1,70 @@
/*
* iwinfo - Wireless Information Library - NL80211 Headers
*
* Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*/
#ifndef __IWINFO_NL80211_H_
#define __IWINFO_NL80211_H_
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <signal.h>
#include <sys/un.h>
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include "iwinfo.h"
#include "iwinfo/utils.h"
#include "api/nl80211.h"
struct nl80211_state {
struct nl_sock *nl_sock;
struct nl_cache *nl_cache;
struct genl_family *nl80211;
struct genl_family *nlctrl;
};
struct nl80211_msg_conveyor {
struct nl_msg *msg;
struct nl_cb *cb;
};
struct nl80211_event_conveyor {
int wait;
int recv;
};
struct nl80211_group_conveyor {
const char *name;
int id;
};
struct nl80211_rssi_rate {
int16_t rate;
int8_t rssi;
};
struct nl80211_array_buf {
void *buf;
int count;
};
#endif

367
iwinfo_utils.c Normal file
View file

@ -0,0 +1,367 @@
/*
* iwinfo - Wireless Information Library - Shared utility routines
*
* Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*
* The signal handling code is derived from the official madwifi tools,
* wlanconfig.c in particular. The encryption property handling was
* inspired by the hostapd madwifi driver.
*/
#include "iwinfo/utils.h"
static int ioctl_socket = -1;
static int iwinfo_ioctl_socket(void)
{
/* Prepare socket */
if (ioctl_socket == -1)
{
ioctl_socket = socket(AF_INET, SOCK_DGRAM, 0);
fcntl(ioctl_socket, F_SETFD, fcntl(ioctl_socket, F_GETFD) | FD_CLOEXEC);
}
return ioctl_socket;
}
int iwinfo_ioctl(int cmd, void *ifr)
{
int s = iwinfo_ioctl_socket();
return ioctl(s, cmd, ifr);
}
int iwinfo_dbm2mw(int in)
{
double res = 1.0;
int ip = in / 10;
int fp = in % 10;
int k;
for(k = 0; k < ip; k++) res *= 10;
for(k = 0; k < fp; k++) res *= LOG10_MAGIC;
return (int)res;
}
int iwinfo_mw2dbm(int in)
{
double fin = (double) in;
int res = 0;
while(fin > 10.0)
{
res += 10;
fin /= 10.0;
}
while(fin > 1.000001)
{
res += 1;
fin /= LOG10_MAGIC;
}
return (int)res;
}
int iwinfo_ifup(const char *ifname)
{
struct ifreq ifr;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr))
return 0;
ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr);
}
int iwinfo_ifdown(const char *ifname)
{
struct ifreq ifr;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (iwinfo_ioctl(SIOCGIFFLAGS, &ifr))
return 0;
ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
return !iwinfo_ioctl(SIOCSIFFLAGS, &ifr);
}
int iwinfo_ifmac(const char *ifname)
{
struct ifreq ifr;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (iwinfo_ioctl(SIOCGIFHWADDR, &ifr))
return 0;
ifr.ifr_hwaddr.sa_data[0] |= 0x02;
ifr.ifr_hwaddr.sa_data[1]++;
ifr.ifr_hwaddr.sa_data[2]++;
return !iwinfo_ioctl(SIOCSIFHWADDR, &ifr);
}
void iwinfo_close(void)
{
if (ioctl_socket > -1)
close(ioctl_socket);
ioctl_socket = -1;
}
struct iwinfo_hardware_entry * iwinfo_hardware(struct iwinfo_hardware_id *id)
{
FILE *db;
char buf[256] = { 0 };
static struct iwinfo_hardware_entry e;
struct iwinfo_hardware_entry *rv = NULL;
if (!(db = fopen(IWINFO_HARDWARE_FILE, "r")))
return NULL;
while (fgets(buf, sizeof(buf) - 1, db) != NULL)
{
memset(&e, 0, sizeof(e));
if (sscanf(buf, "%hx %hx %hx %hx %hd %hd \"%63[^\"]\" \"%63[^\"]\"",
&e.vendor_id, &e.device_id,
&e.subsystem_vendor_id, &e.subsystem_device_id,
&e.txpower_offset, &e.frequency_offset,
e.vendor_name, e.device_name) < 8)
continue;
if ((e.vendor_id != 0xffff) && (e.vendor_id != id->vendor_id))
continue;
if ((e.device_id != 0xffff) && (e.device_id != id->device_id))
continue;
if ((e.subsystem_vendor_id != 0xffff) &&
(e.subsystem_vendor_id != id->subsystem_vendor_id))
continue;
if ((e.subsystem_device_id != 0xffff) &&
(e.subsystem_device_id != id->subsystem_device_id))
continue;
rv = &e;
break;
}
fclose(db);
return rv;
}
int iwinfo_hardware_id_from_mtd(struct iwinfo_hardware_id *id)
{
FILE *mtd;
uint16_t *bc;
int fd, len, off;
char buf[128];
if (!(mtd = fopen("/proc/mtd", "r")))
return -1;
while (fgets(buf, sizeof(buf), mtd) > 0)
{
if (fscanf(mtd, "mtd%d: %x %*x %127s", &off, &len, buf) < 3 ||
(strcmp(buf, "\"boardconfig\"") && strcmp(buf, "\"EEPROM\"") &&
strcmp(buf, "\"factory\"")))
{
off = -1;
continue;
}
break;
}
fclose(mtd);
if (off < 0)
return -1;
snprintf(buf, sizeof(buf), "/dev/mtdblock%d", off);
if ((fd = open(buf, O_RDONLY)) < 0)
return -1;
bc = mmap(NULL, len, PROT_READ, MAP_PRIVATE|MAP_LOCKED, fd, 0);
if ((void *)bc != MAP_FAILED)
{
id->vendor_id = 0;
id->device_id = 0;
for (off = len / 2 - 0x800; off >= 0; off -= 0x800)
{
/* AR531X board data magic */
if ((bc[off] == 0x3533) && (bc[off + 1] == 0x3131))
{
id->vendor_id = bc[off + 0x7d];
id->device_id = bc[off + 0x7c];
id->subsystem_vendor_id = bc[off + 0x84];
id->subsystem_device_id = bc[off + 0x83];
break;
}
/* AR5416 EEPROM magic */
else if ((bc[off] == 0xA55A) || (bc[off] == 0x5AA5))
{
id->vendor_id = bc[off + 0x0D];
id->device_id = bc[off + 0x0E];
id->subsystem_vendor_id = bc[off + 0x13];
id->subsystem_device_id = bc[off + 0x14];
break;
}
/* Rt3xxx SoC */
else if ((bc[off] == 0x3352) || (bc[off] == 0x5233) ||
(bc[off] == 0x3350) || (bc[off] == 0x5033) ||
(bc[off] == 0x3050) || (bc[off] == 0x5030) ||
(bc[off] == 0x3052) || (bc[off] == 0x5230))
{
/* vendor: RaLink */
id->vendor_id = 0x1814;
id->subsystem_vendor_id = 0x1814;
/* device */
if (bc[off] & 0xf0 == 0x30)
id->device_id = (bc[off] >> 8) | (bc[off] & 0x00ff) << 8;
else
id->device_id = bc[off];
/* subsystem from EEPROM_NIC_CONF0_RF_TYPE */
id->subsystem_device_id = (bc[off + 0x1a] & 0x0f00) >> 8;
}
}
munmap(bc, len);
}
close(fd);
return (id->vendor_id && id->device_id) ? 0 : -1;
}
void iwinfo_parse_rsn(struct iwinfo_crypto_entry *c, uint8_t *data, uint8_t len,
uint8_t defcipher, uint8_t defauth)
{
uint16_t i, count;
static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
data += 2;
len -= 2;
if (!memcmp(data, ms_oui, 3))
c->wpa_version += 1;
else if (!memcmp(data, ieee80211_oui, 3))
c->wpa_version += 2;
if (len < 4)
{
c->group_ciphers |= defcipher;
c->pair_ciphers |= defcipher;
c->auth_suites |= defauth;
return;
}
if (!memcmp(data, ms_oui, 3) || !memcmp(data, ieee80211_oui, 3))
{
switch (data[3])
{
case 1: c->group_ciphers |= IWINFO_CIPHER_WEP40; break;
case 2: c->group_ciphers |= IWINFO_CIPHER_TKIP; break;
case 4: c->group_ciphers |= IWINFO_CIPHER_CCMP; break;
case 5: c->group_ciphers |= IWINFO_CIPHER_WEP104; break;
case 6: /* AES-128-CMAC */ break;
default: /* proprietary */ break;
}
}
data += 4;
len -= 4;
if (len < 2)
{
c->pair_ciphers |= defcipher;
c->auth_suites |= defauth;
return;
}
count = data[0] | (data[1] << 8);
if (2 + (count * 4) > len)
return;
for (i = 0; i < count; i++)
{
if (!memcmp(data + 2 + (i * 4), ms_oui, 3) ||
!memcmp(data + 2 + (i * 4), ieee80211_oui, 3))
{
switch (data[2 + (i * 4) + 3])
{
case 1: c->pair_ciphers |= IWINFO_CIPHER_WEP40; break;
case 2: c->pair_ciphers |= IWINFO_CIPHER_TKIP; break;
case 4: c->pair_ciphers |= IWINFO_CIPHER_CCMP; break;
case 5: c->pair_ciphers |= IWINFO_CIPHER_WEP104; break;
case 6: /* AES-128-CMAC */ break;
default: /* proprietary */ break;
}
}
}
data += 2 + (count * 4);
len -= 2 + (count * 4);
if (len < 2)
{
c->auth_suites |= defauth;
return;
}
count = data[0] | (data[1] << 8);
if (2 + (count * 4) > len)
return;
for (i = 0; i < count; i++)
{
if (!memcmp(data + 2 + (i * 4), ms_oui, 3) ||
!memcmp(data + 2 + (i * 4), ieee80211_oui, 3))
{
switch (data[2 + (i * 4) + 3])
{
case 1: c->auth_suites |= IWINFO_KMGMT_8021x; break;
case 2: c->auth_suites |= IWINFO_KMGMT_PSK; break;
case 3: /* FT/IEEE 802.1X */ break;
case 4: /* FT/PSK */ break;
case 5: /* IEEE 802.1X/SHA-256 */ break;
case 6: /* PSK/SHA-256 */ break;
default: /* proprietary */ break;
}
}
}
data += 2 + (count * 4);
len -= 2 + (count * 4);
}

558
iwinfo_wext.c Normal file
View file

@ -0,0 +1,558 @@
/*
* iwinfo - Wireless Information Library - Linux Wireless Extension Backend
*
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*
* Parts of this code are derived from the Linux wireless tools, iwlib.c,
* iwlist.c and iwconfig.c in particular.
*/
#include "iwinfo.h"
#include "iwinfo_wext.h"
static double wext_freq2float(const struct iw_freq *in)
{
int i;
double res = (double) in->m;
for(i = 0; i < in->e; i++) res *= 10;
return res;
}
static inline int wext_freq2mhz(const struct iw_freq *in)
{
int i;
if( in->e == 6 )
{
return in->m;
}
else
{
return (int)(wext_freq2float(in) / 1000000);
}
}
static inline int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq)
{
if( !strncmp(ifname, "mon.", 4) )
strncpy(wrq->ifr_name, &ifname[4], IFNAMSIZ);
else
strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
return iwinfo_ioctl(cmd, wrq);
}
static int wext_probe(const char *ifname)
{
struct iwreq wrq;
if(wext_ioctl(ifname, SIOCGIWNAME, &wrq) >= 0)
return 1;
return 0;
}
static void wext_close(void)
{
/* Nop */
}
static int wext_get_mode(const char *ifname, int *buf)
{
struct iwreq wrq;
if(wext_ioctl(ifname, SIOCGIWMODE, &wrq) >= 0)
{
switch(wrq.u.mode)
{
case 1:
*buf = IWINFO_OPMODE_ADHOC;
break;
case 2:
*buf = IWINFO_OPMODE_CLIENT;
break;
case 3:
*buf = IWINFO_OPMODE_MASTER;
break;
case 6:
*buf = IWINFO_OPMODE_MONITOR;
break;
default:
*buf = IWINFO_OPMODE_UNKNOWN;
break;
}
return 0;
}
return -1;
}
static int wext_get_ssid(const char *ifname, char *buf)
{
struct iwreq wrq;
wrq.u.essid.pointer = (caddr_t) buf;
wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
wrq.u.essid.flags = 0;
if(wext_ioctl(ifname, SIOCGIWESSID, &wrq) >= 0)
return 0;
return -1;
}
static int wext_get_bssid(const char *ifname, char *buf)
{
struct iwreq wrq;
if(wext_ioctl(ifname, SIOCGIWAP, &wrq) >= 0)
{
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
(uint8_t)wrq.u.ap_addr.sa_data[0], (uint8_t)wrq.u.ap_addr.sa_data[1],
(uint8_t)wrq.u.ap_addr.sa_data[2], (uint8_t)wrq.u.ap_addr.sa_data[3],
(uint8_t)wrq.u.ap_addr.sa_data[4], (uint8_t)wrq.u.ap_addr.sa_data[5]);
return 0;
}
return -1;
}
static int wext_get_bitrate(const char *ifname, int *buf)
{
struct iwreq wrq;
if(wext_ioctl(ifname, SIOCGIWRATE, &wrq) >= 0)
{
*buf = (wrq.u.bitrate.value / 1000);
return 0;
}
return -1;
}
static int wext_get_channel(const char *ifname, int *buf)
{
struct iwreq wrq;
struct iw_range range;
double freq;
int i;
if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
{
if( wrq.u.freq.m >= 1000 )
{
freq = wext_freq2float(&wrq.u.freq);
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof(struct iw_range);
wrq.u.data.flags = 0;
if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
{
for(i = 0; i < range.num_frequency; i++)
{
if( wext_freq2float(&range.freq[i]) == freq )
{
*buf = range.freq[i].i;
return 0;
}
}
}
}
else
{
*buf = wrq.u.freq.m;
return 0;
}
}
return -1;
}
static int wext_get_frequency(const char *ifname, int *buf)
{
struct iwreq wrq;
struct iw_range range;
int i, channel;
if(wext_ioctl(ifname, SIOCGIWFREQ, &wrq) >= 0)
{
/* We got a channel number instead ... */
if( wrq.u.freq.m < 1000 )
{
channel = wrq.u.freq.m;
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof(struct iw_range);
wrq.u.data.flags = 0;
if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
{
for(i = 0; i < range.num_frequency; i++)
{
if( range.freq[i].i == channel )
{
*buf = wext_freq2mhz(&range.freq[i]);
return 0;
}
}
}
}
else
{
*buf = wext_freq2mhz(&wrq.u.freq);
return 0;
}
}
return -1;
}
static int wext_get_txpower(const char *ifname, int *buf)
{
struct iwreq wrq;
wrq.u.txpower.flags = 0;
if(wext_ioctl(ifname, SIOCGIWTXPOW, &wrq) >= 0)
{
if(wrq.u.txpower.flags & IW_TXPOW_MWATT)
*buf = iwinfo_mw2dbm(wrq.u.txpower.value);
else
*buf = wrq.u.txpower.value;
return 0;
}
return -1;
}
static int wext_get_signal(const char *ifname, int *buf)
{
struct iwreq wrq;
struct iw_statistics stats;
wrq.u.data.pointer = (caddr_t) &stats;
wrq.u.data.length = sizeof(struct iw_statistics);
wrq.u.data.flags = 1;
if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
{
*buf = (stats.qual.updated & IW_QUAL_DBM)
? (stats.qual.level - 0x100) : stats.qual.level;
return 0;
}
return -1;
}
static int wext_get_noise(const char *ifname, int *buf)
{
struct iwreq wrq;
struct iw_statistics stats;
wrq.u.data.pointer = (caddr_t) &stats;
wrq.u.data.length = sizeof(struct iw_statistics);
wrq.u.data.flags = 1;
if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
{
*buf = (stats.qual.updated & IW_QUAL_DBM)
? (stats.qual.noise - 0x100) : stats.qual.noise;
return 0;
}
return -1;
}
static int wext_get_quality(const char *ifname, int *buf)
{
struct iwreq wrq;
struct iw_statistics stats;
wrq.u.data.pointer = (caddr_t) &stats;
wrq.u.data.length = sizeof(struct iw_statistics);
wrq.u.data.flags = 1;
if(wext_ioctl(ifname, SIOCGIWSTATS, &wrq) >= 0)
{
*buf = stats.qual.qual;
return 0;
}
return -1;
}
static int wext_get_quality_max(const char *ifname, int *buf)
{
struct iwreq wrq;
struct iw_range range;
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof(struct iw_range);
wrq.u.data.flags = 0;
if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
{
*buf = range.max_qual.qual;
return 0;
}
return -1;
}
static int wext_get_assoclist(const char *ifname, char *buf, int *len)
{
/* Stub */
return -1;
}
static int wext_get_txpwrlist(const char *ifname, char *buf, int *len)
{
struct iwreq wrq;
struct iw_range range;
struct iwinfo_txpwrlist_entry entry;
int i;
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof(struct iw_range);
wrq.u.data.flags = 0;
if( (wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0) &&
(range.num_txpower > 0) && (range.num_txpower <= IW_MAX_TXPOWER) &&
!(range.txpower_capa & IW_TXPOW_RELATIVE)
) {
for( i = 0; i < range.num_txpower; i++ )
{
if( range.txpower_capa & IW_TXPOW_MWATT )
{
entry.dbm = iwinfo_mw2dbm(range.txpower[i]);
entry.mw = range.txpower[i];
}
/* Madwifi does neither set mW not dBm caps, also iwlist assumes
* dBm if mW is not set, so don't check here... */
else /* if( range.txpower_capa & IW_TXPOW_DBM ) */
{
entry.dbm = range.txpower[i];
entry.mw = iwinfo_dbm2mw(range.txpower[i]);
}
memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry));
}
*len = i * sizeof(entry);
return 0;
}
return -1;
}
static int wext_get_freqlist(const char *ifname, char *buf, int *len)
{
struct iwreq wrq;
struct iw_range range;
struct iwinfo_freqlist_entry entry;
int i, bl;
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof(struct iw_range);
wrq.u.data.flags = 0;
if(wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0)
{
bl = 0;
for(i = 0; i < range.num_frequency; i++)
{
entry.mhz = wext_freq2mhz(&range.freq[i]);
entry.channel = range.freq[i].i;
entry.restricted = 0;
memcpy(&buf[bl], &entry, sizeof(struct iwinfo_freqlist_entry));
bl += sizeof(struct iwinfo_freqlist_entry);
}
*len = bl;
return 0;
}
return -1;
}
static int wext_get_country(const char *ifname, char *buf)
{
sprintf(buf, "00");
return 0;
}
static int wext_get_countrylist(const char *ifname, char *buf, int *len)
{
/* Stub */
return -1;
}
static int wext_get_hwmodelist(const char *ifname, int *buf)
{
char chans[IWINFO_BUFSIZE] = { 0 };
struct iwinfo_freqlist_entry *e = NULL;
int len = 0;
*buf = 0;
if( !wext_get_freqlist(ifname, chans, &len) )
{
for( e = (struct iwinfo_freqlist_entry *)chans; e->channel; e++ )
{
if( e->channel <= 14 )
{
*buf |= IWINFO_80211_B;
*buf |= IWINFO_80211_G;
}
else
{
*buf |= IWINFO_80211_A;
}
}
return 0;
}
return -1;
}
static int wext_get_encryption(const char *ifname, char *buf)
{
/* No reliable crypto info in wext */
return -1;
}
static int wext_get_phyname(const char *ifname, char *buf)
{
/* No suitable api in wext */
strcpy(buf, ifname);
return 0;
}
static int wext_get_mbssid_support(const char *ifname, int *buf)
{
/* No multi bssid support atm */
return -1;
}
static char * wext_sysfs_ifname_file(const char *ifname, const char *path)
{
FILE *f;
static char buf[128];
char *rv = NULL;
snprintf(buf, sizeof(buf), "/sys/class/net/%s/%s", ifname, path);
if ((f = fopen(buf, "r")) != NULL)
{
memset(buf, 0, sizeof(buf));
if (fread(buf, 1, sizeof(buf), f))
rv = buf;
fclose(f);
}
return rv;
}
static int wext_get_hardware_id(const char *ifname, char *buf)
{
char *data;
struct iwinfo_hardware_id *id = (struct iwinfo_hardware_id *)buf;
memset(id, 0, sizeof(struct iwinfo_hardware_id));
data = wext_sysfs_ifname_file(ifname, "device/vendor");
if (data)
id->vendor_id = strtoul(data, NULL, 16);
data = wext_sysfs_ifname_file(ifname, "device/device");
if (data)
id->device_id = strtoul(data, NULL, 16);
data = wext_sysfs_ifname_file(ifname, "device/subsystem_device");
if (data)
id->subsystem_device_id = strtoul(data, NULL, 16);
data = wext_sysfs_ifname_file(ifname, "device/subsystem_vendor");
if (data)
id->subsystem_vendor_id = strtoul(data, NULL, 16);
return (id->vendor_id > 0 && id->device_id > 0) ? 0 : -1;
}
static int wext_get_hardware_name(const char *ifname, char *buf)
{
sprintf(buf, "Generic WEXT");
return 0;
}
static int wext_get_txpower_offset(const char *ifname, int *buf)
{
/* Stub */
*buf = 0;
return -1;
}
static int wext_get_frequency_offset(const char *ifname, int *buf)
{
/* Stub */
*buf = 0;
return -1;
}
const struct iwinfo_ops wext_ops = {
.name = "wext",
.probe = wext_probe,
.channel = wext_get_channel,
.frequency = wext_get_frequency,
.frequency_offset = wext_get_frequency_offset,
.txpower = wext_get_txpower,
.txpower_offset = wext_get_txpower_offset,
.bitrate = wext_get_bitrate,
.signal = wext_get_signal,
.noise = wext_get_noise,
.quality = wext_get_quality,
.quality_max = wext_get_quality_max,
.mbssid_support = wext_get_mbssid_support,
.hwmodelist = wext_get_hwmodelist,
.mode = wext_get_mode,
.ssid = wext_get_ssid,
.bssid = wext_get_bssid,
.country = wext_get_country,
.hardware_id = wext_get_hardware_id,
.hardware_name = wext_get_hardware_name,
.encryption = wext_get_encryption,
.phyname = wext_get_phyname,
.assoclist = wext_get_assoclist,
.txpwrlist = wext_get_txpwrlist,
.scanlist = wext_get_scanlist,
.freqlist = wext_get_freqlist,
.countrylist = wext_get_countrylist,
.close = wext_close
};

382
iwinfo_wext.h Normal file
View file

@ -0,0 +1,382 @@
/*
* iwinfo - Wireless Information Library - Linux Wireless Extension Headers
*
* Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*/
#ifndef __IWINFO_WEXT_SCAN_H_
#define __IWINFO_WEXT_SCAN_H_
#include <fcntl.h>
#include "iwinfo.h"
#include "iwinfo/utils.h"
#include "api/wext.h"
typedef struct stream_descr
{
char * end; /* End of the stream */
char * current; /* Current event in stream of events */
char * value; /* Current value in event */
} stream_descr;
/*
* Describe how a standard IOCTL looks like.
*/
struct iw_ioctl_description
{
uint8_t header_type; /* NULL, iw_point or other */
uint8_t token_type; /* Future */
uint16_t token_size; /* Granularity of payload */
uint16_t min_tokens; /* Min acceptable token number */
uint16_t max_tokens; /* Max acceptable token number */
uint32_t flags; /* Special handling of the request */
};
/* Type of headers we know about (basically union iwreq_data) */
#define IW_HEADER_TYPE_NULL 0 /* Not available */
#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */
#define IW_HEADER_TYPE_UINT 4 /* __u32 */
#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */
#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */
#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */
#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */
#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */
/* Handling flags */
/* Most are not implemented. I just use them as a reminder of some
* cool features we might need one day ;-) */
#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */
/* Wrapper level flags */
#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */
#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
/* SET : Omit payload from generated iwevent */
#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
/* Driver level flags */
#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
/*
* Meta-data about all the standard Wireless Extension request we
* know about.
*/
static const struct iw_ioctl_description standard_ioctl_descr[] = {
[SIOCSIWCOMMIT - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_NULL,
},
[SIOCGIWNAME - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_CHAR,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWNWID - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
.flags = IW_DESCR_FLAG_EVENT,
},
[SIOCGIWNWID - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWFREQ - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_FREQ,
.flags = IW_DESCR_FLAG_EVENT,
},
[SIOCGIWFREQ - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_FREQ,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWMODE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_UINT,
.flags = IW_DESCR_FLAG_EVENT,
},
[SIOCGIWMODE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_UINT,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWSENS - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWSENS - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWRANGE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_NULL,
},
[SIOCGIWRANGE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = sizeof(struct iw_range),
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWPRIV - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_NULL,
},
[SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
.header_type = IW_HEADER_TYPE_NULL,
},
[SIOCSIWSTATS - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_NULL,
},
[SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
.header_type = IW_HEADER_TYPE_NULL,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWSPY - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = sizeof(struct sockaddr),
.max_tokens = IW_MAX_SPY,
},
[SIOCGIWSPY - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = sizeof(struct sockaddr) +
sizeof(struct iw_quality),
.max_tokens = IW_MAX_SPY,
},
[SIOCSIWTHRSPY - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = sizeof(struct iw_thrspy),
.min_tokens = 1,
.max_tokens = 1,
},
[SIOCGIWTHRSPY - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = sizeof(struct iw_thrspy),
.min_tokens = 1,
.max_tokens = 1,
},
[SIOCSIWAP - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_ADDR,
},
[SIOCGIWAP - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_ADDR,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWMLME - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.min_tokens = sizeof(struct iw_mlme),
.max_tokens = sizeof(struct iw_mlme),
},
[SIOCGIWAPLIST - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = sizeof(struct sockaddr) +
sizeof(struct iw_quality),
.max_tokens = IW_MAX_AP,
.flags = IW_DESCR_FLAG_NOMAX,
},
[SIOCSIWSCAN - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.min_tokens = 0,
.max_tokens = sizeof(struct iw_scan_req),
},
[SIOCGIWSCAN - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_SCAN_MAX_DATA,
.flags = IW_DESCR_FLAG_NOMAX,
},
[SIOCSIWESSID - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_ESSID_MAX_SIZE + 1,
.flags = IW_DESCR_FLAG_EVENT,
},
[SIOCGIWESSID - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_ESSID_MAX_SIZE + 1,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWNICKN - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_ESSID_MAX_SIZE + 1,
},
[SIOCGIWNICKN - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_ESSID_MAX_SIZE + 1,
},
[SIOCSIWRATE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWRATE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWRTS - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWRTS - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWFRAG - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWFRAG - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWTXPOW - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWTXPOW - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWRETRY - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWRETRY - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWENCODE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_ENCODING_TOKEN_MAX,
.flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
},
[SIOCGIWENCODE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_ENCODING_TOKEN_MAX,
.flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
},
[SIOCSIWPOWER - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWPOWER - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWMODUL - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWMODUL - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWGENIE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_GENERIC_IE_MAX,
},
[SIOCGIWGENIE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_GENERIC_IE_MAX,
},
[SIOCSIWAUTH - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCGIWAUTH - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
},
[SIOCSIWENCODEEXT - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.min_tokens = sizeof(struct iw_encode_ext),
.max_tokens = sizeof(struct iw_encode_ext) +
IW_ENCODING_TOKEN_MAX,
},
[SIOCGIWENCODEEXT - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.min_tokens = sizeof(struct iw_encode_ext),
.max_tokens = sizeof(struct iw_encode_ext) +
IW_ENCODING_TOKEN_MAX,
},
[SIOCSIWPMKSA - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.min_tokens = sizeof(struct iw_pmksa),
.max_tokens = sizeof(struct iw_pmksa),
},
};
/*
* Meta-data about all the additional standard Wireless Extension events
* we know about.
*/
static const struct iw_ioctl_description standard_event_descr[] = {
[IWEVTXDROP - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_ADDR,
},
[IWEVQUAL - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_QUAL,
},
[IWEVCUSTOM - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_CUSTOM_MAX,
},
[IWEVREGISTERED - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_ADDR,
},
[IWEVEXPIRED - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_ADDR,
},
[IWEVGENIE - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_GENERIC_IE_MAX,
},
[IWEVMICHAELMICFAILURE - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = sizeof(struct iw_michaelmicfailure),
},
[IWEVASSOCREQIE - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_GENERIC_IE_MAX,
},
[IWEVASSOCRESPIE - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = IW_GENERIC_IE_MAX,
},
[IWEVPMKIDCAND - IWEVFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = sizeof(struct iw_pmkid_cand),
},
};
/* Size (in bytes) of various events */
static const int event_type_size[] = {
IW_EV_LCP_PK_LEN, /* IW_HEADER_TYPE_NULL */
0,
IW_EV_CHAR_PK_LEN, /* IW_HEADER_TYPE_CHAR */
0,
IW_EV_UINT_PK_LEN, /* IW_HEADER_TYPE_UINT */
IW_EV_FREQ_PK_LEN, /* IW_HEADER_TYPE_FREQ */
IW_EV_ADDR_PK_LEN, /* IW_HEADER_TYPE_ADDR */
0,
IW_EV_POINT_PK_LEN, /* Without variable payload */
IW_EV_PARAM_PK_LEN, /* IW_HEADER_TYPE_PARAM */
IW_EV_QUAL_PK_LEN, /* IW_HEADER_TYPE_QUAL */
};
static const unsigned int standard_ioctl_num =
(sizeof(standard_ioctl_descr) / sizeof(struct iw_ioctl_description));
static const unsigned int standard_event_num =
(sizeof(standard_event_descr) / sizeof(struct iw_ioctl_description));
#define IW_IE_CYPHER_NUM 8
#define IW_IE_KEY_MGMT_NUM 3
int wext_get_scanlist(const char *ifname, char *buf, int *len);
#endif

527
iwinfo_wext_scan.c Normal file
View file

@ -0,0 +1,527 @@
/*
* iwinfo - Wireless Information Library - Linux Wireless Extension Backend
*
* Copyright (C) 2009-2010 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*
* Parts of this code are derived from the Linux wireless tools, iwlib.c,
* iwlist.c and iwconfig.c in particular.
*/
#include "iwinfo.h"
#include "iwinfo_wext.h"
static int wext_ioctl(const char *ifname, int cmd, struct iwreq *wrq)
{
strncpy(wrq->ifr_name, ifname, IFNAMSIZ);
return iwinfo_ioctl(cmd, wrq);
}
static inline double wext_freq2float(const struct iw_freq *in)
{
int i;
double res = (double) in->m;
for(i = 0; i < in->e; i++) res *= 10;
return res;
}
static inline int wext_extract_event(struct stream_descr *stream, struct iw_event *iwe, int wev)
{
const struct iw_ioctl_description *descr = NULL;
int event_type = 0;
unsigned int event_len = 1;
char *pointer;
unsigned cmd_index; /* *MUST* be unsigned */
/* Check for end of stream */
if((stream->current + IW_EV_LCP_PK_LEN) > stream->end)
return 0;
/* Extract the event header (to get the event id).
* Note : the event may be unaligned, therefore copy... */
memcpy((char *) iwe, stream->current, IW_EV_LCP_PK_LEN);
/* Check invalid events */
if(iwe->len <= IW_EV_LCP_PK_LEN)
return -1;
/* Get the type and length of that event */
if(iwe->cmd <= SIOCIWLAST)
{
cmd_index = iwe->cmd - SIOCIWFIRST;
if(cmd_index < standard_ioctl_num)
descr = &(standard_ioctl_descr[cmd_index]);
}
else
{
cmd_index = iwe->cmd - IWEVFIRST;
if(cmd_index < standard_event_num)
descr = &(standard_event_descr[cmd_index]);
}
if(descr != NULL)
event_type = descr->header_type;
/* Unknown events -> event_type=0 => IW_EV_LCP_PK_LEN */
event_len = event_type_size[event_type];
/* Fixup for earlier version of WE */
if((wev <= 18) && (event_type == IW_HEADER_TYPE_POINT))
event_len += IW_EV_POINT_OFF;
/* Check if we know about this event */
if(event_len <= IW_EV_LCP_PK_LEN)
{
/* Skip to next event */
stream->current += iwe->len;
return 2;
}
event_len -= IW_EV_LCP_PK_LEN;
/* Set pointer on data */
if(stream->value != NULL)
pointer = stream->value; /* Next value in event */
else
pointer = stream->current + IW_EV_LCP_PK_LEN; /* First value in event */
/* Copy the rest of the event (at least, fixed part) */
if((pointer + event_len) > stream->end)
{
/* Go to next event */
stream->current += iwe->len;
return -2;
}
/* Fixup for WE-19 and later : pointer no longer in the stream */
/* Beware of alignement. Dest has local alignement, not packed */
if( (wev > 18) && (event_type == IW_HEADER_TYPE_POINT) )
memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, pointer, event_len);
else
memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
/* Skip event in the stream */
pointer += event_len;
/* Special processing for iw_point events */
if(event_type == IW_HEADER_TYPE_POINT)
{
/* Check the length of the payload */
unsigned int extra_len = iwe->len - (event_len + IW_EV_LCP_PK_LEN);
if(extra_len > 0)
{
/* Set pointer on variable part (warning : non aligned) */
iwe->u.data.pointer = pointer;
/* Check that we have a descriptor for the command */
if(descr == NULL)
/* Can't check payload -> unsafe... */
iwe->u.data.pointer = NULL; /* Discard paylod */
else
{
/* Those checks are actually pretty hard to trigger,
* because of the checks done in the kernel... */
unsigned int token_len = iwe->u.data.length * descr->token_size;
/* Ugly fixup for alignement issues.
* If the kernel is 64 bits and userspace 32 bits,
* we have an extra 4+4 bytes.
* Fixing that in the kernel would break 64 bits userspace. */
if((token_len != extra_len) && (extra_len >= 4))
{
uint16_t alt_dlen = *((uint16_t *) pointer);
unsigned int alt_token_len = alt_dlen * descr->token_size;
if((alt_token_len + 8) == extra_len)
{
/* Ok, let's redo everything */
pointer -= event_len;
pointer += 4;
/* Dest has local alignement, not packed */
memcpy((char *) iwe + IW_EV_LCP_LEN + IW_EV_POINT_OFF, pointer, event_len);
pointer += event_len + 4;
iwe->u.data.pointer = pointer;
token_len = alt_token_len;
}
}
/* Discard bogus events which advertise more tokens than
* what they carry... */
if(token_len > extra_len)
iwe->u.data.pointer = NULL; /* Discard paylod */
/* Check that the advertised token size is not going to
* produce buffer overflow to our caller... */
if((iwe->u.data.length > descr->max_tokens)
&& !(descr->flags & IW_DESCR_FLAG_NOMAX))
iwe->u.data.pointer = NULL; /* Discard paylod */
/* Same for underflows... */
if(iwe->u.data.length < descr->min_tokens)
iwe->u.data.pointer = NULL; /* Discard paylod */
}
}
else
/* No data */
iwe->u.data.pointer = NULL;
/* Go to next event */
stream->current += iwe->len;
}
else
{
/* Ugly fixup for alignement issues.
* If the kernel is 64 bits and userspace 32 bits,
* we have an extra 4 bytes.
* Fixing that in the kernel would break 64 bits userspace. */
if((stream->value == NULL)
&& ((((iwe->len - IW_EV_LCP_PK_LEN) % event_len) == 4)
|| ((iwe->len == 12) && ((event_type == IW_HEADER_TYPE_UINT) ||
(event_type == IW_HEADER_TYPE_QUAL))) ))
{
pointer -= event_len;
pointer += 4;
/* Beware of alignement. Dest has local alignement, not packed */
memcpy((char *) iwe + IW_EV_LCP_LEN, pointer, event_len);
pointer += event_len;
}
/* Is there more value in the event ? */
if((pointer + event_len) <= (stream->current + iwe->len))
/* Go to next value */
stream->value = pointer;
else
{
/* Go to next event */
stream->value = NULL;
stream->current += iwe->len;
}
}
return 1;
}
static inline void wext_fill_wpa(unsigned char *iebuf, int ielen, struct iwinfo_scanlist_entry *e)
{
static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
while (ielen >= 2 && ielen >= iebuf[1])
{
switch (iebuf[0])
{
case 48: /* RSN */
iwinfo_parse_rsn(&e->crypto, iebuf + 2, iebuf[1],
IWINFO_CIPHER_CCMP, IWINFO_KMGMT_8021x);
break;
case 221: /* Vendor */
if (iebuf[1] >= 4 && !memcmp(iebuf + 2, ms_oui, 3) && iebuf[5] == 1)
iwinfo_parse_rsn(&e->crypto, iebuf + 6, iebuf[1] - 4,
IWINFO_CIPHER_TKIP, IWINFO_KMGMT_PSK);
break;
}
ielen -= iebuf[1] + 2;
iebuf += iebuf[1] + 2;
}
}
static inline void wext_fill_entry(struct stream_descr *stream, struct iw_event *event,
struct iw_range *iw_range, int has_range, struct iwinfo_scanlist_entry *e)
{
int i;
double freq;
/* Now, let's decode the event */
switch(event->cmd)
{
case SIOCGIWAP:
memcpy(e->mac, &event->u.ap_addr.sa_data, 6);
break;
case SIOCGIWFREQ:
if( event->u.freq.m >= 1000 )
{
freq = wext_freq2float(&(event->u.freq));
for(i = 0; i < iw_range->num_frequency; i++)
{
if( wext_freq2float(&iw_range->freq[i]) == freq )
{
e->channel = iw_range->freq[i].i;
break;
}
}
}
else
{
e->channel = event->u.freq.m;
}
break;
case SIOCGIWMODE:
switch(event->u.mode)
{
case 1:
e->mode = IWINFO_OPMODE_ADHOC;
break;
case 2:
case 3:
e->mode = IWINFO_OPMODE_MASTER;
break;
default:
e->mode = IWINFO_OPMODE_UNKNOWN;
break;
}
break;
case SIOCGIWESSID:
if( event->u.essid.pointer && event->u.essid.length && event->u.essid.flags )
memcpy(e->ssid, event->u.essid.pointer, event->u.essid.length);
break;
case SIOCGIWENCODE:
e->crypto.enabled = !(event->u.data.flags & IW_ENCODE_DISABLED);
break;
case IWEVQUAL:
e->signal = event->u.qual.level;
e->quality = event->u.qual.qual;
e->quality_max = iw_range->max_qual.qual;
break;
#if 0
case SIOCGIWRATE:
if(state->val_index == 0)
{
lua_pushstring(L, "bitrates");
lua_newtable(L);
}
//iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
snprintf(buffer, sizeof(buffer), "%d", event->u.bitrate.value);
lua_pushinteger(L, state->val_index + 1);
lua_pushstring(L, buffer);
lua_settable(L, -3);
/* Check for termination */
if(stream->value == NULL)
{
lua_settable(L, -3);
state->val_index = 0;
} else
state->val_index++;
break;
#endif
case IWEVGENIE:
wext_fill_wpa(event->u.data.pointer, event->u.data.length, e);
break;
}
}
int wext_get_scanlist(const char *ifname, char *buf, int *len)
{
struct iwreq wrq;
struct iw_scan_req scanopt; /* Options for 'set' */
unsigned char *buffer = NULL; /* Results */
int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
struct iw_range range;
int has_range = 1;
struct timeval tv; /* Select timeout */
int timeout = 15000000; /* 15s */
int entrylen = 0;
struct iwinfo_scanlist_entry e;
wrq.u.data.pointer = (caddr_t) &range;
wrq.u.data.length = sizeof(struct iw_range);
wrq.u.data.flags = 0;
if( wext_ioctl(ifname, SIOCGIWRANGE, &wrq) >= 0 )
{
/* Init timeout value -> 250ms between set and first get */
tv.tv_sec = 0;
tv.tv_usec = 250000;
/* Clean up set args */
memset(&scanopt, 0, sizeof(scanopt));
wrq.u.data.pointer = NULL;
wrq.u.data.flags = 0;
wrq.u.data.length = 0;
/* Initiate Scanning */
if( wext_ioctl(ifname, SIOCSIWSCAN, &wrq) >= 0 )
{
timeout -= tv.tv_usec;
/* Forever */
while(1)
{
fd_set rfds; /* File descriptors for select */
int last_fd; /* Last fd */
int ret;
/* Guess what ? We must re-generate rfds each time */
FD_ZERO(&rfds);
last_fd = -1;
/* In here, add the rtnetlink fd in the list */
/* Wait until something happens */
ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
/* Check if there was an error */
if(ret < 0)
{
if(errno == EAGAIN || errno == EINTR)
continue;
return -1;
}
/* Check if there was a timeout */
if(ret == 0)
{
unsigned char *newbuf;
realloc:
/* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
newbuf = realloc(buffer, buflen);
if(newbuf == NULL)
{
if(buffer)
free(buffer);
return -1;
}
buffer = newbuf;
/* Try to read the results */
wrq.u.data.pointer = buffer;
wrq.u.data.flags = 0;
wrq.u.data.length = buflen;
if( wext_ioctl(ifname, SIOCGIWSCAN, &wrq) )
{
/* Check if buffer was too small (WE-17 only) */
if((errno == E2BIG) && (range.we_version_compiled > 16))
{
/* Some driver may return very large scan results, either
* because there are many cells, or because they have many
* large elements in cells (like IWEVCUSTOM). Most will
* only need the regular sized buffer. We now use a dynamic
* allocation of the buffer to satisfy everybody. Of course,
* as we don't know in advance the size of the array, we try
* various increasing sizes. Jean II */
/* Check if the driver gave us any hints. */
if(wrq.u.data.length > buflen)
buflen = wrq.u.data.length;
else
buflen *= 2;
/* Try again */
goto realloc;
}
/* Check if results not available yet */
if(errno == EAGAIN)
{
/* Restart timer for only 100ms*/
tv.tv_sec = 0;
tv.tv_usec = 100000;
timeout -= tv.tv_usec;
if(timeout > 0)
continue; /* Try again later */
}
/* Bad error */
free(buffer);
return -1;
} else {
/* We have the results, go to process them */
break;
}
}
}
if( wrq.u.data.length )
{
struct iw_event iwe;
struct stream_descr stream;
int ret;
int first = 1;
memset(&stream, 0, sizeof(stream));
stream.current = (char *)buffer;
stream.end = (char *)buffer + wrq.u.data.length;
do
{
/* Extract an event and print it */
ret = wext_extract_event(&stream, &iwe, range.we_version_compiled);
if(ret >= 0)
{
if( (iwe.cmd == SIOCGIWAP) || (ret == 0) )
{
if( first )
{
first = 0;
}
else if( (entrylen + sizeof(struct iwinfo_scanlist_entry)) <= IWINFO_BUFSIZE )
{
/* if encryption is off, clear the crypto strunct */
if( !e.crypto.enabled )
memset(&e.crypto, 0, sizeof(struct iwinfo_crypto_entry));
memcpy(&buf[entrylen], &e, sizeof(struct iwinfo_scanlist_entry));
entrylen += sizeof(struct iwinfo_scanlist_entry);
}
else
{
/* we exceed the callers buffer size, abort here ... */
break;
}
memset(&e, 0, sizeof(struct iwinfo_scanlist_entry));
}
wext_fill_entry(&stream, &iwe, &range, has_range, &e);
}
} while(ret > 0);
free(buffer);
*len = entrylen;
return 0;
}
*len = 0;
free(buffer);
return 0;
}
}
return -1;
}

730
iwinfo_wl.c Normal file
View file

@ -0,0 +1,730 @@
/*
* iwinfo - Wireless Information Library - Broadcom wl.o Backend
*
* Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
*
* The iwinfo library is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* The iwinfo library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with the iwinfo library. If not, see http://www.gnu.org/licenses/.
*
* This code is based on the wlc.c utility published by OpenWrt.org .
*/
#include "iwinfo.h"
#include "api/broadcom.h"
static int wl_ioctl(const char *name, int cmd, void *buf, int len)
{
struct ifreq ifr;
wl_ioctl_t ioc;
/* do it */
ioc.cmd = cmd;
ioc.buf = buf;
ioc.len = len;
strncpy(ifr.ifr_name, name, IFNAMSIZ);
ifr.ifr_data = (caddr_t) &ioc;
return iwinfo_ioctl(SIOCDEVPRIVATE, &ifr);
}
static int wl_iovar(const char *name, const char *cmd, const char *arg,
int arglen, void *buf, int buflen)
{
int cmdlen = strlen(cmd) + 1;
memcpy(buf, cmd, cmdlen);
if (arg && arglen > 0)
memcpy(buf + cmdlen, arg, arglen);
return wl_ioctl(name, WLC_GET_VAR, buf, buflen);
}
static struct wl_maclist * wl_read_assoclist(const char *ifname)
{
struct wl_maclist *macs;
int maclen = 4 + WL_MAX_STA_COUNT * 6;
if (strstr(ifname, "wds"))
return NULL;
if ((macs = (struct wl_maclist *) malloc(maclen)) != NULL)
{
memset(macs, 0, maclen);
macs->count = WL_MAX_STA_COUNT;
if (!wl_ioctl(ifname, WLC_GET_ASSOCLIST, macs, maclen))
return macs;
free(macs);
}
return NULL;
}
static int wl_probe(const char *ifname)
{
int magic;
return (!wl_ioctl(ifname, WLC_GET_MAGIC, &magic, sizeof(magic)) &&
(magic == WLC_IOCTL_MAGIC));
}
static void wl_close(void)
{
/* Nop */
}
static int wl_get_mode(const char *ifname, int *buf)
{
int ret = -1;
int ap, infra, passive;
if ((ret = wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap))))
return ret;
if ((ret = wl_ioctl(ifname, WLC_GET_INFRA, &infra, sizeof(infra))))
return ret;
if ((ret = wl_ioctl(ifname, WLC_GET_PASSIVE, &passive, sizeof(passive))))
return ret;
if (passive)
*buf = IWINFO_OPMODE_MONITOR;
else if (!infra)
*buf = IWINFO_OPMODE_ADHOC;
else if (ap)
*buf = IWINFO_OPMODE_MASTER;
else
*buf = IWINFO_OPMODE_CLIENT;
return 0;
}
static int wl_get_ssid(const char *ifname, char *buf)
{
int ret = -1;
wlc_ssid_t ssid;
if (!(ret = wl_ioctl(ifname, WLC_GET_SSID, &ssid, sizeof(ssid))))
memcpy(buf, ssid.ssid, ssid.ssid_len);
return ret;
}
static int wl_get_bssid(const char *ifname, char *buf)
{
int ret = -1;
char bssid[6];
if (!(ret = wl_ioctl(ifname, WLC_GET_BSSID, bssid, 6)))
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
(uint8_t)bssid[0], (uint8_t)bssid[1], (uint8_t)bssid[2],
(uint8_t)bssid[3], (uint8_t)bssid[4], (uint8_t)bssid[5]
);
return ret;
}
static int wl_get_channel(const char *ifname, int *buf)
{
return wl_ioctl(ifname, WLC_GET_CHANNEL, buf, sizeof(buf));
}
static int wl_get_frequency(const char *ifname, int *buf)
{
return wext_ops.frequency(ifname, buf);
}
static int wl_get_txpower(const char *ifname, int *buf)
{
/* WLC_GET_VAR "qtxpower" */
return wext_ops.txpower(ifname, buf);
}
static int wl_get_bitrate(const char *ifname, int *buf)
{
int ret = -1;
int rate = 0;
if( !(ret = wl_ioctl(ifname, WLC_GET_RATE, &rate, sizeof(rate))) && (rate > 0))
*buf = ((rate / 2) * 1000) + ((rate & 1) ? 500 : 0);
return ret;
}
static int wl_get_signal(const char *ifname, int *buf)
{
unsigned int ap, rssi, i, rssi_count;
int ioctl_req_version = 0x2000;
char tmp[WLC_IOCTL_MAXLEN];
struct wl_maclist *macs = NULL;
wl_sta_rssi_t starssi;
memset(tmp, 0, WLC_IOCTL_MAXLEN);
memcpy(tmp, &ioctl_req_version, sizeof(ioctl_req_version));
wl_ioctl(ifname, WLC_GET_BSS_INFO, tmp, WLC_IOCTL_MAXLEN);
if (!wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)) && !ap)
{
*buf = tmp[WL_BSS_RSSI_OFFSET];
}
else
{
rssi = rssi_count = 0;
/* Calculate average rssi from conntected stations */
if ((macs = wl_read_assoclist(ifname)) != NULL)
{
for (i = 0; i < macs->count; i++)
{
memcpy(starssi.mac, &macs->ea[i], 6);
if (!wl_ioctl(ifname, WLC_GET_RSSI, &starssi, 12))
{
rssi -= starssi.rssi;
rssi_count++;
}
}
free(macs);
}
*buf = (rssi == 0 || rssi_count == 0) ? 1 : -(rssi / rssi_count);
}
return 0;
}
static int wl_get_noise(const char *ifname, int *buf)
{
unsigned int ap, noise;
int ioctl_req_version = 0x2000;
char tmp[WLC_IOCTL_MAXLEN];
memset(tmp, 0, WLC_IOCTL_MAXLEN);
memcpy(tmp, &ioctl_req_version, sizeof(ioctl_req_version));
wl_ioctl(ifname, WLC_GET_BSS_INFO, tmp, WLC_IOCTL_MAXLEN);
if ((wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap)) < 0) || ap)
{
if (wl_ioctl(ifname, WLC_GET_PHY_NOISE, &noise, sizeof(noise)) < 0)
noise = 0;
}
else
{
noise = tmp[WL_BSS_NOISE_OFFSET];
}
*buf = noise;
return 0;
}
static int wl_get_quality(const char *ifname, int *buf)
{
return wext_ops.quality(ifname, buf);
}
static int wl_get_quality_max(const char *ifname, int *buf)
{
return wext_ops.quality_max(ifname, buf);
}
static int wl_get_encryption(const char *ifname, char *buf)
{
uint32_t wsec, wauth, wpa;
struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf;
if( wl_ioctl(ifname, WLC_GET_WPA_AUTH, &wpa, sizeof(uint32_t)) ||
wl_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(uint32_t)) ||
wl_ioctl(ifname, WLC_GET_AUTH, &wauth, sizeof(uint32_t)) )
return -1;
switch(wsec)
{
case 2:
c->pair_ciphers |= IWINFO_CIPHER_TKIP;
break;
case 4:
c->pair_ciphers |= IWINFO_CIPHER_CCMP;
break;
case 6:
c->pair_ciphers |= IWINFO_CIPHER_TKIP;
c->pair_ciphers |= IWINFO_CIPHER_CCMP;
break;
}
switch(wpa)
{
case 0:
if (wsec && !wauth)
c->auth_algs |= IWINFO_AUTH_OPEN;
else if (wsec && wauth)
c->auth_algs |= IWINFO_AUTH_SHARED;
/* ToDo: evaluate WEP key lengths */
c->pair_ciphers = IWINFO_CIPHER_WEP40 | IWINFO_CIPHER_WEP104;
c->auth_suites |= IWINFO_KMGMT_NONE;
break;
case 2:
c->wpa_version = 1;
c->auth_suites |= IWINFO_KMGMT_8021x;
break;
case 4:
c->wpa_version = 1;
c->auth_suites |= IWINFO_KMGMT_PSK;
break;
case 32:
case 64:
c->wpa_version = 2;
c->auth_suites |= IWINFO_KMGMT_8021x;
break;
case 66:
c->wpa_version = 3;
c->auth_suites |= IWINFO_KMGMT_8021x;
break;
case 128:
c->wpa_version = 2;
c->auth_suites |= IWINFO_KMGMT_PSK;
break;
case 132:
c->wpa_version = 3;
c->auth_suites |= IWINFO_KMGMT_PSK;
break;
default:
break;
}
c->enabled = (c->wpa_version || c->auth_algs) ? 1 : 0;
c->group_ciphers = c->pair_ciphers;
return 0;
}
static int wl_get_phyname(const char *ifname, char *buf)
{
char *p;
strcpy(buf, ifname);
if ((p = strchr(buf, '.')) != NULL)
*p = 0;
return 0;
}
static int wl_get_enctype(const char *ifname, char *buf)
{
uint32_t wsec, wpa;
char algo[11];
if( wl_ioctl(ifname, WLC_GET_WPA_AUTH, &wpa, sizeof(uint32_t)) ||
wl_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(uint32_t)) )
return -1;
switch(wsec)
{
case 2:
sprintf(algo, "TKIP");
break;
case 4:
sprintf(algo, "CCMP");
break;
case 6:
sprintf(algo, "TKIP, CCMP");
break;
}
switch(wpa)
{
case 0:
sprintf(buf, "%s", wsec ? "WEP" : "None");
break;
case 2:
sprintf(buf, "WPA 802.1X (%s)", algo);
break;
case 4:
sprintf(buf, "WPA PSK (%s)", algo);
break;
case 32:
sprintf(buf, "802.1X (%s)", algo);
break;
case 64:
sprintf(buf, "WPA2 802.1X (%s)", algo);
break;
case 66:
sprintf(buf, "mixed WPA/WPA2 802.1X (%s)", algo);
break;
case 128:
sprintf(buf, "WPA2 PSK (%s)", algo);
break;
case 132:
sprintf(buf, "mixed WPA/WPA2 PSK (%s)", algo);
break;
default:
sprintf(buf, "Unknown");
}
return 0;
}
static void wl_get_assoclist_cb(const char *ifname,
struct iwinfo_assoclist_entry *e)
{
wl_sta_info_t sta = { 0 };
if (!wl_iovar(ifname, "sta_info", e->mac, 6, &sta, sizeof(sta)) &&
(sta.ver >= 2))
{
e->inactive = sta.idle * 1000;
e->rx_packets = sta.rx_ucast_pkts;
e->tx_packets = sta.tx_pkts;
e->rx_rate.rate = sta.rx_rate;
e->tx_rate.rate = sta.tx_rate;
/* ToDo: 11n */
e->rx_rate.mcs = -1;
e->tx_rate.mcs = -1;
}
}
static int wl_get_assoclist(const char *ifname, char *buf, int *len)
{
int i, j, noise;
int ap, infra, passive;
char line[128];
char macstr[18];
char devstr[IFNAMSIZ];
struct wl_maclist *macs;
struct wl_sta_rssi rssi;
struct iwinfo_assoclist_entry entry;
FILE *arp;
ap = infra = passive = 0;
wl_ioctl(ifname, WLC_GET_AP, &ap, sizeof(ap));
wl_ioctl(ifname, WLC_GET_INFRA, &infra, sizeof(infra));
wl_ioctl(ifname, WLC_GET_PASSIVE, &passive, sizeof(passive));
if (wl_get_noise(ifname, &noise))
noise = 0;
if ((ap || infra || passive) && ((macs = wl_read_assoclist(ifname)) != NULL))
{
for (i = 0, j = 0; i < macs->count; i++, j += sizeof(struct iwinfo_assoclist_entry))
{
memset(&entry, 0, sizeof(entry));
memcpy(rssi.mac, &macs->ea[i], 6);
if (!wl_ioctl(ifname, WLC_GET_RSSI, &rssi, sizeof(struct wl_sta_rssi)))
entry.signal = (rssi.rssi - 0x100);
else
entry.signal = 0;
entry.noise = noise;
memcpy(entry.mac, &macs->ea[i], 6);
wl_get_assoclist_cb(ifname, &entry);
memcpy(&buf[j], &entry, sizeof(entry));
}
*len = j;
free(macs);
return 0;
}
else if ((arp = fopen("/proc/net/arp", "r")) != NULL)
{
j = 0;
while (fgets(line, sizeof(line), arp) != NULL)
{
if (sscanf(line, "%*s 0x%*d 0x%*d %17s %*s %s", macstr, devstr) && !strcmp(devstr, ifname))
{
rssi.mac[0] = strtol(&macstr[0], NULL, 16);
rssi.mac[1] = strtol(&macstr[3], NULL, 16);
rssi.mac[2] = strtol(&macstr[6], NULL, 16);
rssi.mac[3] = strtol(&macstr[9], NULL, 16);
rssi.mac[4] = strtol(&macstr[12], NULL, 16);
rssi.mac[5] = strtol(&macstr[15], NULL, 16);
if (!wl_ioctl(ifname, WLC_GET_RSSI, &rssi, sizeof(struct wl_sta_rssi)))
entry.signal = (rssi.rssi - 0x100);
else
entry.signal = 0;
entry.noise = noise;
memcpy(entry.mac, rssi.mac, 6);
memcpy(&buf[j], &entry, sizeof(entry));
j += sizeof(entry);
}
}
*len = j;
(void) fclose(arp);
return 0;
}
return -1;
}
static int wl_get_txpwrlist(const char *ifname, char *buf, int *len)
{
struct iwinfo_txpwrlist_entry entry;
uint8_t dbm[11] = { 0, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 };
uint8_t mw[11] = { 1, 3, 6, 10, 15, 25, 39, 63, 100, 158, 251 };
int i;
for (i = 0; i < 11; i++)
{
entry.dbm = dbm[i];
entry.mw = mw[i];
memcpy(&buf[i*sizeof(entry)], &entry, sizeof(entry));
}
*len = 11 * sizeof(entry);
return 0;
}
static int wl_get_scanlist(const char *ifname, char *buf, int *len)
{
return wext_ops.scanlist(ifname, buf, len);
}
static int wl_get_freqlist(const char *ifname, char *buf, int *len)
{
return wext_ops.freqlist(ifname, buf, len);
}
static int wl_get_country(const char *ifname, char *buf)
{
char ccode[WLC_CNTRY_BUF_SZ];
if (!wl_ioctl(ifname, WLC_GET_COUNTRY, ccode, WLC_CNTRY_BUF_SZ))
{
/* IL0 -> World */
if (!strcmp(ccode, "IL0"))
sprintf(buf, "00");
/* YU -> RS */
else if (!strcmp(ccode, "YU"))
sprintf(buf, "RS");
else
memcpy(buf, ccode, 2);
return 0;
}
return -1;
}
static int wl_get_countrylist(const char *ifname, char *buf, int *len)
{
int i, count;
char cdata[WLC_IOCTL_MAXLEN];
struct iwinfo_country_entry *c = (struct iwinfo_country_entry *)buf;
wl_country_list_t *cl = (wl_country_list_t *)cdata;
cl->buflen = sizeof(cdata);
if (!wl_ioctl(ifname, WLC_GET_COUNTRY_LIST, cl, cl->buflen))
{
for (i = 0, count = 0; i < cl->count; i++, c++)
{
snprintf(c->ccode, sizeof(c->ccode), "%s", &cl->country_abbrev[i * WLC_CNTRY_BUF_SZ]);
c->iso3166 = c->ccode[0] * 256 + c->ccode[1];
/* IL0 -> World */
if (!strcmp(c->ccode, "IL0"))
c->iso3166 = 0x3030;
/* YU -> RS */
else if (!strcmp(c->ccode, "YU"))
c->iso3166 = 0x5253;
}
*len = (i * sizeof(struct iwinfo_country_entry));
return 0;
}
return -1;
}
static int wl_get_hwmodelist(const char *ifname, int *buf)
{
int phytype;
uint i, band[WLC_BAND_ALL], bands;
if (!wl_ioctl(ifname, WLC_GET_PHYTYPE, &phytype, sizeof(phytype)) &&
!wl_ioctl(ifname, WLC_GET_BANDLIST, band, sizeof(band)))
{
switch (phytype)
{
case WLC_PHY_TYPE_A:
*buf = IWINFO_80211_A;
break;
case WLC_PHY_TYPE_B:
*buf = IWINFO_80211_B;
break;
case WLC_PHY_TYPE_LP:
case WLC_PHY_TYPE_G:
case WLC_PHY_TYPE_N:
bands = 0;
for (i = 1; i <= band[0]; i++)
{
bands |= band[i];
}
*buf = 0;
if (bands & WLC_BAND_5G)
*buf |= IWINFO_80211_A;
if (bands & WLC_BAND_2G)
{
*buf |= IWINFO_80211_B;
*buf |= IWINFO_80211_G;
}
if (phytype == WLC_PHY_TYPE_N)
*buf |= IWINFO_80211_N;
break;
default:
return -1;
break;
}
return 0;
}
return -1;
}
static int wl_get_mbssid_support(const char *ifname, int *buf)
{
wlc_rev_info_t revinfo;
/* Multi bssid support only works on corerev >= 9 */
if (!wl_ioctl(ifname, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)))
{
if (revinfo.corerev >= 9)
{
*buf = 1;
return 0;
}
}
return -1;
}
static int wl_get_hardware_id(const char *ifname, char *buf)
{
wlc_rev_info_t revinfo;
struct iwinfo_hardware_id *ids = (struct iwinfo_hardware_id *)buf;
if (wl_ioctl(ifname, WLC_GET_REVINFO, &revinfo, sizeof(revinfo)))
return -1;
ids->vendor_id = revinfo.vendorid;
ids->device_id = revinfo.deviceid;
ids->subsystem_vendor_id = revinfo.boardvendor;
ids->subsystem_device_id = revinfo.boardid;
return 0;
}
static int wl_get_hardware_name(const char *ifname, char *buf)
{
struct iwinfo_hardware_id ids;
if (wl_get_hardware_id(ifname, (char *)&ids))
return -1;
sprintf(buf, "Broadcom BCM%04X", ids.device_id);
return 0;
}
static int wl_get_txpower_offset(const char *ifname, int *buf)
{
FILE *p;
char off[8];
*buf = 0;
if ((p = popen("/usr/sbin/nvram get opo", "r")) != NULL)
{
if (fread(off, 1, sizeof(off), p))
*buf = strtoul(off, NULL, 16);
pclose(p);
}
return 0;
}
static int wl_get_frequency_offset(const char *ifname, int *buf)
{
/* Stub */
*buf = 0;
return -1;
}
const struct iwinfo_ops wl_ops = {
.name = "wl",
.probe = wl_probe,
.channel = wl_get_channel,
.frequency = wl_get_frequency,
.frequency_offset = wl_get_frequency_offset,
.txpower = wl_get_txpower,
.txpower_offset = wl_get_txpower_offset,
.bitrate = wl_get_bitrate,
.signal = wl_get_signal,
.noise = wl_get_noise,
.quality = wl_get_quality,
.quality_max = wl_get_quality_max,
.mbssid_support = wl_get_mbssid_support,
.hwmodelist = wl_get_hwmodelist,
.mode = wl_get_mode,
.ssid = wl_get_ssid,
.bssid = wl_get_bssid,
.country = wl_get_country,
.hardware_id = wl_get_hardware_id,
.hardware_name = wl_get_hardware_name,
.encryption = wl_get_encryption,
.phyname = wl_get_phyname,
.assoclist = wl_get_assoclist,
.txpwrlist = wl_get_txpwrlist,
.scanlist = wl_get_scanlist,
.freqlist = wl_get_freqlist,
.countrylist = wl_get_countrylist,
.close = wl_close
};