diff options
Diffstat (limited to 'package/network/utils/iwinfo/src/.svn')
12 files changed, 8301 insertions, 0 deletions
diff --git a/package/network/utils/iwinfo/src/.svn/entries b/package/network/utils/iwinfo/src/.svn/entries new file mode 100644 index 0000000..074e71f --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/entries @@ -0,0 +1,405 @@ +10 + +dir +36060 +svn://svn.openwrt.org/openwrt/trunk/package/network/utils/iwinfo/src +svn://svn.openwrt.org/openwrt + + + +2013-02-03T12:03:24.606559Z +35471 +jow + + + + + + + + + + + + + + +3c298f89-4303-0410-b956-a3cf2f4a3e73 + +iwinfo_nl80211.c +file + + + + +2013-03-17T12:13:18.000000Z +bb86c5d11142be9e72c97e32b41ba20e +2013-01-04T14:08:08.691763Z +35007 +jow + + + + + + + + + + + + + + + + + + + + + +50569 + +iwinfo_lib.c +file + + + + +2013-03-17T12:13:18.000000Z +1377e07a785dbd34c567a2232e6036ba +2013-01-02T19:10:29.781239Z +34982 +jow + + + + + + + + + + + + + + + + + + + + + +16010 + +include +dir + +iwinfo_cli.c +file + + + + +2013-03-17T12:13:18.000000Z +0413ba2472e41009ab5fa4d5288a657c +2012-03-05T17:52:46.765236Z +30825 +jow + + + + + + + + + + + + + + + + + + + + + +16362 + +iwinfo_wext.c +file + + + + +2013-03-17T12:13:18.000000Z +963d4be006ccc0d796c61992d0386bc5 +2012-02-23T13:16:09.383816Z +30692 +jow + + + + + + + + + + + + + + + + + + + + + +10161 + +iwinfo_wext_scan.c +file + + + + +2013-03-17T12:13:18.000000Z +149ccf5fa47e1d32a7fc4e9d23125e89 +2012-02-23T13:16:09.383816Z +30692 +jow + + + + + + + + + + + + + + + + + + + + + +13619 + +COPYING +file + + + + +2013-03-17T12:13:18.000000Z +751419260aa954499f7abaabaa882bbe +2011-12-03T13:57:38.074666Z +29403 +jow + + + + + + + + + + + + + + + + + + + + + +17987 + +iwinfo_madwifi.c +file + + + + +2013-03-17T12:13:18.000000Z +4dcacfe0f02eb819df8ef37e938592dd +2012-08-14T10:33:40.189807Z +33180 +jow + + + + + + + + + + + + + + + + + + + + + +25767 + +iwinfo_utils.c +file + + + + +2013-03-17T12:13:18.000000Z +4f95bd7f48c4f1dad2387cc35a890c80 +2013-02-03T12:03:24.606559Z +35471 +jow + + + + + + + + + + + + + + + + + + + + + +7745 + +Makefile +file + + + + +2013-03-17T12:13:18.000000Z +eeda98cc839124fb4ee9ca56e6700b15 +2011-12-03T13:57:38.074666Z +29403 +jow + + + + + + + + + + + + + + + + + + + + + +1297 + +iwinfo_lua.c +file + + + + +2013-03-17T12:13:18.000000Z +4d47f737663540493ec64cf5489285ba +2012-05-28T00:52:26.626723Z +31932 +jow + + + + + + + + + + + + + + + + + + + + + +19971 + +iwinfo_wl.c +file + + + + +2013-03-17T12:13:18.000000Z +126cb26afc6f6c1205d2615121073c2e +2012-02-23T18:20:51.092372Z +30693 +jow + + + + + + + + + + + + + + + + + + + + + +13419 + diff --git a/package/network/utils/iwinfo/src/.svn/text-base/COPYING.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/COPYING.svn-base new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/COPYING.svn-base @@ -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. diff --git a/package/network/utils/iwinfo/src/.svn/text-base/Makefile.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/Makefile.svn-base new file mode 100644 index 0000000..572bef9 --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/Makefile.svn-base @@ -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) diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_cli.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_cli.c.svn-base new file mode 100644 index 0000000..7ec5aef --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_cli.c.svn-base @@ -0,0 +1,800 @@ +/* + * 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 "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", + (modes & IWINFO_80211_A) ? "a" : "", + (modes & IWINFO_80211_B) ? "b" : "", + (modes & IWINFO_80211_G) ? "g" : "", + (modes & IWINFO_80211_N) ? "n" : ""); + + 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 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\n", + print_mbssid_supp(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; + const struct iwinfo_ops *iw; + + if (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; + } + + 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; +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_lib.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_lib.c.svn-base new file mode 100644 index 0000000..e943546 --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_lib.c.svn-base @@ -0,0 +1,458 @@ +/* + * 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, "" } +}; + +/* + * hardware database + */ + +const char VENDOR_UBNT[] = "Ubiquiti"; +const char VENDOR_ATH[] = "Atheros"; +const char VENDOR_RALINK[] = "RaLink"; + +const struct iwinfo_hardware_entry IWINFO_HARDWARE_ENTRIES[] = { +/* { vendor, model, vendorid, deviceid, subsys vendorid, subsys deviceid, poweroff, freqoff } */ +#if defined(USE_MADWIFI) || defined(USE_NL80211) + { VENDOR_UBNT, "PowerStation2 (18V)", 0xffff, 0xffff, 0xffff, 0xb102, 0, 0 }, + { VENDOR_UBNT, "PowerStation2 (16D)", 0xffff, 0xffff, 0xffff, 0xb202, 0, 0 }, + { VENDOR_UBNT, "PowerStation2 (EXT)", 0xffff, 0xffff, 0xffff, 0xb302, 0, 0 }, + { VENDOR_UBNT, "PowerStation5 (22V)", 0xffff, 0xffff, 0xffff, 0xb105, 0, 0 }, + { VENDOR_UBNT, "PowerStation5 (EXT)", 0xffff, 0xffff, 0xffff, 0xb305, 0, 0 }, + { VENDOR_UBNT, "PicoStation2", 0xffff, 0xffff, 0xffff, 0xc302, 0, 0 }, + { VENDOR_UBNT, "PicoStation2 HP", 0xffff, 0xffff, 0xffff, 0xc3a2, 10, 0 }, + { VENDOR_UBNT, "WispStation5", 0xffff, 0xffff, 0xffff, 0xa105, 0, 0 }, + { VENDOR_UBNT, "LiteStation2", 0xffff, 0xffff, 0xffff, 0xa002, 10, 0 }, + { VENDOR_UBNT, "LiteStation5", 0xffff, 0xffff, 0xffff, 0xa005, 5, 0 }, + { VENDOR_UBNT, "NanoStation2", 0xffff, 0xffff, 0xffff, 0xc002, 10, 0 }, + { VENDOR_UBNT, "NanoStation5", 0xffff, 0xffff, 0xffff, 0xc005, 5, 0 }, + { VENDOR_UBNT, "NanoStation Loco2", 0xffff, 0xffff, 0xffff, 0xc102, 10, 0 }, + { VENDOR_UBNT, "NanoStation Loco5", 0xffff, 0xffff, 0xffff, 0xc105, 5, 0 }, + { VENDOR_UBNT, "Bullet2", 0xffff, 0xffff, 0xffff, 0xc202, 10, 0 }, + { VENDOR_UBNT, "Bullet5", 0xffff, 0xffff, 0xffff, 0xc205, 5, 0 }, + { VENDOR_UBNT, "XR2", 0x168c, 0x001b, 0x0777, 0x3002, 10, 0 }, + { VENDOR_UBNT, "XR2", 0x168c, 0x001b, 0x7777, 0x3002, 10, 0 }, + { VENDOR_UBNT, "XR2.3", 0x168c, 0x001b, 0x0777, 0x3b02, 10, 0 }, + { VENDOR_UBNT, "XR2.6", 0x168c, 0x001b, 0x0777, 0x3c02, 10, 0 }, + { VENDOR_UBNT, "XR3-2.8", 0x168c, 0x001b, 0x0777, 0x3b03, 10, 0 }, + { VENDOR_UBNT, "XR3-3.6", 0x168c, 0x001b, 0x0777, 0x3c03, 10, 0 }, + { VENDOR_UBNT, "XR3", 0x168c, 0x001b, 0x0777, 0x3003, 10, 0 }, + { VENDOR_UBNT, "XR4", 0x168c, 0x001b, 0x0777, 0x3004, 10, 0 }, + { VENDOR_UBNT, "XR5", 0x168c, 0x001b, 0x0777, 0x3005, 10, 0 }, + { VENDOR_UBNT, "XR5", 0x168c, 0x001b, 0x7777, 0x3005, 10, 0 }, + { VENDOR_UBNT, "XR7", 0x168c, 0x001b, 0x0777, 0x3007, 10, 0 }, + { VENDOR_UBNT, "XR9", 0x168c, 0x001b, 0x0777, 0x3009, 10, -1520 }, + { VENDOR_ATH, "AR5413", 0x168c, 0x001b, 0x168c, 0x2063, 0, 0 }, + { VENDOR_UBNT, "SRC", 0x168c, 0x0013, 0x168c, 0x1042, 1, 0 }, + { VENDOR_UBNT, "SR2", 0x168c, 0x0013, 0x0777, 0x2041, 10, 0 }, + { VENDOR_UBNT, "SR4", 0x168c, 0x0013, 0x0777, 0x2004, 6, 0 }, + { VENDOR_UBNT, "SR4", 0x168c, 0x0013, 0x7777, 0x2004, 6, 0 }, + { VENDOR_UBNT, "SR4C", 0x168c, 0x0013, 0x0777, 0x1004, 6, 0 }, + { VENDOR_UBNT, "SR4C", 0x168c, 0x0013, 0x7777, 0x1004, 6, 0 }, + { VENDOR_UBNT, "SR5", 0x168c, 0x0013, 0x168c, 0x2042, 7, 0 }, + { VENDOR_UBNT, "SR9", 0x168c, 0x0013, 0x7777, 0x2009, 12, -1500 }, + { VENDOR_UBNT, "SR71A", 0x168c, 0x0027, 0x168c, 0x2082, 10, 0 }, + { VENDOR_UBNT, "SR71", 0x168c, 0x0027, 0x0777, 0x4082, 10, 0 }, +#endif +#ifdef USE_NL80211 + { VENDOR_UBNT, "PicoStation M2", 0x168c, 0x002a, 0x0777, 0xe302, 12, 0 }, /* ToDo: confirm offset */ + { VENDOR_UBNT, "NanoStation M2", 0x168c, 0x002a, 0x0777, 0xe012, 12, 0 }, /* ToDo: confirm offset */ + { VENDOR_UBNT, "NanoStation M5", 0x168c, 0x002a, 0x0777, 0xe005, 5, 0 }, /* ToDo: confirm offset */ + { VENDOR_UBNT, "Bullet M2", 0x168c, 0x002a, 0x0777, 0xe202, 12, 0 }, + { VENDOR_UBNT, "Bullet M5", 0x168c, 0x002a, 0x0777, 0xe805, 5, 0 }, + + { VENDOR_ATH, "AR9220", 0x168c, 0x0029, 0x168c, 0xa094, 0, 0 }, + { VENDOR_ATH, "AR9223", 0x168c, 0x0029, 0x168c, 0xa095, 0, 0 }, + { VENDOR_ATH, "AR9280", 0x168c, 0x002a, 0x168c, 0xa093, 0, 0 }, + { VENDOR_ATH, "AR9285", 0x168c, 0x002b, 0x168c, 0xa091, 0, 0 }, + { VENDOR_RALINK, "Rt3050", 0x1814, 0x3050, 0x1814, 0x0005, 0, 0 }, + { VENDOR_RALINK, "Rt3052", 0x1814, 0x3052, 0x1814, 0x0008, 0, 0 }, + { VENDOR_RALINK, "Rt3352", 0x1814, 0x3352, 0x1814, 0x000c, 0, 0 }, +#endif + { NULL } +}; + + +const char * iwinfo_type(const char *ifname) +{ +#ifdef USE_NL80211 + if (nl80211_probe(ifname)) + return "nl80211"; + else +#endif + +#ifdef USE_MADWIFI + if (madwifi_probe(ifname)) + return "madwifi"; + else +#endif + +#ifdef USE_WL + if (wl_probe(ifname)) + return "wl"; + else +#endif + + if (wext_probe(ifname)) + return "wext"; + + return NULL; +} + +const struct iwinfo_ops * iwinfo_backend(const char *ifname) +{ + const char *type; + struct iwinfo_ops *ops; + + type = iwinfo_type(ifname); + if (!type) + return NULL; + +#ifdef USE_NL80211 + if (!strcmp(type, "nl80211")) + return &nl80211_ops; + else +#endif + +#ifdef USE_MADWIFI + if (!strcmp(type, "madwifi")) + return &madwifi_ops; + else +#endif + +#ifdef USE_WL + if (!strcmp(type, "wl")) + return &wl_ops; + else +#endif + + if (!strcmp(type, "wext")) + return &wext_ops; + + return NULL; +} + +void iwinfo_finish(void) +{ +#ifdef USE_WL + wl_close(); +#endif +#ifdef USE_MADWIFI + madwifi_close(); +#endif +#ifdef USE_NL80211 + nl80211_close(); +#endif + wext_close(); + iwinfo_close(); +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_lua.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_lua.c.svn-base new file mode 100644 index 0000000..bd8faf9 --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_lua.c.svn-base @@ -0,0 +1,886 @@ +/* + * 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; + 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"); + + 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(wl,channel) +LUA_WRAP_INT(wl,frequency) +LUA_WRAP_INT(wl,frequency_offset) +LUA_WRAP_INT(wl,txpower) +LUA_WRAP_INT(wl,txpower_offset) +LUA_WRAP_INT(wl,bitrate) +LUA_WRAP_INT(wl,signal) +LUA_WRAP_INT(wl,noise) +LUA_WRAP_INT(wl,quality) +LUA_WRAP_INT(wl,quality_max) +LUA_WRAP_STRING(wl,ssid) +LUA_WRAP_STRING(wl,bssid) +LUA_WRAP_STRING(wl,country) +LUA_WRAP_STRING(wl,hardware_name) +LUA_WRAP_STRUCT(wl,mode) +LUA_WRAP_STRUCT(wl,assoclist) +LUA_WRAP_STRUCT(wl,txpwrlist) +LUA_WRAP_STRUCT(wl,scanlist) +LUA_WRAP_STRUCT(wl,freqlist) +LUA_WRAP_STRUCT(wl,countrylist) +LUA_WRAP_STRUCT(wl,hwmodelist) +LUA_WRAP_STRUCT(wl,encryption) +LUA_WRAP_STRUCT(wl,mbssid_support) +LUA_WRAP_STRUCT(wl,hardware_id) +#endif + +#ifdef USE_MADWIFI +/* Madwifi */ +LUA_WRAP_INT(madwifi,channel) +LUA_WRAP_INT(madwifi,frequency) +LUA_WRAP_INT(madwifi,frequency_offset) +LUA_WRAP_INT(madwifi,txpower) +LUA_WRAP_INT(madwifi,txpower_offset) +LUA_WRAP_INT(madwifi,bitrate) +LUA_WRAP_INT(madwifi,signal) +LUA_WRAP_INT(madwifi,noise) +LUA_WRAP_INT(madwifi,quality) +LUA_WRAP_INT(madwifi,quality_max) +LUA_WRAP_STRING(madwifi,ssid) +LUA_WRAP_STRING(madwifi,bssid) +LUA_WRAP_STRING(madwifi,country) +LUA_WRAP_STRING(madwifi,hardware_name) +LUA_WRAP_STRUCT(madwifi,mode) +LUA_WRAP_STRUCT(madwifi,assoclist) +LUA_WRAP_STRUCT(madwifi,txpwrlist) +LUA_WRAP_STRUCT(madwifi,scanlist) +LUA_WRAP_STRUCT(madwifi,freqlist) +LUA_WRAP_STRUCT(madwifi,countrylist) +LUA_WRAP_STRUCT(madwifi,hwmodelist) +LUA_WRAP_STRUCT(madwifi,encryption) +LUA_WRAP_STRUCT(madwifi,mbssid_support) +LUA_WRAP_STRUCT(madwifi,hardware_id) +#endif + +#ifdef USE_NL80211 +/* NL80211 */ +LUA_WRAP_INT(nl80211,channel) +LUA_WRAP_INT(nl80211,frequency) +LUA_WRAP_INT(nl80211,frequency_offset) +LUA_WRAP_INT(nl80211,txpower) +LUA_WRAP_INT(nl80211,txpower_offset) +LUA_WRAP_INT(nl80211,bitrate) +LUA_WRAP_INT(nl80211,signal) +LUA_WRAP_INT(nl80211,noise) +LUA_WRAP_INT(nl80211,quality) +LUA_WRAP_INT(nl80211,quality_max) +LUA_WRAP_STRING(nl80211,ssid) +LUA_WRAP_STRING(nl80211,bssid) +LUA_WRAP_STRING(nl80211,country) +LUA_WRAP_STRING(nl80211,hardware_name) +LUA_WRAP_STRUCT(nl80211,mode) +LUA_WRAP_STRUCT(nl80211,assoclist) +LUA_WRAP_STRUCT(nl80211,txpwrlist) +LUA_WRAP_STRUCT(nl80211,scanlist) +LUA_WRAP_STRUCT(nl80211,freqlist) +LUA_WRAP_STRUCT(nl80211,countrylist) +LUA_WRAP_STRUCT(nl80211,hwmodelist) +LUA_WRAP_STRUCT(nl80211,encryption) +LUA_WRAP_STRUCT(nl80211,mbssid_support) +LUA_WRAP_STRUCT(nl80211,hardware_id) +#endif + +/* Wext */ +LUA_WRAP_INT(wext,channel) +LUA_WRAP_INT(wext,frequency) +LUA_WRAP_INT(wext,frequency_offset) +LUA_WRAP_INT(wext,txpower) +LUA_WRAP_INT(wext,txpower_offset) +LUA_WRAP_INT(wext,bitrate) +LUA_WRAP_INT(wext,signal) +LUA_WRAP_INT(wext,noise) +LUA_WRAP_INT(wext,quality) +LUA_WRAP_INT(wext,quality_max) +LUA_WRAP_STRING(wext,ssid) +LUA_WRAP_STRING(wext,bssid) +LUA_WRAP_STRING(wext,country) +LUA_WRAP_STRING(wext,hardware_name) +LUA_WRAP_STRUCT(wext,mode) +LUA_WRAP_STRUCT(wext,assoclist) +LUA_WRAP_STRUCT(wext,txpwrlist) +LUA_WRAP_STRUCT(wext,scanlist) +LUA_WRAP_STRUCT(wext,freqlist) +LUA_WRAP_STRUCT(wext,countrylist) +LUA_WRAP_STRUCT(wext,hwmodelist) +LUA_WRAP_STRUCT(wext,encryption) +LUA_WRAP_STRUCT(wext,mbssid_support) +LUA_WRAP_STRUCT(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), + { 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), + { 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), + { 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), + { 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_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_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_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_wext); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_setfield(L, -2, "wext"); + + return 1; +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_madwifi.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_madwifi.c.svn-base new file mode 100644 index 0000000..832f40b --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_madwifi.c.svn-base @@ -0,0 +1,1082 @@ +/* + * iwinfo - Wireless Information Library - Madwifi 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/. + * + * 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/madwifi.h" +#include "iwinfo/wext.h" + + +/* + * Madwifi ISO 3166 to Country/Region Code mapping. + */ + +static struct ISO3166_to_CCode +{ + u_int16_t iso3166; + u_int16_t ccode; +} CountryCodes[] = { + { 0x3030 /* 00 */, 0 }, /* World */ + { 0x4145 /* AE */, 784 }, /* U.A.E. */ + { 0x414C /* AL */, 8 }, /* Albania */ + { 0x414D /* AM */, 51 }, /* Armenia */ + { 0x4152 /* AR */, 32 }, /* Argentina */ + { 0x4154 /* AT */, 40 }, /* Austria */ + { 0x4155 /* AU */, 36 }, /* Australia */ + { 0x415A /* AZ */, 31 }, /* Azerbaijan */ + { 0x4245 /* BE */, 56 }, /* Belgium */ + { 0x4247 /* BG */, 100 }, /* Bulgaria */ + { 0x4248 /* BH */, 48 }, /* Bahrain */ + { 0x424E /* BN */, 96 }, /* Brunei Darussalam */ + { 0x424F /* BO */, 68 }, /* Bolivia */ + { 0x4252 /* BR */, 76 }, /* Brazil */ + { 0x4259 /* BY */, 112 }, /* Belarus */ + { 0x425A /* BZ */, 84 }, /* Belize */ + { 0x4341 /* CA */, 124 }, /* Canada */ + { 0x4348 /* CH */, 756 }, /* Switzerland */ + { 0x434C /* CL */, 152 }, /* Chile */ + { 0x434E /* CN */, 156 }, /* People's Republic of China */ + { 0x434F /* CO */, 170 }, /* Colombia */ + { 0x4352 /* CR */, 188 }, /* Costa Rica */ + { 0x4359 /* CY */, 196 }, /* Cyprus */ + { 0x435A /* CZ */, 203 }, /* Czech Republic */ + { 0x4445 /* DE */, 276 }, /* Germany */ + { 0x444B /* DK */, 208 }, /* Denmark */ + { 0x444F /* DO */, 214 }, /* Dominican Republic */ + { 0x445A /* DZ */, 12 }, /* Algeria */ + { 0x4543 /* EC */, 218 }, /* Ecuador */ + { 0x4545 /* EE */, 233 }, /* Estonia */ + { 0x4547 /* EG */, 818 }, /* Egypt */ + { 0x4553 /* ES */, 724 }, /* Spain */ + { 0x4649 /* FI */, 246 }, /* Finland */ + { 0x464F /* FO */, 234 }, /* Faeroe Islands */ + { 0x4652 /* FR */, 250 }, /* France */ + { 0x4652 /* FR */, 255 }, /* France2 */ + { 0x4742 /* GB */, 826 }, /* United Kingdom */ + { 0x4745 /* GE */, 268 }, /* Georgia */ + { 0x4752 /* GR */, 300 }, /* Greece */ + { 0x4754 /* GT */, 320 }, /* Guatemala */ + { 0x484B /* HK */, 344 }, /* Hong Kong S.A.R., P.R.C. */ + { 0x484E /* HN */, 340 }, /* Honduras */ + { 0x4852 /* HR */, 191 }, /* Croatia */ + { 0x4855 /* HU */, 348 }, /* Hungary */ + { 0x4944 /* ID */, 360 }, /* Indonesia */ + { 0x4945 /* IE */, 372 }, /* Ireland */ + { 0x494C /* IL */, 376 }, /* Israel */ + { 0x494E /* IN */, 356 }, /* India */ + { 0x4951 /* IQ */, 368 }, /* Iraq */ + { 0x4952 /* IR */, 364 }, /* Iran */ + { 0x4953 /* IS */, 352 }, /* Iceland */ + { 0x4954 /* IT */, 380 }, /* Italy */ + { 0x4A4D /* JM */, 388 }, /* Jamaica */ + { 0x4A4F /* JO */, 400 }, /* Jordan */ + { 0x4A50 /* JP */, 392 }, /* Japan */ + { 0x4A50 /* JP */, 393 }, /* Japan (JP1) */ + { 0x4A50 /* JP */, 394 }, /* Japan (JP0) */ + { 0x4A50 /* JP */, 395 }, /* Japan (JP1-1) */ + { 0x4A50 /* JP */, 396 }, /* Japan (JE1) */ + { 0x4A50 /* JP */, 397 }, /* Japan (JE2) */ + { 0x4A50 /* JP */, 399 }, /* Japan (JP6) */ + { 0x4A50 /* JP */, 900 }, /* Japan */ + { 0x4A50 /* JP */, 901 }, /* Japan */ + { 0x4A50 /* JP */, 902 }, /* Japan */ + { 0x4A50 /* JP */, 903 }, /* Japan */ + { 0x4A50 /* JP */, 904 }, /* Japan */ + { 0x4A50 /* JP */, 905 }, /* Japan */ + { 0x4A50 /* JP */, 906 }, /* Japan */ + { 0x4A50 /* JP */, 907 }, /* Japan */ + { 0x4A50 /* JP */, 908 }, /* Japan */ + { 0x4A50 /* JP */, 909 }, /* Japan */ + { 0x4A50 /* JP */, 910 }, /* Japan */ + { 0x4A50 /* JP */, 911 }, /* Japan */ + { 0x4A50 /* JP */, 912 }, /* Japan */ + { 0x4A50 /* JP */, 913 }, /* Japan */ + { 0x4A50 /* JP */, 914 }, /* Japan */ + { 0x4A50 /* JP */, 915 }, /* Japan */ + { 0x4A50 /* JP */, 916 }, /* Japan */ + { 0x4A50 /* JP */, 917 }, /* Japan */ + { 0x4A50 /* JP */, 918 }, /* Japan */ + { 0x4A50 /* JP */, 919 }, /* Japan */ + { 0x4A50 /* JP */, 920 }, /* Japan */ + { 0x4A50 /* JP */, 921 }, /* Japan */ + { 0x4A50 /* JP */, 922 }, /* Japan */ + { 0x4A50 /* JP */, 923 }, /* Japan */ + { 0x4A50 /* JP */, 924 }, /* Japan */ + { 0x4A50 /* JP */, 925 }, /* Japan */ + { 0x4A50 /* JP */, 926 }, /* Japan */ + { 0x4A50 /* JP */, 927 }, /* Japan */ + { 0x4A50 /* JP */, 928 }, /* Japan */ + { 0x4A50 /* JP */, 929 }, /* Japan */ + { 0x4A50 /* JP */, 930 }, /* Japan */ + { 0x4A50 /* JP */, 931 }, /* Japan */ + { 0x4A50 /* JP */, 932 }, /* Japan */ + { 0x4A50 /* JP */, 933 }, /* Japan */ + { 0x4A50 /* JP */, 934 }, /* Japan */ + { 0x4A50 /* JP */, 935 }, /* Japan */ + { 0x4A50 /* JP */, 936 }, /* Japan */ + { 0x4A50 /* JP */, 937 }, /* Japan */ + { 0x4A50 /* JP */, 938 }, /* Japan */ + { 0x4A50 /* JP */, 939 }, /* Japan */ + { 0x4A50 /* JP */, 940 }, /* Japan */ + { 0x4A50 /* JP */, 941 }, /* Japan */ + { 0x4B45 /* KE */, 404 }, /* Kenya */ + { 0x4B50 /* KP */, 408 }, /* North Korea */ + { 0x4B52 /* KR */, 410 }, /* South Korea */ + { 0x4B52 /* KR */, 411 }, /* South Korea */ + { 0x4B57 /* KW */, 414 }, /* Kuwait */ + { 0x4B5A /* KZ */, 398 }, /* Kazakhstan */ + { 0x4C42 /* LB */, 422 }, /* Lebanon */ + { 0x4C49 /* LI */, 438 }, /* Liechtenstein */ + { 0x4C54 /* LT */, 440 }, /* Lithuania */ + { 0x4C55 /* LU */, 442 }, /* Luxembourg */ + { 0x4C56 /* LV */, 428 }, /* Latvia */ + { 0x4C59 /* LY */, 434 }, /* Libya */ + { 0x4D41 /* MA */, 504 }, /* Morocco */ + { 0x4D43 /* MC */, 492 }, /* Principality of Monaco */ + { 0x4D4B /* MK */, 807 }, /* the Former Yugoslav Republic of Macedonia */ + { 0x4D4F /* MO */, 446 }, /* Macau */ + { 0x4D58 /* MX */, 484 }, /* Mexico */ + { 0x4D59 /* MY */, 458 }, /* Malaysia */ + { 0x4E49 /* NI */, 558 }, /* Nicaragua */ + { 0x4E4C /* NL */, 528 }, /* Netherlands */ + { 0x4E4F /* NO */, 578 }, /* Norway */ + { 0x4E5A /* NZ */, 554 }, /* New Zealand */ + { 0x4F4D /* OM */, 512 }, /* Oman */ + { 0x5041 /* PA */, 591 }, /* Panama */ + { 0x5045 /* PE */, 604 }, /* Peru */ + { 0x5048 /* PH */, 608 }, /* Republic of the Philippines */ + { 0x504B /* PK */, 586 }, /* Islamic Republic of Pakistan */ + { 0x504C /* PL */, 616 }, /* Poland */ + { 0x5052 /* PR */, 630 }, /* Puerto Rico */ + { 0x5054 /* PT */, 620 }, /* Portugal */ + { 0x5059 /* PY */, 600 }, /* Paraguay */ + { 0x5141 /* QA */, 634 }, /* Qatar */ + { 0x524F /* RO */, 642 }, /* Romania */ + { 0x5255 /* RU */, 643 }, /* Russia */ + { 0x5341 /* SA */, 682 }, /* Saudi Arabia */ + { 0x5345 /* SE */, 752 }, /* Sweden */ + { 0x5347 /* SG */, 702 }, /* Singapore */ + { 0x5349 /* SI */, 705 }, /* Slovenia */ + { 0x534B /* SK */, 703 }, /* Slovak Republic */ + { 0x5356 /* SV */, 222 }, /* El Salvador */ + { 0x5359 /* SY */, 760 }, /* Syria */ + { 0x5448 /* TH */, 764 }, /* Thailand */ + { 0x544E /* TN */, 788 }, /* Tunisia */ + { 0x5452 /* TR */, 792 }, /* Turkey */ + { 0x5454 /* TT */, 780 }, /* Trinidad y Tobago */ + { 0x5457 /* TW */, 158 }, /* Taiwan */ + { 0x5541 /* UA */, 804 }, /* Ukraine */ + { 0x554B /* UK */, 826 }, /* United Kingdom */ + { 0x5553 /* US */, 840 }, /* United States */ + { 0x5553 /* US */, 842 }, /* United States (Public Safety)*/ + { 0x5559 /* UY */, 858 }, /* Uruguay */ + { 0x555A /* UZ */, 860 }, /* Uzbekistan */ + { 0x5645 /* VE */, 862 }, /* Venezuela */ + { 0x564E /* VN */, 704 }, /* Viet Nam */ + { 0x5945 /* YE */, 887 }, /* Yemen */ + { 0x5A41 /* ZA */, 710 }, /* South Africa */ + { 0x5A57 /* ZW */, 716 }, /* Zimbabwe */ +}; + + +static const char * madwifi_phyname(const char *ifname) +{ + static char phyname[IFNAMSIZ]; + + if (strlen(ifname) > 5 && !strncmp(ifname, "radio", 5)) + snprintf(phyname, sizeof(phyname), "wifi%s", ifname + 5); + else + snprintf(phyname, sizeof(phyname), "%s", ifname); + + return (const char *)phyname; +} + +static int madwifi_wrq(struct iwreq *wrq, const char *ifname, int cmd, void *data, size_t len) +{ + strncpy(wrq->ifr_name, ifname, IFNAMSIZ); + + if( data != NULL ) + { + if( len < IFNAMSIZ ) + { + memcpy(wrq->u.name, data, len); + } + else + { + wrq->u.data.pointer = data; + wrq->u.data.length = len; + } + } + + return iwinfo_ioctl(cmd, wrq); +} + +static int get80211priv(const char *ifname, int op, void *data, size_t len) +{ + struct iwreq iwr; + + if( madwifi_wrq(&iwr, ifname, op, data, len) < 0 ) + return -1; + + return iwr.u.data.length; +} + +static char * madwifi_isvap(const char *ifname, const char *wifiname) +{ + int fd, ln; + char path[32]; + char *ret = NULL; + static char name[IFNAMSIZ]; + + if( strlen(ifname) <= 9 ) + { + sprintf(path, "/proc/sys/net/%s/%%parent", ifname); + + if( (fd = open(path, O_RDONLY)) > -1 ) + { + if( wifiname != NULL ) + { + if( read(fd, name, strlen(wifiname)) == strlen(wifiname) ) + ret = strncmp(name, wifiname, strlen(wifiname)) + ? NULL : name; + } + else if( (ln = read(fd, name, IFNAMSIZ)) >= 4 ) + { + name[ln-1] = 0; + ret = name; + } + + (void) close(fd); + } + } + + return ret; +} + +static int madwifi_iswifi(const char *ifname) +{ + int ret; + char path[32]; + struct stat s; + const char *phy; + + ret = 0; + phy = madwifi_phyname(ifname); + + if( strlen(phy) <= 7 ) + { + sprintf(path, "/proc/sys/dev/%s/diversity", phy); + + if( ! stat(path, &s) ) + ret = (s.st_mode & S_IFREG); + } + + return ret; +} + +static char * madwifi_ifadd(const char *ifname) +{ + const char *wifidev = NULL; + struct ifreq ifr = { 0 }; + struct ieee80211_clone_params cp = { 0 }; + static char nif[IFNAMSIZ] = { 0 }; + + if( !(wifidev = madwifi_isvap(ifname, NULL)) && madwifi_iswifi(ifname) ) + wifidev = madwifi_phyname(ifname); + + if( wifidev ) + { + snprintf(nif, sizeof(nif), "tmp.%s", ifname); + + strncpy(cp.icp_name, nif, IFNAMSIZ); + cp.icp_opmode = IEEE80211_M_STA; + cp.icp_flags = IEEE80211_CLONE_BSSID; + + strncpy(ifr.ifr_name, wifidev, IFNAMSIZ); + ifr.ifr_data = (void *)&cp; + + if( !iwinfo_ioctl(SIOC80211IFCREATE, &ifr) ) + { + return nif; + } + else + { + cp.icp_opmode = IEEE80211_M_MONITOR; + + if( !iwinfo_ioctl(SIOC80211IFCREATE, &ifr) ) + return nif; + } + } + + return NULL; +} + +static void madwifi_ifdel(const char *ifname) +{ + struct ifreq ifr = { 0 }; + + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + iwinfo_ioctl(SIOC80211IFDESTROY, &ifr); +} + + +int madwifi_probe(const char *ifname) +{ + return ( !!madwifi_isvap(ifname, NULL) || madwifi_iswifi(ifname) ); +} + +void madwifi_close(void) +{ + /* Nop */ +} + +int madwifi_get_mode(const char *ifname, int *buf) +{ + return wext_get_mode(ifname, buf); +} + +int madwifi_get_ssid(const char *ifname, char *buf) +{ + return wext_get_ssid(ifname, buf); +} + +int madwifi_get_bssid(const char *ifname, char *buf) +{ + return wext_get_bssid(ifname, buf); +} + +int madwifi_get_channel(const char *ifname, int *buf) +{ + int i; + uint16_t freq; + struct iwreq wrq; + struct ieee80211req_chaninfo chans; + + if( madwifi_wrq(&wrq, ifname, SIOCGIWFREQ, NULL, 0) >= 0 ) + { + /* Madwifi returns a Hz frequency, get it's freq list to find channel index */ + freq = (uint16_t)(wrq.u.freq.m / 100000); + + if( get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) >= 0 ) + { + *buf = 0; + + for( i = 0; i < chans.ic_nchans; i++ ) + { + if( freq == chans.ic_chans[i].ic_freq ) + { + *buf = chans.ic_chans[i].ic_ieee; + break; + } + } + + return 0; + } + } + + return -1; +} + +int madwifi_get_frequency(const char *ifname, int *buf) +{ + struct iwreq wrq; + + if( madwifi_wrq(&wrq, ifname, SIOCGIWFREQ, NULL, 0) >= 0 ) + { + *buf = (uint16_t)(wrq.u.freq.m / 100000); + return 0; + } + + return -1; +} + +int madwifi_get_txpower(const char *ifname, int *buf) +{ + return wext_get_txpower(ifname, buf); +} + +int madwifi_get_bitrate(const char *ifname, int *buf) +{ + unsigned int mode, len, rate, rate_count; + uint8_t tmp[24*1024]; + uint8_t *cp; + struct iwreq wrq; + struct ieee80211req_sta_info *si; + + if( madwifi_wrq(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 ) + { + mode = wrq.u.mode; + + /* Calculate bitrate average from associated stations in ad-hoc mode */ + if( mode == 1 ) + { + rate = rate_count = 0; + + if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) + { + cp = tmp; + + do { + si = (struct ieee80211req_sta_info *) cp; + + if( si->isi_rssi > 0 ) + { + rate_count++; + rate += ((si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL) / 2); + } + + cp += si->isi_len; + len -= si->isi_len; + } while (len >= sizeof(struct ieee80211req_sta_info)); + } + + *buf = (rate == 0 || rate_count == 0) ? 0 : (rate / rate_count) * 1000; + return 0; + } + + /* Return whatever wext tells us ... */ + return wext_get_bitrate(ifname, buf); + } + + return -1; +} + +int madwifi_get_signal(const char *ifname, int *buf) +{ + unsigned int mode, len, rssi, rssi_count; + uint8_t tmp[24*1024]; + uint8_t *cp; + struct iwreq wrq; + struct ieee80211req_sta_info *si; + + if( madwifi_wrq(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 ) + { + mode = wrq.u.mode; + + /* Calculate signal average from associated stations in ap or ad-hoc mode */ + if( mode == 1 ) + { + rssi = rssi_count = 0; + + if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) + { + cp = tmp; + + do { + si = (struct ieee80211req_sta_info *) cp; + + if( si->isi_rssi > 0 ) + { + rssi_count++; + rssi -= (si->isi_rssi - 95); + } + + cp += si->isi_len; + len -= si->isi_len; + } while (len >= sizeof(struct ieee80211req_sta_info)); + } + + *buf = (rssi == 0 || rssi_count == 0) ? 1 : -(rssi / rssi_count); + return 0; + } + + /* Return whatever wext tells us ... */ + return wext_get_signal(ifname, buf); + } + + return -1; +} + +int madwifi_get_noise(const char *ifname, int *buf) +{ + return wext_get_noise(ifname, buf); +} + +int madwifi_get_quality(const char *ifname, int *buf) +{ + unsigned int mode, len, quality, quality_count; + uint8_t tmp[24*1024]; + uint8_t *cp; + struct iwreq wrq; + struct ieee80211req_sta_info *si; + + if( madwifi_wrq(&wrq, ifname, SIOCGIWMODE, NULL, 0) >= 0 ) + { + mode = wrq.u.mode; + + /* Calculate signal average from associated stations in ad-hoc mode */ + if( mode == 1 ) + { + quality = quality_count = 0; + + if( (len = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) + { + cp = tmp; + + do { + si = (struct ieee80211req_sta_info *) cp; + + if( si->isi_rssi > 0 ) + { + quality_count++; + quality += si->isi_rssi; + } + + cp += si->isi_len; + len -= si->isi_len; + } while (len >= sizeof(struct ieee80211req_sta_info)); + } + + *buf = (quality == 0 || quality_count == 0) ? 0 : (quality / quality_count); + return 0; + } + + /* Return whatever wext tells us ... */ + return wext_get_quality(ifname, buf); + } + + return -1; +} + +int madwifi_get_quality_max(const char *ifname, int *buf) +{ + return wext_get_quality_max(ifname, buf); +} + +int madwifi_get_encryption(const char *ifname, char *buf) +{ + int ciphers = 0, key_len = 0; + char keybuf[IW_ENCODING_TOKEN_MAX]; + struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf; + struct iwreq wrq; + struct ieee80211req_key wk; + + memset(&wrq, 0, sizeof(wrq)); + + /* Obtain key info */ + if( madwifi_wrq(&wrq, ifname, SIOCGIWENCODE, keybuf, sizeof(keybuf)) < 0 ) + return -1; + +#if 0 + /* Have any encryption? */ + if( (wrq.u.data.flags & IW_ENCODE_DISABLED) || (wrq.u.data.length == 0) ) + return 0; +#endif + + /* Save key len */ + key_len = wrq.u.data.length; + + /* Get wpa protocol version */ + wrq.u.mode = IEEE80211_PARAM_WPA; + if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) + c->wpa_version = wrq.u.mode; + + /* Get authentication suites */ + wrq.u.mode = IEEE80211_PARAM_AUTHMODE; + if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) + { + switch(wrq.u.mode) { + case IEEE80211_AUTH_8021X: + c->auth_suites |= IWINFO_KMGMT_8021x; + break; + + case IEEE80211_AUTH_WPA: + c->auth_suites |= IWINFO_KMGMT_PSK; + break; + + case IEEE80211_AUTH_OPEN: + c->auth_algs |= IWINFO_AUTH_OPEN; + break; + + case IEEE80211_AUTH_SHARED: + c->auth_algs |= IWINFO_AUTH_SHARED; + break; + + default: + c->auth_suites |= IWINFO_KMGMT_NONE; + break; + } + } + + memset(&wk, 0, sizeof(wk)); + memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); + + /* Get key information */ + if( get80211priv(ifname, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk)) >= 0 ) + { + /* Type 0 == WEP */ + if( (wk.ik_type == 0) && (c->auth_algs == 0) ) + c->auth_algs = (IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED); + } + + /* Get used pairwise ciphers */ + wrq.u.mode = IEEE80211_PARAM_UCASTCIPHERS; + if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) + { + ciphers = wrq.u.mode; + + if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_TKIP) ) + c->pair_ciphers |= IWINFO_CIPHER_TKIP; + + if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_AES_CCM) ) + c->pair_ciphers |= IWINFO_CIPHER_CCMP; + + if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_AES_OCB) ) + c->pair_ciphers |= IWINFO_CIPHER_AESOCB; + + if( c->wpa_version && ciphers & (1 << IEEE80211_CIPHER_CKIP) ) + c->pair_ciphers |= IWINFO_CIPHER_CKIP; + + if( !c->pair_ciphers && ciphers & (1 << IEEE80211_CIPHER_WEP) ) + { + switch(key_len) { + case 13: + c->pair_ciphers |= IWINFO_CIPHER_WEP104; + break; + + case 5: + c->pair_ciphers |= IWINFO_CIPHER_WEP40; + break; + + case 0: + break; + + default: + c->pair_ciphers = IWINFO_CIPHER_WEP40 | + IWINFO_CIPHER_WEP104; + break; + } + } + + if( ciphers & (1 << IEEE80211_CIPHER_NONE) ) + c->pair_ciphers |= IWINFO_CIPHER_NONE; + } + + /* Get used group cipher */ + wrq.u.mode = IEEE80211_PARAM_MCASTCIPHER; + if( madwifi_wrq(&wrq, ifname, IEEE80211_IOCTL_GETPARAM, NULL, 0) >= 0 ) + { + ciphers = c->wpa_version ? wrq.u.mode : IEEE80211_CIPHER_WEP; + + switch(ciphers) { + case IEEE80211_CIPHER_TKIP: + c->group_ciphers |= IWINFO_CIPHER_TKIP; + break; + + case IEEE80211_CIPHER_AES_CCM: + c->group_ciphers |= IWINFO_CIPHER_CCMP; + break; + + case IEEE80211_CIPHER_AES_OCB: + c->group_ciphers |= IWINFO_CIPHER_AESOCB; + break; + + case IEEE80211_CIPHER_CKIP: + c->group_ciphers |= IWINFO_CIPHER_CKIP; + break; + + case IEEE80211_CIPHER_WEP: + switch(key_len) { + case 13: + c->group_ciphers |= IWINFO_CIPHER_WEP104; + break; + + case 5: + c->group_ciphers |= IWINFO_CIPHER_WEP40; + break; + + default: + break; + } + break; + + case IEEE80211_CIPHER_NONE: + c->group_ciphers |= IWINFO_CIPHER_NONE; + break; + + default: + break; + } + } + + c->enabled = (c->wpa_version || (c->auth_algs && c->pair_ciphers)) ? 1 : 0; + + return 0; +} + +int madwifi_get_assoclist(const char *ifname, char *buf, int *len) +{ + int bl, tl, noise; + uint8_t *cp; + uint8_t tmp[24*1024]; + struct ieee80211req_sta_info *si; + struct iwinfo_assoclist_entry entry; + + if( (tl = get80211priv(ifname, IEEE80211_IOCTL_STA_INFO, tmp, 24*1024)) > 0 ) + { + cp = tmp; + bl = 0; + + if( madwifi_get_noise(ifname, &noise) ) + noise = 0; + + do { + si = (struct ieee80211req_sta_info *) cp; + + memset(&entry, 0, sizeof(entry)); + + entry.signal = (si->isi_rssi - 95); + entry.noise = noise; + memcpy(entry.mac, &si->isi_macaddr, 6); + + entry.inactive = si->isi_inact * 1000; + + entry.tx_packets = (si->isi_txseqs[0] & IEEE80211_SEQ_SEQ_MASK) + >> IEEE80211_SEQ_SEQ_SHIFT; + + entry.rx_packets = (si->isi_rxseqs[0] & IEEE80211_SEQ_SEQ_MASK) + >> IEEE80211_SEQ_SEQ_SHIFT; + + entry.tx_rate.rate = + (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL) * 500; + + /* XXX: this is just a guess */ + entry.rx_rate.rate = entry.tx_rate.rate; + + entry.rx_rate.mcs = -1; + entry.tx_rate.mcs = -1; + + memcpy(&buf[bl], &entry, sizeof(struct iwinfo_assoclist_entry)); + + bl += sizeof(struct iwinfo_assoclist_entry); + cp += si->isi_len; + tl -= si->isi_len; + } while (tl >= sizeof(struct ieee80211req_sta_info)); + + *len = bl; + return 0; + } + + return -1; +} + +int madwifi_get_txpwrlist(const char *ifname, char *buf, int *len) +{ + int rc = -1; + char *res; + + /* A wifiX device? */ + if( madwifi_iswifi(ifname) ) + { + if( (res = madwifi_ifadd(ifname)) != NULL ) + { + rc = wext_get_txpwrlist(res, buf, len); + madwifi_ifdel(res); + } + } + + /* Its an athX ... */ + else if( !!madwifi_isvap(ifname, NULL) ) + { + rc = wext_get_txpwrlist(ifname, buf, len); + } + + return rc; +} + +int madwifi_get_scanlist(const char *ifname, char *buf, int *len) +{ + int ret; + char *res; + DIR *proc; + struct dirent *e; + + ret = -1; + + /* We got a wifiX device passed, try to lookup a vap on it */ + if( madwifi_iswifi(ifname) ) + { + if( (proc = opendir("/proc/sys/net/")) != NULL ) + { + while( (e = readdir(proc)) != NULL ) + { + if( !!madwifi_isvap(e->d_name, ifname) ) + { + if( iwinfo_ifup(e->d_name) ) + { + ret = wext_get_scanlist(e->d_name, buf, len); + break; + } + } + } + + closedir(proc); + } + + /* Still nothing found, try to create a vap */ + if( ret == -1 ) + { + if( (res = madwifi_ifadd(ifname)) != NULL ) + { + if( iwinfo_ifup(res) ) + { + wext_get_scanlist(res, buf, len); + sleep(1); + + wext_get_scanlist(res, buf, len); + sleep(1); + + ret = wext_get_scanlist(res, buf, len); + } + + iwinfo_ifdown(res); + madwifi_ifdel(res); + } + } + } + + /* Got athX device? */ + else if( !!madwifi_isvap(ifname, NULL) ) + { + ret = wext_get_scanlist(ifname, buf, len); + } + + return ret; +} + +int madwifi_get_freqlist(const char *ifname, char *buf, int *len) +{ + int i, bl; + int rc = -1; + char *res; + struct ieee80211req_chaninfo chans; + struct iwinfo_freqlist_entry entry; + + /* A wifiX device? */ + if( madwifi_iswifi(ifname) ) + { + if( (res = madwifi_ifadd(ifname)) != NULL ) + { + rc = get80211priv(res, IEEE80211_IOCTL_GETCHANINFO, + &chans, sizeof(chans)); + + madwifi_ifdel(res); + } + } + + /* Its an athX ... */ + else if( !!madwifi_isvap(ifname, NULL) ) + { + rc = get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, + &chans, sizeof(chans)); + } + + + /* Got chaninfo? */ + if( rc >= 0 ) + { + bl = 0; + + for( i = 0; i < chans.ic_nchans; i++ ) + { + entry.mhz = chans.ic_chans[i].ic_freq; + entry.channel = chans.ic_chans[i].ic_ieee; + entry.restricted = 0; + + memcpy(&buf[bl], &entry, sizeof(struct iwinfo_freqlist_entry)); + bl += sizeof(struct iwinfo_freqlist_entry); + } + + *len = bl; + return 0; + } + + return -1; +} + +int madwifi_get_country(const char *ifname, char *buf) +{ + int i, fd, ccode = -1; + char buffer[34]; + char *wifi = madwifi_iswifi(ifname) + ? (char *)ifname : madwifi_isvap(ifname, NULL); + + struct ISO3166_to_CCode *e; + + if( wifi ) + { + snprintf(buffer, sizeof(buffer), "/proc/sys/dev/%s/countrycode", wifi); + + if( (fd = open(buffer, O_RDONLY)) > -1 ) + { + memset(buffer, 0, sizeof(buffer)); + + if( read(fd, buffer, sizeof(buffer)-1) > 0 ) + ccode = atoi(buffer); + + close(fd); + } + } + + for( i = 0; i < (sizeof(CountryCodes)/sizeof(CountryCodes[0])); i++ ) + { + e = &CountryCodes[i]; + + if( e->ccode == ccode ) + { + sprintf(buf, "%c%c", e->iso3166 / 256, e->iso3166 % 256); + return 0; + } + } + + return -1; +} + +int madwifi_get_countrylist(const char *ifname, char *buf, int *len) +{ + int i, count; + struct ISO3166_to_CCode *e, *p = NULL; + struct iwinfo_country_entry *c = (struct iwinfo_country_entry *)buf; + + count = 0; + + for( int i = 0; i < (sizeof(CountryCodes)/sizeof(CountryCodes[0])); i++ ) + { + e = &CountryCodes[i]; + + if( !p || (e->iso3166 != p->iso3166) ) + { + c->iso3166 = e->iso3166; + snprintf(c->ccode, sizeof(c->ccode), "%i", e->ccode); + + c++; + count++; + } + + p = e; + } + + *len = (count * sizeof(struct iwinfo_country_entry)); + return 0; +} + +int madwifi_get_hwmodelist(const char *ifname, int *buf) +{ + char chans[IWINFO_BUFSIZE] = { 0 }; + struct iwinfo_freqlist_entry *e = NULL; + int len = 0; + + if( !madwifi_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; +} + +int madwifi_get_mbssid_support(const char *ifname, int *buf) +{ + /* Test whether we can create another interface */ + char *nif = madwifi_ifadd(ifname); + + if( nif ) + { + *buf = iwinfo_ifup(nif); + + iwinfo_ifdown(nif); + madwifi_ifdel(nif); + + return 0; + } + + return -1; +} + +int madwifi_get_hardware_id(const char *ifname, char *buf) +{ + char vendor[64]; + char device[64]; + struct iwinfo_hardware_id *ids; + struct iwinfo_hardware_entry *e; + const char *phy = madwifi_phyname(ifname); + + if (wext_get_hardware_id(phy, buf)) + return iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id *)buf); + + return 0; +} + +static const struct iwinfo_hardware_entry * +madwifi_get_hardware_entry(const char *ifname) +{ + struct iwinfo_hardware_id id; + + if (madwifi_get_hardware_id(ifname, (char *)&id)) + return NULL; + + return iwinfo_hardware(&id); +} + +int madwifi_get_hardware_name(const char *ifname, char *buf) +{ + const struct iwinfo_hardware_entry *hw; + + if (!(hw = madwifi_get_hardware_entry(ifname))) + sprintf(buf, "Generic Atheros"); + else + sprintf(buf, "%s %s", hw->vendor_name, hw->device_name); + + return 0; +} + +int madwifi_get_txpower_offset(const char *ifname, int *buf) +{ + const struct iwinfo_hardware_entry *hw; + + if (!(hw = madwifi_get_hardware_entry(ifname))) + return -1; + + *buf = hw->txpower_offset; + return 0; +} + +int madwifi_get_frequency_offset(const char *ifname, int *buf) +{ + const struct iwinfo_hardware_entry *hw; + + if (!(hw = madwifi_get_hardware_entry(ifname))) + return -1; + + *buf = hw->frequency_offset; + return 0; +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_nl80211.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_nl80211.c.svn-base new file mode 100644 index 0000000..819845a --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_nl80211.c.svn-base @@ -0,0 +1,2246 @@ +/* + * iwinfo - Wireless Information Library - NL80211 Backend + * + * Copyright (C) 2010-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/. + * + * 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. + * + * Parts of this code are derived from the Linux iw utility. + */ + +#include "iwinfo/nl80211.h" +#include "iwinfo/wext.h" + +#define min(x, y) ((x) < (y)) ? (x) : (y) + +static struct nl80211_state *nls = NULL; + +static int nl80211_init(void) +{ + int err, fd; + + if (!nls) + { + nls = malloc(sizeof(struct nl80211_state)); + if (!nls) { + err = -ENOMEM; + goto err; + } + + memset(nls, 0, sizeof(*nls)); + + nls->nl_sock = nl_socket_alloc(); + if (!nls->nl_sock) { + err = -ENOMEM; + goto err; + } + + if (genl_connect(nls->nl_sock)) { + err = -ENOLINK; + goto err; + } + + fd = nl_socket_get_fd(nls->nl_sock); + if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) { + err = -EINVAL; + goto err; + } + + if (genl_ctrl_alloc_cache(nls->nl_sock, &nls->nl_cache)) { + err = -ENOMEM; + goto err; + } + + nls->nl80211 = genl_ctrl_search_by_name(nls->nl_cache, "nl80211"); + if (!nls->nl80211) { + err = -ENOENT; + goto err; + } + + nls->nlctrl = genl_ctrl_search_by_name(nls->nl_cache, "nlctrl"); + if (!nls->nlctrl) { + err = -ENOENT; + goto err; + } + } + + return 0; + + +err: + nl80211_close(); + return err; +} + + +static int nl80211_msg_error(struct sockaddr_nl *nla, + struct nlmsgerr *err, void *arg) +{ + int *ret = arg; + *ret = err->error; + return NL_STOP; +} + +static int nl80211_msg_finish(struct nl_msg *msg, void *arg) +{ + int *ret = arg; + *ret = 0; + return NL_SKIP; +} + +static int nl80211_msg_ack(struct nl_msg *msg, void *arg) +{ + int *ret = arg; + *ret = 0; + return NL_STOP; +} + +static int nl80211_msg_response(struct nl_msg *msg, void *arg) +{ + return NL_SKIP; +} + +static void nl80211_free(struct nl80211_msg_conveyor *cv) +{ + if (cv) + { + if (cv->cb) + nl_cb_put(cv->cb); + + if (cv->msg) + nlmsg_free(cv->msg); + + cv->cb = NULL; + cv->msg = NULL; + } +} + +static struct nl80211_msg_conveyor * nl80211_new(struct genl_family *family, + int cmd, int flags) +{ + static struct nl80211_msg_conveyor cv; + + struct nl_msg *req = NULL; + struct nl_cb *cb = NULL; + + req = nlmsg_alloc(); + if (!req) + goto err; + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + goto err; + + genlmsg_put(req, 0, 0, genl_family_get_id(family), 0, flags, cmd, 0); + + cv.msg = req; + cv.cb = cb; + + return &cv; + +err: +nla_put_failure: + if (cb) + nl_cb_put(cb); + + if (req) + nlmsg_free(req); + + return NULL; +} + +static struct nl80211_msg_conveyor * nl80211_ctl(int cmd, int flags) +{ + if (nl80211_init() < 0) + return NULL; + + return nl80211_new(nls->nlctrl, cmd, flags); +} + +static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname, + int cmd, int flags) +{ + int ifidx = -1, phyidx = -1; + struct nl80211_msg_conveyor *cv; + + if (nl80211_init() < 0) + return NULL; + + if (!strncmp(ifname, "phy", 3)) + phyidx = atoi(&ifname[3]); + else if (!strncmp(ifname, "radio", 5)) + phyidx = atoi(&ifname[5]); + else if (!strncmp(ifname, "mon.", 4)) + ifidx = if_nametoindex(&ifname[4]); + else + ifidx = if_nametoindex(ifname); + + if ((ifidx < 0) && (phyidx < 0)) + return NULL; + + cv = nl80211_new(nls->nl80211, cmd, flags); + if (!cv) + return NULL; + + if (ifidx > -1) + NLA_PUT_U32(cv->msg, NL80211_ATTR_IFINDEX, ifidx); + + if (phyidx > -1) + NLA_PUT_U32(cv->msg, NL80211_ATTR_WIPHY, phyidx); + + return cv; + +nla_put_failure: + nl80211_free(cv); + return NULL; +} + +static struct nl80211_msg_conveyor * nl80211_send( + struct nl80211_msg_conveyor *cv, + int (*cb_func)(struct nl_msg *, void *), void *cb_arg +) { + static struct nl80211_msg_conveyor rcv; + int err = 1; + + if (cb_func) + nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, cb_func, cb_arg); + else + nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_msg_response, &rcv); + + if (nl_send_auto_complete(nls->nl_sock, cv->msg) < 0) + goto err; + + nl_cb_err(cv->cb, NL_CB_CUSTOM, nl80211_msg_error, &err); + nl_cb_set(cv->cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_msg_finish, &err); + nl_cb_set(cv->cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_msg_ack, &err); + + while (err > 0) + nl_recvmsgs(nls->nl_sock, cv->cb); + + return &rcv; + +err: + nl_cb_put(cv->cb); + nlmsg_free(cv->msg); + + return NULL; +} + +static struct nlattr ** nl80211_parse(struct nl_msg *msg) +{ + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + static struct nlattr *attr[NL80211_ATTR_MAX + 1]; + + nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + return attr; +} + + +static int nl80211_subscribe_cb(struct nl_msg *msg, void *arg) +{ + struct nl80211_group_conveyor *cv = arg; + + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *mgrpinfo[CTRL_ATTR_MCAST_GRP_MAX + 1]; + struct nlattr *mgrp; + int mgrpidx; + + if (!attr[CTRL_ATTR_MCAST_GROUPS]) + return NL_SKIP; + + nla_for_each_nested(mgrp, attr[CTRL_ATTR_MCAST_GROUPS], mgrpidx) + { + nla_parse(mgrpinfo, CTRL_ATTR_MCAST_GRP_MAX, + nla_data(mgrp), nla_len(mgrp), NULL); + + if (mgrpinfo[CTRL_ATTR_MCAST_GRP_ID] && + mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME] && + !strncmp(nla_data(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME]), + cv->name, nla_len(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME]))) + { + cv->id = nla_get_u32(mgrpinfo[CTRL_ATTR_MCAST_GRP_ID]); + break; + } + } + + return NL_SKIP; +} + +static int nl80211_subscribe(const char *family, const char *group) +{ + struct nl80211_group_conveyor cv = { .name = group, .id = -ENOENT }; + struct nl80211_msg_conveyor *req; + + req = nl80211_ctl(CTRL_CMD_GETFAMILY, 0); + if (req) + { + NLA_PUT_STRING(req->msg, CTRL_ATTR_FAMILY_NAME, family); + nl80211_send(req, nl80211_subscribe_cb, &cv); + +nla_put_failure: + nl80211_free(req); + } + + return nl_socket_add_membership(nls->nl_sock, cv.id); +} + + +static int nl80211_wait_cb(struct nl_msg *msg, void *arg) +{ + struct nl80211_event_conveyor *cv = arg; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + + if (gnlh->cmd == cv->wait) + cv->recv = gnlh->cmd; + + return NL_SKIP; +} + +static int nl80211_wait_seq_check(struct nl_msg *msg, void *arg) +{ + return NL_OK; +} + +static int nl80211_wait(const char *family, const char *group, int cmd) +{ + struct nl80211_event_conveyor cv = { .wait = cmd }; + struct nl_cb *cb; + + if (nl80211_subscribe(family, group)) + return -ENOENT; + + cb = nl_cb_alloc(NL_CB_DEFAULT); + + if (!cb) + return -ENOMEM; + + nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_wait_seq_check, NULL); + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wait_cb, &cv ); + + while (!cv.recv) + nl_recvmsgs(nls->nl_sock, cb); + + nl_cb_put(cb); + + return 0; +} + + +static int nl80211_freq2channel(int freq) +{ + if (freq == 2484) + return 14; + + if (freq < 2484) + return (freq - 2407) / 5; + + return (freq / 5) - 1000; +} + +static int nl80211_channel2freq(int channel, const char *band) +{ + if (channel == 14) + return 2484; + + if ((channel < 14) && (!band || band[0] != 'a')) + return (channel * 5) + 2407; + + if (channel > 0) + return (1000 + channel) * 5; + + return 0; +} + +static char * nl80211_getval(const char *ifname, const char *buf, const char *key) +{ + int i, len; + char lkey[64] = { 0 }; + const char *ln = buf; + static char lval[256] = { 0 }; + + int matched_if = ifname ? 0 : 1; + + + for( i = 0, len = strlen(buf); i < len; i++ ) + { + if (!lkey[0] && (buf[i] == ' ' || buf[i] == '\t')) + { + ln++; + } + else if (!lkey[0] && (buf[i] == '=')) + { + if ((&buf[i] - ln) > 0) + memcpy(lkey, ln, min(sizeof(lkey) - 1, &buf[i] - ln)); + } + else if (buf[i] == '\n') + { + if (lkey[0]) + { + memcpy(lval, ln + strlen(lkey) + 1, + min(sizeof(lval) - 1, &buf[i] - ln - strlen(lkey) - 1)); + + if ((ifname != NULL) && + (!strcmp(lkey, "interface") || !strcmp(lkey, "bss")) ) + { + matched_if = !strcmp(lval, ifname); + } + else if (matched_if && !strcmp(lkey, key)) + { + return lval; + } + } + + ln = &buf[i+1]; + memset(lkey, 0, sizeof(lkey)); + memset(lval, 0, sizeof(lval)); + } + } + + return NULL; +} + +static int nl80211_ifname2phy_cb(struct nl_msg *msg, void *arg) +{ + char *buf = arg; + struct nlattr **attr = nl80211_parse(msg); + + if (attr[NL80211_ATTR_WIPHY_NAME]) + memcpy(buf, nla_data(attr[NL80211_ATTR_WIPHY_NAME]), + nla_len(attr[NL80211_ATTR_WIPHY_NAME])); + else + buf[0] = 0; + + return NL_SKIP; +} + +static char * nl80211_ifname2phy(const char *ifname) +{ + static char phy[32] = { 0 }; + struct nl80211_msg_conveyor *req; + + memset(phy, 0, sizeof(phy)); + + req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0); + if (req) + { + nl80211_send(req, nl80211_ifname2phy_cb, phy); + nl80211_free(req); + } + + return phy[0] ? phy : NULL; +} + +static char * nl80211_hostapd_info(const char *ifname) +{ + int mode; + char *phy; + char path[32] = { 0 }; + static char buf[4096] = { 0 }; + FILE *conf; + + if (nl80211_get_mode(ifname, &mode)) + return NULL; + + if ((mode == IWINFO_OPMODE_MASTER || mode == IWINFO_OPMODE_AP_VLAN) && + (phy = nl80211_ifname2phy(ifname)) != NULL) + { + snprintf(path, sizeof(path), "/var/run/hostapd-%s.conf", phy); + + if ((conf = fopen(path, "r")) != NULL) + { + fread(buf, sizeof(buf) - 1, 1, conf); + fclose(conf); + + return buf; + } + } + + return NULL; +} + +static inline int nl80211_wpactl_recv(int sock, char *buf, int blen) +{ + fd_set rfds; + struct timeval tv = { 2, 0 }; + + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + + memset(buf, 0, blen); + + + if (select(sock + 1, &rfds, NULL, NULL, &tv) < 0) + return -1; + + if (!FD_ISSET(sock, &rfds)) + return -1; + + return recv(sock, buf, blen, 0); +} + +static char * nl80211_wpactl_info(const char *ifname, const char *cmd, + const char *event) +{ + int numtry = 0; + int sock = -1; + char *rv = NULL; + size_t remote_length, local_length; + static char buffer[10240] = { 0 }; + + struct sockaddr_un local = { 0 }; + struct sockaddr_un remote = { 0 }; + + + sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if (sock < 0) + return NULL; + + remote.sun_family = AF_UNIX; + remote_length = sizeof(remote.sun_family) + sprintf(remote.sun_path, + "/var/run/wpa_supplicant-%s/%s", ifname, ifname); + + if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC) < 0) + goto out; + + if (connect(sock, (struct sockaddr *) &remote, remote_length)) + goto out; + + local.sun_family = AF_UNIX; + local_length = sizeof(local.sun_family) + + sprintf(local.sun_path, "/var/run/iwinfo-%s-%d", ifname, getpid()); + + if (bind(sock, (struct sockaddr *) &local, local_length)) + goto out; + + + if (event) + { + send(sock, "ATTACH", 6, 0); + + if (nl80211_wpactl_recv(sock, buffer, sizeof(buffer)) <= 0) + goto out; + } + + + send(sock, cmd, strlen(cmd), 0); + + while( numtry++ < 5 ) + { + if (nl80211_wpactl_recv(sock, buffer, sizeof(buffer)) <= 0) + { + if (event) + continue; + + break; + } + + if ((!event && buffer[0] != '<') || (event && strstr(buffer, event))) + break; + } + + rv = buffer; + +out: + close(sock); + + if (local.sun_family) + unlink(local.sun_path); + + return rv; +} + +static inline int nl80211_readint(const char *path) +{ + int fd; + int rv = -1; + char buffer[16]; + + if ((fd = open(path, O_RDONLY)) > -1) + { + if (read(fd, buffer, sizeof(buffer)) > 0) + rv = atoi(buffer); + + close(fd); + } + + return rv; +} + +static char * nl80211_phy2ifname(const char *ifname) +{ + int fd, ifidx = -1, cifidx = -1, phyidx = -1; + char buffer[64]; + static char nif[IFNAMSIZ] = { 0 }; + + DIR *d; + struct dirent *e; + + if (!ifname) + return NULL; + else if (!strncmp(ifname, "phy", 3)) + phyidx = atoi(&ifname[3]); + else if (!strncmp(ifname, "radio", 5)) + phyidx = atoi(&ifname[5]); + + memset(nif, 0, sizeof(nif)); + + if (phyidx > -1) + { + if ((d = opendir("/sys/class/net")) != NULL) + { + while ((e = readdir(d)) != NULL) + { + snprintf(buffer, sizeof(buffer), + "/sys/class/net/%s/phy80211/index", e->d_name); + + if (nl80211_readint(buffer) == phyidx) + { + snprintf(buffer, sizeof(buffer), + "/sys/class/net/%s/ifindex", e->d_name); + + if ((cifidx = nl80211_readint(buffer)) >= 0 && + ((ifidx < 0) || (cifidx < ifidx))) + { + ifidx = cifidx; + strncpy(nif, e->d_name, sizeof(nif)); + } + } + } + + closedir(d); + } + } + + return nif[0] ? nif : NULL; +} + +static char * nl80211_ifadd(const char *ifname) +{ + int phyidx; + char *rv = NULL; + static char nif[IFNAMSIZ] = { 0 }; + struct nl80211_msg_conveyor *req, *res; + + req = nl80211_msg(ifname, NL80211_CMD_NEW_INTERFACE, 0); + if (req) + { + snprintf(nif, sizeof(nif), "tmp.%s", ifname); + + NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, nif); + NLA_PUT_U32(req->msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION); + + nl80211_send(req, NULL, NULL); + + rv = nif; + + nla_put_failure: + nl80211_free(req); + } + + return rv; +} + +static void nl80211_ifdel(const char *ifname) +{ + struct nl80211_msg_conveyor *req; + + req = nl80211_msg(ifname, NL80211_CMD_DEL_INTERFACE, 0); + if (req) + { + NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, ifname); + + nl80211_send(req, NULL, NULL); + + nla_put_failure: + nl80211_free(req); + } +} + +static void nl80211_hostapd_hup(const char *ifname) +{ + int fd, pid = 0; + char buf[32]; + char *phy = nl80211_ifname2phy(ifname); + + if (phy) + { + snprintf(buf, sizeof(buf), "/var/run/wifi-%s.pid", phy); + if ((fd = open(buf, O_RDONLY)) > 0) + { + if (read(fd, buf, sizeof(buf)) > 0) + pid = atoi(buf); + + close(fd); + } + + if (pid > 0) + kill(pid, 1); + } +} + + +int nl80211_probe(const char *ifname) +{ + return !!nl80211_ifname2phy(ifname); +} + +void nl80211_close(void) +{ + if (nls) + { + if (nls->nlctrl) + genl_family_put(nls->nlctrl); + + if (nls->nl80211) + genl_family_put(nls->nl80211); + + if (nls->nl_sock) + nl_socket_free(nls->nl_sock); + + if (nls->nl_cache) + nl_cache_free(nls->nl_cache); + + free(nls); + nls = NULL; + } +} + + +static int nl80211_get_mode_cb(struct nl_msg *msg, void *arg) +{ + int *mode = arg; + struct nlattr **tb = nl80211_parse(msg); + const int ifmodes[NL80211_IFTYPE_MAX + 1] = { + IWINFO_OPMODE_UNKNOWN, /* unspecified */ + IWINFO_OPMODE_ADHOC, /* IBSS */ + IWINFO_OPMODE_CLIENT, /* managed */ + IWINFO_OPMODE_MASTER, /* AP */ + IWINFO_OPMODE_AP_VLAN, /* AP/VLAN */ + IWINFO_OPMODE_WDS, /* WDS */ + IWINFO_OPMODE_MONITOR, /* monitor */ + IWINFO_OPMODE_MESHPOINT, /* mesh point */ + IWINFO_OPMODE_P2P_CLIENT, /* P2P-client */ + IWINFO_OPMODE_P2P_GO, /* P2P-GO */ + }; + + if (tb[NL80211_ATTR_IFTYPE]) + *mode = ifmodes[nla_get_u32(tb[NL80211_ATTR_IFTYPE])]; + + return NL_SKIP; +} + +int nl80211_get_mode(const char *ifname, int *buf) +{ + char *res; + struct nl80211_msg_conveyor *req; + + res = nl80211_phy2ifname(ifname); + req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0); + *buf = IWINFO_OPMODE_UNKNOWN; + + if (req) + { + nl80211_send(req, nl80211_get_mode_cb, buf); + nl80211_free(req); + } + + return (*buf == IWINFO_OPMODE_UNKNOWN) ? -1 : 0; +} + + +struct nl80211_ssid_bssid { + unsigned char *ssid; + unsigned char bssid[7]; +}; + +static int nl80211_get_ssid_bssid_cb(struct nl_msg *msg, void *arg) +{ + int ielen; + unsigned char *ie; + struct nl80211_ssid_bssid *sb = arg; + struct nlattr **tb = nl80211_parse(msg); + struct nlattr *bss[NL80211_BSS_MAX + 1]; + + static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { + [NL80211_BSS_INFORMATION_ELEMENTS] = { }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + }; + + if (!tb[NL80211_ATTR_BSS] || + nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], + bss_policy) || + !bss[NL80211_BSS_BSSID] || + !bss[NL80211_BSS_STATUS] || + !bss[NL80211_BSS_INFORMATION_ELEMENTS]) + { + return NL_SKIP; + } + + switch (nla_get_u32(bss[NL80211_BSS_STATUS])) + { + case NL80211_BSS_STATUS_ASSOCIATED: + case NL80211_BSS_STATUS_AUTHENTICATED: + case NL80211_BSS_STATUS_IBSS_JOINED: + + if (sb->ssid) + { + ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + ielen = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + + while (ielen >= 2 && ielen >= ie[1]) + { + if (ie[0] == 0) + { + memcpy(sb->ssid, ie + 2, min(ie[1], IWINFO_ESSID_MAX_SIZE)); + return NL_SKIP; + } + + ielen -= ie[1] + 2; + ie += ie[1] + 2; + } + } + else + { + sb->bssid[0] = 1; + memcpy(sb->bssid + 1, nla_data(bss[NL80211_BSS_BSSID]), 6); + return NL_SKIP; + } + + default: + return NL_SKIP; + } +} + +int nl80211_get_ssid(const char *ifname, char *buf) +{ + char *res; + struct nl80211_msg_conveyor *req; + struct nl80211_ssid_bssid sb; + + /* try to find ssid from scan dump results */ + res = nl80211_phy2ifname(ifname); + req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP); + + sb.ssid = buf; + *buf = 0; + + if (req) + { + nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb); + nl80211_free(req); + } + + /* failed, try to find from hostapd info */ + if ((*buf == 0) && + (res = nl80211_hostapd_info(ifname)) && + (res = nl80211_getval(ifname, res, "ssid"))) + { + memcpy(buf, res, strlen(res)); + } + + return (*buf == 0) ? -1 : 0; +} + +int nl80211_get_bssid(const char *ifname, char *buf) +{ + char *res; + struct nl80211_msg_conveyor *req; + struct nl80211_ssid_bssid sb; + + /* try to find bssid from scan dump results */ + res = nl80211_phy2ifname(ifname); + req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP); + + sb.ssid = NULL; + sb.bssid[0] = 0; + + if (req) + { + nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb); + nl80211_free(req); + } + + /* failed, try to find mac from hostapd info */ + if ((sb.bssid[0] == 0) && + (res = nl80211_hostapd_info(ifname)) && + (res = nl80211_getval(ifname, res, "bssid"))) + { + sb.bssid[0] = 1; + sb.bssid[1] = strtol(&res[0], NULL, 16); + sb.bssid[2] = strtol(&res[3], NULL, 16); + sb.bssid[3] = strtol(&res[6], NULL, 16); + sb.bssid[4] = strtol(&res[9], NULL, 16); + sb.bssid[5] = strtol(&res[12], NULL, 16); + sb.bssid[6] = strtol(&res[15], NULL, 16); + } + + if (sb.bssid[0]) + { + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + sb.bssid[1], sb.bssid[2], sb.bssid[3], + sb.bssid[4], sb.bssid[5], sb.bssid[6]); + + return 0; + } + + return -1; +} + + +static int nl80211_get_frequency_scan_cb(struct nl_msg *msg, void *arg) +{ + int *freq = arg; + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *binfo[NL80211_BSS_MAX + 1]; + + static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { + [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + }; + + if (attr[NL80211_ATTR_BSS] && + !nla_parse_nested(binfo, NL80211_BSS_MAX, + attr[NL80211_ATTR_BSS], bss_policy)) + { + if (binfo[NL80211_BSS_FREQUENCY]) + *freq = nla_get_u32(binfo[NL80211_BSS_FREQUENCY]); + } + + return NL_SKIP; +} + +static int nl80211_get_frequency_info_cb(struct nl_msg *msg, void *arg) +{ + int *freq = arg; + struct nlattr **tb = nl80211_parse(msg); + + if (tb[NL80211_ATTR_WIPHY_FREQ]) + *freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + + return NL_SKIP; +} + +int nl80211_get_frequency(const char *ifname, int *buf) +{ + char *res, *channel; + struct nl80211_msg_conveyor *req; + + /* try to find frequency from interface info */ + res = nl80211_phy2ifname(ifname); + req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0); + *buf = 0; + + if (req) + { + nl80211_send(req, nl80211_get_frequency_info_cb, buf); + nl80211_free(req); + } + + /* failed, try to find frequency from hostapd info */ + if ((*buf == 0) && + (res = nl80211_hostapd_info(ifname)) && + (channel = nl80211_getval(NULL, res, "channel"))) + { + *buf = nl80211_channel2freq(atoi(channel), + nl80211_getval(NULL, res, "hw_mode")); + } + else + { + /* failed, try to find frequency from scan results */ + if (*buf == 0) + { + res = nl80211_phy2ifname(ifname); + req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, + NLM_F_DUMP); + + if (req) + { + nl80211_send(req, nl80211_get_frequency_scan_cb, buf); + nl80211_free(req); + } + } + } + + return (*buf == 0) ? -1 : 0; +} + +int nl80211_get_channel(const char *ifname, int *buf) +{ + if (!nl80211_get_frequency(ifname, buf)) + { + *buf = nl80211_freq2channel(*buf); + return 0; + } + + return -1; +} + + +int nl80211_get_txpower(const char *ifname, int *buf) +{ +#if 0 + char *res; + char path[PATH_MAX]; + + res = nl80211_ifname2phy(ifname); + snprintf(path, sizeof(path), "/sys/kernel/debug/ieee80211/%s/power", + res ? res : ifname); + + if ((*buf = nl80211_readint(path)) > -1) + return 0; +#endif + + return wext_get_txpower(ifname, buf); +} + + +static int nl80211_fill_signal_cb(struct nl_msg *msg, void *arg) +{ + int8_t dbm; + int16_t mbit; + struct nl80211_rssi_rate *rr = arg; + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; + struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; + + static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { + [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, + }; + + static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, + }; + + if (attr[NL80211_ATTR_STA_INFO]) + { + if (!nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, + attr[NL80211_ATTR_STA_INFO], stats_policy)) + { + if (sinfo[NL80211_STA_INFO_SIGNAL]) + { + dbm = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); + rr->rssi = rr->rssi ? (int8_t)((rr->rssi + dbm) / 2) : dbm; + } + + if (sinfo[NL80211_STA_INFO_TX_BITRATE]) + { + if (!nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, + sinfo[NL80211_STA_INFO_TX_BITRATE], + rate_policy)) + { + if (rinfo[NL80211_RATE_INFO_BITRATE]) + { + mbit = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]); + rr->rate = rr->rate + ? (int16_t)((rr->rate + mbit) / 2) : mbit; + } + } + } + } + } + + return NL_SKIP; +} + +static void nl80211_fill_signal(const char *ifname, struct nl80211_rssi_rate *r) +{ + DIR *d; + struct dirent *de; + struct nl80211_msg_conveyor *req; + + r->rssi = 0; + r->rate = 0; + + if ((d = opendir("/sys/class/net")) != NULL) + { + while ((de = readdir(d)) != NULL) + { + if (!strncmp(de->d_name, ifname, strlen(ifname)) && + (!de->d_name[strlen(ifname)] || + !strncmp(&de->d_name[strlen(ifname)], ".sta", 4))) + { + req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION, + NLM_F_DUMP); + + if (req) + { + nl80211_send(req, nl80211_fill_signal_cb, r); + nl80211_free(req); + } + } + } + + closedir(d); + } +} + +int nl80211_get_bitrate(const char *ifname, int *buf) +{ + struct nl80211_rssi_rate rr; + + nl80211_fill_signal(ifname, &rr); + + if (rr.rate) + { + *buf = (rr.rate * 100); + return 0; + } + + return -1; +} + +int nl80211_get_signal(const char *ifname, int *buf) +{ + struct nl80211_rssi_rate rr; + + nl80211_fill_signal(ifname, &rr); + + if (rr.rssi) + { + *buf = rr.rssi; + return 0; + } + + return -1; +} + +static int nl80211_get_noise_cb(struct nl_msg *msg, void *arg) +{ + int8_t *noise = arg; + struct nlattr **tb = nl80211_parse(msg); + struct nlattr *si[NL80211_SURVEY_INFO_MAX + 1]; + + static struct nla_policy sp[NL80211_SURVEY_INFO_MAX + 1] = { + [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 }, + }; + + if (!tb[NL80211_ATTR_SURVEY_INFO]) + return NL_SKIP; + + if (nla_parse_nested(si, NL80211_SURVEY_INFO_MAX, + tb[NL80211_ATTR_SURVEY_INFO], sp)) + return NL_SKIP; + + if (!si[NL80211_SURVEY_INFO_NOISE]) + return NL_SKIP; + + if (!*noise || si[NL80211_SURVEY_INFO_IN_USE]) + *noise = (int8_t)nla_get_u8(si[NL80211_SURVEY_INFO_NOISE]); + + return NL_SKIP; +} + + +int nl80211_get_noise(const char *ifname, int *buf) +{ + int8_t noise; + struct nl80211_msg_conveyor *req; + + req = nl80211_msg(ifname, NL80211_CMD_GET_SURVEY, NLM_F_DUMP); + if (req) + { + noise = 0; + + nl80211_send(req, nl80211_get_noise_cb, &noise); + nl80211_free(req); + + if (noise) + { + *buf = noise; + return 0; + } + } + + return -1; +} + +int nl80211_get_quality(const char *ifname, int *buf) +{ + int signal; + + if (!nl80211_get_signal(ifname, &signal)) + { + /* A positive signal level is usually just a quality + * value, pass through as-is */ + if (signal >= 0) + { + *buf = signal; + } + + /* The cfg80211 wext compat layer assumes a signal range + * of -110 dBm to -40 dBm, the quality value is derived + * by adding 110 to the signal level */ + else + { + if (signal < -110) + signal = -110; + else if (signal > -40) + signal = -40; + + *buf = (signal + 110); + } + + return 0; + } + + return -1; +} + +int nl80211_get_quality_max(const char *ifname, int *buf) +{ + /* The cfg80211 wext compat layer assumes a maximum + * quality of 70 */ + *buf = 70; + + return 0; +} + +int nl80211_get_encryption(const char *ifname, char *buf) +{ + int i; + char k[9]; + char *val, *res; + struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf; + + /* WPA supplicant */ + if ((res = nl80211_wpactl_info(ifname, "STATUS", NULL)) && + (val = nl80211_getval(NULL, res, "pairwise_cipher"))) + { + /* WEP */ + if (strstr(val, "WEP")) + { + if (strstr(val, "WEP-40")) + c->pair_ciphers |= IWINFO_CIPHER_WEP40; + + else if (strstr(val, "WEP-104")) + c->pair_ciphers |= IWINFO_CIPHER_WEP104; + + c->enabled = 1; + c->group_ciphers = c->pair_ciphers; + + c->auth_suites |= IWINFO_KMGMT_NONE; + c->auth_algs |= IWINFO_AUTH_OPEN; /* XXX: assumption */ + } + + /* WPA */ + else + { + if (strstr(val, "TKIP")) + c->pair_ciphers |= IWINFO_CIPHER_TKIP; + + else if (strstr(val, "CCMP")) + c->pair_ciphers |= IWINFO_CIPHER_CCMP; + + else if (strstr(val, "NONE")) + c->pair_ciphers |= IWINFO_CIPHER_NONE; + + else if (strstr(val, "WEP-40")) + c->pair_ciphers |= IWINFO_CIPHER_WEP40; + + else if (strstr(val, "WEP-104")) + c->pair_ciphers |= IWINFO_CIPHER_WEP104; + + + if ((val = nl80211_getval(NULL, res, "group_cipher"))) + { + if (strstr(val, "TKIP")) + c->group_ciphers |= IWINFO_CIPHER_TKIP; + + else if (strstr(val, "CCMP")) + c->group_ciphers |= IWINFO_CIPHER_CCMP; + + else if (strstr(val, "NONE")) + c->group_ciphers |= IWINFO_CIPHER_NONE; + + else if (strstr(val, "WEP-40")) + c->group_ciphers |= IWINFO_CIPHER_WEP40; + + else if (strstr(val, "WEP-104")) + c->group_ciphers |= IWINFO_CIPHER_WEP104; + } + + + if ((val = nl80211_getval(NULL, res, "key_mgmt"))) + { + if (strstr(val, "WPA2")) + c->wpa_version = 2; + + else if (strstr(val, "WPA")) + c->wpa_version = 1; + + + if (strstr(val, "PSK")) + c->auth_suites |= IWINFO_KMGMT_PSK; + + else if (strstr(val, "EAP") || strstr(val, "802.1X")) + c->auth_suites |= IWINFO_KMGMT_8021x; + + else if (strstr(val, "NONE")) + c->auth_suites |= IWINFO_KMGMT_NONE; + } + + c->enabled = (c->wpa_version && c->auth_suites) ? 1 : 0; + } + + return 0; + } + + /* Hostapd */ + else if ((res = nl80211_hostapd_info(ifname))) + { + if ((val = nl80211_getval(ifname, res, "wpa")) != NULL) + c->wpa_version = atoi(val); + + val = nl80211_getval(ifname, res, "wpa_key_mgmt"); + + if (!val || strstr(val, "PSK")) + c->auth_suites |= IWINFO_KMGMT_PSK; + + if (val && strstr(val, "EAP")) + c->auth_suites |= IWINFO_KMGMT_8021x; + + if (val && strstr(val, "NONE")) + c->auth_suites |= IWINFO_KMGMT_NONE; + + if ((val = nl80211_getval(ifname, res, "wpa_pairwise")) != NULL) + { + if (strstr(val, "TKIP")) + c->pair_ciphers |= IWINFO_CIPHER_TKIP; + + if (strstr(val, "CCMP")) + c->pair_ciphers |= IWINFO_CIPHER_CCMP; + + if (strstr(val, "NONE")) + c->pair_ciphers |= IWINFO_CIPHER_NONE; + } + + if ((val = nl80211_getval(ifname, res, "auth_algs")) != NULL) + { + switch(atoi(val)) { + case 1: + c->auth_algs |= IWINFO_AUTH_OPEN; + break; + + case 2: + c->auth_algs |= IWINFO_AUTH_SHARED; + break; + + case 3: + c->auth_algs |= IWINFO_AUTH_OPEN; + c->auth_algs |= IWINFO_AUTH_SHARED; + break; + + default: + break; + } + + for (i = 0; i < 4; i++) + { + snprintf(k, sizeof(k), "wep_key%d", i); + + if ((val = nl80211_getval(ifname, res, k))) + { + if ((strlen(val) == 5) || (strlen(val) == 10)) + c->pair_ciphers |= IWINFO_CIPHER_WEP40; + + else if ((strlen(val) == 13) || (strlen(val) == 26)) + c->pair_ciphers |= IWINFO_CIPHER_WEP104; + } + } + } + + c->group_ciphers = c->pair_ciphers; + c->enabled = (c->wpa_version || c->pair_ciphers) ? 1 : 0; + + return 0; + } + + return -1; +} + + +static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg) +{ + struct nl80211_array_buf *arr = arg; + struct iwinfo_assoclist_entry *e = arr->buf; + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; + struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; + + static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { + [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + }; + + static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, + }; + + /* advance to end of array */ + e += arr->count; + memset(e, 0, sizeof(*e)); + + if (attr[NL80211_ATTR_MAC]) + memcpy(e->mac, nla_data(attr[NL80211_ATTR_MAC]), 6); + + if (attr[NL80211_ATTR_STA_INFO] && + !nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, + attr[NL80211_ATTR_STA_INFO], stats_policy)) + { + if (sinfo[NL80211_STA_INFO_SIGNAL]) + e->signal = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); + + if (sinfo[NL80211_STA_INFO_INACTIVE_TIME]) + e->inactive = nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]); + + if (sinfo[NL80211_STA_INFO_RX_PACKETS]) + e->rx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]); + + if (sinfo[NL80211_STA_INFO_TX_PACKETS]) + e->tx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]); + + if (sinfo[NL80211_STA_INFO_RX_BITRATE] && + !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, + sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy)) + { + if (rinfo[NL80211_RATE_INFO_BITRATE]) + e->rx_rate.rate = + nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100; + + if (rinfo[NL80211_RATE_INFO_MCS]) + e->rx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]); + + if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) + e->rx_rate.is_40mhz = 1; + + if (rinfo[NL80211_RATE_INFO_SHORT_GI]) + e->rx_rate.is_short_gi = 1; + } + + if (sinfo[NL80211_STA_INFO_TX_BITRATE] && + !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, + sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)) + { + if (rinfo[NL80211_RATE_INFO_BITRATE]) + e->tx_rate.rate = + nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100; + + if (rinfo[NL80211_RATE_INFO_MCS]) + e->tx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]); + + if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH]) + e->tx_rate.is_40mhz = 1; + + if (rinfo[NL80211_RATE_INFO_SHORT_GI]) + e->tx_rate.is_short_gi = 1; + } + } + + e->noise = 0; /* filled in by caller */ + arr->count++; + + return NL_SKIP; +} + +int nl80211_get_assoclist(const char *ifname, char *buf, int *len) +{ + DIR *d; + int i, noise = 0; + struct dirent *de; + struct nl80211_msg_conveyor *req; + struct nl80211_array_buf arr = { .buf = buf, .count = 0 }; + struct iwinfo_assoclist_entry *e; + + if ((d = opendir("/sys/class/net")) != NULL) + { + while ((de = readdir(d)) != NULL) + { + if (!strncmp(de->d_name, ifname, strlen(ifname)) && + (!de->d_name[strlen(ifname)] || + !strncmp(&de->d_name[strlen(ifname)], ".sta", 4))) + { + req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION, + NLM_F_DUMP); + + if (req) + { + nl80211_send(req, nl80211_get_assoclist_cb, &arr); + nl80211_free(req); + } + } + } + + closedir(d); + + if (!nl80211_get_noise(ifname, &noise)) + for (i = 0, e = arr.buf; i < arr.count; i++, e++) + e->noise = noise; + + *len = (arr.count * sizeof(struct iwinfo_assoclist_entry)); + return 0; + } + + return -1; +} + +static int nl80211_get_txpwrlist_cb(struct nl_msg *msg, void *arg) +{ + int *dbm_max = arg; + int ch_cur, ch_cmp, bands_remain, freqs_remain; + + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *band, *freq; + + static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { + [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, + [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, + }; + + ch_cur = *dbm_max; /* value int* is initialized with channel by caller */ + *dbm_max = -1; + + nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain) + { + nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band), + nla_len(band), NULL); + + nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain) + { + nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX, + nla_data(freq), nla_len(freq), freq_policy); + + ch_cmp = nl80211_freq2channel(nla_get_u32( + freqs[NL80211_FREQUENCY_ATTR_FREQ])); + + if ((!ch_cur || (ch_cmp == ch_cur)) && + freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) + { + *dbm_max = (int)(0.01 * nla_get_u32( + freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])); + + break; + } + } + } + + return NL_SKIP; +} + +int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len) +{ + int ch_cur; + int dbm_max = -1, dbm_cur, dbm_cnt; + struct nl80211_msg_conveyor *req; + struct iwinfo_txpwrlist_entry entry; + + if (nl80211_get_channel(ifname, &ch_cur)) + ch_cur = 0; + + req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0); + if (req) + { + /* initialize the value pointer with channel for callback */ + dbm_max = ch_cur; + + nl80211_send(req, nl80211_get_txpwrlist_cb, &dbm_max); + nl80211_free(req); + } + + if (dbm_max > 0) + { + for (dbm_cur = 0, dbm_cnt = 0; + dbm_cur < dbm_max; + dbm_cur++, dbm_cnt++) + { + entry.dbm = dbm_cur; + entry.mw = iwinfo_dbm2mw(dbm_cur); + + memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry)); + } + + entry.dbm = dbm_max; + entry.mw = iwinfo_dbm2mw(dbm_max); + + memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry)); + dbm_cnt++; + + *len = dbm_cnt * sizeof(entry); + return 0; + } + + return -1; +} + +static void nl80211_get_scancrypto(const char *spec, + struct iwinfo_crypto_entry *c) +{ + if (strstr(spec, "WPA") || strstr(spec, "WEP")) + { + c->enabled = 1; + + if (strstr(spec, "WPA2-") && strstr(spec, "WPA-")) + c->wpa_version = 3; + + else if (strstr(spec, "WPA2")) + c->wpa_version = 2; + + else if (strstr(spec, "WPA")) + c->wpa_version = 1; + + else if (strstr(spec, "WEP")) + c->auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED; + + + if (strstr(spec, "PSK")) + c->auth_suites |= IWINFO_KMGMT_PSK; + + if (strstr(spec, "802.1X") || strstr(spec, "EAP")) + c->auth_suites |= IWINFO_KMGMT_8021x; + + if (strstr(spec, "WPA-NONE")) + c->auth_suites |= IWINFO_KMGMT_NONE; + + + if (strstr(spec, "TKIP")) + c->pair_ciphers |= IWINFO_CIPHER_TKIP; + + if (strstr(spec, "CCMP")) + c->pair_ciphers |= IWINFO_CIPHER_CCMP; + + if (strstr(spec, "WEP-40")) + c->pair_ciphers |= IWINFO_CIPHER_WEP40; + + if (strstr(spec, "WEP-104")) + c->pair_ciphers |= IWINFO_CIPHER_WEP104; + + c->group_ciphers = c->pair_ciphers; + } + else + { + c->enabled = 0; + } +} + + +struct nl80211_scanlist { + struct iwinfo_scanlist_entry *e; + int len; +}; + + +static void nl80211_get_scanlist_ie(struct nlattr **bss, + struct iwinfo_scanlist_entry *e) +{ + int ielen = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + unsigned char *ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); + static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 }; + + while (ielen >= 2 && ielen >= ie[1]) + { + switch (ie[0]) + { + case 0: /* SSID */ + memcpy(e->ssid, ie + 2, min(ie[1], IWINFO_ESSID_MAX_SIZE)); + break; + + case 48: /* RSN */ + iwinfo_parse_rsn(&e->crypto, ie + 2, ie[1], + IWINFO_CIPHER_CCMP, IWINFO_KMGMT_8021x); + break; + + case 221: /* Vendor */ + if (ie[1] >= 4 && !memcmp(ie + 2, ms_oui, 3) && ie[5] == 1) + iwinfo_parse_rsn(&e->crypto, ie + 6, ie[1] - 4, + IWINFO_CIPHER_TKIP, IWINFO_KMGMT_PSK); + break; + } + + ielen -= ie[1] + 2; + ie += ie[1] + 2; + } +} + +static int nl80211_get_scanlist_cb(struct nl_msg *msg, void *arg) +{ + int8_t rssi; + uint16_t caps; + + struct nl80211_scanlist *sl = arg; + struct nlattr **tb = nl80211_parse(msg); + struct nlattr *bss[NL80211_BSS_MAX + 1]; + + static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { + [NL80211_BSS_TSF] = { .type = NLA_U64 }, + [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_BSS_BSSID] = { }, + [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, + [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, + [NL80211_BSS_INFORMATION_ELEMENTS] = { }, + [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, + [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, + [NL80211_BSS_BEACON_IES] = { }, + }; + + if (!tb[NL80211_ATTR_BSS] || + nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], + bss_policy) || + !bss[NL80211_BSS_BSSID]) + { + return NL_SKIP; + } + + if (bss[NL80211_BSS_CAPABILITY]) + caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]); + else + caps = 0; + + memset(sl->e, 0, sizeof(*sl->e)); + memcpy(sl->e->mac, nla_data(bss[NL80211_BSS_BSSID]), 6); + + if (caps & (1<<1)) + sl->e->mode = IWINFO_OPMODE_ADHOC; + else + sl->e->mode = IWINFO_OPMODE_MASTER; + + if (caps & (1<<4)) + sl->e->crypto.enabled = 1; + + if (bss[NL80211_BSS_FREQUENCY]) + sl->e->channel = nl80211_freq2channel(nla_get_u32( + bss[NL80211_BSS_FREQUENCY])); + + if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) + nl80211_get_scanlist_ie(bss, sl->e); + + if (bss[NL80211_BSS_SIGNAL_MBM]) + { + sl->e->signal = + (uint8_t)((int32_t)nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]) / 100); + + rssi = sl->e->signal - 0x100; + + if (rssi < -110) + rssi = -110; + else if (rssi > -40) + rssi = -40; + + sl->e->quality = (rssi + 110); + sl->e->quality_max = 70; + } + + if (sl->e->crypto.enabled && !sl->e->crypto.wpa_version) + { + sl->e->crypto.auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED; + sl->e->crypto.pair_ciphers = IWINFO_CIPHER_WEP40 | IWINFO_CIPHER_WEP104; + } + + sl->e++; + sl->len++; + + return NL_SKIP; +} + +static int nl80211_get_scanlist_nl(const char *ifname, char *buf, int *len) +{ + struct nl80211_msg_conveyor *req; + struct nl80211_scanlist sl = { .e = (struct iwinfo_scanlist_entry *)buf }; + + req = nl80211_msg(ifname, NL80211_CMD_TRIGGER_SCAN, 0); + if (req) + { + nl80211_send(req, NULL, NULL); + nl80211_free(req); + } + + nl80211_wait("nl80211", "scan", NL80211_CMD_NEW_SCAN_RESULTS); + + req = nl80211_msg(ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP); + if (req) + { + nl80211_send(req, nl80211_get_scanlist_cb, &sl); + nl80211_free(req); + } + + *len = sl.len * sizeof(struct iwinfo_scanlist_entry); + return *len ? 0 : -1; +} + +int nl80211_get_scanlist(const char *ifname, char *buf, int *len) +{ + int freq, rssi, qmax, count; + char *res; + char ssid[128] = { 0 }; + char bssid[18] = { 0 }; + char cipher[256] = { 0 }; + + /* Got a radioX pseudo interface, find some interface on it or create one */ + if (!strncmp(ifname, "radio", 5)) + { + /* Reuse existing interface */ + if ((res = nl80211_phy2ifname(ifname)) != NULL) + { + return nl80211_get_scanlist(res, buf, len); + } + + /* Need to spawn a temporary iface for scanning */ + else if ((res = nl80211_ifadd(ifname)) != NULL) + { + count = nl80211_get_scanlist(res, buf, len); + nl80211_ifdel(res); + return count; + } + } + + struct iwinfo_scanlist_entry *e = (struct iwinfo_scanlist_entry *)buf; + + /* WPA supplicant */ + if ((res = nl80211_wpactl_info(ifname, "SCAN", "CTRL-EVENT-SCAN-RESULTS"))) + { + if ((res = nl80211_wpactl_info(ifname, "SCAN_RESULTS", NULL))) + { + nl80211_get_quality_max(ifname, &qmax); + + /* skip header line */ + while (*res++ != '\n'); + + count = 0; + + while (sscanf(res, "%17s %d %d %255s%*[ \t]%127[^\n]\n", + bssid, &freq, &rssi, cipher, ssid) > 0) + { + /* BSSID */ + e->mac[0] = strtol(&bssid[0], NULL, 16); + e->mac[1] = strtol(&bssid[3], NULL, 16); + e->mac[2] = strtol(&bssid[6], NULL, 16); + e->mac[3] = strtol(&bssid[9], NULL, 16); + e->mac[4] = strtol(&bssid[12], NULL, 16); + e->mac[5] = strtol(&bssid[15], NULL, 16); + + /* SSID */ + memcpy(e->ssid, ssid, min(strlen(ssid), sizeof(e->ssid) - 1)); + + /* Mode (assume master) */ + e->mode = IWINFO_OPMODE_MASTER; + + /* Channel */ + e->channel = nl80211_freq2channel(freq); + + /* Signal */ + e->signal = rssi; + + /* Quality */ + if (rssi < 0) + { + /* The cfg80211 wext compat layer assumes a signal range + * of -110 dBm to -40 dBm, the quality value is derived + * by adding 110 to the signal level */ + if (rssi < -110) + rssi = -110; + else if (rssi > -40) + rssi = -40; + + e->quality = (rssi + 110); + } + else + { + e->quality = rssi; + } + + /* Max. Quality */ + e->quality_max = qmax; + + /* Crypto */ + nl80211_get_scancrypto(cipher, &e->crypto); + + /* advance to next line */ + while (*res && *res++ != '\n'); + + count++; + e++; + + memset(ssid, 0, sizeof(ssid)); + memset(bssid, 0, sizeof(bssid)); + memset(cipher, 0, sizeof(cipher)); + } + + *len = count * sizeof(struct iwinfo_scanlist_entry); + return 0; + } + } + + /* AP scan */ + else + { + /* Got a temp interface, don't create yet another one */ + if (!strncmp(ifname, "tmp.", 4)) + { + if (!iwinfo_ifup(ifname)) + return -1; + + nl80211_get_scanlist_nl(ifname, buf, len); + iwinfo_ifdown(ifname); + return 0; + } + + /* Spawn a new scan interface */ + else + { + if (!(res = nl80211_ifadd(ifname))) + goto out; + + if (!iwinfo_ifmac(res)) + goto out; + + /* if we can take the new interface up, the driver supports an + * additional interface and there's no need to tear down the ap */ + if (iwinfo_ifup(res)) + { + nl80211_get_scanlist_nl(res, buf, len); + iwinfo_ifdown(res); + } + + /* driver cannot create secondary interface, take down ap + * during scan */ + else if (iwinfo_ifdown(ifname) && iwinfo_ifup(res)) + { + nl80211_get_scanlist_nl(res, buf, len); + iwinfo_ifdown(res); + iwinfo_ifup(ifname); + nl80211_hostapd_hup(ifname); + } + + out: + nl80211_ifdel(res); + return 0; + } + } + + return -1; +} + +static int nl80211_get_freqlist_cb(struct nl_msg *msg, void *arg) +{ + int bands_remain, freqs_remain; + + struct nl80211_array_buf *arr = arg; + struct iwinfo_freqlist_entry *e = arr->buf; + + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *band, *freq; + + static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { + [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, + [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, + }; + + nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain) + { + nla_parse(bands, NL80211_BAND_ATTR_MAX, + nla_data(band), nla_len(band), NULL); + + nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain) + { + nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX, + nla_data(freq), nla_len(freq), NULL); + + if (!freqs[NL80211_FREQUENCY_ATTR_FREQ] || + freqs[NL80211_FREQUENCY_ATTR_DISABLED]) + continue; + + e->mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]); + e->channel = nl80211_freq2channel(e->mhz); + + e->restricted = ( + freqs[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] || + freqs[NL80211_FREQUENCY_ATTR_NO_IBSS] || + freqs[NL80211_FREQUENCY_ATTR_RADAR] + ) ? 1 : 0; + + e++; + arr->count++; + } + } + + return NL_SKIP; +} + +int nl80211_get_freqlist(const char *ifname, char *buf, int *len) +{ + struct nl80211_msg_conveyor *req; + struct nl80211_array_buf arr = { .buf = buf, .count = 0 }; + + req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0); + if (req) + { + nl80211_send(req, nl80211_get_freqlist_cb, &arr); + nl80211_free(req); + } + + if (arr.count > 0) + { + *len = arr.count * sizeof(struct iwinfo_freqlist_entry); + return 0; + } + + return -1; +} + +static int nl80211_get_country_cb(struct nl_msg *msg, void *arg) +{ + char *buf = arg; + struct nlattr **attr = nl80211_parse(msg); + + if (attr[NL80211_ATTR_REG_ALPHA2]) + memcpy(buf, nla_data(attr[NL80211_ATTR_REG_ALPHA2]), 2); + else + buf[0] = 0; + + return NL_SKIP; +} + +int nl80211_get_country(const char *ifname, char *buf) +{ + int rv = -1; + struct nl80211_msg_conveyor *req; + + req = nl80211_msg(ifname, NL80211_CMD_GET_REG, 0); + if (req) + { + nl80211_send(req, nl80211_get_country_cb, buf); + nl80211_free(req); + + if (buf[0]) + rv = 0; + } + + return rv; +} + +int nl80211_get_countrylist(const char *ifname, char *buf, int *len) +{ + int i, count; + struct iwinfo_country_entry *e = (struct iwinfo_country_entry *)buf; + const struct iwinfo_iso3166_label *l; + + for (l = IWINFO_ISO3166_NAMES, count = 0; l->iso3166; l++, e++, count++) + { + e->iso3166 = l->iso3166; + e->ccode[0] = (l->iso3166 / 256); + e->ccode[1] = (l->iso3166 % 256); + } + + *len = (count * sizeof(struct iwinfo_country_entry)); + return 0; +} + +static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg) +{ + int *modes = arg; + int bands_remain, freqs_remain; + uint16_t caps = 0; + struct nlattr **attr = nl80211_parse(msg); + struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *band, *freq; + + *modes = 0; + + if (attr[NL80211_ATTR_WIPHY_BANDS]) + { + nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain) + { + nla_parse(bands, NL80211_BAND_ATTR_MAX, + nla_data(band), nla_len(band), NULL); + + if (bands[NL80211_BAND_ATTR_HT_CAPA]) + caps = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]); + + /* Treat any nonzero capability as 11n */ + if (caps > 0) + *modes |= IWINFO_80211_N; + + nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], + freqs_remain) + { + nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX, + nla_data(freq), nla_len(freq), NULL); + + if (!freqs[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + + if (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485) + { + *modes |= IWINFO_80211_B; + *modes |= IWINFO_80211_G; + } + else + { + *modes |= IWINFO_80211_A; + } + } + } + } + + return NL_SKIP; +} + +int nl80211_get_hwmodelist(const char *ifname, int *buf) +{ + struct nl80211_msg_conveyor *req; + + req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0); + if (req) + { + nl80211_send(req, nl80211_get_hwmodelist_cb, buf); + nl80211_free(req); + } + + return *buf ? 0 : -1; +} + +int nl80211_get_mbssid_support(const char *ifname, int *buf) +{ + /* Test whether we can create another interface */ + char *nif = nl80211_ifadd(ifname); + + if (nif) + { + *buf = (iwinfo_ifmac(nif) && iwinfo_ifup(nif)); + + iwinfo_ifdown(nif); + nl80211_ifdel(nif); + + return 0; + } + + return -1; +} + +int nl80211_get_hardware_id(const char *ifname, char *buf) +{ + int rv; + char *res; + + /* Got a radioX pseudo interface, find some interface on it or create one */ + if (!strncmp(ifname, "radio", 5)) + { + /* Reuse existing interface */ + if ((res = nl80211_phy2ifname(ifname)) != NULL) + { + rv = wext_get_hardware_id(res, buf); + } + + /* Need to spawn a temporary iface for finding IDs */ + else if ((res = nl80211_ifadd(ifname)) != NULL) + { + rv = wext_get_hardware_id(res, buf); + nl80211_ifdel(res); + } + } + else + { + rv = wext_get_hardware_id(ifname, buf); + } + + /* Failed to obtain hardware IDs, search board config */ + if (rv) + { + rv = iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id *)buf); + } + + return rv; +} + +static const struct iwinfo_hardware_entry * +nl80211_get_hardware_entry(const char *ifname) +{ + struct iwinfo_hardware_id id; + + if (nl80211_get_hardware_id(ifname, (char *)&id)) + return NULL; + + return iwinfo_hardware(&id); +} + +int nl80211_get_hardware_name(const char *ifname, char *buf) +{ + const struct iwinfo_hardware_entry *hw; + + if (!(hw = nl80211_get_hardware_entry(ifname))) + sprintf(buf, "Generic MAC80211"); + else + sprintf(buf, "%s %s", hw->vendor_name, hw->device_name); + + return 0; +} + +int nl80211_get_txpower_offset(const char *ifname, int *buf) +{ + const struct iwinfo_hardware_entry *hw; + + if (!(hw = nl80211_get_hardware_entry(ifname))) + return -1; + + *buf = hw->txpower_offset; + return 0; +} + +int nl80211_get_frequency_offset(const char *ifname, int *buf) +{ + const struct iwinfo_hardware_entry *hw; + + if (!(hw = nl80211_get_hardware_entry(ifname))) + return -1; + + *buf = hw->frequency_offset; + return 0; +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_utils.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_utils.c.svn-base new file mode 100644 index 0000000..6616f14 --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_utils.c.svn-base @@ -0,0 +1,349 @@ +/* + * 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[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) +{ + const struct iwinfo_hardware_entry *e; + + for (e = IWINFO_HARDWARE_ENTRIES; e->vendor_name; e++) + { + 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; + + return (struct iwinfo_hardware_entry *)e; + } + + return NULL; +} + +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); +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wext.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wext.c.svn-base new file mode 100644 index 0000000..cf3dccc --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wext.c.svn-base @@ -0,0 +1,520 @@ +/* + * 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); +} + + +int wext_probe(const char *ifname) +{ + struct iwreq wrq; + + if(wext_ioctl(ifname, SIOCGIWNAME, &wrq) >= 0) + return 1; + + return 0; +} + +void wext_close(void) +{ + /* Nop */ +} + +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; +} + +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; +} + +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; +} + +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; +} + +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) ⦥ + 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; +} + +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) ⦥ + 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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +int wext_get_quality_max(const char *ifname, int *buf) +{ + struct iwreq wrq; + struct iw_range range; + + wrq.u.data.pointer = (caddr_t) ⦥ + 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; +} + +int wext_get_assoclist(const char *ifname, char *buf, int *len) +{ + /* Stub */ + return -1; +} + +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) ⦥ + 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; +} + +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) ⦥ + 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; +} + +int wext_get_country(const char *ifname, char *buf) +{ + sprintf(buf, "00"); + return 0; +} + +int wext_get_countrylist(const char *ifname, char *buf, int *len) +{ + /* Stub */ + return -1; +} + +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; +} + +int wext_get_encryption(const char *ifname, char *buf) +{ + /* No reliable crypto info in wext */ + return -1; +} + +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; +} + +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; +} + +int wext_get_hardware_name(const char *ifname, char *buf) +{ + sprintf(buf, "Generic WEXT"); + return 0; +} + +int wext_get_txpower_offset(const char *ifname, int *buf) +{ + /* Stub */ + *buf = 0; + return -1; +} + +int wext_get_frequency_offset(const char *ifname, int *buf) +{ + /* Stub */ + *buf = 0; + return -1; +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wext_scan.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wext_scan.c.svn-base new file mode 100644 index 0000000..ecd40d7 --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wext_scan.c.svn-base @@ -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_scan.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) ⦥ + 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; +} diff --git a/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wl.c.svn-base b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wl.c.svn-base new file mode 100644 index 0000000..3d15fc9 --- /dev/null +++ b/package/network/utils/iwinfo/src/.svn/text-base/iwinfo_wl.c.svn-base @@ -0,0 +1,645 @@ +/* + * 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/wl.h" +#include "iwinfo/wext.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 ((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; +} + + +int wl_probe(const char *ifname) +{ + int magic; + return (!wl_ioctl(ifname, WLC_GET_MAGIC, &magic, sizeof(magic)) && + (magic == WLC_IOCTL_MAGIC)); +} + +void wl_close(void) +{ + /* Nop */ +} + +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; +} + +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; +} + +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; +} + +int wl_get_channel(const char *ifname, int *buf) +{ + return wl_ioctl(ifname, WLC_GET_CHANNEL, buf, sizeof(buf)); +} + +int wl_get_frequency(const char *ifname, int *buf) +{ + return wext_get_frequency(ifname, buf); +} + +int wl_get_txpower(const char *ifname, int *buf) +{ + /* WLC_GET_VAR "qtxpower" */ + return wext_get_txpower(ifname, buf); +} + +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; +} + +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; +} + +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; +} + +int wl_get_quality(const char *ifname, int *buf) +{ + return wext_get_quality(ifname, buf); +} + +int wl_get_quality_max(const char *ifname, int *buf) +{ + return wext_get_quality_max(ifname, buf); +} + +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; +} + +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; + } +} + +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; +} + +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; +} + +int wl_get_scanlist(const char *ifname, char *buf, int *len) +{ + return wext_get_scanlist(ifname, buf, len); +} + +int wl_get_freqlist(const char *ifname, char *buf, int *len) +{ + return wext_get_freqlist(ifname, buf, len); +} + +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; +} + +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++) + { + sprintf(c->ccode, &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; +} + +int wl_get_hwmodelist(const char *ifname, int *buf) +{ + return wext_get_hwmodelist(ifname, buf); +} + +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; +} + +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; +} + +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; +} + +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; +} + +int wl_get_frequency_offset(const char *ifname, int *buf) +{ + /* Stub */ + *buf = 0; + return -1; +} |