commit f03f55ff92153337972cb9b2d1856b9a364df073 Author: Polynomialdivision Date: Mon Mar 23 19:18:13 2020 +0100 first version diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..868f2d3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 2.6) +PROJECT(dawn) + +ADD_SUBDIRECTORY(src) \ No newline at end of file diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..4cce1a0 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,33 @@ +## Installation + +### Compiling DAWN + +Add [bowlfeed](https://github.com/berlin-open-wireless-lab/bowl-feed.git) to feeds.conf + + src-git bowlfeed git@github.com:berlin-open-wireless-lab/bowl-feed.git + +Update Feeds + + ./scripts/feeds update -a + +Install DAWN + + ./scripts/feeds install dawn + + +Select dawn under + + make menuconfig + +Compile + + make package/dawn/compile + +### Configure Dawn + +Edit settings under + + /etc/config/dawn + +Restart daemon + /etc/init.d/dawn restart \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8cdb845 --- /dev/null +++ b/LICENSE @@ -0,0 +1,340 @@ + 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. + + {description} + Copyright (C) {year} {fullname} + + 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/README.md b/README.md new file mode 100644 index 0000000..202f4e7 --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +![DAWN PICTURE](https://image.ibb.co/nbmNfJ/dawn_bla.png) + +# DAWN +Decentralized WiFi Controller + +## Related + +|Repro |Content | +|------------------|--------------------------| +|[patches-pending](https://github.com/berlin-open-wireless-lab/patches-pending)|Pending OpenWrt Patches DAWN is depending on| +|[bowl-feed](https://github.com/berlin-open-wireless-lab/bowl-feed)|Feed for DAWN| + +## Installation + +See [installation](INSTALL.md). + +## LuCI App +There is an luci app called [luci-app-dawn](https://github.com/berlin-open-wireless-lab/bowl-feed). + +## Setting up Routers + +You can find a good guide to configure your router is [here](https://gist.github.com/braian87b/bba9da3a7ac23c35b7f1eecafecdd47d). +I setup the OpenWRT Router as dumb APs. + +## Configuration + + +|Option |Standard | Meaning | +|-------------------|---------|---------| +|ht_support | '10' |If AP and station support high throughput.| +|vht_support | '100' |If AP and station support very high throughput.| +|no_ht_support | '0' |If AP and station not supporting high throughput.| +|no_vht_support | '0' |If AP and station not supporting very high throughput. +|rssi | '10' |If RSSI is greater equal rssi_val.| +|low_rssi | '-500' |If RSSI is less than low_rssi_val.| +|freq | '100' |If connection is 5Ghz.| +|chan_util | '0' |If channel utilization is lower chan_util_val.| +|max_chan_util | '-500' |If channel utilization is greater max_chan_util_val.| +|rssi_val | '-60' |Threshold for an good RSSI.| +|low_rssi_val | '-80' |Threshold for an bad RSSI.| +|chan_util_val | '140' |Threshold for an good channel utilization.| +|max_chan_util_val | '170' |Threshold for a bad channel utilization.| +|min_probe_count | '2' |Minimum number of probe requests aftrer calculating if AP is best and sending a probe response.| +|bandwith_threshold | '6' |Threshold for the receiving bit rate indicating if a client is in an active transmission.| +|use_station_count | '1' |Use station count as metric.| +|max_station_diff | '1' |Maximal station difference that is allowed.| +|eval_probe_req | '1' |Evaluate the incoming probe requests.| +|eval_auth_req | '1' |Evaluate the incomning authentication reqeuests.| +|eval_assoc_req | '1' |Evaluate the incoming association requests.| +|deny_auth_reason | '1' |Status code for denying authentications.| +|deny_assoc_reason | '17' |Status code for denying associations.| +|use_driver_recog | '1' |Allow drivers to connect after a certain time.| + + +## ubus interface +To get an overview of all connected Clients sorted by the SSID. + + root@OpenWrt:~# ubus call dawn get_network + { + "Free-Cookies": { + "00:27:19:XX:XX:XX": { + "78:02:F8:XX:XX:XX": { + "freq": 2452, + "ht": 1, + "vht": 0, + "collision_count": 4 + } + }, + "A4:2B:B0:XX:XX:XX": { + "48:27:EA:XX:XX:XX: { + "freq": 2412, + "ht": 1, + "vht": 0, + "collision_count": 4 + }, + } + }, + "Free-Cookies_5G": { + + } + } +To get the hearing map you can use: + + root@OpenWrt:~# ubus call dawn get_hearing_map + { + "Free-Cookies": { + "0E:5B:DB:XX:XX:XX": { + "00:27:19:XX:XX:XX": { + "signal": -64, + "freq": 2452, + "ht_support": true, + "vht_support": false, + "channel_utilization": 12, + "num_sta": 1, + "ht": 1, + "vht": 0, + "score": 10 + }, + "A4:2B:B0:XX:XX:XX": { + "signal": -70, + "freq": 2412, + "ht_support": true, + "vht_support": false, + "channel_utilization": 71, + "num_sta": 3, + "ht": 1, + "vht": 0, + "score": 10 + } + } + } + } + + +## OpenWrt in a Nutshell + +![OpenWrtInANuthshell](https://raw.githubusercontent.com/PolynomialDivision/upload_stuff/master/dawn_pictures/openwrt_in_a_nutshell_dawn.png) + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100755 index 0000000..9370def --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 2.6) +PROJECT(dawn) + +INCLUDE_DIRECTORIES(include) + +ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -Wmissing-declarations -Wno-unknown-warning-option -Wno-format-truncation) + +SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") + +SET(SOURCES + main.c + + storage/datastorage.c + include/datastorage.h + + network/networksocket.c + include/networksocket.h + + network/broadcastsocket.c + include/broadcastsocket.h + + network/multicastsocket.c + include/multicastsocket.h + + utils/ubus.c + include/ubus.h + + utils/dawn_uci.c + include/dawn_uci.h + + crypto/crypto.c + include/crypto.h + + include/utils.h + utils/utils.c + + include/tcpsocket.h + network/tcpsocket.c + + include/dawn_iwinfo.h + utils/dawn_iwinfo.c + + utils/ieee80211_utils.c + include/ieee80211_utils.h) + +SET(LIBS + ubox ubus json-c blobmsg_json uci gcrypt iwinfo) + +ADD_EXECUTABLE(dawn ${SOURCES}) + +TARGET_LINK_LIBRARIES(dawn ${LIBS}) + +INSTALL(TARGETS dawn + RUNTIME DESTINATION /usr/sbin/) \ No newline at end of file diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c new file mode 100644 index 0000000..2c34e57 --- /dev/null +++ b/src/crypto/crypto.c @@ -0,0 +1,100 @@ +// based on: +// https://github.com/vedantk/gcrypt-example/blob/master/gcry.cc + +#include "crypto.h" + +#include +#include +#include + +#define GCRY_CIPHER GCRY_CIPHER_AES128 // Pick the cipher here +#define GCRY_C_MODE GCRY_CIPHER_MODE_ECB // Pick the cipher mode here + +gcry_error_t gcry_error_handle; +gcry_cipher_hd_t gcry_cipher_hd; + +void gcrypt_init() { + if (!gcry_check_version(GCRYPT_VERSION)) { + fprintf(stderr, "gcrypt: library version mismatch"); + } + gcry_error_t err = 0; + err = gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN); + err |= gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0); + err |= gcry_control(GCRYCTL_RESUME_SECMEM_WARN); + err |= gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); + + if (err) { + fprintf(stderr, "gcrypt: failed initialization"); + } +} + +void gcrypt_set_key_and_iv(const char *key, const char *iv) { + size_t keylen = gcry_cipher_get_algo_keylen(GCRY_CIPHER); + size_t blklen = gcry_cipher_get_algo_blklen(GCRY_CIPHER); + + gcry_error_handle = gcry_cipher_open( + &gcry_cipher_hd, // gcry_cipher_hd_t * + GCRY_CIPHER, // int + GCRY_C_MODE, // int + 0); + if (gcry_error_handle) { + fprintf(stderr, "gcry_cipher_open failed: %s/%s\n", + gcry_strsource(gcry_error_handle), + gcry_strerror(gcry_error_handle)); + return; + } + + gcry_error_handle = gcry_cipher_setkey(gcry_cipher_hd, key, keylen); + if (gcry_error_handle) { + fprintf(stderr, "gcry_cipher_setkey failed: %s/%s\n", + gcry_strsource(gcry_error_handle), + gcry_strerror(gcry_error_handle)); + return; + } + + gcry_error_handle = gcry_cipher_setiv(gcry_cipher_hd, iv, blklen); + if (gcry_error_handle) { + fprintf(stderr, "gcry_cipher_setiv failed: %s/%s\n", + gcry_strsource(gcry_error_handle), + gcry_strerror(gcry_error_handle)); + return; + } +} + +// free out buffer after using! +char *gcrypt_encrypt_msg(char *msg, size_t msg_length, int *out_length) { + if (0U != (msg_length & 0xfU)) + msg_length += 0x10U - (msg_length & 0xfU); + + char *out = malloc(msg_length); + gcry_error_handle = gcry_cipher_encrypt(gcry_cipher_hd, out, msg_length, msg, msg_length); + if (gcry_error_handle) { + fprintf(stderr, "gcry_cipher_encrypt failed: %s/%s\n", + gcry_strsource(gcry_error_handle), + gcry_strerror(gcry_error_handle)); + return NULL; + } + *out_length = msg_length; + return out; +} + +// free out buffer after using! +char *gcrypt_decrypt_msg(char *msg, size_t msg_length) { + if (0U != (msg_length & 0xfU)) + msg_length += 0x10U - (msg_length & 0xfU); + + char *out_buffer = malloc(msg_length); + gcry_error_handle = gcry_cipher_decrypt(gcry_cipher_hd, out_buffer, msg_length, msg, msg_length); + if (gcry_error_handle) { + fprintf(stderr, "gcry_cipher_encrypt failed: %s/%s\n", + gcry_strsource(gcry_error_handle), + gcry_strerror(gcry_error_handle)); + free(out_buffer); + return NULL; + } + char *out = malloc(strlen(out_buffer) + 1); + strcpy(out, out_buffer); + free(out_buffer); + return out; +} + diff --git a/src/include/broadcastsocket.h b/src/include/broadcastsocket.h new file mode 100644 index 0000000..bd93409 --- /dev/null +++ b/src/include/broadcastsocket.h @@ -0,0 +1,14 @@ +#ifndef __DAWN_BROADCASTSOCKET_H +#define __DAWN_BROADCASTSOCKET_H + + +/** + * Function that setups a broadcast socket. + * @param _broadcast_ip - The broadcast ip to use. + * @param _broadcast_port - The broadcast port to use. + * @param addr The sockaddr_in struct. + * @return the socket that was created. + */ +int setup_broadcast_socket(const char *_broadcast_ip, unsigned short _broadcast_port, struct sockaddr_in *addr); + +#endif diff --git a/src/include/crypto.h b/src/include/crypto.h new file mode 100644 index 0000000..178e7a9 --- /dev/null +++ b/src/include/crypto.h @@ -0,0 +1,38 @@ +#ifndef DAWN_CRYPTO_H +#define DAWN_CRYPTO_H + +#include + +/** + * Initialize gcrypt. + * Has to be called before using the other functions! + */ +void gcrypt_init(); + +/** + * Set the Key and the iv. + * @param key + * @param iv + */ +void gcrypt_set_key_and_iv(const char *key, const char *iv); + +/** + * Function that encrypts the message. + * Free the string after using it! + * @param msg + * @param msg_length + * @param out_length + * @return the encrypted string. + */ +char *gcrypt_encrypt_msg(char *msg, size_t msg_length, int *out_length); + +/** + * FUnction that decrypts a message. + * Free the string after using it! + * @param msg + * @param msg_length + * @return the decrypted string. + */ +char *gcrypt_decrypt_msg(char *msg, size_t msg_length); + +#endif //DAWN_CRYPTO_H diff --git a/src/include/datastorage.h b/src/include/datastorage.h new file mode 100644 index 0000000..dfbdc09 --- /dev/null +++ b/src/include/datastorage.h @@ -0,0 +1,267 @@ +#ifndef __DAWN_DATASTORAGE_H +#define __DAWN_DATASTORAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +/* Mac */ + +// ---------------- Defines ------------------- +#define MAC_LIST_LENGTH 100 + +// ---------------- Structs ---------------- +uint8_t mac_list[MAC_LIST_LENGTH][ETH_ALEN]; + +// ---------------- Functions ---------- +void insert_macs_from_file(); + +int insert_to_maclist(uint8_t mac[]); + +int mac_in_maclist(uint8_t mac[]); + + +/* Metric */ + +struct probe_metric_s dawn_metric; + +// ---------------- Structs ---------------- +struct probe_metric_s { + int ap_weight; + int ht_support; + int vht_support; + int no_ht_support; + int no_vht_support; + int rssi; + int low_rssi; + int freq; + int chan_util; + int max_chan_util; + int rssi_val; + int low_rssi_val; + int chan_util_val; + int max_chan_util_val; + int min_probe_count; + int bandwith_threshold; + int use_station_count; + int max_station_diff; + int eval_probe_req; + int eval_auth_req; + int eval_assoc_req; + int deny_auth_reason; + int deny_assoc_reason; + int use_driver_recog; + int min_kick_count; + int chan_util_avg_period; + int kicking; +}; + +struct time_config_s { + time_t update_client; + time_t remove_client; + time_t remove_probe; + time_t remove_ap; + time_t update_hostapd; + time_t update_tcp_con; + time_t denied_req_threshold; + time_t update_chan_util; +}; + +struct network_config_s { + const char *broadcast_ip; + int broadcast_port; + int tcp_port; + int network_option; + const char *multicast; + const char *shared_key; + const char *iv; + int bool_multicast; + int use_symm_enc; + int collision_domain; + int bandwidth; +}; + +struct network_config_s network_config; +struct time_config_s timeout_config; + +// ---------------- Global variables ---------------- +struct probe_metric_s dawn_metric; + + +/* Probe, Auth, Assoc */ + +// ---------------- Structs ---------------- +typedef struct probe_entry_s { + uint8_t bssid_addr[ETH_ALEN]; + uint8_t client_addr[ETH_ALEN]; + uint8_t target_addr[ETH_ALEN]; + uint32_t signal; + uint32_t freq; + uint8_t ht_capabilities; + uint8_t vht_capabilities; + time_t time; + int counter; + int deny_counter; + uint8_t max_supp_datarate; + uint8_t min_supp_datarate; +} probe_entry; + +typedef struct auth_entry_s { + uint8_t bssid_addr[ETH_ALEN]; + uint8_t client_addr[ETH_ALEN]; + uint8_t target_addr[ETH_ALEN]; + uint32_t signal; + uint32_t freq; + time_t time; + int counter; +} auth_entry; + +typedef struct hostapd_notify_entry_s { + uint8_t bssid_addr[ETH_ALEN]; + uint8_t client_addr[ETH_ALEN]; +} hostapd_notify_entry; + +typedef struct auth_entry_s assoc_entry; + +#define DENY_REQ_ARRAY_LEN 100 +struct auth_entry_s denied_req_array[DENY_REQ_ARRAY_LEN]; +pthread_mutex_t denied_array_mutex; + +auth_entry insert_to_denied_req_array(auth_entry entry, int inc_counter); + +// ---------------- Defines ---------------- +#define PROBE_ARRAY_LEN 1000 + +#define SSID_MAX_LEN 32 + +// ---------------- Global variables ---------------- +struct probe_entry_s probe_array[PROBE_ARRAY_LEN]; +pthread_mutex_t probe_array_mutex; + +// ---------------- Functions ---------------- +probe_entry insert_to_array(probe_entry entry, int inc_counter); + +void probe_array_insert(probe_entry entry); + +probe_entry probe_array_delete(probe_entry entry); + +probe_entry probe_array_get_entry(uint8_t bssid_addr[], uint8_t client_addr[]); + +void print_probe_array(); + +void print_probe_entry(probe_entry entry); + +void print_auth_entry(auth_entry entry); + +void uloop_add_data_cbs(); + +/* AP, Client */ + +// blobmsg_alloc_string_buffer(&b, "signature", 1024); +#define SIGNATURE_LEN 1024 + +// ---------------- Structs ---------------- +typedef struct client_s { + uint8_t bssid_addr[ETH_ALEN]; + uint8_t client_addr[ETH_ALEN]; + char signature[SIGNATURE_LEN]; + uint8_t ht_supported; + uint8_t vht_supported; + uint32_t freq; + uint8_t auth; + uint8_t assoc; + uint8_t authorized; + uint8_t preauth; + uint8_t wds; + uint8_t wmm; + uint8_t ht; + uint8_t vht; + uint8_t wps; + uint8_t mfp; + time_t time; + uint32_t aid; + uint32_t kick_count; +} client; + +typedef struct ap_s { + uint8_t bssid_addr[ETH_ALEN]; + uint32_t freq; + uint8_t ht_support; + uint8_t vht_support; + uint32_t channel_utilization; + time_t time; + uint32_t station_count; + uint8_t ssid[SSID_MAX_LEN]; + uint32_t collision_domain; + uint32_t bandwidth; + uint32_t ap_weight; +} ap; + +// ---------------- Defines ---------------- +#define ARRAY_AP_LEN 50 +#define TIME_THRESHOLD_AP 30 +#define ARRAY_CLIENT_LEN 1000 +#define TIME_THRESHOLD_CLIENT 30 +#define TIME_THRESHOLD_CLIENT_UPDATE 10 +#define TIME_THRESHOLD_CLIENT_KICK 60 + +// ---------------- Global variables ---------------- +struct client_s client_array[ARRAY_CLIENT_LEN]; +pthread_mutex_t client_array_mutex; +struct ap_s ap_array[ARRAY_AP_LEN]; +pthread_mutex_t ap_array_mutex; + +int mac_is_equal(uint8_t addr1[], uint8_t addr2[]); + +int mac_is_greater(uint8_t addr1[], uint8_t addr2[]); + +// ---------------- Functions ---------------- + +void insert_client_to_array(client entry); + +void kick_clients(uint8_t bssid[], uint32_t id); + +void client_array_insert(client entry); + +client client_array_delete(client entry); + +void print_client_array(); + +void print_client_entry(client entry); + +ap insert_to_ap_array(ap entry); + +void print_ap_array(); + +ap ap_array_get_ap(uint8_t bssid_addr[]); + +int build_hearing_map_sort_client(struct blob_buf *b); + +int build_network_overview(struct blob_buf *b); + +int probe_array_set_all_probe_count(uint8_t client_addr[], uint32_t probe_count); + +int ap_get_collision_count(int col_domain); + +/* Utils */ + +// ---------------- Defines ------------------- +#define SORT_NUM 5 + +// ---------------- Global variables ---------------- +char *sort_string; + +// ---------------- Functions ------------------- +int better_ap_available(uint8_t bssid_addr[], uint8_t client_addr[], int automatic_kick); + + +#endif \ No newline at end of file diff --git a/src/include/dawn_iwinfo.h b/src/include/dawn_iwinfo.h new file mode 100644 index 0000000..5b143b5 --- /dev/null +++ b/src/include/dawn_iwinfo.h @@ -0,0 +1,68 @@ +#ifndef DAWN_RSSI_H +#define DAWN_RSSI_H + +#include +#include +#include +#include + +/** + * Get RSSI using the mac adress of the client. + * Function uses libiwinfo and searches through all interfaces that are existing. + * @param client_addr - mac adress of the client + * @return The RSSI of the client if successful. INT_MIN if client was not found. + */ +int get_rssi_iwinfo(__uint8_t *client_addr); + +/** + * Get expected throughut using the mac adress of the client. + * Function uses libiwinfo and searches through all interfaces that are existing. + * @param client_addr - mac adress of the client + * @return + * + The expected throughput of the client if successful. + * + INT_MIN if client was not found. + * + 0 if the client is not supporting this feature. + */ +int get_expected_throughput_iwinfo(uint8_t *client_addr); + +/** + * Get rx and tx bandwidth using the mac of the client. + * Function uses libiwinfo and searches through all interfaces that are existing. + * @param client_addr - mac adress of the client + * @param rx_rate - float pointer for returning the rx rate + * @param tx_rate - float pointer for returning the tx rate + * @return 0 if successful 1 otherwise. + */ +int get_bandwidth_iwinfo(__uint8_t *client_addr, float *rx_rate, float *tx_rate); + +/** + * Function checks if two bssid adresses have the same essid. + * Function uses libiwinfo and searches through all interfaces that are existing. + * @param bssid_addr + * @param bssid_addr_to_compares + * @return 1 if the bssid adresses have the same essid. + */ +int compare_essid_iwinfo(__uint8_t *bssid_addr, __uint8_t *bssid_addr_to_compare); + +/** + * Function returns the expected throughput using the interface and the client address. + * @param ifname + * @param client_addr + * @return + * + The expected throughput of the client if successful. + * + INT_MIN if client was not found. + * + 0 if the client is not supporting this feature. + */ +int get_expected_throughput(const char *ifname, uint8_t *client_addr); + +int get_bssid(const char *ifname, uint8_t *bssid_addr); + +int get_ssid(const char *ifname, char *ssid); + +int get_channel_utilization(const char *ifname, uint64_t *last_channel_time, uint64_t *last_channel_time_busy); + +int support_ht(const char *ifname); + +int support_vht(const char *ifname); + +#endif //DAWN_RSSI_H diff --git a/src/include/dawn_uci.h b/src/include/dawn_uci.h new file mode 100644 index 0000000..7f13930 --- /dev/null +++ b/src/include/dawn_uci.h @@ -0,0 +1,50 @@ +#ifndef DAWN_UCI_H +#define DAWN_UCI_H + +/** + * Init uci. Call this function before using the other functions! + * @return if call was successful. + */ +int uci_init(); + +/** + * Clear uci. Call this function after using uci! + * @return if call was successful. + */ +int uci_clear(); + +/** + * Function that returns the metric for the load balancing sheme using uci. + * @return the load balancing metric. + */ +struct probe_metric_s uci_get_dawn_metric(); + +/** + * Function that returns a struct with all the time config values. + * @return the time config values. + */ +struct time_config_s uci_get_time_config(); + +/** + * Function that returns all the network informations. + * @return the network config values. + */ +struct network_config_s uci_get_dawn_network(); + +/** + * Function that returns the hostapd directory reading from the config file. + * @return the hostapd directory. + */ +const char *uci_get_dawn_hostapd_dir(); + +/** + * Function that returns the sort order. + * @return the sort order. + */ +const char *uci_get_dawn_sort_order(); + +int uci_set_network(char* uci_cmd); + +int uci_reset(); + +#endif //DAWN_UCI_H_H diff --git a/src/include/ieee80211_utils.h b/src/include/ieee80211_utils.h new file mode 100644 index 0000000..92e9f20 --- /dev/null +++ b/src/include/ieee80211_utils.h @@ -0,0 +1,20 @@ +#ifndef DAWN_IEEE80211_UTILS_H +#define DAWN_IEEE80211_UTILS_H + +#include + +/** + * Calculate bitrate using the supported rates values. + * @param supp_rate_val + * @return the bitrate. + */ +double iee80211_calculate_bitrate(uint8_t supp_rate_val); + +/** + * Calculate expected throughput in Mbit/sec. + * @param exp_thr + * @return + */ +double iee80211_calculate_expected_throughput_mbit(int exp_thr); + +#endif //DAWN_IEEE80211_UTILS_H diff --git a/src/include/multicastsocket.h b/src/include/multicastsocket.h new file mode 100644 index 0000000..dab0547 --- /dev/null +++ b/src/include/multicastsocket.h @@ -0,0 +1,21 @@ +#ifndef __DAWN_MULTICASTSTSOCKET_H +#define __DAWN_MULTICASTSSOCKET_H + +/** + * Setup a multicast socket. + * Setup permissions. Join the multicast group, etc. ... + * @param _multicast_ip - multicast ip to use. + * @param _multicast_port - multicast port to use. + * @param addr + * @return the multicast socket. + */ +int setup_multicast_socket(const char *_multicast_ip, unsigned short _multicast_port, struct sockaddr_in *addr); + +/** + * Removes the multicast socket. + * @param socket + * @return + */ +int remove_multicast_socket(int socket); + +#endif diff --git a/src/include/networksocket.h b/src/include/networksocket.h new file mode 100644 index 0000000..2b26bfd --- /dev/null +++ b/src/include/networksocket.h @@ -0,0 +1,39 @@ +#ifndef __DAWN_NETWORKSOCKET_H +#define __DAWN_NETWORKSOCKET_H + +#include + +pthread_mutex_t send_mutex; + +/** + * Init a socket using the runopts. + * @param _ip - ip to use. + * @param _port - port to use. + * @param _multicast_socket - if socket should be multicast or broadcast. + * @return the socket. + */ +int init_socket_runopts(const char *_ip, int _port, int _multicast_socket); + +/** + * Send message via network. + * @param msg + * @return + */ +int send_string(char *msg); + +/** + * Send encrypted message via network. + * @param msg + * @return + */ +int send_string_enc(char *msg); + +/** + * Close socket. + */ +void close_socket(); + +// save connections +// struct sockaddr_in addr[100]; + +#endif diff --git a/src/include/tcpsocket.h b/src/include/tcpsocket.h new file mode 100644 index 0000000..1bd3670 --- /dev/null +++ b/src/include/tcpsocket.h @@ -0,0 +1,46 @@ +#ifndef DAWN_TCPSOCKET_H +#define DAWN_TCPSOCKET_H + +#include +#include +#include + +#define ARRAY_NETWORK_LEN 50 + +struct network_con_s { + struct list_head list; + + struct uloop_fd fd; + struct ustream_fd stream; + struct sockaddr_in sock_addr; + int connected; +}; + +/** + * Add tcp connection. + * @param ipv4 + * @param port + * @return + */ +int add_tcp_conncection(char *ipv4, int port); + +/** + * Opens a tcp server and adds it to the uloop. + * @param port + * @return + */ +int run_server(int port); + +/** + * Send message via tcp to all other hosts. + * @param msg + */ +void send_tcp(char *msg); + +/** + * Debug message. + */ +void print_tcp_array(); + + +#endif //DAWN_TCPSOCKET_H diff --git a/src/include/ubus.h b/src/include/ubus.h new file mode 100644 index 0000000..e786695 --- /dev/null +++ b/src/include/ubus.h @@ -0,0 +1,165 @@ +#ifndef __DAWN_UBUS_H +#define __DAWN_UBUS_H + +#include +#include + +#include "datastorage.h" + +// 802.11 Status codes +#define WLAN_STATUS_SUCCESS 0 +#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 +#define WLAN_STATUS_DENIED_NOT_HT_SUPPORT 27 +#define WLAN_STATUS_DENIED_NOT_VHT_SUPPORT 104 + +// Disassociation Reason +#define UNSPECIFIED_REASON 0 +#define NO_MORE_STAS 5 + +const char *hostapd_dir_glob; + +/** + * Init ubus. + * Setup tcp socket. + * Start ubus timer. + * @param ubus_socket + * @param hostapd_dir + * @return + */ +int dawn_init_ubus(const char *ubus_socket, const char *hostapd_dir); + +/** + * Start the umdns timer for updating the zeroconfiguration properties. + */ +void start_umdns_update(); + +/** + * Call umdns update to update the TCP connections. + * @return + */ +int ubus_call_umdns(); + +/** + * Parse to probe request. + * @param msg + * @param prob_req + * @return + */ +int parse_to_probe_req(struct blob_attr *msg, probe_entry *prob_req); + +/** + * Parse to authentication request. + * @param msg + * @param auth_req + * @return + */ +int parse_to_auth_req(struct blob_attr *msg, auth_entry *auth_req); + +/** + * Parse to association request. + * @param msg + * @param assoc_req + * @return + */ +int parse_to_assoc_req(struct blob_attr *msg, assoc_entry *assoc_req); + +/** + * Dump a client array into the database. + * @param msg - message to parse. + * @param do_kick - use the automatic kick function when updating the clients. + * @param id - ubus id. + * @return + */ +int parse_to_clients(struct blob_attr *msg, int do_kick, uint32_t id); + +/** + * Parse to hostapd notify. + * Notify are such notifications like: + * + Disassociation + * + Deauthentication + * + ... + * @param msg + * @param notify_req + * @return + */ +int parse_to_hostapd_notify(struct blob_attr *msg, hostapd_notify_entry *notify_req); + +/** + * Kick client from hostapd interface. + * @param id - the ubus id. + * @param client_addr - the client adress of the client to kick. + * @param reason - the reason to kick the client. + * @param deauth - if the client should be deauthenticated. + * @param ban_time - the ban time the client is not allowed to connect again. + */ +void del_client_interface(uint32_t id, const uint8_t *client_addr, uint32_t reason, uint8_t deauth, uint32_t ban_time); + +/** + * Kick client from all hostapd interfaces. + * @param client_addr - the client adress of the client to kick. + * @param reason - the reason to kick the client. + * @param deauth - if the client should be deauthenticated. + * @param ban_time - the ban time the client is not allowed to connect again. + */ +void del_client_all_interfaces(const uint8_t *client_addr, uint32_t reason, uint8_t deauth, uint32_t ban_time); + +/** + * Send probe message via the network. + * @param probe_entry + * @return + */ +int ubus_send_probe_via_network(struct probe_entry_s probe_entry); + +/** + * Update the hostapd sockets. + * @param t + */ +void update_hostapd_sockets(struct uloop_timeout *t); + +/** + * Set client timer for updating the clients. + * @param time + */ +void add_client_update_timer(time_t time); + +/** + * Handle network messages. + * @param msg + * @return + */ +int handle_network_msg(char *msg); + +/** + * Send message via network. + * @param msg + * @param method + * @return + */ +int send_blob_attr_via_network(struct blob_attr *msg, char *method); + +/** + * Add mac to a list that contains addresses of clients that can not be controlled. + * @param buf + * @param name + * @param addr + */ +void blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const uint8_t *addr); + +/** + * Function to set the probe counter to the min probe request. + * This allows that the client is able to connect directly without sending multiple probe requests to the Access Point. + * @param client_addr + * @return + */ +int send_set_probe(uint8_t client_addr[]); + +/** + * Send control message to all hosts to add the mac to a don't control list. + * @param client_addr + * @return + */ +int send_add_mac(uint8_t *client_addr); + +int uci_send_via_network(); + +#endif diff --git a/src/include/utils.h b/src/include/utils.h new file mode 100644 index 0000000..edc556d --- /dev/null +++ b/src/include/utils.h @@ -0,0 +1,50 @@ +#ifndef __DAWN_UTILS_H +#define __DAWN_UTILS_H + +#include +#include + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define STR2MAC(a) &(a)[0], &(a)[1], &(a)[2], &(a)[3], &(a)[4], &(a)[5] + +#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X" + +/** + * Convert char to binary. + * @param ch + * @return + */ +int hex_to_bin(char ch); + +/** + * Convert mac adress string to mac adress. + * @param txt + * @param addr + * @return + */ +int hwaddr_aton(const char *txt, uint8_t *addr); + +/** + * Convert mac to use big characters. + * @param in + * @param out + * @return + */ +int convert_mac(char *in, char *out); + +/** + * Write mac to a file. + * @param path + * @param addr + */ +void write_mac_to_file(char *path, uint8_t addr[]); + +/** + * Check if a string is greater than another one. + * @param str + * @param str_2 + * @return + */ +int string_is_greater(uint8_t *str, uint8_t *str_2); + +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..7bf3a5f --- /dev/null +++ b/src/main.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include + +#include "datastorage.h" +#include "networksocket.h" +#include "ubus.h" +#include "dawn_uci.h" +#include "tcpsocket.h" +#include "crypto.h" + +void daemon_shutdown(); + +void signal_handler(int sig); + +int init_mutex(); + +struct sigaction signal_action; + +void daemon_shutdown() { + // kill threads + close_socket(); + uci_clear(); + uloop_cancelled = true; + + // free ressources + fprintf(stdout, "Freeing mutex ressources\n"); + pthread_mutex_destroy(&probe_array_mutex); + pthread_mutex_destroy(&client_array_mutex); + pthread_mutex_destroy(&ap_array_mutex); +} + +void signal_handler(int sig) { + switch (sig) { + case SIGHUP: + daemon_shutdown(); + break; + case SIGINT: + daemon_shutdown(); + break; + case SIGTERM: + daemon_shutdown(); + exit(EXIT_SUCCESS); + default: + daemon_shutdown(); + break; + } +} + +int init_mutex() { + + if (pthread_mutex_init(&probe_array_mutex, NULL) != 0) { + fprintf(stderr, "Mutex init failed!\n"); + return 1; + } + + if (pthread_mutex_init(&client_array_mutex, NULL) != 0) { + fprintf(stderr, "Mutex init failed!\n"); + return 1; + } + + if (pthread_mutex_init(&ap_array_mutex, NULL) != 0) { + fprintf(stderr, "Mutex init failed!\n"); + return 1; + } + + if (pthread_mutex_init(&denied_array_mutex, NULL) != 0) { + fprintf(stderr, "Mutex init failed!\n"); + return 1; + } + return 0; +} + +int main(int argc, char **argv) { + + const char *ubus_socket = NULL; + + argc -= optind; + argv += optind; + + // connect signals + signal_action.sa_handler = signal_handler; + sigemptyset(&signal_action.sa_mask); + signal_action.sa_flags = 0; + sigaction(SIGHUP, &signal_action, NULL); + sigaction(SIGTERM, &signal_action, NULL); + sigaction(SIGINT, &signal_action, NULL); + + uci_init(); + struct network_config_s net_config = uci_get_dawn_network(); + network_config = net_config; + + // init crypto + gcrypt_init(); + gcrypt_set_key_and_iv(net_config.shared_key, net_config.iv); + + struct time_config_s time_config = uci_get_time_config(); + timeout_config = time_config; // TODO: Refactor... + + hostapd_dir_glob = uci_get_dawn_hostapd_dir(); + sort_string = (char *) uci_get_dawn_sort_order(); + + init_mutex(); + + switch (net_config.network_option) { + case 0: + init_socket_runopts(net_config.broadcast_ip, net_config.broadcast_port, 0); + break; + case 1: + init_socket_runopts(net_config.broadcast_ip, net_config.broadcast_port, 1); + break; + default: + break; + } + + insert_macs_from_file(); + dawn_init_ubus(ubus_socket, hostapd_dir_glob); + + return 0; +} \ No newline at end of file diff --git a/src/network/broadcastsocket.c b/src/network/broadcastsocket.c new file mode 100644 index 0000000..b6eec18 --- /dev/null +++ b/src/network/broadcastsocket.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include + +#include "networksocket.h" +#include "broadcastsocket.h" + +int setup_broadcast_socket(const char *_broadcast_ip, unsigned short _broadcast_port, struct sockaddr_in *addr) { + int sock; + int broadcast_permission; + + // Create socket + if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + fprintf(stderr, "Failed to create socket.\n"); + return -1; + } + + // Allow broadcast + broadcast_permission = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (void *) &broadcast_permission, + sizeof(broadcast_permission)) < 0) { + fprintf(stderr, "Failed to create socket.\n"); + return -1; + } + + // Constract addess + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = inet_addr(_broadcast_ip); + addr->sin_port = htons(_broadcast_port); + + // Bind socket + while (bind(sock, (struct sockaddr *) addr, sizeof(*addr)) < 0) { + fprintf(stderr, "Binding socket failed!\n"); + sleep(1); + } + return sock; +} \ No newline at end of file diff --git a/src/network/multicastsocket.c b/src/network/multicastsocket.c new file mode 100644 index 0000000..4d87fcb --- /dev/null +++ b/src/network/multicastsocket.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "multicastsocket.h" + +// based on: http://openbook.rheinwerk-verlag.de/linux_unix_programmierung/Kap11-018.htm + +static struct ip_mreq command; + +int setup_multicast_socket(const char *_multicast_ip, unsigned short _multicast_port, struct sockaddr_in *addr) { + int loop = 1; + int sock; + + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = inet_addr(_multicast_ip); + addr->sin_port = htons (_multicast_port); + + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket()"); + exit(EXIT_FAILURE); + } + + // allow multiple processes to use the same port + loop = 1; + if (setsockopt(sock, + SOL_SOCKET, + SO_REUSEADDR, + &loop, sizeof(loop)) < 0) { + perror("setsockopt:SO_REUSEADDR"); + exit(EXIT_FAILURE); + } + if (bind(sock, + (struct sockaddr *) addr, + sizeof(*addr)) < 0) { + perror("bind"); + exit(EXIT_FAILURE); + } + + // allow broadcast + loop = 1; + if (setsockopt(sock, + IPPROTO_IP, + IP_MULTICAST_LOOP, + &loop, sizeof(loop)) < 0) { + perror("setsockopt:IP_MULTICAST_LOOP"); + exit(EXIT_FAILURE); + } + + // join broadcast group + command.imr_multiaddr.s_addr = inet_addr(_multicast_ip); + command.imr_interface.s_addr = htonl (INADDR_ANY); + if (command.imr_multiaddr.s_addr == -1) { + perror("Wrong multicast address!\n"); + exit(EXIT_FAILURE); + } + if (setsockopt(sock, + IPPROTO_IP, + IP_ADD_MEMBERSHIP, + &command, sizeof(command)) < 0) { + perror("setsockopt:IP_ADD_MEMBERSHIP"); + } + return sock; +} + +int remove_multicast_socket(int socket) { + if (setsockopt(socket, + IPPROTO_IP, + IP_DROP_MEMBERSHIP, + &command, sizeof(command)) < 0) { + perror("setsockopt:IP_DROP_MEMBERSHIP"); + return -1; + } + return 0; +} \ No newline at end of file diff --git a/src/network/networksocket.c b/src/network/networksocket.c new file mode 100644 index 0000000..ef9c9c1 --- /dev/null +++ b/src/network/networksocket.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include + +#include "networksocket.h" +#include "datastorage.h" +#include "multicastsocket.h" +#include "broadcastsocket.h" +#include "ubus.h" +#include "crypto.h" + +/* Network Defines */ +#define MAX_RECV_STRING 2048 + +/* Network Attributes */ +int sock; +struct sockaddr_in addr; +const char *ip; +unsigned short port; +char recv_string[MAX_RECV_STRING + 1]; +int recv_string_len; +int multicast_socket; + +void *receive_msg(void *args); + +void *receive_msg_enc(void *args); + +int init_socket_runopts(const char *_ip, int _port, int _multicast_socket) { + + port = _port; + ip = _ip; + multicast_socket = _multicast_socket; + + if (multicast_socket) { + printf("Settingup multicastsocket!\n"); + sock = setup_multicast_socket(ip, port, &addr); + } else { + sock = setup_broadcast_socket(ip, port, &addr); + } + + pthread_t sniffer_thread; + if (network_config.use_symm_enc) { + if (pthread_create(&sniffer_thread, NULL, receive_msg_enc, NULL)) { + fprintf(stderr, "Could not create receiving thread!\n"); + return -1; + } + } else { + if (pthread_create(&sniffer_thread, NULL, receive_msg, NULL)) { + fprintf(stderr, "Could not create receiving thread!\n"); + return -1; + } + } + + fprintf(stdout, "Connected to %s:%d\n", ip, port); + + return 0; +} + +void *receive_msg(void *args) { + while (1) { + if ((recv_string_len = + recvfrom(sock, recv_string, MAX_RECV_STRING, 0, NULL, 0)) < 0) { + fprintf(stderr, "Could not receive message!"); + continue; + } + + if (recv_string == NULL) { + return 0; + } + + if (strlen(recv_string) <= 0) { + return 0; + } + recv_string[recv_string_len] = '\0'; + + printf("Received network message: %s\n", recv_string); + handle_network_msg(recv_string); + } +} + +void *receive_msg_enc(void *args) { + while (1) { + if ((recv_string_len = + recvfrom(sock, recv_string, MAX_RECV_STRING, 0, NULL, 0)) < 0) { + fprintf(stderr, "Could not receive message!\n"); + continue; + } + + if (recv_string == NULL) { + return 0; + } + + if (strlen(recv_string) <= 0) { + return 0; + } + recv_string[recv_string_len] = '\0'; + + char *base64_dec_str = malloc(B64_DECODE_LEN(strlen(recv_string))); + int base64_dec_length = b64_decode(recv_string, base64_dec_str, B64_DECODE_LEN(strlen(recv_string))); + char *dec = gcrypt_decrypt_msg(base64_dec_str, base64_dec_length); + + printf("Received network message: %s\n", dec); + free(base64_dec_str); + handle_network_msg(dec); + free(dec); + } +} + +int send_string(char *msg) { + pthread_mutex_lock(&send_mutex); + size_t msglen = strlen(msg); + + if (sendto(sock, + msg, + msglen, + 0, + (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + perror("sendto()"); + pthread_mutex_unlock(&send_mutex); + exit(EXIT_FAILURE); + } + pthread_mutex_unlock(&send_mutex); + + return 0; +} + +int send_string_enc(char *msg) { + pthread_mutex_lock(&send_mutex); + + int length_enc; + size_t msglen = strlen(msg); + char *enc = gcrypt_encrypt_msg(msg, msglen + 1, &length_enc); + + char *base64_enc_str = malloc(B64_ENCODE_LEN(length_enc)); + size_t base64_enc_length = b64_encode(enc, length_enc, base64_enc_str, B64_ENCODE_LEN(length_enc)); + + if (sendto(sock, + base64_enc_str, + base64_enc_length, // very important to use actual length of string because of '\0' in encrypted msg + 0, + (struct sockaddr *) &addr, + sizeof(addr)) < 0) { + perror("sendto()"); + pthread_mutex_unlock(&send_mutex); + exit(EXIT_FAILURE); + } + free(base64_enc_str); + free(enc); + pthread_mutex_unlock(&send_mutex); + return 0; +} + +void close_socket() { + if (multicast_socket) { + remove_multicast_socket(sock); + } + close(sock); +} diff --git a/src/network/tcpsocket.c b/src/network/tcpsocket.c new file mode 100644 index 0000000..34b4330 --- /dev/null +++ b/src/network/tcpsocket.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include // base64 encoding +#include +#include +#include +#include +#include "tcpsocket.h" +#include +#include "ubus.h" +#include "crypto.h" + +LIST_HEAD(tcp_sock_list); + +struct network_con_s *tcp_list_contains_address(struct sockaddr_in entry); + +static struct uloop_fd server; +struct client *next_client = NULL; + +struct client { + struct sockaddr_in sin; + + struct ustream_fd s; + int ctr; + int counter; +}; + +static void client_close(struct ustream *s) { + struct client *cl = container_of(s, + struct client, s.stream); + + fprintf(stderr, "Connection closed\n"); + ustream_free(s); + close(cl->s.fd.fd); + free(cl); +} + +static void client_notify_write(struct ustream *s, int bytes) { + return; +} + +static void client_notify_state(struct ustream *s) { + struct client *cl = container_of(s, + struct client, s.stream); + + if (!s->eof) + return; + + fprintf(stderr, "eof!, pending: %d, total: %d\n", s->w.data_bytes, cl->ctr); + + if (!s->w.data_bytes) + return client_close(s); + +} + +static void client_to_server_close(struct ustream *s) { + struct network_con_s *con = container_of(s, + struct network_con_s, stream.stream); + + fprintf(stderr, "Connection to server closed\n"); + ustream_free(s); + close(con->fd.fd); + list_del(&con->list); + free(con); +} + +static void client_to_server_state(struct ustream *s) { + struct client *cl = container_of(s, + struct client, s.stream); + + if (!s->eof) + return; + + fprintf(stderr, "eof!, pending: %d, total: %d\n", s->w.data_bytes, cl->ctr); + + if (!s->w.data_bytes) + return client_to_server_close(s); + +} + +static void client_read_cb(struct ustream *s, int bytes) { + char *str; + int len; + + do { + str = ustream_get_read_buf(s, &len); + if (!str) + break; + + if (network_config.use_symm_enc) { + char *base64_dec_str = malloc(B64_DECODE_LEN(strlen(str))); + int base64_dec_length = b64_decode(str, base64_dec_str, B64_DECODE_LEN(strlen(str))); + char *dec = gcrypt_decrypt_msg(base64_dec_str, base64_dec_length); + + free(base64_dec_str); + handle_network_msg(dec); + free(dec); + } else { + handle_network_msg(str); + } + + ustream_consume(s, len); + + } while (1); + + if (s->w.data_bytes > 256 && !ustream_read_blocked(s)) { + fprintf(stderr, "Block read, bytes: %d\n", s->w.data_bytes); + ustream_set_read_blocked(s, true); + } +} + +static void server_cb(struct uloop_fd *fd, unsigned int events) { + struct client *cl; + unsigned int sl = sizeof(struct sockaddr_in); + int sfd; + + if (!next_client) + next_client = calloc(1, sizeof(*next_client)); + + cl = next_client; + sfd = accept(server.fd, (struct sockaddr *) &cl->sin, &sl); + if (sfd < 0) { + fprintf(stderr, "Accept failed\n"); + return; + } + + cl->s.stream.string_data = 1; + cl->s.stream.notify_read = client_read_cb; + cl->s.stream.notify_state = client_notify_state; + cl->s.stream.notify_write = client_notify_write; + ustream_fd_init(&cl->s, sfd); + next_client = NULL; + fprintf(stderr, "New connection\n"); +} + +int run_server(int port) { + char port_str[12]; + sprintf(port_str, "%d", port); + + server.cb = server_cb; + server.fd = usock(USOCK_TCP | USOCK_SERVER | USOCK_IPV4ONLY | USOCK_NUMERIC, INADDR_ANY, port_str); + if (server.fd < 0) { + perror("usock"); + return 1; + } + + uloop_fd_add(&server, ULOOP_READ); + + return 0; +} + +static void client_not_be_used_read_cb(struct ustream *s, int bytes) { + int len; + char buf[2048]; + + len = ustream_read(s, buf, sizeof(buf)); + buf[len] = '\0'; + printf("Read %d bytes from SSL connection: %s\n", len, buf); +} + +static void connect_cb(struct uloop_fd *f, unsigned int events) { + + struct network_con_s *entry = container_of(f, + struct network_con_s, fd); + + if (f->eof || f->error) { + fprintf(stderr, "Connection failed\n"); + close(entry->fd.fd); + list_del(&entry->list); + free(entry); + return; + } + + fprintf(stderr, "Connection established\n"); + uloop_fd_delete(&entry->fd); + + entry->stream.stream.notify_read = client_not_be_used_read_cb; + entry->stream.stream.notify_state = client_to_server_state; + + ustream_fd_init(&entry->stream, entry->fd.fd); + entry->connected = 1; +} + +int add_tcp_conncection(char *ipv4, int port) { + struct sockaddr_in serv_addr; + + char port_str[12]; + sprintf(port_str, "%d", port); + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(ipv4); + serv_addr.sin_port = htons(port); + + struct network_con_s *tmp = tcp_list_contains_address(serv_addr); + if (tmp != NULL) { + if(tmp->connected == true) + { + return 0; + } else{ + // Delete already existing entry + close(tmp->fd.fd); + list_del(&tmp->list); + free(tmp); + } + } + + struct network_con_s *tcp_entry = calloc(1, sizeof(struct network_con_s)); + tcp_entry->fd.fd = usock(USOCK_TCP | USOCK_NONBLOCK, ipv4, port_str); + tcp_entry->sock_addr = serv_addr; + + if (tcp_entry->fd.fd < 0) { + free(tcp_entry); + return -1; + } + tcp_entry->fd.cb = connect_cb; + uloop_fd_add(&tcp_entry->fd, ULOOP_WRITE | ULOOP_EDGE_TRIGGER); + + printf("New TCP connection to %s:%d\n", ipv4, port); + list_add(&tcp_entry->list, &tcp_sock_list); + + return 0; +} + +void send_tcp(char *msg) { + print_tcp_array(); + if (network_config.use_symm_enc) { + int length_enc; + size_t msglen = strlen(msg); + char *enc = gcrypt_encrypt_msg(msg, msglen + 1, &length_enc); + + char *base64_enc_str = malloc(B64_ENCODE_LEN(length_enc)); + size_t base64_enc_length = b64_encode(enc, length_enc, base64_enc_str, B64_ENCODE_LEN(length_enc)); + struct network_con_s *con; + list_for_each_entry(con, &tcp_sock_list, list) + { + if (con->connected) { + int len_ustream = ustream_write(&con->stream.stream, base64_enc_str, base64_enc_length, 0); + printf("Ustream send: %d\n", len_ustream); + if (len_ustream <= 0) { + fprintf(stderr,"Ustream error!\n"); + //TODO: ERROR HANDLING! + } + } + + } + + free(base64_enc_str); + free(enc); + } else { + struct network_con_s *con; + + list_for_each_entry(con, &tcp_sock_list, list) + { + if (con->connected) { + if (ustream_printf(&con->stream.stream, "%s", msg) == 0) { + //TODO: ERROR HANDLING! + fprintf(stderr,"Ustream error!\n"); + } + } + } + } +} + +struct network_con_s* tcp_list_contains_address(struct sockaddr_in entry) { + struct network_con_s *con; + + list_for_each_entry(con, &tcp_sock_list, list) + { + if(entry.sin_addr.s_addr == con->sock_addr.sin_addr.s_addr) + { + return con; + } + } + return NULL; +} + +void print_tcp_array() { + struct network_con_s *con; + + printf("--------Connections------\n"); + list_for_each_entry(con, &tcp_sock_list, list) + { + printf("Conenctin to Port: %d, Connected: %s\n", con->sock_addr.sin_port, con->connected ? "True" : "False"); + } + printf("------------------\n"); +} \ No newline at end of file diff --git a/src/storage/datastorage.c b/src/storage/datastorage.c new file mode 100644 index 0000000..372c0f2 --- /dev/null +++ b/src/storage/datastorage.c @@ -0,0 +1,1290 @@ +#include "datastorage.h" + +#include +#include + +#include "ubus.h" +#include "dawn_iwinfo.h" +#include "utils.h" +#include "ieee80211_utils.h" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] + +int go_next_help(char sort_order[], int i, probe_entry entry, + probe_entry next_entry); + +int go_next(char sort_order[], int i, probe_entry entry, + probe_entry next_entry); + +void remove_old_probe_entries(time_t current_time, long long int threshold); + +int client_array_go_next(char sort_order[], int i, client entry, + client next_entry); + +int client_array_go_next_help(char sort_order[], int i, client entry, + client next_entry); + +void remove_old_client_entries(time_t current_time, long long int threshold); + +int eval_probe_metric(struct probe_entry_s probe_entry); + +int kick_client(struct client_s client_entry); + +void ap_array_insert(ap entry); + +ap ap_array_delete(ap entry); + +void remove_old_ap_entries(time_t current_time, long long int threshold); + +void print_ap_entry(ap entry); + +int probe_array_update_rssi(uint8_t bssid_addr[], uint8_t client_addr[], uint32_t rssi); + +int is_connected(uint8_t bssid_addr[], uint8_t client_addr[]); + +int is_connected_somehwere(uint8_t client_addr[]); + +int compare_station_count(uint8_t *bssid_addr_own, uint8_t *bssid_addr_to_compare, uint8_t *client_addr, + int automatic_kick); + +int compare_ssid(uint8_t *bssid_addr_own, uint8_t *bssid_addr_to_compare); + +void denied_req_array_insert(auth_entry entry); + +auth_entry denied_req_array_delete(auth_entry entry); + +int denied_req_array_go_next(char sort_order[], int i, auth_entry entry, + auth_entry next_entry); + +int denied_req_array_go_next_help(char sort_order[], int i, auth_entry entry, + auth_entry next_entry); + +int probe_entry_last = -1; +int client_entry_last = -1; +int ap_entry_last = -1; +int mac_list_entry_last = -1; +int denied_req_last = -1; + +void remove_probe_array_cb(struct uloop_timeout *t); + +struct uloop_timeout probe_timeout = { + .cb = remove_probe_array_cb +}; + +void remove_client_array_cb(struct uloop_timeout *t); + +struct uloop_timeout client_timeout = { + .cb = remove_client_array_cb +}; + +void remove_ap_array_cb(struct uloop_timeout *t); + +struct uloop_timeout ap_timeout = { + .cb = remove_ap_array_cb +}; + +void denied_req_array_cb(struct uloop_timeout *t); + +struct uloop_timeout denied_req_timeout = { + .cb = denied_req_array_cb +}; + +int build_hearing_map_sort_client(struct blob_buf *b) { + print_probe_array(); + pthread_mutex_lock(&probe_array_mutex); + + void *client_list, *ap_list, *ssid_list; + char ap_mac_buf[20]; + char client_mac_buf[20]; + + blob_buf_init(b, 0); + int m; + for (m = 0; m <= ap_entry_last; m++) { + if (m > 0) { + if (strcmp((char *) ap_array[m].ssid, (char *) ap_array[m - 1].ssid) == 0) { + continue; + } + } + ssid_list = blobmsg_open_table(b, (char *) ap_array[m].ssid); + + int i; + for (i = 0; i <= probe_entry_last; i++) { + /*if(!mac_is_equal(ap_array[m].bssid_addr, probe_array[i].bssid_addr)) + { + continue; + }*/ + + ap ap_entry_i = ap_array_get_ap(probe_array[i].bssid_addr); + + if (!mac_is_equal(ap_entry_i.bssid_addr, probe_array[i].bssid_addr)) { + continue; + } + + if (strcmp((char *) ap_entry_i.ssid, (char *) ap_array[m].ssid) != 0) { + continue; + } + + int k; + sprintf(client_mac_buf, MACSTR, MAC2STR(probe_array[i].client_addr)); + client_list = blobmsg_open_table(b, client_mac_buf); + for (k = i; k <= probe_entry_last; k++) { + ap ap_entry = ap_array_get_ap(probe_array[k].bssid_addr); + + if (!mac_is_equal(ap_entry.bssid_addr, probe_array[k].bssid_addr)) { + continue; + } + + if (strcmp((char *) ap_entry.ssid, (char *) ap_array[m].ssid) != 0) { + continue; + } + + if (!mac_is_equal(probe_array[k].client_addr, probe_array[i].client_addr)) { + i = k - 1; + break; + } else if (k == probe_entry_last) { + i = k; + } + + sprintf(ap_mac_buf, MACSTR, MAC2STR(probe_array[k].bssid_addr)); + ap_list = blobmsg_open_table(b, ap_mac_buf); + blobmsg_add_u32(b, "signal", probe_array[k].signal); + blobmsg_add_u32(b, "freq", probe_array[k].freq); + blobmsg_add_u8(b, "ht_capabilities", probe_array[k].ht_capabilities); + blobmsg_add_u8(b, "vht_capabilities", probe_array[k].vht_capabilities); + + + // check if ap entry is available + blobmsg_add_u32(b, "channel_utilization", ap_entry.channel_utilization); + blobmsg_add_u32(b, "num_sta", ap_entry.station_count); + blobmsg_add_u8(b, "ht_support", ap_entry.ht_support); + blobmsg_add_u8(b, "vht_support", ap_entry.vht_support); + + blobmsg_add_u32(b, "score", eval_probe_metric(probe_array[k])); + blobmsg_close_table(b, ap_list); + } + blobmsg_close_table(b, client_list); + } + blobmsg_close_table(b, ssid_list); + } + pthread_mutex_unlock(&probe_array_mutex); + return 0; +} + +int build_network_overview(struct blob_buf *b) { + void *client_list, *ap_list, *ssid_list; + char ap_mac_buf[20]; + char client_mac_buf[20]; + + blob_buf_init(b, 0); + int m; + for (m = 0; m <= ap_entry_last; m++) { + if (m > 0) { + if (strcmp((char *) ap_array[m].ssid, (char *) ap_array[m - 1].ssid) == 0) { + continue; + } + } + + ssid_list = blobmsg_open_table(b, (char *) ap_array[m].ssid); + + int i; + for (i = 0; i <= client_entry_last; i++) { + ap ap_entry_i = ap_array_get_ap(client_array[i].bssid_addr); + + if (strcmp((char *) ap_entry_i.ssid, (char *) ap_array[m].ssid) != 0) { + continue; + } + int k; + sprintf(ap_mac_buf, MACSTR, MAC2STR(client_array[i].bssid_addr)); + ap_list = blobmsg_open_table(b, ap_mac_buf); + + blobmsg_add_u32(b, "freq", ap_entry_i.freq); + blobmsg_add_u32(b, "channel_utilization", ap_entry_i.channel_utilization); + blobmsg_add_u32(b, "num_sta", ap_entry_i.station_count); + blobmsg_add_u8(b, "ht_support", ap_entry_i.ht_support); + blobmsg_add_u8(b, "vht_support", ap_entry_i.vht_support); + + for (k = i; k <= client_entry_last; k++) { + if (!mac_is_equal(client_array[k].bssid_addr, client_array[i].bssid_addr)) { + i = k - 1; + break; + } else if (k == client_entry_last) { + i = k; + } + + sprintf(client_mac_buf, MACSTR, MAC2STR(client_array[k].client_addr)); + client_list = blobmsg_open_table(b, client_mac_buf); + if(strlen(client_array[k].signature) != 0) + { + char *s; + s = blobmsg_alloc_string_buffer(b, "signature", 1024); + sprintf(s, "%s", client_array[k].signature); + blobmsg_add_string_buffer(b); + } + blobmsg_add_u8(b, "ht", client_array[k].ht); + blobmsg_add_u8(b, "vht", client_array[k].vht); + blobmsg_add_u32(b, "collision_count", ap_get_collision_count(ap_array[m].collision_domain)); + + int n; + for(n = 0; n <= probe_entry_last; n++) + { + if (mac_is_equal(client_array[k].client_addr, probe_array[n].client_addr) && + mac_is_equal(client_array[k].bssid_addr, probe_array[n].bssid_addr)) { + blobmsg_add_u32(b, "signal", probe_array[n].signal); + break; + } + } + blobmsg_close_table(b, client_list); + } + blobmsg_close_table(b, ap_list); + } + blobmsg_close_table(b, ssid_list); + } + return 0; +} + +int eval_probe_metric(struct probe_entry_s probe_entry) { + + int score = 0; + + ap ap_entry = ap_array_get_ap(probe_entry.bssid_addr); + + // check if ap entry is available + if (mac_is_equal(ap_entry.bssid_addr, probe_entry.bssid_addr)) { + score += probe_entry.ht_capabilities && ap_entry.ht_support ? dawn_metric.ht_support : 0; + score += !probe_entry.ht_capabilities && !ap_entry.ht_support ? dawn_metric.no_ht_support : 0; + + // performance anomaly? + if (network_config.bandwidth >= 1000 || network_config.bandwidth == -1) { + score += probe_entry.vht_capabilities && ap_entry.vht_support ? dawn_metric.vht_support : 0; + } + + score += !probe_entry.vht_capabilities && !ap_entry.vht_support ? dawn_metric.no_vht_support : 0; + score += ap_entry.channel_utilization <= dawn_metric.chan_util_val ? dawn_metric.chan_util : 0; + score += ap_entry.channel_utilization > dawn_metric.max_chan_util_val ? dawn_metric.max_chan_util : 0; + + score += ap_entry.ap_weight; + } + + score += (probe_entry.freq > 5000) ? dawn_metric.freq : 0; + score += (probe_entry.signal >= dawn_metric.rssi_val) ? dawn_metric.rssi : 0; + score += (probe_entry.signal <= dawn_metric.low_rssi_val) ? dawn_metric.low_rssi : 0; + + if (score < 0) + score = -2; // -1 already used... + + printf("Score: %d of:\n", score); + print_probe_entry(probe_entry); + + return score; +} + +int compare_ssid(uint8_t *bssid_addr_own, uint8_t *bssid_addr_to_compare) { + ap ap_entry_own = ap_array_get_ap(bssid_addr_own); + ap ap_entry_to_compre = ap_array_get_ap(bssid_addr_to_compare); + + if (mac_is_equal(ap_entry_own.bssid_addr, bssid_addr_own) && + mac_is_equal(ap_entry_to_compre.bssid_addr, bssid_addr_to_compare)) { + return (strcmp((char *) ap_entry_own.ssid, (char *) ap_entry_to_compre.ssid) == 0); + } + return 0; +} + +int compare_station_count(uint8_t *bssid_addr_own, uint8_t *bssid_addr_to_compare, uint8_t *client_addr, + int automatic_kick) { + + ap ap_entry_own = ap_array_get_ap(bssid_addr_own); + ap ap_entry_to_compre = ap_array_get_ap(bssid_addr_to_compare); + + // check if ap entry is available + if (mac_is_equal(ap_entry_own.bssid_addr, bssid_addr_own) + && mac_is_equal(ap_entry_to_compre.bssid_addr, bssid_addr_to_compare) + ) { + printf("Comparing own %d to %d\n", ap_entry_own.station_count, ap_entry_to_compre.station_count); + + + int sta_count = ap_entry_own.station_count; + int sta_count_to_compare = ap_entry_to_compre.station_count; + if (is_connected(bssid_addr_own, client_addr)) { + printf("Own is already connected! Decrease counter!\n"); + sta_count--; + } + + if (is_connected(bssid_addr_to_compare, client_addr)) { + printf("Comparing station is already connected! Decrease counter!\n"); + sta_count_to_compare--; + } + printf("Comparing own station count %d to %d\n", sta_count, sta_count_to_compare); + + return sta_count - sta_count_to_compare > dawn_metric.max_station_diff; + } + + return 0; +} + + +int better_ap_available(uint8_t bssid_addr[], uint8_t client_addr[], int automatic_kick) { + int own_score = -1; + + // find first client entry in probe array + int i; + for (i = 0; i <= probe_entry_last; i++) { + if (mac_is_equal(probe_array[i].client_addr, client_addr)) { + break; + } + } + + // find own probe entry and calculate score + int j; + for (j = i; j <= probe_entry_last; j++) { + if (!mac_is_equal(probe_array[j].client_addr, client_addr)) { + // this shouldn't happen! + //return 1; // kick client! + //return 0; + break; + } + if (mac_is_equal(bssid_addr, probe_array[j].bssid_addr)) { + printf("Calculating own score!\n"); + own_score = eval_probe_metric(probe_array[j]); + break; + } + } + + // no entry for own ap + if (own_score == -1) { + return -1; + } + + int k; + for (k = i; k <= probe_entry_last; k++) { + int score_to_compare; + + if (!mac_is_equal(probe_array[k].client_addr, client_addr)) { + break; + } + + if (mac_is_equal(bssid_addr, probe_array[k].bssid_addr)) { + printf("Own Score! Skipping!\n"); + print_probe_entry(probe_array[k]); + continue; + } + + // check if same ssid! + if (!compare_ssid(bssid_addr, probe_array[k].bssid_addr)) { + continue; + } + + printf("Calculating score to compare!\n"); + score_to_compare = eval_probe_metric(probe_array[k]); + + if (own_score < score_to_compare) { + return 1; + } + if (dawn_metric.use_station_count && own_score == score_to_compare) { + + // only compare if score is bigger or equal 0 + if (own_score >= 0) { + + // if ap have same value but station count is different... + if (compare_station_count(bssid_addr, probe_array[k].bssid_addr, probe_array[k].client_addr, + automatic_kick)) { + return 1; + } + } + } + } + return 0; +} + +int kick_client(struct client_s client_entry) { + return !mac_in_maclist(client_entry.client_addr) && + better_ap_available(client_entry.bssid_addr, client_entry.client_addr, 1); +} + +void kick_clients(uint8_t bssid[], uint32_t id) { + pthread_mutex_lock(&client_array_mutex); + pthread_mutex_lock(&probe_array_mutex); + printf("-------- KICKING CLIENS!!!---------\n"); + char mac_buf_ap[20]; + sprintf(mac_buf_ap, MACSTR, MAC2STR(bssid)); + printf("EVAL %s\n", mac_buf_ap); + + // Seach for BSSID + int i; + for (i = 0; i <= client_entry_last; i++) { + if (mac_is_equal(client_array[i].bssid_addr, bssid)) { + break; + } + } + + // Go threw clients + int j; + for (j = i; j <= client_entry_last; j++) { + if (!mac_is_equal(client_array[j].bssid_addr, bssid)) { + break; + } + + // update rssi + int rssi = get_rssi_iwinfo(client_array[j].client_addr); + int exp_thr = get_expected_throughput_iwinfo(client_array[j].client_addr); + double exp_thr_tmp = iee80211_calculate_expected_throughput_mbit(exp_thr); + printf("Expectd throughput %f Mbit/sec\n", exp_thr_tmp); + + if (rssi != INT_MIN) { + pthread_mutex_unlock(&probe_array_mutex); + if (!probe_array_update_rssi(client_array[j].bssid_addr, client_array[j].client_addr, rssi)) { + printf("Failed to update rssi!\n"); + } else { + printf("Updated rssi: %d\n", rssi); + } + pthread_mutex_lock(&probe_array_mutex); + + } + + int do_kick = kick_client(client_array[j]); + + // better ap available + if (do_kick > 0) { + + // kick after algorithm decided to kick several times + // + rssi is changing a lot + // + chan util is changing a lot + // + ping pong behavior of clients will be reduced + client_array[j].kick_count++; + printf("Comparing kick count! kickcount: %d to min_kick_count: %d!\n", client_array[j].kick_count, + dawn_metric.min_kick_count); + if (client_array[j].kick_count < dawn_metric.min_kick_count) { + continue; + } + + printf("Better AP available. Kicking client:\n"); + print_client_entry(client_array[j]); + printf("Check if client is active receiving!\n"); + + float rx_rate, tx_rate; + if (get_bandwidth_iwinfo(client_array[j].client_addr, &rx_rate, &tx_rate)) { + // only use rx_rate for indicating if transmission is going on + // <= 6MBits <- probably no transmission + // tx_rate has always some weird value so don't use ist + if (rx_rate > dawn_metric.bandwith_threshold) { + printf("Client is probably in active transmisison. Don't kick! RxRate is: %f\n", rx_rate); + continue; + } + } + printf("Client is probably NOT in active transmisison. KICK! RxRate is: %f\n", rx_rate); + + + // here we should send a messsage to set the probe.count for all aps to the min that there is no delay between switching + // the hearing map is full... + send_set_probe(client_array[j].client_addr); + + // don't deauth station? <- deauth is better! + // maybe we can use handovers... + del_client_interface(id, client_array[j].client_addr, NO_MORE_STAS, 1, 1000); + client_array_delete(client_array[j]); + + // don't delete clients in a row. use update function again... + // -> chan_util update, ... + add_client_update_timer(timeout_config.update_client * 1000 / 4); + break; + + // no entry in probe array for own bssid + } else if (do_kick == -1) { + printf("No Information about client. Force reconnect:\n"); + print_client_entry(client_array[j]); + del_client_interface(id, client_array[j].client_addr, 0, 1, 0); + + // ap is best + } else { + printf("AP is best. Client will stay:\n"); + print_client_entry(client_array[j]); + // set kick counter to 0 again + client_array[j].kick_count = 0; + } + } + + printf("---------------------------\n"); + + pthread_mutex_unlock(&probe_array_mutex); + pthread_mutex_unlock(&client_array_mutex); +} + +int is_connected_somehwere(uint8_t client_addr[]) { + int i; + int found_in_array = 0; + + if (client_entry_last == -1) { + return 0; + } + + for (i = 0; i <= client_entry_last; i++) { + if (mac_is_equal(client_addr, client_array[i].client_addr)) { + found_in_array = 1; + break; + } + } + return found_in_array; +} + +int is_connected(uint8_t bssid_addr[], uint8_t client_addr[]) { + int i; + int found_in_array = 0; + + if (client_entry_last == -1) { + return 0; + } + + for (i = 0; i <= client_entry_last; i++) { + + if (mac_is_equal(bssid_addr, client_array[i].bssid_addr) && + mac_is_equal(client_addr, client_array[i].client_addr)) { + found_in_array = 1; + break; + } + } + return found_in_array; +} + +int client_array_go_next_help(char sort_order[], int i, client entry, + client next_entry) { + switch (sort_order[i]) { + // bssid-mac + case 'b': + return mac_is_greater(entry.bssid_addr, next_entry.bssid_addr); + // client-mac + case 'c': + return mac_is_greater(entry.client_addr, next_entry.client_addr) && + mac_is_equal(entry.bssid_addr, next_entry.bssid_addr); + default: + break; + } + return 0; +} + +int client_array_go_next(char sort_order[], int i, client entry, + client next_entry) { + int conditions = 1; + for (int j = 0; j < i; j++) { + i &= !(client_array_go_next(sort_order, j, entry, next_entry)); + } + return conditions && client_array_go_next_help(sort_order, i, entry, next_entry); +} + +void client_array_insert(client entry) { + if (client_entry_last == -1) { + client_array[0] = entry; + client_entry_last++; + return; + } + + int i; + for (i = 0; i <= client_entry_last; i++) { + if (!client_array_go_next("bc", 2, entry, client_array[i])) { + break; + } + } + for (int j = client_entry_last; j >= i; j--) { + if (j + 1 <= ARRAY_CLIENT_LEN) { + client_array[j + 1] = client_array[j]; + } + } + client_array[i] = entry; + + if (client_entry_last < ARRAY_CLIENT_LEN) { + client_entry_last++; + } +} + +client client_array_delete(client entry) { + + int i; + int found_in_array = 0; + client tmp; + + if (client_entry_last == -1) { + return tmp; + } + + for (i = 0; i <= client_entry_last; i++) { + if (mac_is_equal(entry.bssid_addr, client_array[i].bssid_addr) && + mac_is_equal(entry.client_addr, client_array[i].client_addr)) { + found_in_array = 1; + tmp = client_array[i]; + break; + } + } + + for (int j = i; j < client_entry_last; j++) { + client_array[j] = client_array[j + 1]; + } + + if (client_entry_last > -1 && found_in_array) { + client_entry_last--; + } + return tmp; +} + + +void probe_array_insert(probe_entry entry) { + if (probe_entry_last == -1) { + probe_array[0] = entry; + probe_entry_last++; + return; + } + + int i; + for (i = 0; i <= probe_entry_last; i++) { + if (!go_next(sort_string, SORT_NUM, entry, probe_array[i])) { + break; + } + } + for (int j = probe_entry_last; j >= i; j--) { + if (j + 1 <= PROBE_ARRAY_LEN) { + probe_array[j + 1] = probe_array[j]; + } + } + probe_array[i] = entry; + + if (probe_entry_last < PROBE_ARRAY_LEN) { + probe_entry_last++; + } +} + +probe_entry probe_array_delete(probe_entry entry) { + int i; + int found_in_array = 0; + probe_entry tmp; + + if (probe_entry_last == -1) { + return tmp; + } + + for (i = 0; i <= probe_entry_last; i++) { + if (mac_is_equal(entry.bssid_addr, probe_array[i].bssid_addr) && + mac_is_equal(entry.client_addr, probe_array[i].client_addr)) { + found_in_array = 1; + tmp = probe_array[i]; + break; + } + } + + for (int j = i; j < probe_entry_last; j++) { + probe_array[j] = probe_array[j + 1]; + } + + if (probe_entry_last > -1 && found_in_array) { + probe_entry_last--; + } + return tmp; +} + +int probe_array_set_all_probe_count(uint8_t client_addr[], uint32_t probe_count) { + + int updated = 0; + + if (probe_entry_last == -1) { + return 0; + } + + pthread_mutex_lock(&probe_array_mutex); + for (int i = 0; i <= probe_entry_last; i++) { + if (mac_is_equal(client_addr, probe_array[i].client_addr)) { + printf("Setting probecount for given mac!\n"); + probe_array[i].counter = probe_count; + } else if (!mac_is_greater(client_addr, probe_array[i].client_addr)) { + printf("MAC not found!\n"); + break; + } + } + pthread_mutex_unlock(&probe_array_mutex); + + return updated; +} + +int probe_array_update_rssi(uint8_t bssid_addr[], uint8_t client_addr[], uint32_t rssi) { + + int updated = 0; + + if (probe_entry_last == -1) { + return 0; + } + + + pthread_mutex_lock(&probe_array_mutex); + for (int i = 0; i <= probe_entry_last; i++) { + if (mac_is_equal(bssid_addr, probe_array[i].bssid_addr) && + mac_is_equal(client_addr, probe_array[i].client_addr)) { + probe_array[i].signal = rssi; + updated = 1; + ubus_send_probe_via_network(probe_array[i]); + break; + //TODO: break?! + } + } + pthread_mutex_unlock(&probe_array_mutex); + + return updated; +} + +probe_entry probe_array_get_entry(uint8_t bssid_addr[], uint8_t client_addr[]) { + + int i; + probe_entry tmp = {.bssid_addr = {0, 0, 0, 0, 0, 0}, .client_addr = {0, 0, 0, 0, 0, 0}}; + + if (probe_entry_last == -1) { + return tmp; + } + + pthread_mutex_lock(&probe_array_mutex); + for (i = 0; i <= probe_entry_last; i++) { + if (mac_is_equal(bssid_addr, probe_array[i].bssid_addr) && + mac_is_equal(client_addr, probe_array[i].client_addr)) { + tmp = probe_array[i]; + break; + } + } + pthread_mutex_unlock(&probe_array_mutex); + + return tmp; +} + +void print_probe_array() { + printf("------------------\n"); + printf("Probe Entry Last: %d\n", probe_entry_last); + for (int i = 0; i <= probe_entry_last; i++) { + print_probe_entry(probe_array[i]); + } + printf("------------------\n"); +} + +probe_entry insert_to_array(probe_entry entry, int inc_counter) { + pthread_mutex_lock(&probe_array_mutex); + + entry.time = time(0); + entry.counter = 0; + probe_entry tmp = probe_array_delete(entry); + + if (mac_is_equal(entry.bssid_addr, tmp.bssid_addr) + && mac_is_equal(entry.client_addr, tmp.client_addr)) { + entry.counter = tmp.counter; + } + + if (inc_counter) { + + entry.counter++; + } + + probe_array_insert(entry); + + pthread_mutex_unlock(&probe_array_mutex); + + return entry; +} + +ap insert_to_ap_array(ap entry) { + pthread_mutex_lock(&ap_array_mutex); + + entry.time = time(0); + ap_array_delete(entry); + ap_array_insert(entry); + pthread_mutex_unlock(&ap_array_mutex); + + return entry; +} + +int ap_get_collision_count(int col_domain) { + + int ret_sta_count = 0; + + pthread_mutex_lock(&ap_array_mutex); + int i; + + for (i = 0; i <= ap_entry_last; i++) { + if (ap_array[i].collision_domain == col_domain) + ret_sta_count += ap_array[i].station_count; + } + pthread_mutex_unlock(&ap_array_mutex); + + return ret_sta_count; +} + +ap ap_array_get_ap(uint8_t bssid_addr[]) { + ap ret = {.bssid_addr = {0, 0, 0, 0, 0, 0}}; + + if (ap_entry_last == -1) { + return ret; + } + + pthread_mutex_lock(&ap_array_mutex); + int i; + + for (i = 0; i <= ap_entry_last; i++) { + if (mac_is_equal(bssid_addr, ap_array[i].bssid_addr)) { + //|| mac_is_greater(ap_array[i].bssid_addr, bssid_addr)) { + break; + } + } + ret = ap_array[i]; + pthread_mutex_unlock(&ap_array_mutex); + + return ret; +} + +void ap_array_insert(ap entry) { + if (ap_entry_last == -1) { + ap_array[0] = entry; + ap_entry_last++; + return; + } + + int i; + for (i = 0; i <= ap_entry_last; i++) { + if (mac_is_greater(entry.bssid_addr, ap_array[i].bssid_addr) && + strcmp((char *) entry.ssid, (char *) ap_array[i].ssid) == 0) { + continue; + } + + if (!string_is_greater(entry.ssid, ap_array[i].ssid)) { + break; + } + + } + for (int j = ap_entry_last; j >= i; j--) { + if (j + 1 <= ARRAY_AP_LEN) { + ap_array[j + 1] = ap_array[j]; + } + } + ap_array[i] = entry; + + if (ap_entry_last < ARRAY_AP_LEN) { + ap_entry_last++; + } +} + +ap ap_array_delete(ap entry) { + int i; + int found_in_array = 0; + ap tmp; + + if (ap_entry_last == -1) { + return tmp; + } + + for (i = 0; i <= ap_entry_last; i++) { + if (mac_is_equal(entry.bssid_addr, ap_array[i].bssid_addr)) { + found_in_array = 1; + tmp = ap_array[i]; + break; + } + } + + for (int j = i; j < ap_entry_last; j++) { + ap_array[j] = ap_array[j + 1]; + } + + if (ap_entry_last > -1 && found_in_array) { + ap_entry_last--; + } + return tmp; +} + +void remove_old_client_entries(time_t current_time, long long int threshold) { + for (int i = 0; i <= client_entry_last; i++) { + if (client_array[i].time < current_time - threshold) { + client_array_delete(client_array[i]); + } + } +} + +void remove_old_probe_entries(time_t current_time, long long int threshold) { + for (int i = 0; i <= probe_entry_last; i++) { + if (probe_array[i].time < current_time - threshold) { + if (!is_connected(probe_array[i].bssid_addr, probe_array[i].client_addr)) + probe_array_delete(probe_array[i]); + } + } +} + +void remove_old_ap_entries(time_t current_time, long long int threshold) { + for (int i = 0; i <= ap_entry_last; i++) { + if (ap_array[i].time < current_time - threshold) { + ap_array_delete(ap_array[i]); + } + } +} + +void uloop_add_data_cbs() { + uloop_timeout_add(&probe_timeout); + uloop_timeout_add(&client_timeout); + uloop_timeout_add(&ap_timeout); + + if (dawn_metric.use_driver_recog) { + uloop_timeout_add(&denied_req_timeout); + } +} + +void remove_probe_array_cb(struct uloop_timeout *t) { + pthread_mutex_lock(&probe_array_mutex); + printf("[Thread] : Removing old probe entries!\n"); + remove_old_probe_entries(time(0), timeout_config.remove_probe); + printf("[Thread] : Removing old entries finished!\n"); + pthread_mutex_unlock(&probe_array_mutex); + uloop_timeout_set(&probe_timeout, timeout_config.remove_probe * 1000); +} + +void remove_client_array_cb(struct uloop_timeout *t) { + pthread_mutex_lock(&client_array_mutex); + printf("[Thread] : Removing old client entries!\n"); + remove_old_client_entries(time(0), timeout_config.update_client); + pthread_mutex_unlock(&client_array_mutex); + uloop_timeout_set(&client_timeout, timeout_config.update_client * 1000); +} + +void remove_ap_array_cb(struct uloop_timeout *t) { + pthread_mutex_lock(&ap_array_mutex); + printf("[ULOOP] : Removing old ap entries!\n"); + remove_old_ap_entries(time(0), timeout_config.remove_ap); + pthread_mutex_unlock(&ap_array_mutex); + uloop_timeout_set(&ap_timeout, timeout_config.remove_ap * 1000); +} + +void denied_req_array_cb(struct uloop_timeout *t) { + pthread_mutex_lock(&denied_array_mutex); + printf("[ULOOP] : Processing denied authentication!\n"); + + time_t current_time = time(0); + + for (int i = 0; i <= denied_req_last; i++) { + // check counter + + //check timer + if (denied_req_array[i].time < current_time - timeout_config.denied_req_threshold) { + + // client is not connected for a given time threshold! + if (!is_connected_somehwere(denied_req_array[i].client_addr)) { + printf("Client has propaly a bad driver!\n"); + + // problem that somehow station will land into this list + // maybe delete again? + if (insert_to_maclist(denied_req_array[i].client_addr) == 0) { + send_add_mac(denied_req_array[i].client_addr); + write_mac_to_file("/tmp/dawn_mac_list", denied_req_array[i].client_addr); + } + } + denied_req_array_delete(denied_req_array[i]); + } + } + pthread_mutex_unlock(&denied_array_mutex); + uloop_timeout_set(&denied_req_timeout, timeout_config.denied_req_threshold * 1000); +} + +void insert_client_to_array(client entry) { + pthread_mutex_lock(&client_array_mutex); + entry.time = time(0); + entry.kick_count = 0; + + client client_tmp = client_array_delete(entry); + + if (mac_is_equal(entry.bssid_addr, client_tmp.bssid_addr)) { + entry.kick_count = client_tmp.kick_count; + } + + client_array_insert(entry); + + pthread_mutex_unlock(&client_array_mutex); +} + +void insert_macs_from_file() { + FILE *fp; + char *line = NULL; + size_t len = 0; + ssize_t read; + + fp = fopen("/tmp/dawn_mac_list", "r"); + if (fp == NULL) + exit(EXIT_FAILURE); + + while ((read = getline(&line, &len, fp)) != -1) { + printf("Retrieved line of length %zu :\n", read); + printf("%s", line); + + int tmp_int_mac[ETH_ALEN]; + sscanf(line, MACSTR, STR2MAC(tmp_int_mac)); + + mac_list_entry_last++; + for (int i = 0; i < ETH_ALEN; ++i) { + mac_list[mac_list_entry_last][i] = (uint8_t) tmp_int_mac[i]; + } + } + + printf("Printing MAC list:\n"); + for (int i = 0; i <= mac_list_entry_last; i++) { + char mac_buf_target[20]; + sprintf(mac_buf_target, MACSTR, MAC2STR(mac_list[i])); + printf("%d: %s\n", i, mac_buf_target); + } + + fclose(fp); + if (line) + free(line); + //exit(EXIT_SUCCESS); +} + +int insert_to_maclist(uint8_t mac[]) { + if (mac_in_maclist(mac)) { + return -1; + } + + mac_list_entry_last++; + for (int i = 0; i < ETH_ALEN; ++i) { + mac_list[mac_list_entry_last][i] = mac[i]; + } + + return 0; +} + + +int mac_in_maclist(uint8_t mac[]) { + for (int i = 0; i <= mac_list_entry_last; i++) { + if (mac_is_equal(mac, mac_list[i])) { + return 1; + } + } + return 0; +} + +auth_entry insert_to_denied_req_array(auth_entry entry, int inc_counter) { + pthread_mutex_lock(&denied_array_mutex); + + entry.time = time(0); + entry.counter = 0; + auth_entry tmp = denied_req_array_delete(entry); + + if (mac_is_equal(entry.bssid_addr, tmp.bssid_addr) + && mac_is_equal(entry.client_addr, tmp.client_addr)) { + entry.counter = tmp.counter; + } + + if (inc_counter) { + + entry.counter++; + } + + denied_req_array_insert(entry); + + pthread_mutex_unlock(&denied_array_mutex); + + return entry; +} + +int denied_req_array_go_next_help(char sort_order[], int i, auth_entry entry, + auth_entry next_entry) { + switch (sort_order[i]) { + // bssid-mac + case 'b': + return mac_is_greater(entry.bssid_addr, next_entry.bssid_addr); + // client-mac + case 'c': + return mac_is_greater(entry.client_addr, next_entry.client_addr) && + mac_is_equal(entry.bssid_addr, next_entry.bssid_addr); + default: + break; + } + return 0; +} + +int denied_req_array_go_next(char sort_order[], int i, auth_entry entry, + auth_entry next_entry) { + int conditions = 1; + for (int j = 0; j < i; j++) { + i &= !(denied_req_array_go_next(sort_order, j, entry, next_entry)); + } + return conditions && denied_req_array_go_next_help(sort_order, i, entry, next_entry); +} + +void denied_req_array_insert(auth_entry entry) { + if (denied_req_last == -1) { + denied_req_array[0] = entry; + denied_req_last++; + return; + } + + int i; + for (i = 0; i <= denied_req_last; i++) { + if (!denied_req_array_go_next("bc", 2, entry, denied_req_array[i])) { + break; + } + } + for (int j = denied_req_last; j >= i; j--) { + if (j + 1 <= DENY_REQ_ARRAY_LEN) { + denied_req_array[j + 1] = denied_req_array[j]; + } + } + denied_req_array[i] = entry; + + if (denied_req_last < DENY_REQ_ARRAY_LEN) { + denied_req_last++; + } +} + +auth_entry denied_req_array_delete(auth_entry entry) { + + int i; + int found_in_array = 0; + auth_entry tmp; + + if (denied_req_last == -1) { + return tmp; + } + + for (i = 0; i <= denied_req_last; i++) { + if (mac_is_equal(entry.bssid_addr, denied_req_array[i].bssid_addr) && + mac_is_equal(entry.client_addr, denied_req_array[i].client_addr)) { + found_in_array = 1; + tmp = denied_req_array[i]; + break; + } + } + + for (int j = i; j < denied_req_last; j++) { + denied_req_array[j] = denied_req_array[j + 1]; + } + + if (denied_req_last > -1 && found_in_array) { + denied_req_last--; + } + return tmp; +} + +int go_next_help(char sort_order[], int i, probe_entry entry, + probe_entry next_entry) { + switch (sort_order[i]) { + // bssid-mac + case 'b': + return mac_is_greater(entry.bssid_addr, next_entry.bssid_addr) && + mac_is_equal(entry.client_addr, next_entry.client_addr); + break; + + // client-mac + case 'c': + return mac_is_greater(entry.client_addr, next_entry.client_addr); + break; + + // frequency + // mac is 5 ghz or 2.4 ghz? + case 'f': + return //entry.freq < next_entry.freq && + entry.freq < 5000 && + next_entry.freq >= 5000 && + //entry.freq < 5 && + mac_is_equal(entry.client_addr, next_entry.client_addr); + break; + + // signal strength (RSSI) + case 's': + return entry.signal < next_entry.signal && + mac_is_equal(entry.client_addr, next_entry.client_addr); + break; + + default: + return 0; + break; + } +} + +int go_next(char sort_order[], int i, probe_entry entry, + probe_entry next_entry) { + int conditions = 1; + for (int j = 0; j < i; j++) { + i &= !(go_next(sort_order, j, entry, next_entry)); + } + return conditions && go_next_help(sort_order, i, entry, next_entry); +} + +int mac_is_equal(uint8_t addr1[], uint8_t addr2[]) { + return memcmp(addr1, addr2, ETH_ALEN * sizeof(uint8_t)) == 0; +} + +int mac_is_greater(uint8_t addr1[], uint8_t addr2[]) { + for (int i = 0; i < ETH_ALEN; i++) { + if (addr1[i] > addr2[i]) { + return 1; + } + if (addr1[i] < addr2[i]) { + return 0; + } + + // if equal continue... + } + return 0; +} + +void print_probe_entry(probe_entry entry) { + char mac_buf_ap[20]; + char mac_buf_client[20]; + char mac_buf_target[20]; + + sprintf(mac_buf_ap, MACSTR, MAC2STR(entry.bssid_addr)); + sprintf(mac_buf_client, MACSTR, MAC2STR(entry.client_addr)); + sprintf(mac_buf_target, MACSTR, MAC2STR(entry.target_addr)); + + printf( + "bssid_addr: %s, client_addr: %s, signal: %d, freq: " + "%d, counter: %d, vht: %d, min_rate: %d, max_rate: %d\n", + mac_buf_ap, mac_buf_client, entry.signal, entry.freq, entry.counter, entry.vht_capabilities, + entry.min_supp_datarate, entry.max_supp_datarate); +} + +void print_auth_entry(auth_entry entry) { + char mac_buf_ap[20]; + char mac_buf_client[20]; + char mac_buf_target[20]; + + sprintf(mac_buf_ap, MACSTR, MAC2STR(entry.bssid_addr)); + sprintf(mac_buf_client, MACSTR, MAC2STR(entry.client_addr)); + sprintf(mac_buf_target, MACSTR, MAC2STR(entry.target_addr)); + + printf( + "bssid_addr: %s, client_addr: %s, signal: %d, freq: " + "%d\n", + mac_buf_ap, mac_buf_client, entry.signal, entry.freq); +} + +void print_client_entry(client entry) { + char mac_buf_ap[20]; + char mac_buf_client[20]; + + sprintf(mac_buf_ap, MACSTR, MAC2STR(entry.bssid_addr)); + sprintf(mac_buf_client, MACSTR, MAC2STR(entry.client_addr)); + + printf("bssid_addr: %s, client_addr: %s, freq: %d, ht_supported: %d, vht_supported: %d, ht: %d, vht: %d, kick: %d\n", + mac_buf_ap, mac_buf_client, entry.freq, entry.ht_supported, entry.vht_supported, entry.ht, entry.vht, + entry.kick_count); +} + +void print_client_array() { + printf("--------Clients------\n"); + printf("Client Entry Last: %d\n", client_entry_last); + for (int i = 0; i <= client_entry_last; i++) { + print_client_entry(client_array[i]); + } + printf("------------------\n"); +} + +void print_ap_entry(ap entry) { + char mac_buf_ap[20]; + + sprintf(mac_buf_ap, MACSTR, MAC2STR(entry.bssid_addr)); + printf("ssid: %s, bssid_addr: %s, freq: %d, ht: %d, vht: %d, chan_utilz: %d, col_d: %d, bandwidth: %d, col_count: %d\n", + entry.ssid, mac_buf_ap, entry.freq, entry.ht_support, entry.vht_support, + entry.channel_utilization, entry.collision_domain, entry.bandwidth, + ap_get_collision_count(entry.collision_domain) + ); +} + +void print_ap_array() { + printf("--------APs------\n"); + for (int i = 0; i <= ap_entry_last; i++) { + print_ap_entry(ap_array[i]); + } + printf("------------------\n"); +} \ No newline at end of file diff --git a/src/utils/dawn_iwinfo.c b/src/utils/dawn_iwinfo.c new file mode 100644 index 0000000..87b44b9 --- /dev/null +++ b/src/utils/dawn_iwinfo.c @@ -0,0 +1,356 @@ +#include "dawn_iwinfo.h" + +#include +#include +#include + +#include "utils.h" +#include "ubus.h" + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] + +int call_iwinfo(char *client_addr); + +int parse_rssi(char *iwinfo_string); + +int get_rssi(const char *ifname, uint8_t *client_addr); + +int get_bandwidth(const char *ifname, uint8_t *client_addr, float *rx_rate, float *tx_rate); + +#define IWINFO_BUFSIZE 24 * 1024 + +#define IWINFO_ESSID_MAX_SIZE 32 + +int compare_essid_iwinfo(__uint8_t *bssid_addr, __uint8_t *bssid_addr_to_compare) { + const struct iwinfo_ops *iw; + + char mac_buf[20]; + char mac_buf_to_compare[20]; + sprintf(mac_buf, MACSTR, MAC2STR(bssid_addr)); + sprintf(mac_buf_to_compare, MACSTR, MAC2STR(bssid_addr_to_compare)); + + DIR *dirp; + struct dirent *entry; + dirp = opendir(hostapd_dir_glob); // error handling? + if (!dirp) { + fprintf(stderr, "[COMPARE ESSID] Failed to open %s\n", hostapd_dir_glob); + return 0; + } + + char *essid = NULL; + char *essid_to_compare = NULL; + + char buf_essid[IWINFO_ESSID_MAX_SIZE + 1] = {0}; + char buf_essid_to_compare[IWINFO_ESSID_MAX_SIZE + 1] = {0}; + + while ((entry = readdir(dirp)) != NULL && (essid == NULL || essid_to_compare == NULL)) { + if (entry->d_type == DT_SOCK) { + + iw = iwinfo_backend(entry->d_name); + + static char buf_bssid[18] = {0}; + if (iw->bssid(entry->d_name, buf_bssid)) + snprintf(buf_bssid, sizeof(buf_bssid), "00:00:00:00:00:00"); + + if (strcmp(mac_buf, buf_bssid) == 0) { + + if (iw->ssid(entry->d_name, buf_essid)) + memset(buf_essid, 0, sizeof(buf_essid)); + essid = buf_essid; + } + + if (strcmp(mac_buf_to_compare, buf_bssid) == 0) { + if (iw->ssid(entry->d_name, buf_essid_to_compare)) + memset(buf_essid_to_compare, 0, sizeof(buf_essid_to_compare)); + essid_to_compare = buf_essid_to_compare; + } + } + } + closedir(dirp); + + printf("Comparing: %s with %s\n", essid, essid_to_compare); + + if (essid == NULL || essid_to_compare == NULL) { + return -1; + } + + if (strcmp(essid, essid_to_compare) == 0) { + return 0; + } + + return -1; +} + +int get_bandwidth_iwinfo(__uint8_t *client_addr, float *rx_rate, float *tx_rate) { + + DIR *dirp; + struct dirent *entry; + dirp = opendir(hostapd_dir_glob); // error handling? + if (!dirp) { + fprintf(stderr, "[BANDWITH INFO] Failed to open %s\n", hostapd_dir_glob); + return 0; + } + + int sucess = 0; + + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_type == DT_SOCK) { + if (get_bandwidth(entry->d_name, client_addr, rx_rate, tx_rate)) { + sucess = 1; + break; + } + } + } + closedir(dirp); + return sucess; +} + +int get_bandwidth(const char *ifname, uint8_t *client_addr, float *rx_rate, float *tx_rate) { + + int i, len; + char buf[IWINFO_BUFSIZE]; + struct iwinfo_assoclist_entry *e; + const struct iwinfo_ops *iw; + + iw = iwinfo_backend(ifname); + + if (iw->assoclist(ifname, buf, &len)) { + fprintf(stderr, "No information available\n"); + iwinfo_finish(); + return 0; + } else if (len <= 0) { + fprintf(stderr, "No station connected\n"); + iwinfo_finish(); + return 0; + } + + for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) { + e = (struct iwinfo_assoclist_entry *) &buf[i]; + + if (mac_is_equal(client_addr, e->mac)) { + *rx_rate = e->rx_rate.rate / 1000; + *tx_rate = e->tx_rate.rate / 1000; + return 1; + } + } + + return 0; +} + +int get_rssi_iwinfo(__uint8_t *client_addr) { + + DIR *dirp; + struct dirent *entry; + dirp = opendir(hostapd_dir_glob); // error handling? + if (!dirp) { + fprintf(stderr, "[RSSI INFO] No hostapd sockets!\n"); + return INT_MIN; + } + + int rssi = INT_MIN; + + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_type == DT_SOCK) { + rssi = get_rssi(entry->d_name, client_addr); + if (rssi != INT_MIN) + break; + } + } + closedir(dirp); + return rssi; +} + +int get_rssi(const char *ifname, uint8_t *client_addr) { + + int i, len; + char buf[IWINFO_BUFSIZE]; + struct iwinfo_assoclist_entry *e; + const struct iwinfo_ops *iw; + + iw = iwinfo_backend(ifname); + + if (iw->assoclist(ifname, buf, &len)) { + fprintf(stderr, "No information available\n"); + iwinfo_finish(); + return INT_MIN; + } else if (len <= 0) { + fprintf(stderr, "No station connected\n"); + iwinfo_finish(); + return INT_MIN; + } + + for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) { + e = (struct iwinfo_assoclist_entry *) &buf[i]; + + if (mac_is_equal(client_addr, e->mac)) + return e->signal; + } + + iwinfo_finish(); + return INT_MIN; +} + +int get_expected_throughput_iwinfo(__uint8_t *client_addr) { + + DIR *dirp; + struct dirent *entry; + dirp = opendir(hostapd_dir_glob); // error handling? + if (!dirp) { + fprintf(stderr, "[RSSI INFO] Failed to open dir:%s\n", hostapd_dir_glob); + return INT_MIN; + } + + int exp_thr = INT_MIN; + + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_type == DT_SOCK) { + exp_thr = get_expected_throughput(entry->d_name, client_addr); + if (exp_thr != INT_MIN) + break; + } + } + closedir(dirp); + return exp_thr; +} + +int get_expected_throughput(const char *ifname, uint8_t *client_addr) { + + int i, len; + char buf[IWINFO_BUFSIZE]; + struct iwinfo_assoclist_entry *e; + const struct iwinfo_ops *iw; + + iw = iwinfo_backend(ifname); + + if (iw->assoclist(ifname, buf, &len)) { + fprintf(stderr, "No information available\n"); + return INT_MIN; + } else if (len <= 0) { + fprintf(stderr, "No station connected\n"); + return INT_MIN; + } + + for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) { + e = (struct iwinfo_assoclist_entry *) &buf[i]; + + if (mac_is_equal(client_addr, e->mac)) + return e->thr; + } + iwinfo_finish(); + + return INT_MIN; +} + +int get_bssid(const char *ifname, uint8_t *bssid_addr) { + const struct iwinfo_ops *iw; + + iw = iwinfo_backend(ifname); + + static char buf[18] = { 0 }; + + if (iw->bssid(ifname, buf)) + snprintf(buf, sizeof(buf), "00:00:00:00:00:00"); + + hwaddr_aton(buf,bssid_addr); + iwinfo_finish(); + + return 0; +} + +int get_ssid(const char *ifname, char* ssid) { + const struct iwinfo_ops *iw; + char buf[IWINFO_ESSID_MAX_SIZE+1] = { 0 }; + + iw = iwinfo_backend(ifname); + if (iw->ssid(ifname, buf)) + memset(buf, 0, sizeof(buf)); + + memcpy(ssid, buf, (SSID_MAX_LEN) * sizeof(char)); + strcpy(ssid, buf); + return 0; +} + +int get_channel_utilization(const char *ifname, uint64_t *last_channel_time, uint64_t *last_channel_time_busy) { + + int len; + const struct iwinfo_ops *iw; + char buf[IWINFO_BUFSIZE]; + struct iwinfo_survey_entry *e; + int ret = 0; + + iw = iwinfo_backend(ifname); + + int freq; + if (iw->frequency(ifname, &freq)) + { + return 0; + } + + if (iw->survey(ifname, buf, &len)) + { + fprintf(stderr, "Survey not possible!\n\n"); + return 0; + } + else if (len <= 0) + { + fprintf(stderr, "No survey results\n\n"); + return 0; + } + + for (int i = 0, x = 1; i < len; i += sizeof(struct iwinfo_survey_entry), x++) + { + e = (struct iwinfo_survey_entry *) &buf[i]; + + if(e->mhz == freq) + { + uint64_t dividend = e->busy_time - *last_channel_time_busy; + uint64_t divisor = e->active_time - *last_channel_time; + *last_channel_time = e->active_time; + *last_channel_time_busy = e->busy_time; + + if(divisor) + ret = (int)(dividend * 255 / divisor); + + break; + } + } + + iwinfo_finish(); + return ret; +} + +int support_ht(const char *ifname) { + const struct iwinfo_ops *iw; + + iw = iwinfo_backend(ifname); + int htmodes = 0; + + if (iw->htmodelist(ifname, &htmodes)) + { + printf("No HT mode information available\n"); + return 0; + } + + uint32_t ht_support_bitmask = (1 << 0) | (1 << 2); + int ret = htmodes & ht_support_bitmask ? 1 : 0; + iwinfo_finish(); + return ret; +} + +int support_vht(const char *ifname) { + const struct iwinfo_ops *iw; + + iw = iwinfo_backend(ifname); + int htmodes = 0; + + if (iw->htmodelist(ifname, &htmodes)) + { + fprintf(stderr, "No VHT mode information available\n"); + return 0; + } + + uint32_t vht_support_bitmask = (1 << 2) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); + int ret = htmodes & vht_support_bitmask ? 1 : 0; + iwinfo_finish(); + return ret; +} \ No newline at end of file diff --git a/src/utils/dawn_uci.c b/src/utils/dawn_uci.c new file mode 100644 index 0000000..2d56338 --- /dev/null +++ b/src/utils/dawn_uci.c @@ -0,0 +1,202 @@ +#include +#include +#include + +#include "dawn_uci.h" + + +static struct uci_context *uci_ctx; +static struct uci_package *uci_pkg; + +// why is this not included in uci lib...?! +// found here: https://github.com/br101/pingcheck/blob/master/uci.c +static int uci_lookup_option_int(struct uci_context *uci, struct uci_section *s, + const char *name) { + const char *str = uci_lookup_option_string(uci, s, name); + return str == NULL ? -1 : atoi(str); +} + +struct time_config_s uci_get_time_config() { + struct time_config_s ret; + + struct uci_element *e; + uci_foreach_element(&uci_pkg->sections, e) + { + struct uci_section *s = uci_to_section(e); + + if (strcmp(s->type, "times") == 0) { + ret.update_client = uci_lookup_option_int(uci_ctx, s, "update_client"); + ret.remove_client = uci_lookup_option_int(uci_ctx, s, "remove_client"); + ret.remove_probe = uci_lookup_option_int(uci_ctx, s, "remove_probe"); + ret.update_hostapd = uci_lookup_option_int(uci_ctx, s, "update_hostapd"); + ret.remove_ap = uci_lookup_option_int(uci_ctx, s, "remove_ap"); + ret.update_tcp_con = uci_lookup_option_int(uci_ctx, s, "update_tcp_con"); + ret.denied_req_threshold = uci_lookup_option_int(uci_ctx, s, "denied_req_threshold"); + ret.update_chan_util = uci_lookup_option_int(uci_ctx, s, "update_chan_util"); + return ret; + } + } + + return ret; +} + +struct probe_metric_s uci_get_dawn_metric() { + struct probe_metric_s ret; + + struct uci_element *e; + uci_foreach_element(&uci_pkg->sections, e) + { + struct uci_section *s = uci_to_section(e); + + if (strcmp(s->type, "metric") == 0) { + ret.ap_weight = uci_lookup_option_int(uci_ctx, s, "ap_weight"); + ret.kicking = uci_lookup_option_int(uci_ctx, s, "kicking"); + ret.ht_support = uci_lookup_option_int(uci_ctx, s, "ht_support"); + ret.vht_support = uci_lookup_option_int(uci_ctx, s, "vht_support"); + ret.no_ht_support = uci_lookup_option_int(uci_ctx, s, "no_ht_support"); + ret.no_vht_support = uci_lookup_option_int(uci_ctx, s, "no_vht_support"); + ret.rssi = uci_lookup_option_int(uci_ctx, s, "rssi"); + ret.freq = uci_lookup_option_int(uci_ctx, s, "freq"); + ret.rssi_val = uci_lookup_option_int(uci_ctx, s, "rssi_val"); + ret.chan_util = uci_lookup_option_int(uci_ctx, s, "chan_util"); + ret.max_chan_util = uci_lookup_option_int(uci_ctx, s, "max_chan_util"); + ret.chan_util_val = uci_lookup_option_int(uci_ctx, s, "chan_util_val"); + ret.max_chan_util_val = uci_lookup_option_int(uci_ctx, s, "max_chan_util_val"); + ret.min_probe_count = uci_lookup_option_int(uci_ctx, s, "min_probe_count"); + ret.low_rssi = uci_lookup_option_int(uci_ctx, s, "low_rssi"); + ret.low_rssi_val = uci_lookup_option_int(uci_ctx, s, "low_rssi_val"); + ret.bandwith_threshold = uci_lookup_option_int(uci_ctx, s, "bandwith_threshold"); + ret.use_station_count = uci_lookup_option_int(uci_ctx, s, "use_station_count"); + ret.eval_probe_req = uci_lookup_option_int(uci_ctx, s, "eval_probe_req"); + ret.eval_auth_req = uci_lookup_option_int(uci_ctx, s, "eval_auth_req"); + ret.eval_assoc_req = uci_lookup_option_int(uci_ctx, s, "eval_assoc_req"); + ret.deny_auth_reason = uci_lookup_option_int(uci_ctx, s, "deny_auth_reason"); + ret.deny_assoc_reason = uci_lookup_option_int(uci_ctx, s, "deny_assoc_reason"); + ret.max_station_diff = uci_lookup_option_int(uci_ctx, s, "max_station_diff"); + ret.use_driver_recog = uci_lookup_option_int(uci_ctx, s, "use_driver_recog"); + ret.min_kick_count = uci_lookup_option_int(uci_ctx, s, "min_number_to_kick"); + ret.chan_util_avg_period = uci_lookup_option_int(uci_ctx, s, "chan_util_avg_period"); + return ret; + } + } + + return ret; +} + +struct network_config_s uci_get_dawn_network() { + struct network_config_s ret; + + struct uci_element *e; + uci_foreach_element(&uci_pkg->sections, e) + { + struct uci_section *s = uci_to_section(e); + + if (strcmp(s->type, "network") == 0) { + ret.broadcast_ip = uci_lookup_option_string(uci_ctx, s, "broadcast_ip"); + ret.broadcast_port = uci_lookup_option_int(uci_ctx, s, "broadcast_port"); + ret.bool_multicast = uci_lookup_option_int(uci_ctx, s, "multicast"); + ret.shared_key = uci_lookup_option_string(uci_ctx, s, "shared_key"); + ret.iv = uci_lookup_option_string(uci_ctx, s, "iv"); + ret.network_option = uci_lookup_option_int(uci_ctx, s, "network_option"); + ret.tcp_port = uci_lookup_option_int(uci_ctx, s, "tcp_port"); + ret.use_symm_enc = uci_lookup_option_int(uci_ctx, s, "use_symm_enc"); + ret.collision_domain = uci_lookup_option_int(uci_ctx, s, "collision_domain"); + ret.bandwidth = uci_lookup_option_int(uci_ctx, s, "bandwidth"); + return ret; + } + } + + return ret; +} + +const char *uci_get_dawn_hostapd_dir() { + struct uci_element *e; + uci_foreach_element(&uci_pkg->sections, e) + { + struct uci_section *s = uci_to_section(e); + + if (strcmp(s->type, "hostapd") == 0) { + return uci_lookup_option_string(uci_ctx, s, "hostapd_dir"); + } + } + return NULL; +} + +const char *uci_get_dawn_sort_order() { + struct uci_element *e; + uci_foreach_element(&uci_pkg->sections, e) + { + struct uci_section *s = uci_to_section(e); + + if (strcmp(s->type, "ordering") == 0) { + return uci_lookup_option_string(uci_ctx, s, "sort_order"); + } + } + return NULL; +} + +int uci_reset() +{ + uci_unload(uci_ctx, uci_pkg); + uci_load(uci_ctx, "dawn", &uci_pkg); + + return 0; +} + +int uci_init() { + struct uci_context *ctx = uci_ctx; + + if (!ctx) { + ctx = uci_alloc_context(); + uci_ctx = ctx; + + ctx->flags &= ~UCI_FLAG_STRICT; + } else { + // shouldn't happen? + uci_pkg = uci_lookup_package(ctx, "dawn"); + if (uci_pkg) + uci_unload(ctx, uci_pkg); + } + + if (uci_load(ctx, "dawn", &uci_pkg)) + return -1; + + return 1; +} + +int uci_clear() { + if (uci_pkg != NULL) { + uci_unload(uci_ctx, uci_pkg); + } + if (uci_ctx != NULL) { + uci_free_context(uci_ctx); + } + return 1; +} + +int uci_set_network(char* uci_cmd) +{ + struct uci_ptr ptr; + int ret = UCI_OK; + struct uci_context *ctx; + + ctx = uci_alloc_context(); + ctx->flags |= UCI_FLAG_STRICT; + + if (uci_lookup_ptr(ctx, &ptr, uci_cmd, 1) != UCI_OK) { + return 1; + } + + ret = uci_set(ctx, &ptr); + + + if (uci_lookup_ptr(ctx, &ptr, "dawn", 1) != UCI_OK) { + return 1; + } + + if (uci_commit(ctx, &ptr.p, 0) != UCI_OK) { + fprintf(stderr, "Failed to commit UCI cmd: %s\n", uci_cmd); + } + + return ret; +} \ No newline at end of file diff --git a/src/utils/ieee80211_utils.c b/src/utils/ieee80211_utils.c new file mode 100644 index 0000000..21c13fc --- /dev/null +++ b/src/utils/ieee80211_utils.c @@ -0,0 +1,11 @@ +#include "ieee80211_utils.h" + +#include + +double iee80211_calculate_bitrate(uint8_t supp_rate_val) { + return ((double) supp_rate_val) / 2; +} + +double iee80211_calculate_expected_throughput_mbit(int exp_thr) { + return (((double) exp_thr) / 1000); +} \ No newline at end of file diff --git a/src/utils/ubus.c b/src/utils/ubus.c new file mode 100644 index 0000000..bb7b9a7 --- /dev/null +++ b/src/utils/ubus.c @@ -0,0 +1,1619 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +#define REQ_TYPE_PROBE 0 +#define REQ_TYPE_AUTH 1 +#define REQ_TYPE_ASSOC 2 + +#include "ubus.h" + +#include "networksocket.h" +#include "utils.h" +#include "dawn_uci.h" +#include "dawn_iwinfo.h" +#include "datastorage.h" +#include "tcpsocket.h" + +static struct ubus_context *ctx = NULL; + +static struct blob_buf b; +static struct blob_buf b_send_network; +static struct blob_buf network_buf; +static struct blob_buf data_buf; +static struct blob_buf b_probe; +static struct blob_buf b_domain; +static struct blob_buf b_notify; +static struct blob_buf b_clients; +static struct blob_buf b_umdns; + +void update_clients(struct uloop_timeout *t); + +void update_tcp_connections(struct uloop_timeout *t); + +void update_channel_utilization(struct uloop_timeout *t); + +struct uloop_timeout client_timer = { + .cb = update_clients +}; +struct uloop_timeout hostapd_timer = { + .cb = update_hostapd_sockets +}; +struct uloop_timeout umdns_timer = { + .cb = update_tcp_connections +}; +struct uloop_timeout channel_utilization_timer = { + .cb = update_channel_utilization +}; + +#define MAX_HOSTAPD_SOCKETS 10 +#define MAX_INTERFACE_NAME 64 + +LIST_HEAD(hostapd_sock_list); + +struct hostapd_sock_entry { + struct list_head list; + + uint32_t id; + char iface_name[MAX_INTERFACE_NAME]; + uint8_t bssid_addr[ETH_ALEN]; + char ssid[SSID_MAX_LEN]; + uint8_t ht_support; + uint8_t vht_support; + uint64_t last_channel_time; + uint64_t last_channel_time_busy; + int chan_util_samples_sum; + int chan_util_num_sample_periods; + int chan_util_average; + struct ubus_subscriber subscriber; + struct ubus_event_handler wait_handler; + bool subscribed; +}; + +struct hostapd_sock_entry* hostapd_sock_arr[MAX_HOSTAPD_SOCKETS]; +int hostapd_sock_last = -1; + +enum { + NETWORK_METHOD, + NETWORK_DATA, + __NETWORK_MAX, +}; + +static const struct blobmsg_policy network_policy[__NETWORK_MAX] = { + [NETWORK_METHOD] = {.name = "method", .type = BLOBMSG_TYPE_STRING}, + [NETWORK_DATA] = {.name = "data", .type = BLOBMSG_TYPE_STRING}, +}; + +enum { + HOSTAPD_NOTIFY_BSSID_ADDR, + HOSTAPD_NOTIFY_CLIENT_ADDR, + __HOSTAPD_NOTIFY_MAX, +}; + +static const struct blobmsg_policy hostapd_notify_policy[__HOSTAPD_NOTIFY_MAX] = { + [HOSTAPD_NOTIFY_BSSID_ADDR] = {.name = "bssid", .type = BLOBMSG_TYPE_STRING}, + [HOSTAPD_NOTIFY_CLIENT_ADDR] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, +}; + +enum { + AUTH_BSSID_ADDR, + AUTH_CLIENT_ADDR, + AUTH_TARGET_ADDR, + AUTH_SIGNAL, + AUTH_FREQ, + __AUTH_MAX, +}; + +static const struct blobmsg_policy auth_policy[__AUTH_MAX] = { + [AUTH_BSSID_ADDR] = {.name = "bssid", .type = BLOBMSG_TYPE_STRING}, + [AUTH_CLIENT_ADDR] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, + [AUTH_TARGET_ADDR] = {.name = "target", .type = BLOBMSG_TYPE_STRING}, + [AUTH_SIGNAL] = {.name = "signal", .type = BLOBMSG_TYPE_INT32}, + [AUTH_FREQ] = {.name = "freq", .type = BLOBMSG_TYPE_INT32}, +}; + +enum { + PROB_BSSID_ADDR, + PROB_CLIENT_ADDR, + PROB_TARGET_ADDR, + PROB_SIGNAL, + PROB_FREQ, + PROB_HT_CAPABILITIES, + PROB_VHT_CAPABILITIES, + __PROB_MAX, +}; + +static const struct blobmsg_policy prob_policy[__PROB_MAX] = { + [PROB_BSSID_ADDR] = {.name = "bssid", .type = BLOBMSG_TYPE_STRING}, + [PROB_CLIENT_ADDR] = {.name = "address", .type = BLOBMSG_TYPE_STRING}, + [PROB_TARGET_ADDR] = {.name = "target", .type = BLOBMSG_TYPE_STRING}, + [PROB_SIGNAL] = {.name = "signal", .type = BLOBMSG_TYPE_INT32}, + [PROB_FREQ] = {.name = "freq", .type = BLOBMSG_TYPE_INT32}, + [PROB_HT_CAPABILITIES] = {.name = "ht_capabilities", .type = BLOBMSG_TYPE_TABLE}, + [PROB_VHT_CAPABILITIES] = {.name = "vht_capabilities", .type = BLOBMSG_TYPE_TABLE}, +}; + +enum { + CLIENT_TABLE, + CLIENT_TABLE_BSSID, + CLIENT_TABLE_SSID, + CLIENT_TABLE_FREQ, + CLIENT_TABLE_HT, + CLIENT_TABLE_VHT, + CLIENT_TABLE_CHAN_UTIL, + CLIENT_TABLE_NUM_STA, + CLIENT_TABLE_COL_DOMAIN, + CLIENT_TABLE_BANDWIDTH, + CLIENT_TABLE_WEIGHT, + __CLIENT_TABLE_MAX, +}; + +static const struct blobmsg_policy client_table_policy[__CLIENT_TABLE_MAX] = { + [CLIENT_TABLE] = {.name = "clients", .type = BLOBMSG_TYPE_TABLE}, + [CLIENT_TABLE_BSSID] = {.name = "bssid", .type = BLOBMSG_TYPE_STRING}, + [CLIENT_TABLE_SSID] = {.name = "ssid", .type = BLOBMSG_TYPE_STRING}, + [CLIENT_TABLE_FREQ] = {.name = "freq", .type = BLOBMSG_TYPE_INT32}, + [CLIENT_TABLE_HT] = {.name = "ht_supported", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_TABLE_VHT] = {.name = "vht_supported", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_TABLE_CHAN_UTIL] = {.name = "channel_utilization", .type = BLOBMSG_TYPE_INT32}, + [CLIENT_TABLE_NUM_STA] = {.name = "num_sta", .type = BLOBMSG_TYPE_INT32}, + [CLIENT_TABLE_COL_DOMAIN] = {.name = "collision_domain", .type = BLOBMSG_TYPE_INT32}, + [CLIENT_TABLE_BANDWIDTH] = {.name = "bandwidth", .type = BLOBMSG_TYPE_INT32}, + [CLIENT_TABLE_WEIGHT] = {.name = "ap_weight", .type = BLOBMSG_TYPE_INT32}, +}; + +enum { + CLIENT_SIGNATURE, + CLIENT_AUTH, + CLIENT_ASSOC, + CLIENT_AUTHORIZED, + CLIENT_PREAUTH, + CLIENT_WDS, + CLIENT_WMM, + CLIENT_HT, + CLIENT_VHT, + CLIENT_WPS, + CLIENT_MFP, + CLIENT_AID, + __CLIENT_MAX, +}; + +static const struct blobmsg_policy client_policy[__CLIENT_MAX] = { + [CLIENT_SIGNATURE] = {.name = "signature", .type = BLOBMSG_TYPE_STRING}, + [CLIENT_AUTH] = {.name = "auth", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_ASSOC] = {.name = "assoc", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_AUTHORIZED] = {.name = "authorized", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_PREAUTH] = {.name = "preauth", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_WDS] = {.name = "wds", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_WMM] = {.name = "wmm", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_HT] = {.name = "ht", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_VHT] = {.name = "vht", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_WPS] = {.name = "wps", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_MFP] = {.name = "mfp", .type = BLOBMSG_TYPE_INT8}, + [CLIENT_AID] = {.name = "aid", .type = BLOBMSG_TYPE_INT32}, +}; + +enum { + DAWN_UMDNS_TABLE, + __DAWN_UMDNS_TABLE_MAX, +}; + +static const struct blobmsg_policy dawn_umdns_table_policy[__DAWN_UMDNS_TABLE_MAX] = { + [DAWN_UMDNS_TABLE] = {.name = "_dawn._tcp", .type = BLOBMSG_TYPE_TABLE}, +}; + +enum { + DAWN_UMDNS_IPV4, + DAWN_UMDNS_PORT, + __DAWN_UMDNS_MAX, +}; + +static const struct blobmsg_policy dawn_umdns_policy[__DAWN_UMDNS_MAX] = { + [DAWN_UMDNS_IPV4] = {.name = "ipv4", .type = BLOBMSG_TYPE_STRING}, + [DAWN_UMDNS_PORT] = {.name = "port", .type = BLOBMSG_TYPE_INT32}, +}; + +/* Function Definitions */ +static int hostapd_notify(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg); + +static int ubus_get_clients(); + +static int +add_mac(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg); + +static int reload_config(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg); + +static int get_hearing_map(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg); + +static int get_network(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg); + +static int handle_set_probe(struct blob_attr *msg); + +static int parse_add_mac_to_file(struct blob_attr *msg); + +static void ubus_add_oject(); + +static void respond_to_notify(uint32_t id); + +int handle_uci_config(struct blob_attr *msg); + +void subscribe_to_new_interfaces(const char *hostapd_sock_path); + +bool subscriber_to_interface(const char *ifname); + +bool subscribe(struct hostapd_sock_entry *hostapd_entry); + +void add_client_update_timer(time_t time) { + uloop_timeout_set(&client_timer, time); +} + +static inline int +subscription_wait(struct ubus_event_handler *handler) { + return ubus_register_event_handler(ctx, handler, "ubus.object.add"); +} + +void blobmsg_add_macaddr(struct blob_buf *buf, const char *name, const uint8_t *addr) { + char *s; + + s = blobmsg_alloc_string_buffer(buf, name, 20); + sprintf(s, MACSTR, MAC2STR(addr)); + blobmsg_add_string_buffer(buf); +} + +static int decide_function(probe_entry *prob_req, int req_type) { + if (mac_in_maclist(prob_req->client_addr)) { + return 1; + } + + if (prob_req->counter < dawn_metric.min_probe_count) { + return 0; + } + + if (req_type == REQ_TYPE_PROBE && !dawn_metric.eval_probe_req) { + return 1; + } + + if (req_type == REQ_TYPE_AUTH && !dawn_metric.eval_auth_req) { + return 1; + } + + if (req_type == REQ_TYPE_ASSOC && !dawn_metric.eval_assoc_req) { + return 1; + } + + if (better_ap_available(prob_req->bssid_addr, prob_req->client_addr, 0)) { + return 0; + } + + return 1; +} + +int parse_to_hostapd_notify(struct blob_attr *msg, hostapd_notify_entry *notify_req) { + struct blob_attr *tb[__HOSTAPD_NOTIFY_MAX]; + + blobmsg_parse(hostapd_notify_policy, __HOSTAPD_NOTIFY_MAX, tb, blob_data(msg), blob_len(msg)); + + if (hwaddr_aton(blobmsg_data(tb[HOSTAPD_NOTIFY_BSSID_ADDR]), notify_req->bssid_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (hwaddr_aton(blobmsg_data(tb[HOSTAPD_NOTIFY_CLIENT_ADDR]), notify_req->client_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + return 0; +} + +int parse_to_auth_req(struct blob_attr *msg, auth_entry *auth_req) { + struct blob_attr *tb[__AUTH_MAX]; + + blobmsg_parse(auth_policy, __AUTH_MAX, tb, blob_data(msg), blob_len(msg)); + + if (hwaddr_aton(blobmsg_data(tb[AUTH_BSSID_ADDR]), auth_req->bssid_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (hwaddr_aton(blobmsg_data(tb[AUTH_CLIENT_ADDR]), auth_req->client_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (hwaddr_aton(blobmsg_data(tb[AUTH_TARGET_ADDR]), auth_req->target_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (tb[PROB_SIGNAL]) { + auth_req->signal = blobmsg_get_u32(tb[AUTH_SIGNAL]); + } + + if (tb[PROB_FREQ]) { + auth_req->freq = blobmsg_get_u32(tb[AUTH_FREQ]); + } + + return 0; +} + +int parse_to_assoc_req(struct blob_attr *msg, assoc_entry *assoc_req) { + return (parse_to_auth_req(msg, assoc_req)); +} + +int parse_to_probe_req(struct blob_attr *msg, probe_entry *prob_req) { + struct blob_attr *tb[__PROB_MAX]; + + blobmsg_parse(prob_policy, __PROB_MAX, tb, blob_data(msg), blob_len(msg)); + + if (hwaddr_aton(blobmsg_data(tb[PROB_BSSID_ADDR]), prob_req->bssid_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (hwaddr_aton(blobmsg_data(tb[PROB_CLIENT_ADDR]), prob_req->client_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (hwaddr_aton(blobmsg_data(tb[PROB_TARGET_ADDR]), prob_req->target_addr)) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (tb[PROB_SIGNAL]) { + prob_req->signal = blobmsg_get_u32(tb[PROB_SIGNAL]); + } + + if (tb[PROB_FREQ]) { + prob_req->freq = blobmsg_get_u32(tb[PROB_FREQ]); + } + + if (tb[PROB_HT_CAPABILITIES]) { + prob_req->ht_capabilities = true; + } else + { + prob_req->ht_capabilities = false; + } + + if (tb[PROB_VHT_CAPABILITIES]) { + prob_req->vht_capabilities = true; + } else + { + prob_req->vht_capabilities = false; + } + + return 0; +} + +static int handle_auth_req(struct blob_attr *msg) { + + print_probe_array(); + auth_entry auth_req; + parse_to_auth_req(msg, &auth_req); + + printf("Auth entry: "); + print_auth_entry(auth_req); + + if (mac_in_maclist(auth_req.client_addr)) { + return WLAN_STATUS_SUCCESS; + } + + probe_entry tmp = probe_array_get_entry(auth_req.bssid_addr, auth_req.client_addr); + + printf("Entry found\n"); + print_probe_entry(tmp); + + // block if entry was not already found in probe database + if (!(mac_is_equal(tmp.bssid_addr, auth_req.bssid_addr) && mac_is_equal(tmp.client_addr, auth_req.client_addr))) { + printf("Deny authentication!\n"); + + if (dawn_metric.use_driver_recog) { + insert_to_denied_req_array(auth_req, 1); + } + return dawn_metric.deny_auth_reason; + } + + if (!decide_function(&tmp, REQ_TYPE_AUTH)) { + printf("Deny authentication\n"); + if (dawn_metric.use_driver_recog) { + insert_to_denied_req_array(auth_req, 1); + } + return dawn_metric.deny_auth_reason; + } + + // maybe send here that the client is connected? + printf("Allow authentication!\n"); + return WLAN_STATUS_SUCCESS; +} + +static int handle_assoc_req(struct blob_attr *msg) { + + print_probe_array(); + auth_entry auth_req; + parse_to_assoc_req(msg, &auth_req); + printf("Association entry: "); + print_auth_entry(auth_req); + + if (mac_in_maclist(auth_req.client_addr)) { + return WLAN_STATUS_SUCCESS; + } + + probe_entry tmp = probe_array_get_entry(auth_req.bssid_addr, auth_req.client_addr); + + printf("Entry found\n"); + print_probe_entry(tmp); + + // block if entry was not already found in probe database + if (!(mac_is_equal(tmp.bssid_addr, auth_req.bssid_addr) && mac_is_equal(tmp.client_addr, auth_req.client_addr))) { + printf("Deny associtation!\n"); + if (dawn_metric.use_driver_recog) { + insert_to_denied_req_array(auth_req, 1); + } + return dawn_metric.deny_assoc_reason; + } + + if (!decide_function(&tmp, REQ_TYPE_ASSOC)) { + printf("Deny association\n"); + if (dawn_metric.use_driver_recog) { + insert_to_denied_req_array(auth_req, 1); + } + return dawn_metric.deny_assoc_reason; + } + + printf("Allow association!\n"); + return WLAN_STATUS_SUCCESS; +} + +static int handle_probe_req(struct blob_attr *msg) { + probe_entry prob_req; + probe_entry tmp_prob_req; + + if (parse_to_probe_req(msg, &prob_req) == 0) { + tmp_prob_req = insert_to_array(prob_req, 1); + send_blob_attr_via_network(msg, "probe"); + } + + if (!decide_function(&tmp_prob_req, REQ_TYPE_PROBE)) { + return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; // no reason needed... + } + return WLAN_STATUS_SUCCESS; +} + +static int handle_deauth_req(struct blob_attr *msg) { + + hostapd_notify_entry notify_req; + parse_to_hostapd_notify(msg, ¬ify_req); + + client client_entry; + memcpy(client_entry.bssid_addr, notify_req.bssid_addr, sizeof(uint8_t) * ETH_ALEN); + memcpy(client_entry.client_addr, notify_req.client_addr, sizeof(uint8_t) * ETH_ALEN); + + pthread_mutex_lock(&client_array_mutex); + client_array_delete(client_entry); + pthread_mutex_unlock(&client_array_mutex); + + printf("[WC] Deauth: %s\n", "deauth"); + + return 0; +} + +static int handle_set_probe(struct blob_attr *msg) { + + hostapd_notify_entry notify_req; + parse_to_hostapd_notify(msg, ¬ify_req); + + client client_entry; + memcpy(client_entry.bssid_addr, notify_req.bssid_addr, sizeof(uint8_t) * ETH_ALEN); + memcpy(client_entry.client_addr, notify_req.client_addr, sizeof(uint8_t) * ETH_ALEN); + + probe_array_set_all_probe_count(client_entry.client_addr, dawn_metric.min_probe_count); + + return 0; +} + +int handle_network_msg(char *msg) { + struct blob_attr *tb[__NETWORK_MAX]; + char *method; + char *data; + + blob_buf_init(&network_buf, 0); + blobmsg_add_json_from_string(&network_buf, msg); + + blobmsg_parse(network_policy, __NETWORK_MAX, tb, blob_data(network_buf.head), blob_len(network_buf.head)); + + if (!tb[NETWORK_METHOD] || !tb[NETWORK_DATA]) { + return -1; + } + + method = blobmsg_data(tb[NETWORK_METHOD]); + data = blobmsg_data(tb[NETWORK_DATA]); + + blob_buf_init(&data_buf, 0); + blobmsg_add_json_from_string(&data_buf, data); + + if (!data_buf.head) { + return -1; + } + + if (blob_len(data_buf.head) <= 0) { + return -1; + } + + if (strlen(method) < 2) { + return -1; + } + + if (strncmp(method, "probe", 5) == 0) { + probe_entry entry; + if (parse_to_probe_req(data_buf.head, &entry) == 0) { + insert_to_array(entry, 0); + } + } else if (strncmp(method, "clients", 5) == 0) { + parse_to_clients(data_buf.head, 0, 0); + } else if (strncmp(method, "deauth", 5) == 0) { + printf("METHOD DEAUTH\n"); + handle_deauth_req(data_buf.head); + } else if (strncmp(method, "setprobe", 5) == 0) { + printf("HANDLING SET PROBE!\n"); + handle_set_probe(data_buf.head); + } else if (strncmp(method, "addmac", 5) == 0) { + parse_add_mac_to_file(data_buf.head); + } else if (strncmp(method, "macfile", 5) == 0) { + parse_add_mac_to_file(data_buf.head); + } else if (strncmp(method, "uci", 2) == 0) { + printf("HANDLING UCI!\n"); + handle_uci_config(data_buf.head); + } else + { + printf("No method fonud for: %s\n", method); + } + + return 0; +} + + +int send_blob_attr_via_network(struct blob_attr *msg, char *method) { + + if (!msg) { + return -1; + } + + char *data_str; + char *str; + data_str = blobmsg_format_json(msg, true); + blob_buf_init(&b_send_network, 0); + blobmsg_add_string(&b_send_network, "method", method); + blobmsg_add_string(&b_send_network, "data", data_str); + + str = blobmsg_format_json(b_send_network.head, true); + + if (network_config.network_option == 2) { + send_tcp(str); + } else { + if (network_config.use_symm_enc) { + send_string_enc(str); + } else { + send_string(str); + } + } + + free(data_str); + free(str); + + return 0; +} + +static int hostapd_notify(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { + char *str; + str = blobmsg_format_json(msg, true); + printf("Method new: %s : %s\n", method, str); + free(str); + + struct hostapd_sock_entry *entry; + struct ubus_subscriber *subscriber; + + subscriber = container_of(obj, struct ubus_subscriber, obj); + entry = container_of(subscriber, struct hostapd_sock_entry, subscriber); + + struct blob_attr *cur; int rem; + blob_buf_init(&b_notify, 0); + blobmsg_for_each_attr(cur, msg, rem){ + blobmsg_add_blob(&b_notify, cur); + } + + blobmsg_add_macaddr(&b_notify, "bssid", entry->bssid_addr); + blobmsg_add_string(&b_notify, "ssid", entry->ssid); + + if (strncmp(method, "probe", 5) == 0) { + return handle_probe_req(b_notify.head); + } else if (strncmp(method, "auth", 4) == 0) { + return handle_auth_req(b_notify.head); + } else if (strncmp(method, "assoc", 5) == 0) { + return handle_assoc_req(b_notify.head); + } else if (strncmp(method, "deauth", 6) == 0) { + send_blob_attr_via_network(b_notify.head, "deauth"); + return handle_deauth_req(b_notify.head); + } + return 0; +} + +int dawn_init_ubus(const char *ubus_socket, const char *hostapd_dir) { + uloop_init(); + signal(SIGPIPE, SIG_IGN); + + ctx = ubus_connect(ubus_socket); + if (!ctx) { + fprintf(stderr, "Failed to connect to ubus\n"); + return -1; + } else { + printf("Connected to ubus\n"); + } + + ubus_add_uloop(ctx); + + // set dawn metric + dawn_metric = uci_get_dawn_metric(); + + uloop_timeout_add(&hostapd_timer); + + // remove probe + uloop_add_data_cbs(); + + // get clients + uloop_timeout_add(&client_timer); + + uloop_timeout_add(&channel_utilization_timer); + + ubus_call_umdns(); + + ubus_add_oject(); + + start_umdns_update(); + + if (network_config.network_option == 2) + run_server(network_config.tcp_port); + + subscribe_to_new_interfaces(hostapd_dir_glob); + + uloop_run(); + + close_socket(); + + ubus_free(ctx); + uloop_done(); + return 0; +} + +// TOOD: Refactor this! +static void +dump_client(struct blob_attr **tb, uint8_t client_addr[], const char *bssid_addr, uint32_t freq, uint8_t ht_supported, + uint8_t vht_supported) { + client client_entry; + + hwaddr_aton(bssid_addr, client_entry.bssid_addr); + memcpy(client_entry.client_addr, client_addr, ETH_ALEN * sizeof(uint8_t)); + client_entry.freq = freq; + client_entry.ht_supported = ht_supported; + client_entry.vht_supported = vht_supported; + + if (tb[CLIENT_AUTH]) { + client_entry.auth = blobmsg_get_u8(tb[CLIENT_AUTH]); + } + if (tb[CLIENT_ASSOC]) { + client_entry.assoc = blobmsg_get_u8(tb[CLIENT_ASSOC]); + } + if (tb[CLIENT_AUTHORIZED]) { + client_entry.authorized = blobmsg_get_u8(tb[CLIENT_AUTHORIZED]); + } + if (tb[CLIENT_PREAUTH]) { + client_entry.preauth = blobmsg_get_u8(tb[CLIENT_PREAUTH]); + } + if (tb[CLIENT_WDS]) { + client_entry.wds = blobmsg_get_u8(tb[CLIENT_WDS]); + } + if (tb[CLIENT_WMM]) { + client_entry.wmm = blobmsg_get_u8(tb[CLIENT_WMM]); + } + if (tb[CLIENT_HT]) { + client_entry.ht = blobmsg_get_u8(tb[CLIENT_HT]); + } + if (tb[CLIENT_VHT]) { + client_entry.vht = blobmsg_get_u8(tb[CLIENT_VHT]); + } + if (tb[CLIENT_WPS]) { + client_entry.wps = blobmsg_get_u8(tb[CLIENT_WPS]); + } + if (tb[CLIENT_MFP]) { + client_entry.mfp = blobmsg_get_u8(tb[CLIENT_MFP]); + } + if (tb[CLIENT_AID]) { + client_entry.aid = blobmsg_get_u32(tb[CLIENT_AID]); + } + + // copy signature + if (tb[CLIENT_SIGNATURE]) { + memcpy(client_entry.signature, blobmsg_data(tb[CLIENT_SIGNATURE]), SIGNATURE_LEN * sizeof(char)); + } else + { + memset(client_entry.signature, 0, 1024); + } + + insert_client_to_array(client_entry); +} + +static int +dump_client_table(struct blob_attr *head, int len, const char *bssid_addr, uint32_t freq, uint8_t ht_supported, + uint8_t vht_supported) { + struct blob_attr *attr; + struct blobmsg_hdr *hdr; + int station_count = 0; + + __blob_for_each_attr(attr, head, len) + { + hdr = blob_data(attr); + + struct blob_attr *tb[__CLIENT_MAX]; + blobmsg_parse(client_policy, __CLIENT_MAX, tb, blobmsg_data(attr), blobmsg_len(attr)); + //char* str = blobmsg_format_json_indent(attr, true, -1); + + int tmp_int_mac[ETH_ALEN]; + uint8_t tmp_mac[ETH_ALEN]; + sscanf((char *) hdr->name, MACSTR, STR2MAC(tmp_int_mac)); + for (int i = 0; i < ETH_ALEN; ++i) + tmp_mac[i] = (uint8_t) tmp_int_mac[i]; + + dump_client(tb, tmp_mac, bssid_addr, freq, ht_supported, vht_supported); + station_count++; + } + return station_count; +} + +int parse_to_clients(struct blob_attr *msg, int do_kick, uint32_t id) { + struct blob_attr *tb[__CLIENT_TABLE_MAX]; + + if (!msg) { + return -1; + } + + if (!blob_data(msg)) { + return -1; + } + + if (blob_len(msg) <= 0) { + return -1; + } + + blobmsg_parse(client_table_policy, __CLIENT_TABLE_MAX, tb, blob_data(msg), blob_len(msg)); + + if (tb[CLIENT_TABLE] && tb[CLIENT_TABLE_BSSID] && tb[CLIENT_TABLE_FREQ]) { + int num_stations = 0; + num_stations = dump_client_table(blobmsg_data(tb[CLIENT_TABLE]), blobmsg_data_len(tb[CLIENT_TABLE]), + blobmsg_data(tb[CLIENT_TABLE_BSSID]), blobmsg_get_u32(tb[CLIENT_TABLE_FREQ]), + blobmsg_get_u8(tb[CLIENT_TABLE_HT]), blobmsg_get_u8(tb[CLIENT_TABLE_VHT])); + ap ap_entry; + hwaddr_aton(blobmsg_data(tb[CLIENT_TABLE_BSSID]), ap_entry.bssid_addr); + ap_entry.freq = blobmsg_get_u32(tb[CLIENT_TABLE_FREQ]); + + if(tb[CLIENT_TABLE_HT]){ + ap_entry.ht_support = blobmsg_get_u8(tb[CLIENT_TABLE_HT]); + } else { + ap_entry.ht_support = false; + } + + if(tb[CLIENT_TABLE_VHT]){ + ap_entry.vht_support = blobmsg_get_u8(tb[CLIENT_TABLE_VHT]); + } else + { + ap_entry.vht_support = false; + } + + if(tb[CLIENT_TABLE_CHAN_UTIL]) { + ap_entry.channel_utilization = blobmsg_get_u32(tb[CLIENT_TABLE_CHAN_UTIL]); + } else // if this is not existing set to 0? + { + ap_entry.channel_utilization = 0; + } + + if(tb[CLIENT_TABLE_SSID]) { + strcpy((char *) ap_entry.ssid, blobmsg_get_string(tb[CLIENT_TABLE_SSID])); + } + + if (tb[CLIENT_TABLE_COL_DOMAIN]) { + ap_entry.collision_domain = blobmsg_get_u32(tb[CLIENT_TABLE_COL_DOMAIN]); + } else { + ap_entry.collision_domain = -1; + } + + if (tb[CLIENT_TABLE_BANDWIDTH]) { + ap_entry.bandwidth = blobmsg_get_u32(tb[CLIENT_TABLE_BANDWIDTH]); + } else { + ap_entry.bandwidth = -1; + } + + ap_entry.station_count = num_stations; + + if (tb[CLIENT_TABLE_WEIGHT]) { + ap_entry.ap_weight = blobmsg_get_u32(tb[CLIENT_TABLE_WEIGHT]); + } else { + ap_entry.ap_weight = 0; + } + + insert_to_ap_array(ap_entry); + + if (do_kick && dawn_metric.kicking) { + kick_clients(ap_entry.bssid_addr, id); + } + } + return 0; +} + +static void ubus_get_clients_cb(struct ubus_request *req, int type, struct blob_attr *msg) { + struct hostapd_sock_entry *sub, *entry = NULL; + + if (!msg) + return; + + char *data_str = blobmsg_format_json(msg, 1); + blob_buf_init(&b_domain, 0); + blobmsg_add_json_from_string(&b_domain, data_str); + blobmsg_add_u32(&b_domain, "collision_domain", network_config.collision_domain); + blobmsg_add_u32(&b_domain, "bandwidth", network_config.bandwidth); + + list_for_each_entry(sub, &hostapd_sock_list, list) + { + if (sub->id == req->peer) { + entry = sub; + } + } + + if (entry == NULL) { + fprintf(stderr, "Failed to find interface!\n"); + return; + } + + if (!entry->subscribed) { + fprintf(stderr, "Interface %s is not subscribed!\n", entry->iface_name); + return; + } + + blobmsg_add_macaddr(&b_domain, "bssid", entry->bssid_addr); + blobmsg_add_string(&b_domain, "ssid", entry->ssid); + blobmsg_add_u8(&b_domain, "ht_supported", entry->ht_support); + blobmsg_add_u8(&b_domain, "vht_supported", entry->vht_support); + + blobmsg_add_u32(&b_domain, "ap_weight", dawn_metric.ap_weight); + + //int channel_util = get_channel_utilization(entry->iface_name, &entry->last_channel_time, &entry->last_channel_time_busy); + blobmsg_add_u32(&b_domain, "channel_utilization", entry->chan_util_average); + + send_blob_attr_via_network(b_domain.head, "clients"); + parse_to_clients(b_domain.head, 1, req->peer); + + print_client_array(); + print_ap_array(); + + free(data_str); +} + +static int ubus_get_clients() { + int timeout = 1; + struct hostapd_sock_entry *sub; + list_for_each_entry(sub, &hostapd_sock_list, list) + { + if (sub->subscribed) { + blob_buf_init(&b_clients, 0); + ubus_invoke(ctx, sub->id, "get_clients", b_clients.head, ubus_get_clients_cb, NULL, timeout * 1000); + } + } + return 0; +} + +void update_clients(struct uloop_timeout *t) { + ubus_get_clients(); + // maybe to much?! don't set timer again... + uloop_timeout_set(&client_timer, timeout_config.update_client * 1000); +} + +void update_channel_utilization(struct uloop_timeout *t) { + struct hostapd_sock_entry *sub; + + list_for_each_entry(sub, &hostapd_sock_list, list) + { + + if (sub->subscribed) { + sub->chan_util_samples_sum += get_channel_utilization(sub->iface_name, &sub->last_channel_time, + &sub->last_channel_time_busy); + sub->chan_util_num_sample_periods++; + + if (sub->chan_util_num_sample_periods > dawn_metric.chan_util_avg_period) { + sub->chan_util_average = sub->chan_util_samples_sum / sub->chan_util_num_sample_periods; + sub->chan_util_samples_sum = 0; + sub->chan_util_num_sample_periods = 0; + } + } + } + uloop_timeout_set(&channel_utilization_timer, timeout_config.update_chan_util * 1000); +} + +void update_tcp_connections(struct uloop_timeout *t) { + ubus_call_umdns(); + uloop_timeout_set(&umdns_timer, timeout_config.update_tcp_con * 1000); +} + +void start_umdns_update() { + // update connections + uloop_timeout_add(&umdns_timer); +} + +void update_hostapd_sockets(struct uloop_timeout *t) { + subscribe_to_new_interfaces(hostapd_dir_glob); + uloop_timeout_set(&hostapd_timer, timeout_config.update_hostapd * 1000); +} + +void del_client_all_interfaces(const uint8_t *client_addr, uint32_t reason, uint8_t deauth, uint32_t ban_time) { + struct hostapd_sock_entry *sub; + + blob_buf_init(&b, 0); + blobmsg_add_macaddr(&b, "addr", client_addr); + blobmsg_add_u32(&b, "reason", reason); + blobmsg_add_u8(&b, "deauth", deauth); + blobmsg_add_u32(&b, "ban_time", ban_time); + + list_for_each_entry(sub, &hostapd_sock_list, list) + { + if (sub->subscribed) { + int timeout = 1; + ubus_invoke(ctx, sub->id, "del_client", b.head, NULL, NULL, timeout * 1000); + } + } +} + +void del_client_interface(uint32_t id, const uint8_t *client_addr, uint32_t reason, uint8_t deauth, uint32_t ban_time) { + struct hostapd_sock_entry *sub; + + blob_buf_init(&b, 0); + blobmsg_add_macaddr(&b, "addr", client_addr); + blobmsg_add_u32(&b, "reason", reason); + blobmsg_add_u8(&b, "deauth", deauth); + blobmsg_add_u32(&b, "ban_time", ban_time); + + + list_for_each_entry(sub, &hostapd_sock_list, list) + { + if (sub->subscribed) { + int timeout = 1; + ubus_invoke(ctx, id, "del_client", b.head, NULL, NULL, timeout * 1000); + } + } + +} + +static void ubus_umdns_cb(struct ubus_request *req, int type, struct blob_attr *msg) { + struct blob_attr *tb[__DAWN_UMDNS_TABLE_MAX]; + + if (!msg) + return; + + blobmsg_parse(dawn_umdns_table_policy, __DAWN_UMDNS_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[DAWN_UMDNS_TABLE]) { + return; + } + + struct blob_attr *attr; + struct blobmsg_hdr *hdr; + int len = blobmsg_data_len(tb[DAWN_UMDNS_TABLE]); + + __blob_for_each_attr(attr, blobmsg_data(tb[DAWN_UMDNS_TABLE]), len) + { + hdr = blob_data(attr); + + struct blob_attr *tb_dawn[__DAWN_UMDNS_MAX]; + blobmsg_parse(dawn_umdns_policy, __DAWN_UMDNS_MAX, tb_dawn, blobmsg_data(attr), blobmsg_len(attr)); + + printf("Hostname: %s\n", hdr->name); + if (tb_dawn[DAWN_UMDNS_IPV4] && tb_dawn[DAWN_UMDNS_PORT]) { + printf("IPV4: %s\n", blobmsg_get_string(tb_dawn[DAWN_UMDNS_IPV4])); + printf("Port: %d\n", blobmsg_get_u32(tb_dawn[DAWN_UMDNS_PORT])); + } else { + return; + } + add_tcp_conncection(blobmsg_get_string(tb_dawn[DAWN_UMDNS_IPV4]), blobmsg_get_u32(tb_dawn[DAWN_UMDNS_PORT])); + } +} + +int ubus_call_umdns() { + u_int32_t id; + if (ubus_lookup_id(ctx, "umdns", &id)) { + fprintf(stderr, "Failed to look up test object for %s\n", "umdns"); + return -1; + } + + int timeout = 1; + blob_buf_init(&b_umdns, 0); + ubus_invoke(ctx, id, "update", b_umdns.head, NULL, NULL, timeout * 1000); + ubus_invoke(ctx, id, "browse", b_umdns.head, ubus_umdns_cb, NULL, timeout * 1000); + + return 0; +} + +//TODO: ADD STUFF HERE!!!! +int ubus_send_probe_via_network(struct probe_entry_s probe_entry) { + blob_buf_init(&b_probe, 0); + blobmsg_add_macaddr(&b_probe, "bssid", probe_entry.bssid_addr); + blobmsg_add_macaddr(&b_probe, "address", probe_entry.client_addr); + blobmsg_add_macaddr(&b_probe, "target", probe_entry.target_addr); + blobmsg_add_u32(&b_probe, "signal", probe_entry.signal); + blobmsg_add_u32(&b_probe, "freq", probe_entry.freq); + + if(probe_entry.ht_capabilities) + { + void *ht_cap = blobmsg_open_table(&b, "ht_capabilities"); + blobmsg_close_table(&b, ht_cap); + } + + if(probe_entry.vht_capabilities) { + void *vht_cap = blobmsg_open_table(&b, "vht_capabilities"); + blobmsg_close_table(&b, vht_cap); + } + + send_blob_attr_via_network(b_probe.head, "probe"); + + return 0; +} + +int send_set_probe(uint8_t client_addr[]) { + blob_buf_init(&b_probe, 0); + blobmsg_add_macaddr(&b_probe, "bssid", client_addr); + blobmsg_add_macaddr(&b_probe, "address", client_addr); + + send_blob_attr_via_network(b_probe.head, "setprobe"); + + return 0; +} + +enum { + MAC_ADDR, + __ADD_DEL_MAC_MAX +}; + +static const struct blobmsg_policy add_del_policy[__ADD_DEL_MAC_MAX] = { + [MAC_ADDR] = {"addrs", BLOBMSG_TYPE_ARRAY}, +}; + +static const struct ubus_method dawn_methods[] = { + UBUS_METHOD("add_mac", add_mac, add_del_policy), + UBUS_METHOD_NOARG("get_hearing_map", get_hearing_map), + UBUS_METHOD_NOARG("get_network", get_network), + UBUS_METHOD_NOARG("reload_config", reload_config) +}; + +static struct ubus_object_type dawn_object_type = + UBUS_OBJECT_TYPE("dawn", dawn_methods); + +static struct ubus_object dawn_object = { + .name = "dawn", + .type = &dawn_object_type, + .methods = dawn_methods, + .n_methods = ARRAY_SIZE(dawn_methods), +}; + +static int parse_add_mac_to_file(struct blob_attr *msg) { + struct blob_attr *tb[__ADD_DEL_MAC_MAX]; + struct blob_attr *attr; + + printf("Parsing MAC!\n"); + + blobmsg_parse(add_del_policy, __ADD_DEL_MAC_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[MAC_ADDR]) + return UBUS_STATUS_INVALID_ARGUMENT; + + int len = blobmsg_data_len(tb[MAC_ADDR]); + printf("Length of array maclist: %d\n", len); + + __blob_for_each_attr(attr, blobmsg_data(tb[MAC_ADDR]), len) + { + printf("Iteration through MAC-list\n"); + uint8_t addr[ETH_ALEN]; + hwaddr_aton(blobmsg_data(attr), addr); + + if (insert_to_maclist(addr) == 0) { + write_mac_to_file("/tmp/dawn_mac_list", addr); + } + } + + return 0; +} + +static int add_mac(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { + parse_add_mac_to_file(msg); + + // here we need to send it via the network! + send_blob_attr_via_network(msg, "addmac"); + + return 0; +} + +int send_add_mac(uint8_t *client_addr) { + blob_buf_init(&b, 0); + blobmsg_add_macaddr(&b, "addr", client_addr); + send_blob_attr_via_network(b.head, "addmac"); + return 0; +} + +static int reload_config(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { + int ret; + blob_buf_init(&b, 0); + uci_reset(); + dawn_metric = uci_get_dawn_metric(); + timeout_config = uci_get_time_config(); + hostapd_dir_glob = uci_get_dawn_hostapd_dir(); + sort_string = (char *) uci_get_dawn_sort_order(); + uci_send_via_network(); + ret = ubus_send_reply(ctx, req, b.head); + if (ret) + fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret)); + return 0; +} + +static int get_hearing_map(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { + int ret; + + build_hearing_map_sort_client(&b); + ret = ubus_send_reply(ctx, req, b.head); + if (ret) + fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret)); + return 0; +} + + +static int get_network(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { + int ret; + + build_network_overview(&b); + ret = ubus_send_reply(ctx, req, b.head); + if (ret) + fprintf(stderr, "Failed to send reply: %s\n", ubus_strerror(ret)); + return 0; +} + +static void ubus_add_oject() { + int ret; + + ret = ubus_add_object(ctx, &dawn_object); + if (ret) + fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret)); +} + +static void respond_to_notify(uint32_t id) { + // This is needed to respond to the ubus notify ... + // Maybe we need to disable on shutdown... + // But it is not possible when we disable the notify that other daemons are running that relay on this notify... + int ret; + + blob_buf_init(&b, 0); + blobmsg_add_u32(&b, "notify_response", 1); + + int timeout = 1; + ret = ubus_invoke(ctx, id, "notify_response", b.head, NULL, NULL, timeout * 1000); + if (ret) + fprintf(stderr, "Failed to invoke: %s\n", ubus_strerror(ret)); +} + +static void hostapd_handle_remove(struct ubus_context *ctx, + struct ubus_subscriber *s, uint32_t id) { + fprintf(stdout, "Object %08x went away\n", id); + struct hostapd_sock_entry *hostapd_sock = container_of(s, + struct hostapd_sock_entry, subscriber); + + if (hostapd_sock->id != id) { + printf("ID is not the same!\n"); + return; + } + + hostapd_sock->subscribed = false; + subscription_wait(&hostapd_sock->wait_handler); + +} + +bool subscribe(struct hostapd_sock_entry *hostapd_entry) { + char subscribe_name[sizeof("hostapd.") + MAX_INTERFACE_NAME + 1]; + + if (hostapd_entry->subscribed) + return false; + + sprintf(subscribe_name, "hostapd.%s", hostapd_entry->iface_name); + + if (ubus_lookup_id(ctx, subscribe_name, &hostapd_entry->id)) { + fprintf(stdout, "Failed to lookup ID!"); + subscription_wait(&hostapd_entry->wait_handler); + return false; + } + + if (ubus_subscribe(ctx, &hostapd_entry->subscriber, hostapd_entry->id)) { + fprintf(stdout, "Failed to register subscriber!"); + subscription_wait(&hostapd_entry->wait_handler); + return false; + } + + hostapd_entry->subscribed = true; + + get_bssid(hostapd_entry->iface_name, hostapd_entry->bssid_addr); + get_ssid(hostapd_entry->iface_name, hostapd_entry->ssid); + + hostapd_entry->ht_support = (uint8_t) support_ht(hostapd_entry->iface_name); + hostapd_entry->vht_support = (uint8_t) support_vht(hostapd_entry->iface_name); + + respond_to_notify(hostapd_entry->id); + + printf("Subscribed to: %s\n", hostapd_entry->iface_name); + + return true; +} + +static void +wait_cb(struct ubus_context *ctx, struct ubus_event_handler *ev_handler, + const char *type, struct blob_attr *msg) { + static const struct blobmsg_policy wait_policy = { + "path", BLOBMSG_TYPE_STRING + }; + + struct blob_attr *attr; + const char *path; + struct hostapd_sock_entry *sub = container_of(ev_handler, + struct hostapd_sock_entry, wait_handler); + + if (strcmp(type, "ubus.object.add")) + return; + + blobmsg_parse(&wait_policy, 1, &attr, blob_data(msg), blob_len(msg)); + if (!attr) + return; + + path = blobmsg_data(attr); + + path = strchr(path, '.'); + if (!path) + return; + + if (strcmp(sub->iface_name, path + 1)) + return; + + subscribe(sub); +} + +bool subscriber_to_interface(const char *ifname) { + + struct hostapd_sock_entry *hostapd_entry; + + hostapd_entry = calloc(1, sizeof(struct hostapd_sock_entry)); + strcpy(hostapd_entry->iface_name, ifname); + hostapd_entry->subscriber.cb = hostapd_notify; + hostapd_entry->subscriber.remove_cb = hostapd_handle_remove; + hostapd_entry->wait_handler.cb = wait_cb; + + hostapd_entry->subscribed = false; + + if (ubus_register_subscriber(ctx, &hostapd_entry->subscriber)) { + fprintf(stderr, "Failed to register subscriber!"); + return false; + } + + list_add(&hostapd_entry->list, &hostapd_sock_list); + + return subscribe(hostapd_entry); +} + +void subscribe_to_new_interfaces(const char *hostapd_sock_path) { + DIR *dirp; + struct dirent *entry; + struct hostapd_sock_entry *sub = NULL; + + if (ctx == NULL) { + return; + } + + dirp = opendir(hostapd_sock_path); // error handling? + if (!dirp) { + fprintf(stderr, "[SUBSCRIBING] No hostapd sockets!\n"); + return; + } + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_type == DT_SOCK) { + bool do_subscribe = true; + list_for_each_entry(sub, &hostapd_sock_list, list) + { + if (strncmp(sub->iface_name, entry->d_name, MAX_INTERFACE_NAME) == 0) { + do_subscribe = false; + break; + } + } + if (do_subscribe) { + subscriber_to_interface(entry->d_name); + } + + } + } + closedir(dirp); + return; +} + +int uci_send_via_network() +{ + void *metric, *times; + + blob_buf_init(&b, 0); + metric = blobmsg_open_table(&b, "metric"); + blobmsg_add_u32(&b, "ht_support", dawn_metric.ht_support); + blobmsg_add_u32(&b, "vht_support", dawn_metric.vht_support); + blobmsg_add_u32(&b, "no_ht_support", dawn_metric.no_ht_support); + blobmsg_add_u32(&b, "no_vht_support", dawn_metric.no_vht_support); + blobmsg_add_u32(&b, "rssi", dawn_metric.rssi); + blobmsg_add_u32(&b, "low_rssi", dawn_metric.low_rssi); + blobmsg_add_u32(&b, "freq", dawn_metric.freq); + blobmsg_add_u32(&b, "chan_util", dawn_metric.chan_util); + + + blobmsg_add_u32(&b, "max_chan_util", dawn_metric.max_chan_util); + blobmsg_add_u32(&b, "rssi_val", dawn_metric.rssi_val); + blobmsg_add_u32(&b, "low_rssi_val", dawn_metric.low_rssi_val); + blobmsg_add_u32(&b, "chan_util_val", dawn_metric.chan_util_val); + blobmsg_add_u32(&b, "max_chan_util_val", dawn_metric.max_chan_util_val); + blobmsg_add_u32(&b, "min_probe_count", dawn_metric.min_probe_count); + blobmsg_add_u32(&b, "bandwith_threshold", dawn_metric.bandwith_threshold); + blobmsg_add_u32(&b, "use_station_count", dawn_metric.use_station_count); + blobmsg_add_u32(&b, "max_station_diff", dawn_metric.max_station_diff); + blobmsg_add_u32(&b, "eval_probe_req", dawn_metric.eval_probe_req); + blobmsg_add_u32(&b, "eval_auth_req", dawn_metric.eval_auth_req); + blobmsg_add_u32(&b, "eval_assoc_req", dawn_metric.eval_assoc_req); + blobmsg_add_u32(&b, "kicking", dawn_metric.kicking); + blobmsg_add_u32(&b, "deny_auth_reason", dawn_metric.deny_auth_reason); + blobmsg_add_u32(&b, "deny_assoc_reason", dawn_metric.deny_assoc_reason); + blobmsg_add_u32(&b, "use_driver_recog", dawn_metric.use_driver_recog); + blobmsg_add_u32(&b, "min_number_to_kick", dawn_metric.min_kick_count); + blobmsg_add_u32(&b, "chan_util_avg_period", dawn_metric.chan_util_avg_period); + blobmsg_close_table(&b, metric); + + times = blobmsg_open_table(&b, "times"); + blobmsg_add_u32(&b, "update_client", timeout_config.update_client); + blobmsg_add_u32(&b, "denied_req_threshold", timeout_config.denied_req_threshold); + blobmsg_add_u32(&b, "remove_client", timeout_config.remove_client); + blobmsg_add_u32(&b, "remove_probe", timeout_config.remove_probe); + blobmsg_add_u32(&b, "remove_ap", timeout_config.remove_ap); + blobmsg_add_u32(&b, "update_hostapd", timeout_config.update_hostapd); + blobmsg_add_u32(&b, "update_tcp_con", timeout_config.update_tcp_con); + blobmsg_add_u32(&b, "update_chan_util", timeout_config.update_chan_util); + blobmsg_close_table(&b, times); + + send_blob_attr_via_network(b.head, "uci"); + + return 0; +} +enum { + UCI_TABLE_METRIC, + UCI_TABLE_TIMES, + __UCI_TABLE_MAX +}; + +enum { + UCI_HT_SUPPORT, + UCI_VHT_SUPPORT, + UCI_NO_HT_SUPPORT, + UCI_NO_VHT_SUPPORT, + UCI_RSSI, + UCI_LOW_RSSI, + UCI_FREQ, + UCI_CHAN_UTIL, + UCI_MAX_CHAN_UTIL, + UCI_RSSI_VAL, + UCI_LOW_RSSI_VAL, + UCI_CHAN_UTIL_VAL, + UCI_MAX_CHAN_UTIL_VAL, + UCI_MIN_PROBE_COUNT, + UCI_BANDWITH_THRESHOLD, + UCI_USE_STATION_COUNT, + UCI_MAX_STATION_DIFF, + UCI_EVAL_PROBE_REQ, + UCI_EVAL_AUTH_REQ, + UCI_EVAL_ASSOC_REQ, + UCI_KICKING, + UCI_DENY_AUTH_REASON, + UCI_DENY_ASSOC_REASON, + UCI_USE_DRIVER_RECOG, + UCI_MIN_NUMBER_TO_KICK, + UCI_CHAN_UTIL_AVG_PERIOD, + __UCI_METIC_MAX +}; + +enum { + UCI_UPDATE_CLIENT, + UCI_DENIED_REQ_THRESHOLD, + UCI_REMOVE_CLIENT, + UCI_REMOVE_PROBE, + UCI_REMOVE_AP, + UCI_UPDATE_HOSTAPD, + UCI_UPDATE_TCP_CON, + UCI_UPDATE_CHAN_UTIL, + __UCI_TIMES_MAX, +}; + +static const struct blobmsg_policy uci_table_policy[__UCI_TABLE_MAX] = { + [UCI_TABLE_METRIC] = {.name = "metric", .type = BLOBMSG_TYPE_TABLE}, + [UCI_TABLE_TIMES] = {.name = "times", .type = BLOBMSG_TYPE_TABLE} +}; + +static const struct blobmsg_policy uci_metric_policy[__UCI_METIC_MAX] = { + [UCI_HT_SUPPORT] = {.name = "ht_support", .type = BLOBMSG_TYPE_INT32}, + [UCI_VHT_SUPPORT] = {.name = "vht_support", .type = BLOBMSG_TYPE_INT32}, + [UCI_NO_HT_SUPPORT] = {.name = "no_ht_support", .type = BLOBMSG_TYPE_INT32}, + [UCI_NO_VHT_SUPPORT] = {.name = "no_vht_support", .type = BLOBMSG_TYPE_INT32}, + [UCI_RSSI] = {.name = "rssi", .type = BLOBMSG_TYPE_INT32}, + [UCI_LOW_RSSI] = {.name = "low_rssi", .type = BLOBMSG_TYPE_INT32}, + [UCI_FREQ] = {.name = "freq", .type = BLOBMSG_TYPE_INT32}, + [UCI_CHAN_UTIL] = {.name = "chan_util", .type = BLOBMSG_TYPE_INT32}, + [UCI_MAX_CHAN_UTIL] = {.name = "max_chan_util", .type = BLOBMSG_TYPE_INT32}, + [UCI_RSSI_VAL] = {.name = "rssi_val", .type = BLOBMSG_TYPE_INT32}, + [UCI_LOW_RSSI_VAL] = {.name = "low_rssi_val", .type = BLOBMSG_TYPE_INT32}, + [UCI_CHAN_UTIL_VAL] = {.name = "chan_util_val", .type = BLOBMSG_TYPE_INT32}, + [UCI_MAX_CHAN_UTIL_VAL] = {.name = "max_chan_util_val", .type = BLOBMSG_TYPE_INT32}, + [UCI_MIN_PROBE_COUNT] = {.name = "min_probe_count", .type = BLOBMSG_TYPE_INT32}, + [UCI_BANDWITH_THRESHOLD] = {.name = "bandwith_threshold", .type = BLOBMSG_TYPE_INT32}, + [UCI_USE_STATION_COUNT] = {.name = "use_station_count", .type = BLOBMSG_TYPE_INT32}, + [UCI_MAX_STATION_DIFF] = {.name = "max_station_diff", .type = BLOBMSG_TYPE_INT32}, + [UCI_EVAL_PROBE_REQ] = {.name = "eval_probe_req", .type = BLOBMSG_TYPE_INT32}, + [UCI_EVAL_AUTH_REQ] = {.name = "eval_auth_req", .type = BLOBMSG_TYPE_INT32}, + [UCI_EVAL_ASSOC_REQ] = {.name = "eval_assoc_req", .type = BLOBMSG_TYPE_INT32}, + [UCI_KICKING] = {.name = "kicking", .type = BLOBMSG_TYPE_INT32}, + [UCI_DENY_AUTH_REASON] = {.name = "deny_auth_reason", .type = BLOBMSG_TYPE_INT32}, + [UCI_DENY_ASSOC_REASON] = {.name = "deny_assoc_reason", .type = BLOBMSG_TYPE_INT32}, + [UCI_USE_DRIVER_RECOG] = {.name = "use_driver_recog", .type = BLOBMSG_TYPE_INT32}, + [UCI_MIN_NUMBER_TO_KICK] = {.name = "min_number_to_kick", .type = BLOBMSG_TYPE_INT32}, + [UCI_CHAN_UTIL_AVG_PERIOD] = {.name = "chan_util_avg_period", .type = BLOBMSG_TYPE_INT32}, +}; + +static const struct blobmsg_policy uci_times_policy[__UCI_TIMES_MAX] = { + [UCI_UPDATE_CLIENT] = {.name = "update_client", .type = BLOBMSG_TYPE_INT32}, + [UCI_DENIED_REQ_THRESHOLD] = {.name = "denied_req_threshold", .type = BLOBMSG_TYPE_INT32}, + [UCI_REMOVE_CLIENT] = {.name = "remove_client", .type = BLOBMSG_TYPE_INT32}, + [UCI_REMOVE_PROBE] = {.name = "remove_probe", .type = BLOBMSG_TYPE_INT32}, + [UCI_REMOVE_AP] = {.name = "remove_ap", .type = BLOBMSG_TYPE_INT32}, + [UCI_UPDATE_HOSTAPD] = {.name = "update_hostapd", .type = BLOBMSG_TYPE_INT32}, + [UCI_UPDATE_TCP_CON] = {.name = "update_tcp_con", .type = BLOBMSG_TYPE_INT32}, + [UCI_UPDATE_CHAN_UTIL] = {.name = "update_chan_util", .type = BLOBMSG_TYPE_INT32}, + +}; + +int handle_uci_config(struct blob_attr *msg) { + + struct blob_attr *tb[__UCI_TABLE_MAX]; + blobmsg_parse(uci_table_policy, __UCI_TABLE_MAX, tb, blob_data(msg), blob_len(msg)); + + struct blob_attr *tb_metric[__UCI_METIC_MAX]; + blobmsg_parse(uci_metric_policy, __UCI_METIC_MAX, tb_metric, blobmsg_data(tb[UCI_TABLE_METRIC]), blobmsg_len(tb[UCI_TABLE_METRIC])); + + char cmd_buffer[1024]; + sprintf(cmd_buffer, "dawn.@metric[0].ht_support=%d", blobmsg_get_u32(tb_metric[UCI_HT_SUPPORT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].vht_support=%d", blobmsg_get_u32(tb_metric[UCI_VHT_SUPPORT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].no_ht_support=%d", blobmsg_get_u32(tb_metric[UCI_NO_HT_SUPPORT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].no_vht_support=%d", blobmsg_get_u32(tb_metric[UCI_NO_VHT_SUPPORT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].rssi=%d", blobmsg_get_u32(tb_metric[UCI_RSSI])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].low_rssi=%d", blobmsg_get_u32(tb_metric[UCI_LOW_RSSI])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].freq=%d", blobmsg_get_u32(tb_metric[UCI_FREQ])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].chan_util=%d", blobmsg_get_u32(tb_metric[UCI_CHAN_UTIL])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].rssi_val=%d", blobmsg_get_u32(tb_metric[UCI_RSSI_VAL])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].low_rssi_val=%d", blobmsg_get_u32(tb_metric[UCI_LOW_RSSI_VAL])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].chan_util_val=%d", blobmsg_get_u32(tb_metric[UCI_CHAN_UTIL_VAL])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].max_chan_util=%d", blobmsg_get_u32(tb_metric[UCI_MAX_CHAN_UTIL])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].max_chan_util_val=%d", blobmsg_get_u32(tb_metric[UCI_MAX_CHAN_UTIL_VAL])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].min_probe_count=%d", blobmsg_get_u32(tb_metric[UCI_MIN_PROBE_COUNT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].bandwith_threshold=%d", blobmsg_get_u32(tb_metric[UCI_BANDWITH_THRESHOLD])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].use_station_count=%d", blobmsg_get_u32(tb_metric[UCI_USE_STATION_COUNT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].max_station_diff=%d", blobmsg_get_u32(tb_metric[UCI_MAX_STATION_DIFF])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].eval_probe_req=%d", blobmsg_get_u32(tb_metric[UCI_EVAL_PROBE_REQ])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].eval_auth_req=%d", blobmsg_get_u32(tb_metric[UCI_EVAL_AUTH_REQ])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].evalcd_assoc_req=%d", blobmsg_get_u32(tb_metric[UCI_EVAL_ASSOC_REQ])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].kicking=%d", blobmsg_get_u32(tb_metric[UCI_KICKING])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].deny_auth_reason=%d", blobmsg_get_u32(tb_metric[UCI_DENY_AUTH_REASON])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].deny_assoc_reason=%d", blobmsg_get_u32(tb_metric[UCI_DENY_ASSOC_REASON])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].use_driver_recog=%d", blobmsg_get_u32(tb_metric[UCI_USE_DRIVER_RECOG])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].min_number_to_kick=%d", blobmsg_get_u32(tb_metric[UCI_MIN_NUMBER_TO_KICK])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@metric[0].chan_util_avg_period=%d", blobmsg_get_u32(tb_metric[UCI_CHAN_UTIL_AVG_PERIOD])); + uci_set_network(cmd_buffer); + + struct blob_attr *tb_times[__UCI_TIMES_MAX]; + blobmsg_parse(uci_times_policy, __UCI_TIMES_MAX, tb_times, blobmsg_data(tb[UCI_TABLE_TIMES]), blobmsg_len(tb[UCI_TABLE_TIMES])); + + sprintf(cmd_buffer, "dawn.@times[0].update_client=%d", blobmsg_get_u32(tb_times[UCI_UPDATE_CLIENT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@times[0].denied_req_threshold=%d", blobmsg_get_u32(tb_times[UCI_DENIED_REQ_THRESHOLD])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@times[0].remove_client=%d", blobmsg_get_u32(tb_times[UCI_REMOVE_CLIENT])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@times[0].remove_probe=%d", blobmsg_get_u32(tb_times[UCI_REMOVE_PROBE])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@times[0].remove_ap=%d", blobmsg_get_u32(tb_times[UCI_REMOVE_AP])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@times[0].update_hostapd=%d", blobmsg_get_u32(tb_times[UCI_UPDATE_HOSTAPD])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@times[0].update_tcp_con=%d", blobmsg_get_u32(tb_times[UCI_UPDATE_TCP_CON])); + uci_set_network(cmd_buffer); + + sprintf(cmd_buffer, "dawn.@times[0].update_chan_util=%d", blobmsg_get_u32(tb_times[UCI_UPDATE_CHAN_UTIL])); + uci_set_network(cmd_buffer); + + uci_reset(); + dawn_metric = uci_get_dawn_metric(); + timeout_config = uci_get_time_config(); + + return 0; +} \ No newline at end of file diff --git a/src/utils/utils.c b/src/utils/utils.c new file mode 100644 index 0000000..1a9210b --- /dev/null +++ b/src/utils/utils.c @@ -0,0 +1,80 @@ +#include "utils.h" +#include "ubus.h" + +int string_is_greater(uint8_t *str, uint8_t *str_2) { + + int length_1 = strlen((char *) str); + int length_2 = strlen((char *) str_2); + + int length = length_1 < length_2 ? length_1 : length_2; + + for (int i = 0; i < length; i++) { + if (str[i] > str_2[i]) { + return 1; + } + if (str[i] < str_2[i]) { + return 0; + } + } + return length_1 > length_2; +} + +// source: https://elixir.bootlin.com/linux/v4.9/source/lib/hexdump.c#L28 +int hex_to_bin(char ch) { + if ((ch >= '0') && (ch <= '9')) return ch - '0'; + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; + return -1; +} + +// based on: hostapd src/utils/common.c +int hwaddr_aton(const char *txt, uint8_t *addr) { + int i; + + for (i = 0; i < ETH_ALEN; i++) { + int a, b; + + a = hex_to_bin(*txt++); + if (a < 0) return -1; + b = hex_to_bin(*txt++); + if (b < 0) return -1; + *addr++ = (a << 4) | b; + if (i < 5 && *txt++ != ':') return -1; + } + + return 0; +} + +int convert_mac(char *in, char *out) { + int i, j = 0; + + for (i = 0; i < 6; i++) { + if (in[j + 1] != ':' && in[j + 1] != '\0') { + out[3 * i] = toupper(in[j]); + out[(3 * i) + 1] = toupper(in[j + 1]); + out[(3 * i) + 2] = in[j + 2]; + j += 3; + } else { + out[3 * i] = '0'; + out[(3 * i) + 1] = toupper(in[j]); + out[(3 * i) + 2] = toupper(in[j + 1]); + j += 2; + } + } + return 0; +} + +void write_mac_to_file(char *path, uint8_t addr[]) { + FILE *f = fopen(path, "a"); + if (f == NULL) { + fprintf(stderr,"Error opening mac file!\n"); + exit(1); + } + + char mac_buf[20]; + sprintf(mac_buf, MACSTR, MAC2STR(addr)); + + fprintf(f, "%s\n", mac_buf); + + fclose(f); +} \ No newline at end of file