commit 92df7a383a90cb6120b911386271995aae9a1011 Author: Guy Resheff Date: Sun Mar 8 08:19:45 2026 -0700 Upstream vwifi v7.0 (Raizo62/vwifi @ 4a9842e) Unmodified upstream source from https://github.com/Raizo62/vwifi Commit: 4a9842e "CMakeLists.txt : VERSION = 7.0" Simulator of WiFi (802.11) interfaces to communicate between several Virtual Machines via mac80211_hwsim + TCP relay. License: Apache-2.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..30d4da3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Old build artifacts +# vwifi-server +# vwifi-client +# vwifi-ctrl +# vwifi-add-interfaces +# obj/ + +# CMake build artifacts +build/ +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +compile_commands.json +Makefile +*.a +*.so + +# For cppcheck +vwifi-cppcheck.xml +# For eclipse : +.project +.cproject +.settings +# For Visual Studio Code : +.vscode diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..86f45bf --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Raizo62 (David Ansart / https://github.com/Raizo62) +SecurityLab (Boussad Ait-Salem / https://securitylab.fr/home) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1493569 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,162 @@ +cmake_minimum_required(VERSION 3.10) + +project(vwifi VERSION 7.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +# --- Compiler Flags --- +# Add flags similar to the Makefile's MODE settings +# Using Release build type for optimizations by default +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose build type: Debug Release RelWithDebInfo MinSizeRel" FORCE) +endif() + +option(ENABLE_VHOST "Enable vhost support" ON) +if(NOT ENABLE_VHOST) + add_definitions(-DDISABLE_VHOST) +endif() + +# Common flags (add more as needed based on Makefile MODE) +add_compile_options(-Wall -Wextra -pedantic) +if(CMAKE_BUILD_TYPE STREQUAL "Release") + add_compile_options(-O3 -s) + # add_definitions(-DNDEBUG) # Uncomment if asserts should be disabled in release +elseif(CMAKE_BUILD_TYPE STREQUAL "Debug") + add_compile_options(-g) + add_definitions(-D_DEBUG) +endif() + +# Add version definition +# Check if this is a git repository and get the commit hash +find_package(Git QUIET) +if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") + execute_process( + COMMAND "${GIT_EXECUTABLE}" log --pretty=format:%h -n 1 + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) +endif() + +if(GIT_COMMIT_HASH) + set(FULL_VERSION "${PROJECT_VERSION}-${GIT_COMMIT_HASH}") + message(STATUS "Building Git version: ${FULL_VERSION}") +else() + set(FULL_VERSION "${PROJECT_VERSION}") + message(STATUS "Building version: ${FULL_VERSION} (Not a Git repo or git error)") +endif() + +add_definitions(-DVERSION=\"${FULL_VERSION}\") + +# --- Find Dependencies --- +find_package(Threads REQUIRED) +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBNL3 REQUIRED IMPORTED_TARGET libnl-genl-3.0 libnl-3.0) + +# --- Include Directories --- +include_directories(src) +include_directories(${LIBNL3_INCLUDE_DIRS}) + +# --- Common Static Library --- +# List all .cc files EXCEPT the main files for the executables +set(COMMON_SOURCES + src/ccoordinate.cc + src/cctrlserver.cc + src/cdynbuffer.cc + src/cinfosocket.cc + src/cinfowifi.cc + src/ckernelwifi.cc + src/cmonwirelessdevice.cc + src/cselect.cc + src/csocket.cc + src/csocketclient.cc + src/csocketclientitcp.cc + src/csocketclientvtcp.cc + src/csocketserver.cc + src/csocketserverfunctionitcp.cc + src/csocketserverfunctionvtcp.cc + src/cthread.cc + src/cwifi.cc + src/cwificlient.cc + src/cwifiserver.cc + src/cwifiserveritcp.cc + src/cwifiservervtcp.cc + src/cwirelessdevice.cc + src/cwirelessdevicelist.cc + src/tools.cc + src/addinterfaces.cc +) + +add_library(vwifi_common STATIC ${COMMON_SOURCES}) +# Link common library dependencies once +target_link_libraries(vwifi_common PUBLIC Threads::Threads PkgConfig::LIBNL3) + + +# --- Executables --- +add_executable(vwifi-server src/vwifi-server.cc) +target_link_libraries(vwifi-server PRIVATE vwifi_common) + +add_executable(vwifi-client src/vwifi-client.cc) +target_link_libraries(vwifi-client PRIVATE vwifi_common) + +add_executable(vwifi-ctrl src/vwifi-ctrl.cc) +target_link_libraries(vwifi-ctrl PRIVATE vwifi_common) + +add_executable(vwifi-add-interfaces src/vwifi-add-interfaces.cc) +# vwifi-add-interfaces seems to only need addinterfaces.o, which is in vwifi_common +target_link_libraries(vwifi-add-interfaces PRIVATE vwifi_common) + +# Optional: vwifi-inet-monitor (based on commented out Makefile line) +# add_executable(vwifi-inet-monitor src/vwifi-inet-monitor.cc) +# target_link_libraries(vwifi-inet-monitor PRIVATE vwifi_common) # Check its specific dependencies if uncommenting + +# --- Installation --- +include(GNUInstallDirs) +install(TARGETS vwifi-server vwifi-client vwifi-ctrl vwifi-add-interfaces + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +# Optional: Install man pages if needed (requires CMake code) +# install(FILES man/vwifi.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME vwifi.1) + +# --- Optional: Add tests --- +# enable_testing() +# add_subdirectory(tests) # If tests have their own CMakeLists.txt + +# --- Custom Target for Cppcheck --- +find_program(CPPCHECK_EXECUTABLE cppcheck) +if(CPPCHECK_EXECUTABLE) + file(GLOB_RECURSE ALL_CC_SOURCES "src/*.cc") + + get_property(GLOBAL_DEFINITIONS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS) + set(CPPCHECK_DEFS "") + foreach(DEF ${GLOBAL_DEFINITIONS}) + if(DEF MATCHES "^-D") + set(CPPCHECK_DEFS "${CPPCHECK_DEFS} ${DEF}") + else() + set(CPPCHECK_DEFS "${CPPCHECK_DEFS} -D${DEF}") + endif() + endforeach() + set(CPPCHECK_DEFS "${CPPCHECK_DEFS} -D_DEBUG") + + get_property(COMMON_COMPILE_OPTIONS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_OPTIONS) + set(CPPCHECK_CFLAGS "") + foreach(OPT ${COMMON_COMPILE_OPTIONS}) + set(CPPCHECK_CFLAGS "${CPPCHECK_CFLAGS} ${OPT}") + endforeach() + + # Définition du chemin de sortie du fichier XML + # CMAKE_CURRENT_BINARY_DIR pointe vers le répertoire de construction + set(CPPCHECK_OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-cppcheck.xml") + + add_custom_target( + cppcheck + COMMAND ${CPPCHECK_EXECUTABLE} --verbose --enable=all --enable=style --xml + ${CPPCHECK_CFLAGS} ${CPPCHECK_DEFS} ${ALL_CC_SOURCES} 2> ${CPPCHECK_OUTPUT_FILE} + # WORKING_DIRECTORY reste le répertoire source pour que cppcheck trouve les fichiers + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running Cppcheck static analysis and generating XML report in build directory." + BYPRODUCTS ${CPPCHECK_OUTPUT_FILE} + ) +endif() diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f052d61 --- /dev/null +++ b/README.md @@ -0,0 +1,384 @@ +# What is this ? + +Simulate Wi-Fi (802.11) between Linux Virtual Machines on Qemu/VirtualBox/... + +* It can be used in Hypervisors (GNS3, QEmu, Virtualbox, VMware, Hyper-V, ...) +* The Wireless emulator uses the `mac80211_hwsim` linux driver +* Implements the packet loss simulation based on distance +* Emulates the node mobility in GNS3 + +* Tested: + * with `hostapd` and `wpa_supplicant` with these configurations: + * Open + * WEP + * WPA2 + * WPA-EAP + * in the context of WPA2 attack with `Aircrack-NG` (Kali / Parrot-OS) + * with OpenWRT + +* Remaining features to be implemented: + + * Integrate to other OS (Windows...) + * Add obstacle models + * Etc. + +![Example](./screenshots/GNS3_Attack_with_KaliLinux.png) + +# Explanations + +* With the parameter "-h" (or "--help"), all programs display help and their parameters + +* ***vwifi-client*** should be started on the VMs, and ***vwifi-server*** on the Host. +* ***vwifi-client*** and ***vwifi-server*** can communicate either with the VHOST protocol (by default), or with the TCP protocol. +* With the option "-s" (or "--spy"), ***vwifi-client*** : + * receives always all communications, even if the loss of packets is enable ; + * works only with TCP ; + * connects to 127.0.0.1, by default ; +* ***vwifi-client*** uses the `mac80211_hwsim` kernel module to have the wifi interfaces. +* To use TCP protocol, ***vwifi-server*** and ***vwifi-client*** must be connected to a different IP network than that of the wifi. +* ***vwifi-add-interfaces*** is used to create the wlan interfaces to the module `mac80211_hwsim`. ***vwifi-client*** controls only these interfaces. ***vwifi-add-interfaces*** can be run several times. +* ***vwifi-ctrl*** is used to interact with ***vwifi-server***. +* ***vwifi-server*** can directly enable packet loss with the parameter "-l" (or "--lost-packets") +* If ***vwifi-server*** detects the same IP for several ***vwifi-client*** (due to PAT/NPAT/...), use the option "-u" ("-- use-port-in-hash") on ***vwifi-server*** to add the network port to create the ID for each client, instead of just using the IP. Attention, the display of ID by ***vwifi-server*** and ***vwifi-client*** will no longer be the same. + +* You can change the defaults IP and ports with parameters (see the parameter "-h" to help) + +# Install + +## On Debian-based Linux distributions + +### Dependencies + +```bash +sudo apt-get update +sudo apt-get install cmake make g++ pkg-config +sudo apt-get install libnl-3-dev libnl-genl-3-dev +``` + +### Building + +* Optional: To download and update the file `mac80211_hwsim.h` (if needed, requires wget) : + +```bash +wget -q -N https://raw.githubusercontent.com/torvalds/linux/master/drivers/net/wireless/virtual/mac80211_hwsim.h -P src +``` +* To change the default ports and IP, edit: `src/config.h` + +* To configure : + +```bash +mkdir build +cd build +cmake .. +``` +* To Customize the build : + * For a debug build : Add `-DCMAKE_BUILD_TYPE=Debug` + * To disable VHOST protocol : Add `-DENABLE_VHOST=OFF` + +* To build : `make` + +* To install : `sudo make install` + +## On OpenWRT + +* See the wiki : [Install-vwifi-on-OpenWRT-X86_64](https://github.com/Raizo62/vwifi/wiki/Install-on-OpenWRT-X86_64) + +# Configuration + +## Method 1 : With VHOST + +### Host + +* Shell : + * Load the module VHOST : + ```bash + # sudo modprobe -r vhost_vsock vmw_vsock_virtio_transport_common vsock # if necessary + + sudo modprobe vhost_vsock + sudo chmod a+rw /dev/vhost-vsock + ``` + * Start the ***vwifi-server*** : + ```bash + vwifi-server + ``` + +* Hypervisor + * QEmu : add the option : `-device vhost-vsock-pci,id=vwifi0,guest-cid=NUM` with NUM an identifier greater than 2 + * GNS3 (>= 2.2) : QEmu : add the option : `-device vhost-vsock-pci,id=vwifi0,guest-cid=%guest-cid%` + +### Each Guest + +* Load the necessary module mac80211_hwsim with 0 radios : +```bash +sudo modprobe mac80211_hwsim radios=0 +``` + +* Create the wlan interfaces (on this example, 2 interfaces) : + * Without parameters, the MAC address is preset with the default value "74:F8:F6", and the 4th byte is randomized + * ***vwifi-client*** can do the same with the parameters "--number" and "--mac" +```bash +sudo vwifi-add-interfaces 2 0a:0b:0c:03:02 +``` + +* Connect all these wlan interfaces to the ***vwifi-server*** : +```bash +sudo vwifi-client +``` + +* ***vwifi-client*** displays the CID of the VM in the Hypervisor. It is used by ***vwifi-server*** to identify this guest. + +## Method 2 : With TCP + +* ***vwifi-server*** and ***vwifi-client*** must be connected to a different IP network than that of the wifi (for example : 172.16.0.0/16) + +### Host + +* Start the ***vwifi-server*** : + +```bash +vwifi-server +``` + +* We will suppose that the Host have the IP address : 172.16.0.1 + +### Each Guest + +* Load the necessary module mac80211_hwsim with 0 radios : +```bash +sudo modprobe mac80211_hwsim radios=0 +``` + +* Create the wlan interfaces (on this example, 2 interfaces) : + * Without parameters, the MAC address is preset with the default value "74:F8:F6", and the 4th byte is randomized + * ***vwifi-client*** can do the same with the parameters "--number" and "--mac" +```bash +sudo vwifi-add-interfaces 2 0a:0b:0c:03:02 +``` + +* Connect all these wlan interfaces to the ***vwifi-server*** : +```bash +sudo vwifi-client 172.16.0.1 +``` + +* ***vwifi-client*** displays an ID which is an hashsum of the IP. It is used by ***vwifi-server*** to identify this guest. + +# Capture packets from Host + +## Configure the Spy + +```bash +sudo modprobe mac80211_hwsim radios=0 +sudo vwifi-client -s -n 1 +``` + +## Capture + +* Configure wlan0 to monitor mode : +```bash +sudo ip link set wlan0 down +sudo iw wlan0 set monitor control +sudo ip link set wlan0 up +``` + +### With tcpdump + +* Capture from wlan0 : +```bash +sudo tcpdump -n -i wlan0 +``` + +### With wireshark + +* Start Wireshark and capture from wlan0 : +```bash +sudo wireshark +``` + +# Control + +## Host + +* Show the list of connected guest (display : cid and coordinate x, y z) : +```bash +vwifi-ctrl ls +``` + +* Set the new coordinate (11, 12, 13) of the guest with the cid 10 : +```bash +vwifi-ctrl set 10 11 12 13 +``` + +* Set the name "AP" of the guest with the cid 10 : +```bash +vwifi-ctrl setname 10 AP +``` + +* Enable the lost of packets : +```bash +vwifi-ctrl loss yes +``` + +* Disable the lost of packets : +```bash +vwifi-ctrl loss no +``` + +* Display the config of ***vwifi-server*** : +```bash +vwifi-ctrl status +``` + +* Display the distance in meters between the guest with the cid 10 and the guest with the cid 20 : +```bash +vwifi-ctrl distance 10 20 +``` + +* Set the scale of the distances between the clients to 0.005 +```bash +vwifi-ctrl scale 0.005 +``` + +# Examples of commands to test Wifi + +## Test 1 : WPA + +### Packages needed on the guests for this test + +```bash +sudo apt install hostapd wpasupplicant +``` + +### Guests + +* Guest Wifi 1 : + +```bash +sudo ip a a 10.0.0.1/8 dev wlan0 + +sudo hostapd tests/hostapd_wpa.conf +``` + +* Guest Wifi 2 : +```bash +sudo wpa_supplicant -Dnl80211 -iwlan0 -c tests/wpa_supplicant.conf + +sudo ip a a 10.0.0.2/8 dev wlan0 +ping 10.0.0.1 +``` + +* Guest Wifi 3 : +```bash +sudo wpa_supplicant -Dnl80211 -iwlan0 -c tests/wpa_supplicant.conf + +sudo ip a a 10.0.0.3/8 dev wlan0 +ping 10.0.0.2 +``` + +## Test 2 : Open + +### Packages needed on the guests for this test + +```bash +sudo apt install hostapd iw tcpdump +``` + +### Guests + +* Guest Wifi 1 : + +```bash +sudo ip a a 10.0.0.1/8 dev wlan0 + +sudo hostapd tests/hostapd_open.conf +``` + +* Guest Wifi 2 : +```bash +sudo ip link set up wlan0 +sudo iw dev wlan0 connect mac80211_open + +sudo ip a a 10.0.0.2/8 dev wlan0 +ping 10.0.0.1 +``` + +* Guest Wifi 3 : +```bash +sudo ip link set up wlan0 +sudo tcpdump -n -e -I -i wlan0 -w /hosthome/projects/vwifi_capture_wlan0.pcap +``` + +### Host + +```bash +tail -f -c +0b /home/user/projects/vwifi_capture_wlan0.pcap | wireshark -k -i - +``` + +## Test 3 : Ad-Hoc + +### Packages needed on the guests for this test + +```bash +sudo apt install iw +``` + +### Guests + +* Guest Wifi 1 : +```bash +sudo ip link set up wlan0 +sudo iw wlan0 set type ibss +sudo iw wlan0 ibss join MYNETWORK 2412 # frequency 2412 is channel 1 + +sudo ip a a 10.0.0.1/8 dev wlan0 +``` + +* Guest Wifi 2 : +```bash +sudo ip link set up wlan0 +sudo iw wlan0 set type ibss +sudo iw wlan0 ibss join MYNETWORK 2412 # frequency 2412 is channel 1 + +sudo ip a a 10.0.0.2/8 dev wlan0 +ping 10.0.0.1 +``` + +## Test 4 : WEP + +### Packages needed on the guests for this test + +```bash +sudo apt install hostapd +``` + +### Guests + +* Guest Wifi 1 : + +```bash +sudo ip a a 10.0.0.1/8 dev wlan0 + +sudo hostapd tests/hostapd_wep.conf +``` + +* Guest Wifi 2 : +```bash +cat << EOF | sudo tee -a /etc/network/interfaces > /dev/null + +iface wlan0 inet static + wireless-essid AP_WEP + wireless-key s:12345 + address 10.0.0.2 + netmask 255.255.255.0 + +EOF +sudo ifup wlan0 + +ping 10.0.0.1 +``` + +# Others Tools + +* start-vwifi-client.sh : do all the commands necessary to start ***vwifi-client*** on a Guest +* fast-vwifi-update.sh : set with ***vwifi-ctrl*** the coordinates of each VMs which has the option `guest-cid=`, found in the open project of GNS3 +* client.sh : configure the client wifi with Open or WPA +* Makefile.dependency.sh : generate automatically the file "Makefile.in", include in "Makefile", which contains dependencies for "make" diff --git a/screenshots/GNS3_Attack_with_KaliLinux.png b/screenshots/GNS3_Attack_with_KaliLinux.png new file mode 100644 index 0000000..ed974c6 Binary files /dev/null and b/screenshots/GNS3_Attack_with_KaliLinux.png differ diff --git a/src/addinterfaces.cc b/src/addinterfaces.cc new file mode 100644 index 0000000..8771fcd --- /dev/null +++ b/src/addinterfaces.cc @@ -0,0 +1,152 @@ +/* + From : https://android.googlesource.com/device/generic/goldfish/+/refs/heads/master/wifi/mac80211_create_radios/main.cpp + Licence http://www.apache.org/licenses/LICENSE-2.0 +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include // getuid + +#include "addinterfaces.h" +#include "config_hwsim.h" + +const char* nlErrStr(const int e) +{ + return (e < 0) ? nl_geterror(e) : ""; +} + +#define RETURN(R) return (R); + +#define RETURN_ERROR(C, R) \ + do { \ + fprintf(stderr,"%s:%d '%s' failed\n", __func__, __LINE__, C); \ + return (R); \ + } while (false); + +#define RETURN_NL_ERROR(C, NLR, R) \ + do { \ + fprintf(stderr,"%s:%d '%s' failed with '%s'\n", __func__, __LINE__, C, nlErrStr((NLR))); \ + return (R); \ + } while (false); + +struct nl_sock_deleter +{ + void operator()(struct nl_sock* x) const + { + nl_socket_free(x); + } +}; + +struct nl_msg_deleter +{ + void operator()(struct nl_msg* x) const + { + nlmsg_free(x); + } +}; + +int ParseAddress(const char* str, TByte addr[ETH_ALEN]) +{ + return sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &addr[0], &addr[1], &addr[2],&addr[3], &addr[4], &addr[5]); +} + +std::unique_ptr CreateNlMessage( + const int family, + const int cmd) +{ + std::unique_ptr msg(nlmsg_alloc()); + if (!msg) + { + RETURN_ERROR("nlmsg_alloc", nullptr); + } + void* user = genlmsg_put(msg.get(), NL_AUTO_PORT, NL_AUTO_SEQ, family, 0, + NLM_F_REQUEST, cmd, VERSION_NR); + if (!user) + { + RETURN_ERROR("genlmsg_put", nullptr); + } + RETURN(msg); +} + +std::unique_ptr +BuildCreateRadioMessage(const int family, const TByte mac[ETH_ALEN]) +{ + std::unique_ptr msg = + CreateNlMessage(family, HWSIM_CMD_NEW_RADIO); + if (!msg) + { + RETURN(nullptr); + } + int ret; + ret = nla_put(msg.get(), HWSIM_ATTR_PERM_ADDR, ETH_ALEN, mac); + if (ret) + { + RETURN_NL_ERROR("nla_put(HWSIM_ATTR_PERM_ADDR)", ret, nullptr); + } + ret = nla_put_flag(msg.get(), HWSIM_ATTR_SUPPORT_P2P_DEVICE); + if (ret) + { + RETURN_NL_ERROR("nla_put(HWSIM_ATTR_SUPPORT_P2P_DEVICE)", ret, nullptr); + } + RETURN(msg); +} + +int CreateRadios(struct nl_sock* socket, const int netlinkFamily, + const int nRadios, TByte* mac) +{ + for (int idx = 0; idx < nRadios; ++idx) + { + if( nRadios != 1 ) // if i set only 1 interface, the mac address is not modified : the user can choose all the mac address + mac[5] = idx; + std::unique_ptr msg = + BuildCreateRadioMessage(netlinkFamily, mac); + if (msg) + { + int ret = nl_send_auto(socket, msg.get()); + if (ret < 0) + { + RETURN_NL_ERROR("nl_send_auto", ret, 1); + } + } + else + { + RETURN(1); + } + } + RETURN(0); +} + +int ManageRadios(const int nRadios, TByte* macPrefix) +{ + std::unique_ptr socket(nl_socket_alloc()); + if (!socket) + { + RETURN_ERROR("nl_socket_alloc", 1); + } + int ret; + ret = genl_connect(socket.get()); + if (ret) + { + RETURN_NL_ERROR("genl_connect", ret, 1); + } + const int netlinkFamily = genl_ctrl_resolve(socket.get(), KERNEL_HWSIM_FAMILY_NAME); + if (netlinkFamily < 0) + { + fprintf(stderr,"The kernel module 'mac80211_hwsim' is not loaded\n"); + return 2; + //RETURN_NL_ERROR("genl_ctrl_resolve", ret, 1); + } + ret = CreateRadios(socket.get(), netlinkFamily, nRadios, macPrefix); + if (ret) + { + RETURN(ret); + } + RETURN(0); +} diff --git a/src/addinterfaces.h b/src/addinterfaces.h new file mode 100644 index 0000000..3b60524 --- /dev/null +++ b/src/addinterfaces.h @@ -0,0 +1,10 @@ +#ifndef _ADDINTERFACE_H_ +#define _ADDINTERFACE_H_ + +#include "types.h" + +int ParseAddress(const char* str, TByte addr[ETH_ALEN]); + +int ManageRadios(const int nRadios, TByte* macPrefix); + +#endif diff --git a/src/ccoordinate.cc b/src/ccoordinate.cc new file mode 100644 index 0000000..7d6fd72 --- /dev/null +++ b/src/ccoordinate.cc @@ -0,0 +1,80 @@ +#include "ccoordinate.h" + +#include // sqrt + +TScale Scale=1; + +CCoordinate::CCoordinate(TValue x, TValue y, TValue z) +{ + Set(x, y, z); +} + +CCoordinate::CCoordinate() +{ + X=0; + Y=0; + Z=0; +} + +CCoordinate::CCoordinate(const CCoordinate& coo) +{ + *this=coo; +} + +void CCoordinate::SetX(TValue x) +{ + X=x; +} +void CCoordinate::SetY(TValue y) +{ + Y=y; +} + +void CCoordinate::SetZ(TValue z) +{ + Z=z; +} + +void CCoordinate::Set(TValue x, TValue y) +{ + SetX(x); + SetY(y); +} + +void CCoordinate::Set(TValue x, TValue y, TValue z) +{ + Set(x, y); + SetZ(z); +} + +void CCoordinate::Set(CCoordinate coo) +{ + Set(coo.X,coo.Y,coo.Z); +} + +TDistance CCoordinate::DistanceWith(TValue x, TValue y, TValue z) +{ + return Scale*sqrt( (X-x)*(X-x)+(Y-y)*(Y-y)+(Z-z)*(Z-z) ); +} + +TDistance CCoordinate::DistanceWith(CCoordinate coo) +{ + return DistanceWith(coo.X, coo.Y, coo.Z); +} + +void CCoordinate::Display(ostream& os) const +{ + os << X << " " << Y << " " << Z; +} + +ostream& operator<<(ostream& os, const CCoordinate& coo) +{ + coo.Display(os) ; + return os; +} + +CCoordinate& CCoordinate::operator=(const CCoordinate& coo) +{ + Set(coo.X,coo.Y,coo.Z); + return *this; +} diff --git a/src/ccoordinate.h b/src/ccoordinate.h new file mode 100644 index 0000000..7fd4bde --- /dev/null +++ b/src/ccoordinate.h @@ -0,0 +1,41 @@ +#ifndef _CCOORDINATE_H_ +#define _CCOORDINATE_H_ + +#include + +#include "types.h" // TValue, TDistance + +using namespace std; + +extern TScale Scale; + +class CCoordinate +{ + TValue X; + TValue Y; + TValue Z; + + public : + CCoordinate(); + CCoordinate(TValue x, TValue y, TValue z); + CCoordinate(const CCoordinate& coo); + + void SetX(TValue x); + void SetY(TValue y); + void SetZ(TValue z); + + void Set(TValue x, TValue y); + void Set(TValue x, TValue y, TValue z); + + void Set(CCoordinate coo); + + TDistance DistanceWith(TValue x, TValue y, TValue z); + TDistance DistanceWith(CCoordinate coo); + + void Display(ostream& os) const; + friend ostream& operator<<(ostream& os, const CCoordinate& coo); + + CCoordinate& operator=(const CCoordinate& coo); +}; + +#endif diff --git a/src/cctrlserver.cc b/src/cctrlserver.cc new file mode 100644 index 0000000..6adcace --- /dev/null +++ b/src/cctrlserver.cc @@ -0,0 +1,455 @@ +#include // strcpy + +#include "cctrlserver.h" +#include "config.h" // MAX_SIZE_NAME + + +CCTRLServer::CCTRLServer(CWifiServer* wifiServerVTCP, CWifiServer* wifiServerITCP, CWifiServer* wifiServerSPY, CSelect* scheduler) : CSocketServer() +{ + WifiServerVTCP=wifiServerVTCP; + WifiServerITCP=wifiServerITCP; + WifiServerSPY=wifiServerSPY; + Scheduler=scheduler; +} + +CCTRLServer::~CCTRLServer() +{ + // Close any open connections + CloseAllClient(); +} + +bool CCTRLServer::_Listen(TDescriptor& master, TPort port) +{ + return CSocketServerFunctionITCP::_Listen(master, port); +} + +TDescriptor CCTRLServer::_Accept(TDescriptor master, TCID& cid) +{ + return CSocketServerFunctionITCP::_Accept(master, cid); +} + +ssize_t CCTRLServer::Read(char* data, ssize_t sizeOfData) +{ + return CSocket::Read(GetSocketClient(0),data, sizeOfData); +} + +ssize_t CCTRLServer::Send(char* data, ssize_t sizeOfData) +{ + return CSocket::Send(GetSocketClient(0),data, sizeOfData); +} + +TOrder CCTRLServer::GetOrder() +{ + TOrder order; + + if( GetNumberClient() != 1 ) + return TORDER_NO; + + if( Read(reinterpret_cast(&order), sizeof(TOrder)) == SOCKET_ERROR ) + return TORDER_NO; + + return order; +} + +bool CCTRLServer::SendCInfoWifi(CInfoWifi* infoWifi) +{ + TCID cid=infoWifi->GetCid(); + if( Send(reinterpret_cast(&cid),sizeof(cid)) == SOCKET_ERROR ) + { + cerr<<"Error : SendCInfoWifi : cid : "<GetCid()<(&coo),sizeof(coo)) == SOCKET_ERROR ) + { + cerr<<"Error : SendCInfoWifi : CCoordinate : "<GetCid()<GetSizeName(); + if( Send(reinterpret_cast(&sizeName),sizeof(sizeName)) == SOCKET_ERROR ) + { + cerr<<"Error : SendCInfoWifi : size of name : "<GetCid()< 0 ) + { + char name[MAX_SIZE_NAME+1]; // +1 : \0 + strcpy(name,(infoWifi->GetName()).c_str()); + if( Send(name,sizeName+1) == SOCKET_ERROR ) // +1 : \0 + { + cerr<<"Error : SendCInfoWifi : name : "<GetCid()<GetNumberClient(); + + if( Send(reinterpret_cast(&number), sizeof(number)) == SOCKET_ERROR ) + return; + + for(TIndex i=0; iIsEnable(i) ) + { + infoWifi=WifiServerSPY->GetReferenceOnInfoWifiByIndex(i); + if( ! SendCInfoWifi(infoWifi) ) + { + cerr<<"Error : SendList : Send : Spies : CInfoWifi : "<<*infoWifi<GetNumberClient(); + + if( Send(reinterpret_cast(&number), sizeof(number)) == SOCKET_ERROR ) + return; + + for(TIndex i=0; iIsEnable(i) ) + { + infoWifi=WifiServerITCP->GetReferenceOnInfoWifiByIndex(i); + if( ! SendCInfoWifi(infoWifi) ) + { + cerr<<"Error : SendList : Send : Clients : CInfoWifi : "<<*infoWifi<(&cid), sizeof(TCID)) == SOCKET_ERROR ) + return; + + CCoordinate coo; + + if( Read(reinterpret_cast(&coo), sizeof(coo)) == SOCKET_ERROR ) + return; + + if( cid < TCID_GUEST_MIN ) + return; + + // because the same List is shared by WifiServerVTCP and WifiServerITCP + + CInfoWifi* infoWifi; + + infoWifi=WifiServerITCP->GetReferenceOnInfoWifiByCID(cid); + if( infoWifi != NULL ) + { + infoWifi->Set(coo); + return; + } + + infoWifi=WifiServerITCP->GetReferenceOnInfoWifiDeconnectedByCID(cid); + if( infoWifi != NULL ) + { + infoWifi->Set(coo); + return; + } + + CInfoWifi infoNewWifi(cid,coo); + WifiServerITCP->AddInfoWifiDeconnected(infoNewWifi); +} + +void CCTRLServer::SetName() +{ + TCID cid; + + if( Read(reinterpret_cast(&cid), sizeof(TCID)) == SOCKET_ERROR ) + return; + + int sizeName; + char strName[MAX_SIZE_NAME+1]; // +1 : \0 + + if( Read(reinterpret_cast(&sizeName), sizeof(sizeName)) == SOCKET_ERROR ) + return; + + if( Read(reinterpret_cast(strName), sizeof(strName)) == SOCKET_ERROR ) + return; + + if( cid < TCID_GUEST_MIN ) + return; + + // because the same List is shared by WifiServerVTCP and WifiServerITCP + + string name(strName); + + CInfoWifi* infoWifi; + + infoWifi=WifiServerITCP->GetReferenceOnInfoWifiByCID(cid); + if( infoWifi != NULL ) + { + infoWifi->SetName(name); + return; + } + + infoWifi=WifiServerITCP->GetReferenceOnInfoWifiDeconnectedByCID(cid); + if( infoWifi != NULL ) + { + infoWifi->SetName(name); + return; + } + + infoWifi=WifiServerSPY->GetReferenceOnInfoWifiByCID(cid); + if( infoWifi != NULL ) + { + infoWifi->SetName(name); + return; + } +} + +void CCTRLServer::ChangePacketLoss() +{ + int value; + + if( Read(reinterpret_cast(&value), sizeof(value)) == SOCKET_ERROR ) + return; + + if ( value ) + { + #ifdef _DEBUG + cout<<"Packet loss : Enable"<(&CanLostPackets),sizeof(CanLostPackets)) == SOCKET_ERROR ) + { + cerr<<"Error : SendStatus : Send : PacketLoss"<(&Scale),sizeof(Scale)) == SOCKET_ERROR ) + { + cerr<<"Error : SendStatus : Send : Scale"<(&WifiServerVTCP->Port),sizeof(WifiServerVTCP->Port)) == SOCKET_ERROR ) + { + cerr<<"Error : SendStatus : Send : Port VHOST"<(&WifiServerITCP->Port),sizeof(WifiServerITCP->Port)) == SOCKET_ERROR ) + { + cerr<<"Error : SendStatus : Send : Port INET"<(&WifiServerITCP->MaxClientDeconnected),sizeof(WifiServerITCP->MaxClientDeconnected)) == SOCKET_ERROR ) + { + cerr<<"Error : SendStatus : Send : Size MaxClientDeconnected"<GetNumberClient() > 0 ); + if( Send(reinterpret_cast(&spyIsConnected),sizeof(spyIsConnected)) == SOCKET_ERROR ) + { + cerr<<"Error : SendStatus : Send : spyIsConnected"<(&CanLostPackets),sizeof(CanLostPackets)) == SOCKET_ERROR ) + { + cerr<<"Error : SendShow : Send : PacketLoss"<(&Scale),sizeof(Scale)) == SOCKET_ERROR ) + { + cerr<<"Error : SendShow : Send : Scale"<GetNumberClient() > 0 ); + if( Send(reinterpret_cast(&spyIsConnected),sizeof(spyIsConnected)) == SOCKET_ERROR ) + { + cerr<<"Error : SendShow : Send : spyIsConnected"<(&cid1), sizeof(TCID)) == SOCKET_ERROR ) + return; + + if( Read(reinterpret_cast(&cid2), sizeof(TCID)) == SOCKET_ERROR ) + return; + + int codeError; + + // because the same List is shared by WifiServerVTCP and WifiServerITCP + + CCoordinate* coo1; + + coo1=WifiServerITCP->GetReferenceOnInfoWifiByCID(cid1); + if( coo1 == NULL ) + { + coo1=WifiServerITCP->GetReferenceOnInfoWifiDeconnectedByCID(cid1); + if( coo1 == NULL ) + { + codeError=-1; + if( Send(reinterpret_cast(&codeError),sizeof(codeError)) == SOCKET_ERROR ) + cerr<<"Error : SendDistance : Send : unknown cid1"<GetReferenceOnInfoWifiByCID(cid2); + if( coo2 == NULL ) + { + coo2=WifiServerITCP->GetReferenceOnInfoWifiDeconnectedByCID(cid2); + if( coo2 == NULL ) + { + codeError=-2; + if( Send(reinterpret_cast(&codeError),sizeof(codeError)) == SOCKET_ERROR ) + cerr<<"Error : SendDistance : Send : unknown cid2"<(&codeError),sizeof(codeError)) == SOCKET_ERROR ) + { + cerr<<"Error : SendDistance : Send : no error"<DistanceWith(*coo2); + + if( Send(reinterpret_cast(&distance),sizeof(distance)) == SOCKET_ERROR ) + { + cerr<<"Error : SendDistance : Send : distance"<(&new_scale), sizeof(new_scale)) == SOCKET_ERROR ) + return; + + Scale=new_scale; +} + +void CCTRLServer::CloseAllClient() +{ + // because the same List is shared by WifiServerVTCP and WifiServerITCP + + // Clients : + + // be careful : In the Scheduler, i must delete only the nodes of WifiServer, not the node of the CTRLServer + for (TIndex i = 0; i < WifiServerITCP->GetNumberClient(); i++) + Scheduler->DelNode((*WifiServerITCP)[i]); + + WifiServerITCP->CloseAllClient(); + + // Spies : + + for (TIndex i = 0; i < WifiServerSPY->GetNumberClient(); i++) + Scheduler->DelNode((*WifiServerSPY)[i]); + + WifiServerSPY->CloseAllClient(); +} + +void CCTRLServer::ReceiveOrder() +{ + if ( Accept() == SOCKET_ERROR ) + return; + + TOrder order=GetOrder(); + + switch( order ) + { + case TORDER_NO : break ; + + case TORDER_LIST : + SendList(); + break; + + case TORDER_CHANGE_COORDINATE : + ChangeCoordinate(); + break; + + case TORDER_SETNAME : + SetName(); + break; + + case TORDER_PACKET_LOSS : + ChangePacketLoss(); + break; + + case TORDER_STATUS : + SendStatus(); + break; + + case TORDER_SHOW : + SendShow(); + break; + + case TORDER_DISTANCE_BETWEEN_CID : + SendDistance(); + break; + + case TORDER_SET_SCALE : + SetScale(); + break; + + case TORDER_CLOSE_ALL_CLIENT : + CloseAllClient(); + break; + } + + CloseClient(0); +} diff --git a/src/cctrlserver.h b/src/cctrlserver.h new file mode 100644 index 0000000..3aed303 --- /dev/null +++ b/src/cctrlserver.h @@ -0,0 +1,56 @@ +#ifndef _CCTRLSERVER_H_ +#define _CCTRLSERVER_H_ + +#include "cwifiserver.h" // CWifiServer CSocketServer +#include "csocketserverfunctionitcp.h" // CSocketServerFunctionITCP +#include "cselect.h" // CSelect +#include "types.h" // TOrder + +class CCTRLServer : public CSocketServer, public CSocketServerFunctionITCP +{ + CWifiServer* WifiServerVTCP; + CWifiServer* WifiServerITCP; + CWifiServer* WifiServerSPY; + CSelect* Scheduler; + + bool _Listen(TDescriptor& master, TPort port) override; + TDescriptor _Accept(TDescriptor master, TCID& cid) override; + + using CSocketServer::Read; + ssize_t Read(char* data, ssize_t sizeOfData); + + using CSocketServer::Send; + ssize_t Send(char* data, ssize_t sizeOfData); + + TOrder GetOrder(); + + bool SendCInfoWifi(CInfoWifi* infoWifi); + + void SendList(); + + void ChangeCoordinate(); + + void SetName(); + + void ChangePacketLoss(); + + void SendStatus(); + + void SendShow(); + + void SendDistance(); + + void SetScale(); + + void CloseAllClient(); + + public : + + CCTRLServer(CWifiServer* wifiServerVTCP, CWifiServer* wifiServerITCP, CWifiServer* wifiServerSPY, CSelect* scheduler); + + virtual ~CCTRLServer(); + + void ReceiveOrder(); +}; + +#endif diff --git a/src/cdynbuffer.cc b/src/cdynbuffer.cc new file mode 100644 index 0000000..6b2dfec --- /dev/null +++ b/src/cdynbuffer.cc @@ -0,0 +1,62 @@ +#include +#include // memcpy + +#include "cdynbuffer.h" + +const int DEFAULT_SIZE_BUFFER=1024; + +CDynBuffer::CDynBuffer() +{ + Buffer = nullptr; + Size=0; + Allocate(DEFAULT_SIZE_BUFFER,false); +} + +CDynBuffer::~CDynBuffer() +{ + if( Buffer != nullptr ) + { + delete Buffer; + Buffer=nullptr; + Size=0; + } +} + +void CDynBuffer::NeededSize(int size, bool keepValues) +{ + if( size <= Size ) + return; + + Allocate(size,keepValues); +} + +char* CDynBuffer::GetBuffer() const +{ + return Buffer; +} + +void CDynBuffer::Allocate(int size, bool keepValues) +{ + if( ! keepValues ) + { + if( Buffer != nullptr ) + delete[] Buffer; + + Buffer = new char [size]; + + } + else + { + char* newBuffer = new char [size]; + + if( Buffer != nullptr ) + { + memcpy(newBuffer,Buffer,Size); + delete[] Buffer; + } + + Buffer = newBuffer; + } + + Size=size; +} diff --git a/src/cdynbuffer.h b/src/cdynbuffer.h new file mode 100644 index 0000000..4bad9bc --- /dev/null +++ b/src/cdynbuffer.h @@ -0,0 +1,25 @@ +#ifndef _CDYNBUFFER_H_ +#define _CDYNBUFFER_H_ + +class CDynBuffer +{ + private : + + char* Buffer; + int Size; + + void Allocate(int size, bool keepValues); + + public : + + CDynBuffer(); + + ~CDynBuffer(); + + void NeededSize(int size, bool keepValues); + + char* GetBuffer() const; + +}; + +#endif diff --git a/src/cinfosocket.cc b/src/cinfosocket.cc new file mode 100644 index 0000000..8829beb --- /dev/null +++ b/src/cinfosocket.cc @@ -0,0 +1,53 @@ +#include // close +#include // assert + +#include "cinfosocket.h" + +CInfoSocket::CInfoSocket() +{ + SetDescriptor(-1); + DisableIt(); +} + +CInfoSocket::CInfoSocket(TDescriptor descriptor) +{ + SetDescriptor(descriptor); + EnableIt(); +} + +void CInfoSocket::SetDescriptor(TDescriptor descriptor) +{ + Descriptor=descriptor; + EnableIt(); +} + +TDescriptor CInfoSocket::GetDescriptor() const +{ + return Descriptor; +} + +void CInfoSocket::EnableIt() +{ + assert( Descriptor >= 0 ); + + Enable=true; +} + +void CInfoSocket::DisableIt() +{ + Enable=false; +} + +bool CInfoSocket::IsEnable() +{ + return Enable; +} + +void CInfoSocket::Close() +{ + if( IsEnable() ) + { + DisableIt(); + close(Descriptor); + } +} diff --git a/src/cinfosocket.h b/src/cinfosocket.h new file mode 100644 index 0000000..3b54609 --- /dev/null +++ b/src/cinfosocket.h @@ -0,0 +1,35 @@ +#ifndef _CINFOSOCKET_H_ +#define _CINFOSOCKET_H_ + +#include // ostream + +#include "types.h" // TDescriptor + +using namespace std; + +class CInfoSocket +{ + TDescriptor Descriptor; + bool Enable; + + void EnableIt(); + + public : + + CInfoSocket(); + + explicit CInfoSocket(TDescriptor descriptor); + + void SetDescriptor(TDescriptor descriptor); + + TDescriptor GetDescriptor() const; + + void DisableIt(); + + bool IsEnable(); + + void Close(); + +}; + +#endif diff --git a/src/cinfowifi.cc b/src/cinfowifi.cc new file mode 100644 index 0000000..35c7f37 --- /dev/null +++ b/src/cinfowifi.cc @@ -0,0 +1,63 @@ +#include // assert + +#include "config.h" // MAX_SIZE_NAME +#include "cinfowifi.h" + +CInfoWifi::CInfoWifi(): CCoordinate() +{ + SetCid(0); +} + +CInfoWifi::CInfoWifi(TCID cid, CCoordinate coo) : CCoordinate(coo) +{ + SetCid(cid); +} + +void CInfoWifi::SetCid(TCID cid) +{ + // with the empty constructor : cid=0 + assert( cid==0 || cid >=TCID_GUEST_MIN ); + Cid=cid; +} + +TCID CInfoWifi::GetCid() const +{ + return Cid; +} + +void CInfoWifi::SetName(string name) +{ + if( name.size() > MAX_SIZE_NAME ) + name.resize(MAX_SIZE_NAME); + + Name=name; +} + +string CInfoWifi::GetName() const +{ + return Name; +} + +int CInfoWifi::GetSizeName() const +{ + return Name.size(); +} + +bool CInfoWifi::HasName() const +{ + return ! Name.empty(); +} + +void CInfoWifi::Display(ostream& os) const +{ + os << Cid << " "; + if( HasName() ) + os << "("< // ostream +#include + +#include "ccoordinate.h" +#include "types.h" // TCID + +const TCID TCID_GUEST_MIN=3; + +using namespace std; + +class CInfoWifi : public CCoordinate +{ + TCID Cid; + string Name; + + public : + + CInfoWifi(); + CInfoWifi(TCID cid, CCoordinate coo); + + void SetCid(TCID cid); + + TCID GetCid() const; + + void SetName(string name); + string GetName() const; + int GetSizeName() const; + bool HasName() const; + + void Display(ostream& os) const; + + friend ostream& operator<<(ostream& os, const CInfoWifi& infowifi); + +}; + +#endif diff --git a/src/ckernelwifi.cc b/src/ckernelwifi.cc new file mode 100644 index 0000000..97e438b --- /dev/null +++ b/src/ckernelwifi.cc @@ -0,0 +1,1095 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "ckernelwifi.h" // before #include + +#include +#include +#include + +#include // struct ifreq + +#include "ieee80211.h" // IEEE80211_TX_MAX_RATES + +#include +#include +#include + +#include "config.h" +#include + +#include + +#include "csocket.h" + +CDynBuffer Buffer; + +/* allow calling non static function from static function */ +ckernelwifi::CallFromStaticFunc * CKernelWifi::forward = nullptr ; + +void CKernelWifi::cout_mac_address(struct ether_addr *src) +{ + char addr[18]; + + mac_address_to_string(addr, src); + std::cout << addr; +} + +int CKernelWifi::send_tx_info_frame_nl(struct ether_addr *src, unsigned int flags, int signal, struct hwsim_tx_rate *tx_attempts, u64 cookie) +{ + struct nl_msg *msg = nullptr; + + msg = nlmsg_alloc(); + + if (!msg) { + + std::cerr << "Error allocating new message MSG !" << std::endl ; + nlmsg_free(msg); + return 0; + } + + if (m_family_id < 0){ + + std::cerr << __func__ << "m_family_id < 0" << std::endl ; + nlmsg_free(msg); + return 0; + } + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, m_family_id, 0, NLM_F_REQUEST, HWSIM_CMD_TX_INFO_FRAME, VERSION_NR); + + /* i have to ack the src the driver expects + * so there are no mac address modifications here + */ + if( nla_put(msg, HWSIM_ATTR_ADDR_TRANSMITTER, sizeof(struct ether_addr), src) || + nla_put_u32(msg, HWSIM_ATTR_FLAGS, flags) || + nla_put_u32(msg, HWSIM_ATTR_SIGNAL, signal) || + nla_put(msg, HWSIM_ATTR_TX_INFO, IEEE80211_TX_MAX_RATES * sizeof(struct hwsim_tx_rate), tx_attempts) || + nla_put_u64(msg, HWSIM_ATTR_COOKIE, cookie) ) + { + std::cerr << "Error filling payload" << std::endl; + nlmsg_free(msg); + return 0; + } + + //nl_send_auto_complete(_netlink_socket, msg); //deprecated + + if (nl_send_auto(_netlink_socket, msg) < 0) + { + nlmsg_free(msg); + return 0 ; + } + + nlmsg_free(msg); + + return 1; +} + +int CKernelWifi::process_messages_cb(struct nl_msg *msg,[[maybe_unused]] void *arg){ + + forward->process_messages(msg); + return 0 ; + +} + +int CKernelWifi::process_messages(struct nl_msg *msg) +{ + if ( ! is_connected_to_server()) + return 1 ; + + //struct ether_addr *dst; + + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr * gnlh = reinterpret_cast(nlmsg_data(nlh)); + + char addr[18]; + memset(addr, 0, 18); + + /* get message length needed for vsock sending */ + int msg_len = nlh->nlmsg_len; + + if (nlh->nlmsg_type != m_family_id) + return 1; + + /* ignore if anything other than a frame + do we need to free the msg? */ + if ( gnlh->cmd != HWSIM_CMD_FRAME ) + return 1; + + /* processing original HWSIM_CMD_FRAME */ + struct nlattr *attrs[HWSIM_ATTR_MAX + 1]; + genlmsg_parse(nlh, 0, attrs, HWSIM_ATTR_MAX, NULL); + + /* this check was duplicated below in a second if statement, now gone */ + if (!(attrs[HWSIM_ATTR_ADDR_TRANSMITTER])) + return 1; + + /* we get hwsim mac (id)*/ + struct ether_addr *src = reinterpret_cast(nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER])); + struct ether_addr macsrchwsim; + memcpy(&macsrchwsim,src,sizeof(macsrchwsim)); // backup the original mac src + + /* Let's flag this frame as ACK'ed */ + /* whatever that means... */ + unsigned int flags = nla_get_u32(attrs[HWSIM_ATTR_FLAGS]); + flags |= HWSIM_TX_STAT_ACK; + + /* this is the signal sent to the sender, not the receiver */ + int signal = -10; + + /* We get the tx_rates struct */ + struct hwsim_tx_rate* tx_rates = reinterpret_cast(nla_data(attrs[HWSIM_ATTR_TX_INFO])); + + u64 cookie = nla_get_u64(attrs[HWSIM_ATTR_COOKIE]); + + /* this has to be an ack the driver expects */ + /* what does the driver do with these values? can i remove them? */ + send_tx_info_frame_nl(src, flags, signal, tx_rates, cookie); + + /* + * no need to send a tx info frame indicating failure with a + * signal of 0 - that was done in the tx code i took this from + * if i check for ack messages than i could add a failure message + */ + + /* we are now done with our code addition which sends the ack */ + + /* we get the attributes*/ + char* data = reinterpret_cast(nla_data(attrs[HWSIM_ATTR_FRAME])); + unsigned int data_len = nla_len(attrs[HWSIM_ATTR_FRAME]); + + /* copy source address from frame */ + /* if we rebuild the nl msg, this can change */ + struct ether_addr framesrc; + memcpy(&framesrc, data + 10, ETH_ALEN); + //cout_mac_address(&framesrc); + + /* copy dst address from frame */ + struct ether_addr framedst; + memcpy(&framedst, data + 4, ETH_ALEN); + //cout_mac_address(&framedst); + + /* compare tx src to frame src, update TX src ATTR in msg if needed */ + /* if we rebuild the nl msg, this can change */ + if (memcmp(&framesrc, src, ETH_ALEN) != 0) { + +#ifdef _DEBUG + std::cout << "updating the TX src ATTR" << std::endl ; +#endif + /* copy dest address from frame to nlh */ + memcpy(reinterpret_cast(nlh) + 24, &framesrc, ETH_ALEN); + } + + /* send msg to a server */ + TPower power=10; + + WirelessDevice dev ; + if ( _list_winterfaces.get_device_by_mac(dev,framesrc)) + { + power = dev.getTxPower() / 100; // must add the remainder if not multiple of 2 + } + + int value=_SendSignal(&power, reinterpret_cast(nlh), msg_len); + if( value == SOCKET_ERROR ) + manage_server_crash(); + + // Send also on the others interfaces on the same VM : + // -------------------> + /* we get frequence */ + TFrequency freq; + if (attrs[HWSIM_ATTR_FREQ]) + freq = nla_get_u32(attrs[HWSIM_ATTR_FREQ]); + else + freq = 0; + + int rate_idx = 7; // number of attempts + + const auto& inets = _list_winterfaces.list_devices(); + for (const auto& inet : inets) + { + struct ether_addr macdsthwsim = inet.getMachwsim(); + if( memcmp(&macsrchwsim,&macdsthwsim,sizeof(struct ether_addr)) ) // if( macsrchwsim != macdsthwsim ) + send_cloned_frame_msg(&macdsthwsim, data, data_len, rate_idx, power, freq); + } + delete &inets; + // <------------------------ + + return 0 ; +} + +int CKernelWifi::send_register_msg() +{ + struct nl_msg *msg; + + msg = nlmsg_alloc(); + + if (!msg) { + std::cerr << "Error allocating new message MSG!" << std::endl ; + return 0; + } + + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, m_family_id,0, NLM_F_REQUEST, HWSIM_CMD_REGISTER, VERSION_NR); + + if (nl_send_auto(_netlink_socket, msg) < 0) + { + nlmsg_free(msg); + return 0 ; + } + + //nl_send_auto_complete(_netlink_socket, msg); //deprecated + nlmsg_free(msg); + + return 1; +} + +int CKernelWifi::init_netlink_first(void) +{ + int nlsockfd; + struct timeval tv; + +// _cb = nl_cb_alloc(NL_CB_DEBUG); + _cb = nl_cb_alloc(NL_CB_CUSTOM); + + if (!_cb) { + std::cerr << "Error allocating netlink callbacks" << std::endl ; + return 0; + } + + _netlink_socket = nl_socket_alloc_cb(_cb); + if (!_netlink_socket) { + std::cerr << "Error allocationg netlink socket" << std::endl; + nl_cb_put(_cb); + return 0; + } + + /* disable auto-ack from kernel to reduce load */ + nl_socket_disable_auto_ack(_netlink_socket); + + if(genl_connect(_netlink_socket) < 0){ + + nl_close(_netlink_socket); + nl_socket_free(_netlink_socket); + nl_cb_put(_cb); + + return 0 ; + } + + m_family_id = genl_ctrl_resolve(_netlink_socket, KERNEL_HWSIM_FAMILY_NAME); + + while (m_family_id < 0 ) { + + if ( ! _being_initialized) + return 0 ; + + // if ( ! started()){ + // return 0 ; + // } + +#ifdef _DEBUG + std::cout << "Family "<(Buffer.GetBuffer()); + + /* generic netlink header */ + struct genlmsghdr* gnlh = reinterpret_cast(nlmsg_data(nlh)); + + /* exit if the message does not contain frame data */ + if (gnlh->cmd != HWSIM_CMD_FRAME) { + + std::cerr << "Error - received no frame data in message" << std::endl; + return ; + } + + /* we get the attributes*/ + struct nlattr *attrs[HWSIM_ATTR_MAX + 1]; + genlmsg_parse(nlh, 0, attrs, HWSIM_ATTR_MAX, NULL); + + /* we get frequence */ + TFrequency freq; + if (attrs[HWSIM_ATTR_FREQ]) + freq = nla_get_u32(attrs[HWSIM_ATTR_FREQ]); + else + freq = 0; + +#ifdef _DEBUG + + std::cout << "freq : " << freq << std::endl ; +#endif + + if (!attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) { + + std::cerr << "Error - message does not contain addr transmitter" << std::endl; + return; + } + + unsigned int data_len = nla_len(attrs[HWSIM_ATTR_FRAME]); + char* data = reinterpret_cast(nla_data(attrs[HWSIM_ATTR_FRAME])); + + /* we extract and handle a distance here */ + +#ifdef _DEBUG + struct ether_addr *src = nullptr; + struct ether_addr framesrc; + + /* copy hwsim id src */ + src = reinterpret_cast(nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER])); + std::cout << "src hwsim: "; cout_mac_address(src);std::cout<get_winterface_infos(0); + + using namespace std::chrono_literals; + std::this_thread::sleep_for(1s); + + } + +} + +int CKernelWifi::init(){ + + /* init netlink will loop until driver is loaded */ + if ( ! init_netlink()){ + + std::cerr << "ERROR: could not initialize netlink" << std::endl; + return 0 ; + } + + /* Send a register msg to the kernel */ + if (!send_register_msg()){ + + nl_close(_netlink_socket); + nl_socket_free(_netlink_socket); + nl_cb_put(_cb); + return 0 ; + } + + _mutex_initialized.lock(); + _initialized = true ; + _mutex_initialized.unlock(); + + std::cout << "Registered with family "<setNewInetCallback([this](const WirelessDevice& wd) { return handle_new_winet_notification(wd);}); + monwireless->setDelInetCallback([this](const WirelessDevice& wd) { return handle_del_winet_notification(wd);}); + monwireless->setInitInetCallback([this](const WirelessDevice& wd) { return handle_init_winet_notification(wd);}); + + monwireless->start(); + + /* get initial wireless network interfaces created when we called sudo modprobe mac80211_hwsim */ + monwireless->get_winterface_infos(0); + + }catch ( const std::exception & e){ + + std::cerr << e.what() << std::endl ; + return 0 ; + + } + + being_started(true); + + /*connect to vsock/tcp server */ + int id; + while( ! _Connect(&id) ) + { + if (! is_being_started()) + return 0 ; + std::cerr<<"socket.Connect error"< lk(_mutex_condition); + _condition.wait(lk, []{return intthread::InterruptibleThread::all_thread_interrupted(); }); + + std::cout << "int stop after kill" << std::endl ; + + return 0 ; +} + +void CKernelWifi::being_started(bool v){ + + std::lock_guard lk(_being_started_mutex); + _being_started = v ; + +} + +bool CKernelWifi::is_being_started(){ + + std::lock_guard lk(_being_started_mutex); + return _being_started; + +} + +void CKernelWifi::clean_all(){ + + nl_close(_netlink_socket); + nl_socket_free(_netlink_socket); + nl_cb_put(_cb); +} + +void CKernelWifi::connected_to_server(bool v){ + + std::lock_guard lk(_mutex_connected_to_server); + _connected_to_server = v ; + +} + +bool CKernelWifi::is_connected_to_server(){ + + std::lock_guard lk(_mutex_connected_to_server); + return _connected_to_server ; + +} + +void CKernelWifi::manage_server_crash(){ + + connected_to_server(false) ; + +} + +void CKernelWifi::manage_server_crash_loop(){ + + while (true) { + + try { + + intthread::interruption_point(); + + } + + catch (const intthread::thread_interrupted& interrupt) { + dead(); + break; + } + + if (! is_connected_to_server()) { + + std::cout << "manage disconnection with server" << std::endl ; + + if (reconnect_to_server()){ + + connected_to_server(true) ; + } + + } + + using namespace std::chrono_literals; + std::this_thread::sleep_for(1s); + } +} + +bool CKernelWifi::reconnect_to_server(){ + + _Close(); + std::cout << "Reconnecting to vsock/tcp server..." << std::endl ; + + /*connect to vsock/tcp server */ + int id; + if( ! _Connect(&id) ) + { + std::cerr<<"socket.Connect error"<ether_addr_octet[0], mac->ether_addr_octet[1], mac->ether_addr_octet[2], + mac->ether_addr_octet[3], mac->ether_addr_octet[4], mac->ether_addr_octet[5]); +} + +void CKernelWifi::handle_new_winet_notification(WirelessDevice wirelessdevice){ + + //std::cout << "Change in wireless configuration of : " << wirelessdevice << std::endl ; + + /* it is necessary to do this in the case of reloading hwsim driver and not just adding wirelessdevice to _list_winterfaces */ + struct ether_addr paddr ; + std::memset(&paddr, 0, sizeof(paddr)); + + if(get_pmaddr(paddr,wirelessdevice.getName().c_str())){ + + //paddr.ether_addr_octet[0] |= 0x40 ; + wirelessdevice.setMachwsim(paddr); + _list_winterfaces.add_device(wirelessdevice); + } + + //std::cout << __func__ << _list_winterfaces << std::endl ; + +} + +void CKernelWifi::handle_del_winet_notification(const WirelessDevice& wirelessdevice){ + + //std::cout << "Delete wireless interface : " << wirelessdevice << std::endl ; + _list_winterfaces.delete_device(wirelessdevice); + +} + +/* called the first time we detect the interface */ +void CKernelWifi::handle_init_winet_notification(WirelessDevice wirelessdevice){ + + struct ether_addr paddr ; + std::memset(&paddr, 0, sizeof(paddr)); + + if(get_pmaddr(paddr,wirelessdevice.getName().c_str())){ + + //paddr.ether_addr_octet[0] |= 0x40 ; + wirelessdevice.setMachwsim(paddr); + _list_winterfaces.add_device(wirelessdevice); + } + + //std::cout << __func__ << _list_winterfaces << std::endl ; +} + +/* get the permanent mac address, this function with nl_recvmsgs(wifi.nls, wifi.cb) permit change mac address before or after launching the application */ +bool CKernelWifi::get_pmaddr(struct ether_addr & paddr ,const char *ifname) + +{ + int sock; + struct ifreq ifr; + struct ethtool_perm_addr *epmaddr; + + epmaddr = reinterpret_cast(malloc(sizeof(struct ethtool_perm_addr) + MAX_ADDR_LEN)); + if (!epmaddr) + { + perror("malloc"); + return 0; + } + + std::memset(&ifr, 0, sizeof(ifr)); + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + perror("socket"); + free(epmaddr); + return 0; + } + + memcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + epmaddr->cmd = ETHTOOL_GPERMADDR; + epmaddr->size = MAX_ADDR_LEN; + ifr.ifr_data = reinterpret_cast(epmaddr); + + if (ioctl(sock, SIOCETHTOOL, &ifr) == -1) + { + perror("ioctl"); + free(epmaddr); + return 0; + } + else + { + if (epmaddr->size != ETH_ALEN) + { + free(epmaddr); + return 0; + } + else + { + for(int i=0 ; i < 6 ; i++) + paddr.ether_addr_octet[i] = epmaddr->data[i] ; + } + } + + free(epmaddr); + close(sock); + + return 1; +} + diff --git a/src/ckernelwifi.h b/src/ckernelwifi.h new file mode 100644 index 0000000..c10ca12 --- /dev/null +++ b/src/ckernelwifi.h @@ -0,0 +1,275 @@ +#ifndef _CKERNELWIFI_H_ +#define _CKERNELWIFI_H_ + +#include +#include + +#include "config_hwsim.h" + +#include "cwirelessdevice.h" +#include "cwirelessdevicelist.h" +#include "cmonwirelessdevice.h" +#include "cselect.h" +#include + +#include "cthread.h" +#include + +#include "cdynbuffer.h" + +namespace ckernelwifi{ + + class CallFromStaticFunc ; +} +class CKernelWifi : public intthread::AsyncTask { + + protected : + + pthread_t serverloop_id ; + + CSelect Scheduler; + bool _connected_to_server { false }; + std::mutex _mutex_connected_to_server ; + std::condition_variable _cond_connected_to_server ; + + bool _being_initialized { false } ; + + bool _being_started { false } ; + std::mutex _being_started_mutex ; + + WirelessDeviceList _list_winterfaces ; + + /** pointer for netlink socket */ + struct nl_sock * _netlink_socket { nullptr }; + + /** pointer for netlink callback function */ + struct nl_cb * _cb { nullptr }; + + /** For the family ID used by hwsim */ + int m_family_id { 1 }; + + intthread::InterruptibleThread hwsimloop_task ; + intthread::InterruptibleThread serverloop_task ; + intthread::InterruptibleThread monitorloop_task ; + intthread::InterruptibleThread winterface_update_loop_task ; + intthread::InterruptibleThread connection_to_server_loop_task ; + + bool _initialized { false } ; + std::mutex _mutex_initialized ; + + MonitorWirelessDevice * monwireless = nullptr ; + + int init(); + int init_first(); + + void mac_address_to_string(char *address, struct ether_addr *mac); + + public : + + static ckernelwifi::CallFromStaticFunc * forward ; + + /** + * \brief Default Constructor + */ + CKernelWifi(); + + /** + * \brief Default Destructor + */ + ~CKernelWifi(); + + /** + * \brief start the all activity + */ + int start(); + + /** + * \brief stop the all activity + */ + int stop(); + + int process_messages(struct nl_msg *msg); + + /** + * \brief free dynamicly allocated memory and socket descriptors + */ + void clean_all(); + + bool initialized(); + + void connected_to_server(bool v); + + bool is_connected_to_server(); + + bool reconnect_to_server() ; + + void manage_server_crash_loop() ; + + void being_started(bool v); + + bool is_being_started(); + + protected : + + void cout_mac_address(struct ether_addr *src); + + /** + * \brief Callback function to process messages received from kernel + * It processes the frames received from hwsim via netlink messages. + * These frames get sent via vsock to vwifi-server. + * \param msg - pointer to netlink message + * \param arg - pointer to additional args + * \return success or failure + */ + static int process_messages_cb(struct nl_msg *msg, void *arg); + + /** + * \brief Send a register message to kernel via netlink + * This informs hwsim we wish to receive frames + * Taken from wmediumd + * \return void + */ + int send_register_msg(); + + /** + * \brief Initialize netlink communications + * Taken from wmediumd + * \return void + */ + int init_netlink(); + int init_netlink_first(); + + /** + * \brief start receiving hwsim netlink frame from hwsim driver + */ + void recv_msg_from_hwsim_loop_start(); + + /** + * \brief Send a tx_info frame to the kernel space. This frame indicates + * that the frame was transmitted/acked successfully. The ack is sent back + * to the driver with HWSIM_ATTR_ADDR_TRANSMITTER unmodified. + * This is derived form wmediumd. + * TODO: modify if we create more accurate acking. + * \param src - mac address of transmitting radio + * \param flags - falgs + * \param signal - signal strength + * \param tx_attempts - number of transmit attempts + * \param cookie - unique identifier for frame + * \return success or failure + */ + int send_tx_info_frame_nl(struct ether_addr *src, + unsigned int flags, int signal, + struct hwsim_tx_rate *tx_attempts, + u64 cookie); + + /** + * \brief start receiving hwsim frame from vwifi-server loop + */ + void recv_msg_from_server_loop_start(); + + static void recv_msg_from_server_signal_handle(int sig_num); + + /** + * @brief this is meant to be a thread which detects removal of driver + * Used to suspend normal actions until driver is loaded + * @return void + */ + void monitor_hwsim_loop(); + + void winet_update_loop(); + + /** + * \brief Send a cloned frame to the kernel space driver. + * This will send a frame to the driver using netlink. + * It is received by hwsim with hwsim_cloned_frame_received_nl() + * This is taken from wmediumd and modified. It is called after the + * message has been received from wmasterd. + * \param dst - mac address of receving radio + * \param data - frame data + * \param data_len - length of frame + * \param rate_idx - number of attempts + * \param signal - signal strength + * \param freq - frequency + * \return success or failure + */ + int send_cloned_frame_msg(struct ether_addr *dst, char *data, int data_len,int rate_idx, int signal, uint32_t freq); + + /** + * \brief handle messages received from server + */ + + void recv_from_server(); + + /** + * \brief callback from cmonitorwirelessdevice that is called to + * handle addding wireless inet + */ + void handle_new_winet_notification(WirelessDevice); + + /** + * \brief callback from cmonitorwirelessdevice that is called to + * handle deleting wireless inet + */ + void handle_del_winet_notification(const WirelessDevice&); + + + /** + * \brief callback from cmonitorwirelessdevice that is called to + * handle initial wireless inet + */ + void handle_init_winet_notification(WirelessDevice); + + /** + * \brief get permanent mac address of ifname interface + */ + bool get_pmaddr(struct ether_addr &,const char *ifname); + + /** + *\biref reconnecting to a server when detecting a socket disconnection + */ + void manage_server_crash(); + + // virtual : + + virtual bool _Connect(int* id) = 0; + + virtual ssize_t _SendSignal(TPower* power, const char* buffer, int sizeOfBuffer) = 0; + virtual ssize_t _RecvSignal(TPower* power, CDynBuffer* buffer) = 0; + + virtual void _Close() = 0; + +}; + +/** + * \namespace ckernelwifi + * + * A namespace is used here, since a class CallFromStaticFunc is defined in other files + */ +namespace ckernelwifi { + + /** + * \class CallFromStaticFunc + * \brief this class is an artifact used to call a member function from static function + */ + class CallFromStaticFunc { + + CKernelWifi * m_obj ; + + public: + + explicit CallFromStaticFunc(CKernelWifi * obj){ + + m_obj = obj ; + }; + + int process_messages(struct nl_msg *msg) { + + // add exception to check null ptr + m_obj->process_messages(msg); + return 0 ; + }; + }; +} + +#endif /* _CKERNELWIFI_H_ */ + diff --git a/src/clistinfo.h b/src/clistinfo.h new file mode 100644 index 0000000..6ba2d5d --- /dev/null +++ b/src/clistinfo.h @@ -0,0 +1,11 @@ +#ifndef _CLISTINFO_H_ +#define _CLISTINFO_H_ + +#include // vector + +template +class CListInfo : public std::vector +{ +}; + +#endif diff --git a/src/cmonwirelessdevice.cc b/src/cmonwirelessdevice.cc new file mode 100644 index 0000000..0fdf666 --- /dev/null +++ b/src/cmonwirelessdevice.cc @@ -0,0 +1,672 @@ +#include "cmonwirelessdevice.h" +#include "cwirelessdevice.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef _DEBUG +#include // IFF_UP +#endif + +/* allow calling a non static function from static function */ +monitorinet::CallFromStaticFunc * MonitorWirelessDevice::forward = nullptr ; + + + +void MonitorWirelessDevice::setNewInetCallback(CallbackFunction cb){ + + _newinet_cb = cb ; +} + +void MonitorWirelessDevice::setDelInetCallback(CallbackFunction cb){ + + _delinet_cb = cb ; +} + +void MonitorWirelessDevice::setInitInetCallback(CallbackFunction cb){ + + _initinet_cb = cb ; +} + + + +MonitorWirelessDevice::MonitorWirelessDevice(){ + + + struct sockaddr_nl addr; + + /* create a netlink route socket */ + if(( _inetsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) + throw std::runtime_error("couldn't create a AF_NETLINK socket"); + + /* joins the multicast groups for link notifications */ + std::memset(&addr, 0, sizeof addr); + addr.nl_family = AF_NETLINK; + addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; + + if (bind(_inetsock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + throw std::runtime_error("couldn't bind to AF_NETLINK socket"); + + + /* allows calls from static callback to non static member function */ + forward = new monitorinet::CallFromStaticFunc(this); + + /* init netlink 80211 */ + if (nl80211_init() < 0) + throw std::runtime_error("Error initializing netlink 802.11"); + + +} + + +MonitorWirelessDevice::~MonitorWirelessDevice(){ + +#ifdef _DEBUG + std::cout << __func__ << std::endl ; +#endif + if (started()) + stop(); + + while(!outside_loop()); + + clean(); +} + + +void MonitorWirelessDevice::clean(){ + + close(_inetsock); + nl_cb_put(wifi.cb); + nl_cb_put(wifi.cb1); + nl_close(wifi.nls); + nl_socket_free(wifi.nls); +} + +int MonitorWirelessDevice::main_loop() { + + fd_set rfds; + struct timeval tv; + + + _outsideloopmutex.lock() ; + _outsideloop = false ; + _outsideloopmutex.unlock(); + + + while (started()) { + + FD_ZERO(&rfds); + FD_CLR(_inetsock, &rfds); + FD_SET(_inetsock, &rfds); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + int retval = select(FD_SETSIZE, &rfds, NULL, NULL, &tv); + if (retval == -1){ + perror("select in MonitorWirelessDevice main_loop function"); + stop(); + } + else + if (retval){ + +#ifdef _DEBUG + std::cout << __func__ << "process event received from AF_NETLINK socket" << std::endl ; +#endif + recv_inet_event(); + } + } + + + _outsideloopmutex.lock() ; + _outsideloop = true ; + _outsideloopmutex.unlock(); + + + + return 0; +} + + +bool MonitorWirelessDevice::outside_loop(){ + + bool outsideorno = false ; + _outsideloopmutex.lock(); + if (_outsideloop) outsideorno = true ; + _outsideloopmutex.unlock(); + + return outsideorno ; +} + +void MonitorWirelessDevice::start() { + + if(started()) + return ; + + if (!outside_loop()) + return ; + + _startedmutex.lock() ; + _started = true ; + _startedmutex.unlock(); + + std::thread mainloop(&MonitorWirelessDevice::main_loop,this); + + mainloop.detach(); +} + +void MonitorWirelessDevice::stop() { + + _startedmutex.lock(); + _started = false ; + _startedmutex.unlock(); +} + +bool MonitorWirelessDevice::started() { + + bool startorno = false ; + _startedmutex.lock(); + if (_started) startorno = true ; + _startedmutex.unlock(); + + return startorno ; +} + + + + +/***********************************************************************************************/ +/***************** handle netlink net device events from kernel ******************************/ +/**********************************************************************************************/ + + +void MonitorWirelessDevice::recv_inet_event() +{ + + int len; + char buf[IFLIST_REPLY_BUFFER]; + struct iovec iov = { buf, sizeof(buf) }; + struct sockaddr_nl snl; + struct msghdr msg = { static_cast(&snl), sizeof(snl), &iov, 1, NULL, 0, 0 }; + struct nlmsghdr *nlmsgheader; + + /* read the waiting message */ + len = recvmsg(_inetsock, &msg, 0); + if (len < 0) + perror("read_netlink"); + for (nlmsgheader = reinterpret_cast(buf); NLMSG_OK(nlmsgheader, (unsigned int)len); nlmsgheader = NLMSG_NEXT(nlmsgheader, len)) { + + switch (nlmsgheader->nlmsg_type) { + case NLMSG_DONE: + break; + + case NLMSG_ERROR: + perror("read_netlink"); + break; + +// case RTM_SETLINK: /* we try to use it in order to detect chaging in wireless inet configuration, but it didn't work +//#ifdef _DEBUG +// std::cout << "Network interface configuration modified" << std::endl ; +//#endif +// break; + + + case RTM_NEWLINK: +#ifdef _DEBUG + std::cout << "Network interface added" << std::endl ; +#endif + new_net_interface(nlmsgheader); + break; + case RTM_DELLINK: +#ifdef _DEBUG + std::cout << "Network interface deleted" << std::endl ; +#endif + del_net_interface(nlmsgheader); + + break; + + default: + break; + } + } +} + + + +void MonitorWirelessDevice::new_net_interface(struct nlmsghdr *h) +{ + int len; + struct rtattr *tb[IFLA_MAX + 1]; + char *name; + struct rtattr *rta; + struct ifinfomsg *ifi; + struct ether_addr macaddr ; + ifi = static_cast(NLMSG_DATA(h)); + + /*if (!(ifi->ifi_flags & IFLA_ADDRESS)) + { + std::cout << "! IFLA_ADDRESS" << std::endl ; + return; + }*/ + + +#ifdef _DEBUG + if (ifi->ifi_flags & IFF_UP) { // get UP flag of the network interface + + std::cout << "interface UP" << std::endl; + + } else { + + std::cout << "Interface DOWN" << std::endl; + + + } +#endif + + /* retrieve all attributes */ + memset(tb, 0, sizeof(tb)); + rta = IFLA_RTA(ifi); + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); + while (RTA_OK(rta, len)) { + if (rta->rta_type <= IFLA_MAX) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta, len); + } + + /* require name field to be set */ + if (tb[IFLA_IFNAME]) { + name = static_cast(RTA_DATA(tb[IFLA_IFNAME])); + } else { + std::cerr << "do not find interface name" << std::endl ; + return; + } + +#ifdef _DEBUG + if (ifi->ifi_family == AF_UNSPEC) + std::cout << "family: AF_UNSPEC" << std::endl; + + if (ifi->ifi_family == AF_INET6) + std::cout << "family: AF_INET6" << std::endl ; +#endif + + + /* require address field to be set */ + if (tb[IFLA_ADDRESS]) { + + std::memcpy(&macaddr, static_cast(RTA_DATA(tb[IFLA_ADDRESS])), ETH_ALEN); + + } + + std::string inet_name(name); + + WirelessDevice inetdevice (inet_name,ifi->ifi_index,ifi->ifi_type,macaddr,0); + + if(inetdevice.checkif_wireless_device()){ + + get_winterface_infos(ifi->ifi_index); // we can call a callback here, instead calling it in recv_winterface_infos, to reduce cpu + } + +} + + + +void MonitorWirelessDevice::del_net_interface(struct nlmsghdr *h) +{ + int len; + struct rtattr *tb[IFLA_MAX + 1]; + char *name; + struct rtattr *rta; + struct ifinfomsg *ifi; + struct ether_addr macaddr ; + ifi = static_cast(NLMSG_DATA(h)); + + /*if (!(ifi->ifi_flags & IFLA_ADDRESS)) + { + std::cout << "! IFLA_ADDRESS" << std::endl ; + return; + }*/ + + + /* retrieve all attributes */ + memset(tb, 0, sizeof(tb)); + rta = IFLA_RTA(ifi); + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); + while (RTA_OK(rta, len)) { + if (rta->rta_type <= IFLA_MAX) + tb[rta->rta_type] = rta; + rta = RTA_NEXT(rta, len); + } + + /* require name field to be set */ + if (tb[IFLA_IFNAME]) { + name = static_cast(RTA_DATA(tb[IFLA_IFNAME])); + } else { + std::cerr << "do not find interface name" << std::endl ; + return; + } + +#ifdef _DEBUG + if (ifi->ifi_family == AF_UNSPEC) + std::cout << "family: AF_UNSPEC" << std::endl; + + if (ifi->ifi_family == AF_INET6) + std::cout << "family: AF_INET6" << std::endl ; +#endif + + + /* require address field to be set */ + if (tb[IFLA_ADDRESS]) { + + std::memcpy(&macaddr, static_cast(RTA_DATA(tb[IFLA_ADDRESS])), ETH_ALEN); + + + std::string inet_name(name); + + WirelessDevice inetdevice (inet_name,ifi->ifi_index,ifi->ifi_type,macaddr,0); + + if(inetdevice.checkif_wireless_device()){ + + _delinet_cb(inetdevice); + } + } +} + + + + +/***********************************************************************************************/ +/***************** handle communication with nl80211 module ***********************************/ +/**********************************************************************************************/ + +int MonitorWirelessDevice::nl80211_init(){ + + + std::cout << __func__ << std::endl ; + + /* init netlink socket with nl80211 module */ + wifi.nls = nl_socket_alloc(); + + if (!wifi.nls) { + + std::cerr << "Failed to allocate netlink socket." << std::endl ; + return -ENOMEM; + } + + + nl_socket_set_buffer_size(wifi.nls, 8192, 8192); + + if (genl_connect(wifi.nls)) { + + std::cerr << "Failed to connect to generic netlink" << std::endl ; + nl_close(wifi.nls); + nl_socket_free(wifi.nls); + return -ENOLINK; + } + + wifi.nl80211_id = genl_ctrl_resolve(wifi.nls, "nl80211"); + if (wifi.nl80211_id < 0) { + + std::cerr << "nl80211 not found." << std::endl ; + nl_close(wifi.nls); + nl_socket_free(wifi.nls); + return -ENOENT; + } + + + /*set a callback that receive messages from a module */ + wifi.cb = nl_cb_alloc(NL_CB_DEFAULT); + + if (!wifi.cb) { + + std::cerr << "Failed to allocate netlink callback." << std::endl ; + nl_close(wifi.nls); + nl_socket_free(wifi.nls); + return -ENOMEM; + } + + /*set a callback that receive messages from a module */ + wifi.cb1 = nl_cb_alloc(NL_CB_DEFAULT); + + if (!wifi.cb1) { + + std::cerr << "Failed to allocate netlink callback." << std::endl ; + nl_close(wifi.nls); + nl_socket_free(wifi.nls); + return -ENOMEM; + } + + /* set callbacks */ + nl_cb_set(wifi.cb1, NL_CB_VALID, NL_CB_CUSTOM,recv_winterface_extra_infos_cb, &(wifi.err1)); + nl_cb_set(wifi.cb1, NL_CB_FINISH, NL_CB_CUSTOM, handle_iee80211_com_finish_cb, &(wifi.err1)); + nl_cb_set(wifi.cb, NL_CB_VALID, NL_CB_CUSTOM,recv_winterface_infos_cb, &(wifi.err)); + nl_cb_set(wifi.cb, NL_CB_FINISH, NL_CB_CUSTOM, handle_iee80211_com_finish_cb, &(wifi.err)); + + return wifi.nl80211_id ; +} + + +int MonitorWirelessDevice::get_winterface_infos(int ifindex) +{ + + + wifi.err = 1 ; + int flags ; + + /* for one interface or for all interface */ + if (ifindex != 0) + + flags = 0; + else + flags = NLM_F_DUMP; + + + + /* allocate a msg to send to a module */ + struct nl_msg *msg = nlmsg_alloc(); + + if (!msg) { + + std::cerr << "Failed to allocate netlink message." << std::endl ; + return -ENOMEM; + } + + + + /* send get inerface command to deriver */ + genlmsg_put(msg, 0, 0, wifi.nl80211_id, 0, flags , NL80211_CMD_GET_INTERFACE, 0); + //genlmsg_put(msg,NL_AUTO_PORT,NL_AUTO_SEQ,wifi.nl80211_id,0,flags, NL80211_CMD_GET_INTERFACE, 0); + + if (ifindex != 0) + nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex); + + + if (nl_send_auto(wifi.nls, msg) < 0) + { + nlmsg_free(msg); + return -1 ; + } + + if (ifindex != 0) + nl_recvmsgs(wifi.nls, wifi.cb); + else + while(wifi.err > 0) + nl_recvmsgs(wifi.nls, wifi.cb); + + nlmsg_free(msg); + + return 0 ; + +} + + +int MonitorWirelessDevice::recv_winterface_infos_cb(struct nl_msg *msg, [[maybe_unused]] void *arg){ + + forward->recv_winterface_infos(msg); + return 0 ; +} + + +int MonitorWirelessDevice::recv_winterface_infos(struct nl_msg *msg){ + + + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = static_cast(nlmsg_data(nlmsg_hdr(msg))); + + char *ifname; + int ifindex; + int iftype; + struct ether_addr macaddr ; + uint32_t txp = 0; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),genlmsg_attrlen(gnlh, 0), NULL); + + if (tb_msg[NL80211_ATTR_IFNAME]) + + ifname = nla_get_string(tb_msg[NL80211_ATTR_IFNAME]) ; + + else + return NL_SKIP; + + if (tb_msg[NL80211_ATTR_IFINDEX]) + + ifindex = nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]); + else + return NL_SKIP; + + if (tb_msg[NL80211_ATTR_MAC]) + + std::memcpy(&macaddr, static_cast(nla_data(tb_msg[NL80211_ATTR_MAC])), ETH_ALEN); + else + return NL_SKIP; + + + if (tb_msg[NL80211_ATTR_IFTYPE]) + + iftype = nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]); + else + return NL_SKIP; + + if (tb_msg[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]) { + + txp = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_TX_POWER_LEVEL]); + + } + + std::string inet_name(ifname); + + WirelessDevice inetdevice (inet_name,ifindex,iftype,macaddr,txp); + + if(!init_interfaces){ + + _initinet_cb(inetdevice); + init_interfaces = true ; + } + else + _newinet_cb(inetdevice) ; + + return NL_SKIP; +} + +int MonitorWirelessDevice::recv_winterface_extra_infos_cb(struct nl_msg *msg, [[maybe_unused]] void *arg){ + + forward->recv_winterface_extra_infos(msg); + return 0 ; +} + + + +int MonitorWirelessDevice::recv_winterface_extra_infos(struct nl_msg *msg){ + + + + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = static_cast(nlmsg_data(nlmsg_hdr(msg))); + + struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; + // struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; + + struct nla_policy stats[NL80211_STA_INFO_MAX + 1]; + stats[NL80211_STA_INFO_INACTIVE_TIME].type = NLA_U32 ; + stats[NL80211_STA_INFO_RX_BYTES].type = NLA_U32 ; + stats[NL80211_STA_INFO_TX_BYTES].type = NLA_U32 ; + stats[NL80211_STA_INFO_RX_PACKETS].type = NLA_U32 ; + stats[NL80211_STA_INFO_TX_PACKETS].type = NLA_U32 ; + stats[NL80211_STA_INFO_SIGNAL].type = NLA_U8 ; + stats[NL80211_STA_INFO_TX_BITRATE].type = NLA_NESTED; + stats[NL80211_STA_INFO_LLID].type = NLA_U16 ; + stats[NL80211_STA_INFO_PLID].type = NLA_U16 ; + stats[NL80211_STA_INFO_PLINK_STATE].type = NLA_U8 ; + + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),genlmsg_attrlen(gnlh, 0), NULL); + + + /* get signal power-tx */ + if (!tb_msg[NL80211_ATTR_STA_INFO]) { + + std::cerr << __func__ << "sta stats missing!" << std::endl ; + return NL_SKIP; + } + + if (nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,tb_msg[NL80211_ATTR_STA_INFO], stats)) + + { + + std::cerr << "failed to parse nested attributes" << std::endl; + return NL_SKIP; + + } + + + if (sinfo[NL80211_STA_INFO_SIGNAL]) { + + int signal = 100+(int8_t)nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); + std::cout << __func__ << " Signal : " << signal << std::endl ; + } + + + return NL_SKIP; +} + + + + + +int MonitorWirelessDevice::handle_iee80211_com_finish_cb( [[maybe_unused]] struct nl_msg *msg, void *arg){ + + forward->handle_iee80211_com_finish(arg); + return 0 ; + +} + +int MonitorWirelessDevice::handle_iee80211_com_finish(void *arg){ + +#ifdef _DEBUG + std::cout << __func__ << std::endl ; +#endif + + int *ret = static_cast(arg); + *ret = 0; + return NL_SKIP; +} + + diff --git a/src/cmonwirelessdevice.h b/src/cmonwirelessdevice.h new file mode 100644 index 0000000..05c95a6 --- /dev/null +++ b/src/cmonwirelessdevice.h @@ -0,0 +1,199 @@ +#ifndef _CMONITORWIRELESSDEVICE_H_ +#define _CMONITORWIRELESSDEVICE_H_ + + +#include "cwirelessdevice.h" +#include +#include +#include + +namespace monitorinet { + class CallFromStaticFunc; +} + + +/** Buffer size for netlink route interface list */ +#define IFLIST_REPLY_BUFFER 4096 + +typedef std::function CallbackFunction ; + + +typedef struct { + struct nl_sock *nls; + int nl80211_id; + int err,err1 ; + struct nl_cb* cb; + struct nl_cb* cb1; +} WIFI; + + +class MonitorWirelessDevice { + + + + + /* set to true when wireless interfaces are initialised */ + bool init_interfaces = false ; + + /* for netlink communication with 80211 module */ + WIFI wifi ; + + bool _outsideloop { true } ; + bool _started { false } ; + int _inetsock ; + + std::mutex _startedmutex ; + std::mutex _outsideloopmutex ; + + int main_loop(); + + /** + * \brief processes netlink route events from the kernel + * Determines the event type for netlink route messages (del/new). + * \return void + */ + void recv_inet_event(); + bool outside_loop(); + void clean(); + + /** + * \brief processes RTM_NEWLINK messages + * Detects when interfaces are created and modified + * \param struct nlmsghdr * - netlink message header + * \return void + */ + void new_net_interface(struct nlmsghdr *) ; + + + void del_net_interface(struct nlmsghdr *h); + + + /** + * \brief callback to be set through setCallback function by another object + * this callback is called by new_net_interface function in order to send a created, deleted or changed wirelessdevice + */ + CallbackFunction _newinet_cb ; + + /** + * \brief callback to be set through setCallback function by another object + * this callback is called by new_net_interface function in order to send a created, deleted or changed wirelessdevice + */ + CallbackFunction _delinet_cb ; + + + /** + * \brief callback to be set through setCallback function by another object + * this callback is called by recv_winterface_infos function in order to send infos of each existing wireless interface + */ + CallbackFunction _initinet_cb ; + + static int recv_winterface_infos_cb(struct nl_msg *msg, void *arg); + static int recv_winterface_extra_infos_cb(struct nl_msg *msg, void *arg); + static int handle_iee80211_com_finish_cb(struct nl_msg *msg, void *arg); + + static monitorinet::CallFromStaticFunc * forward ; + +public: + + + MonitorWirelessDevice(); + ~MonitorWirelessDevice(); + MonitorWirelessDevice(const MonitorWirelessDevice &) = delete ; + MonitorWirelessDevice & operator=(const MonitorWirelessDevice&) = delete ; + + void start(); + void stop(); + bool started(); + + + /** + * \brief set new interface notification callback + * \param CallbackFunction - defined earlier as typedef std::function CallbackFunction + * \return void + */ + void setNewInetCallback(CallbackFunction); + + /** + * \brief set delete interface notification callback + * \param CallbackFunction - defined earlier as typedef std::function CallbackFunction + * \return void + */ + void setInitInetCallback(CallbackFunction); + + + + /** + * \brief set interface initial list notification callback + * \param CallbackFunction - defined earlier as typedef std::function CallbackFunction + * \return void + */ + void setDelInetCallback(CallbackFunction); + + + /** + *\fn int get_interface_infos() + * \brief Uses nl80211 to initialize a list of wireless interfaces Processes multiple netlink messages containing interface data + *\return error codes + */ + int get_winterface_infos(int); + + int recv_winterface_infos(struct nl_msg *msg); + int recv_winterface_extra_infos(struct nl_msg *msg); + + int handle_iee80211_com_finish(void *arg); + + int nl80211_init() ; + +}; + + + + +/** + * \namespace monitorinet + * + * A namespace is used here, since a class CallFromStaticFunc is defined in other files + */ +namespace monitorinet { + + /** + * \class CallFromStaticFunc + * \brief this class is an artifact used to call a member function from static function + */ + class CallFromStaticFunc { + + MonitorWirelessDevice * m_obj ; + + public: + + explicit CallFromStaticFunc(MonitorWirelessDevice * obj){ + + m_obj = obj ; + }; + + int recv_winterface_infos(struct nl_msg *msg) { + + // add exception to check null ptr + m_obj->recv_winterface_infos(msg); + return 0 ; + }; + + int recv_winterface_extra_infos(struct nl_msg *msg) { + + // add exception to check null ptr + m_obj->recv_winterface_extra_infos(msg); + return 0 ; + }; + + + int handle_iee80211_com_finish(void *arg) { + + // add exception to check null ptr + m_obj->handle_iee80211_com_finish(arg); + return 0 ; + }; + + }; +} + +#endif diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..122df59 --- /dev/null +++ b/src/config.h @@ -0,0 +1,33 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "types.h" // TIndex / TPort + +#ifndef DISABLE_VHOST + #define ENABLE_VHOST +#endif + +const TIndex WIFI_MAX_DECONNECTED_CLIENT = 15; + +const bool LOST_PACKET_BY_DEFAULT=false; + +const TPort DEFAULT_WIFI_CLIENT_PORT_VHOST = 8211; +const TPort DEFAULT_WIFI_CLIENT_PORT_INET = DEFAULT_WIFI_CLIENT_PORT_VHOST+1; + +const TPort DEFAULT_WIFI_SPY_PORT = DEFAULT_WIFI_CLIENT_PORT_VHOST+2; + +const TPort DEFAULT_CTRL_PORT = DEFAULT_WIFI_CLIENT_PORT_VHOST+3; + +#define DEFAULT_ADDRESS_IP "127.0.0.1" + +const int MAX_SIZE_NAME=12; + +const int DEFAULT_NUMBER_WLAN_INTERFACE=0; +#define DEFAULT_MAC_PREFIX "74:F8:F6" + +#ifdef _DEBUG + // #define _VERBOSE1 + // #define _VERBOSE2 +#endif + +#endif diff --git a/src/config_hwsim.h b/src/config_hwsim.h new file mode 100644 index 0000000..1e31743 --- /dev/null +++ b/src/config_hwsim.h @@ -0,0 +1,8 @@ +#ifndef _CONFIG_HWSIM_ +#define _CONFIG_HWSIM_ + +#include "hwsim.h" + +constexpr char KERNEL_HWSIM_FAMILY_NAME[] = "MAC80211_HWSIM"; + +#endif diff --git a/src/cselect.cc b/src/cselect.cc new file mode 100644 index 0000000..108ad25 --- /dev/null +++ b/src/cselect.cc @@ -0,0 +1,99 @@ +#include // errno +#include // assert +#include // NULL + +#include "cselect.h" + +using namespace std; + +CSelect::CSelect() +{ + Init(); +} + +void CSelect::Init() +{ + //clear the socket set + FD_ZERO(&Master); + + //clear the socket set + FD_ZERO(&Dup); + + MaxDescriptor=-1; +} + +void CSelect::UpdateMaxDescriptor(TDescriptor descriptor) +{ + //highest file descriptor number, need it for the select function + if ( descriptor > MaxDescriptor ) + MaxDescriptor=descriptor; +} + +bool CSelect::AddNode(TDescriptor descriptor) +{ + //add new socket to array of sockets + ListNodes.push_back(descriptor); + + //add child sockets to set + FD_SET( descriptor , &Master); + + //highest file descriptor number, need it for the select function + UpdateMaxDescriptor(descriptor); + + return true; +} + +void CSelect::DelNode(TDescriptor descriptor) +{ + MaxDescriptor=-1; + for (auto node = ListNodes.begin() ; node != ListNodes.end(); ++node) + { + if( *node == descriptor ) + { + auto node_to_delete = node; + + FD_CLR(descriptor , &Master); + + for (++node ; node != ListNodes.end(); ++node) + UpdateMaxDescriptor(*node); + + ListNodes.erase(node_to_delete); + + return; + } + UpdateMaxDescriptor(*node); + } +} + +TDescriptor CSelect::Wait() +{ + return Wait(NULL); +} + +TDescriptor CSelect::Wait(const sigset_t *sigmask) +{ + /* back up master */ + Dup = Master; + + //wait for an activity on one of the sockets , timeout is NULL , + //so wait indefinitely + int activity=pselect( MaxDescriptor + 1 , &Dup , NULL , NULL , NULL, sigmask); + + if ((activity < 0) && (errno!=EINTR)) + return SCHEDULER_ERROR; + + return activity; +} + + +bool CSelect::DescriptorHasAction(TDescriptor descriptor) +{ + return FD_ISSET( descriptor , &Dup); +} + +bool CSelect::NodeHasAction(TIndex index) +{ + assert( index < ListNodes.size() ); + + return FD_ISSET( ListNodes[index] , &Dup); +} diff --git a/src/cselect.h b/src/cselect.h new file mode 100644 index 0000000..0ba3be0 --- /dev/null +++ b/src/cselect.h @@ -0,0 +1,45 @@ +#ifndef _CSELECT_H_ +#define _CSELECT_H_ + +#include // fd_set +#include +#include // vector + +#include "types.h" // TDescriptor + +const int SCHEDULER_ERROR=-1; + +class CSelect +{ + private : + + //set of socket descriptors + fd_set Master; + fd_set Dup; + + TDescriptor MaxDescriptor; + + std::vector ListNodes; + + void UpdateMaxDescriptor(TDescriptor descriptor); + + void Init(); + + public : + + CSelect(); + + bool AddNode(TDescriptor descriptor); + + void DelNode(TDescriptor descriptor); + + TDescriptor Wait(); + + TDescriptor Wait(const sigset_t *sigmask); + + bool DescriptorHasAction(TDescriptor descriptor); + + bool NodeHasAction(TIndex index); +}; + +#endif diff --git a/src/csocket.cc b/src/csocket.cc new file mode 100644 index 0000000..423662c --- /dev/null +++ b/src/csocket.cc @@ -0,0 +1,106 @@ +#include //perror + +#include // cout + +#include //socket +#include // struct sockaddr_in & inet_ntoa & ntohs +#include // struct sockaddr_vm +#include // close +#include // F_GETFL O_NONBLOCK + +#include "csocket.h" + +using namespace std; + +CSocket::CSocket() +{ + Master=0; +} + +CSocket::~CSocket() +{ + Close(); +} + +CSocket::CSocket( const CSocket & socket ) +{ + Master=socket.Master; +} + +TDescriptor CSocket::GetDescriptor() const +{ + return Master; +} + +ssize_t CSocket::Send(TDescriptor descriptor, const char* data, ssize_t sizeOfData) +{ + ssize_t ret = send(descriptor, data, sizeOfData, 0); + if ( ret != sizeOfData ) + return SOCKET_ERROR ; + + return ret; +} + +ssize_t CSocket::SendBigData(TDescriptor descriptor, const char* data, TMinimalSize sizeOfData) +{ + ssize_t ret = Send(descriptor, (char*)&sizeOfData, (unsigned)sizeof(sizeOfData)); + if( ret == SOCKET_ERROR ) + return SOCKET_ERROR; + + return Send(descriptor, data, sizeOfData); +} + +ssize_t CSocket::Read(TDescriptor descriptor, char* data, ssize_t sizeOfData) +{ + ssize_t ret = recv(descriptor , data, sizeOfData, 0); + if ( ret <= 0 ) + return SOCKET_ERROR ; + + return ret; +} + +ssize_t CSocket::ReadEqualSize(TDescriptor descriptor, CDynBuffer* data, ssize_t byteAlreadyRead, ssize_t sizeToRead) +{ + ssize_t sizeToRead_backup = sizeToRead; + sizeToRead-=byteAlreadyRead; + + data->NeededSize(sizeToRead_backup,(byteAlreadyRead!=0)); + + char* buffer = data->GetBuffer(); + buffer+=byteAlreadyRead; + + while( sizeToRead > 0 ) + { + ssize_t sizeRead=Read(descriptor, buffer, sizeToRead); + + if( sizeRead == SOCKET_ERROR ) + return SOCKET_ERROR; + + sizeToRead-=sizeRead; + + buffer+=sizeRead; + } + + return sizeToRead_backup; +} + +ssize_t CSocket::ReadBigData(TDescriptor descriptor, CDynBuffer* data) +{ + TMinimalSize size; + + int ret = Read(descriptor, (char*)&size, (unsigned)sizeof(size)); + if( ret == SOCKET_ERROR ) + return SOCKET_ERROR; + + return ReadEqualSize(descriptor, data, 0, size); +} + +CSocket::operator int() +{ + return Master; +} + +void CSocket::Close() +{ + close(Master); +} diff --git a/src/csocket.h b/src/csocket.h new file mode 100644 index 0000000..520a977 --- /dev/null +++ b/src/csocket.h @@ -0,0 +1,43 @@ +#ifndef _CSOCKET_H_ +#define _CSOCKET_H_ + +#include // ssize_t + +#include "types.h" // TDescriptor / TSocket +#include "cdynbuffer.h" // CDynBuffer + +const int SOCKET_ERROR=-1; + +class CSocket +{ + friend class CWifi; + + protected : + + TDescriptor Master; + + CSocket(); + + CSocket( const CSocket & socket ); + + TDescriptor GetDescriptor() const; + + virtual ssize_t Send(TDescriptor descriptor, const char* data, ssize_t sizeOfData); + virtual ssize_t SendBigData(TDescriptor descriptor, const char* data, TMinimalSize sizeOfData); + + virtual ssize_t Read(TDescriptor descriptor, char* data, ssize_t sizeOfData); + virtual ssize_t ReadBigData(TDescriptor descriptor, CDynBuffer* data); + + private : + ssize_t ReadEqualSize(TDescriptor descriptor, CDynBuffer* data, ssize_t byteAlreadyRead, ssize_t sizeToRead); + + public : + + void Close(); + + ~CSocket(); + + operator int(); +}; + +#endif diff --git a/src/csocketclient.cc b/src/csocketclient.cc new file mode 100644 index 0000000..f970c5e --- /dev/null +++ b/src/csocketclient.cc @@ -0,0 +1,102 @@ +#include // cout +#include //perror + +#include // ioctl +#include // open + +#include // INADDR_ANY +#include // close +#include // assert + +#include "csocketclient.h" +#include "tools.h" + +using namespace std; + +// ----------------- CSocketClient + +CSocketClient::~CSocketClient() +{ + CSocket::Close(); +} + +CSocketClient::CSocketClient() : CSocket() +{ + Init(); +} + +void CSocketClient::Init() +{ + IsConnected=false; + StopTheReconnect=false ; +} + +bool CSocketClient::ConnectLoop() +{ + while ( ! StopTheReconnect ) + { + if( _Connect() ) + return true; + } + + // The system asks to stop the reconnect + return false; +} + +bool CSocketClient::Connect(struct sockaddr* server, size_t size_of_server) +{ + if( ! _Configure() ) + { + cerr<<"Error : CSocketClient::Connect : Configure"< // cout +#include //perror + +#include // ioctl +#include // open + +#include // INADDR_ANY +#include // close +#include // assert + +#include "csocketclientitcp.h" +#include "tools.h" + +using namespace std; + +CSocketClientITCP::CSocketClientITCP() : CSocketClient() +{ +} + +void CSocketClientITCP::Init(const char* IP, TPort port) +{ + Server.sin_family = AF_INET; + Server.sin_addr.s_addr = inet_addr(IP); + Server.sin_port = htons(port); +} + +bool CSocketClientITCP::_Configure() +{ + Master = socket(AF_INET , SOCK_STREAM , 0); + + if( Master == SOCKET_ERROR ) + { + perror("CSocketClientITCP::Configure : socket"); + return false; + } + + return true; +} + +bool CSocketClientITCP::_Connect() +{ + return Connect((struct sockaddr*) &Server, sizeof(Server)); +} + +int CSocketClientITCP::_GetID() +{ + struct sockaddr_in my_addr; + + socklen_t len = sizeof(my_addr); + getsockname(Master, (struct sockaddr *) &my_addr, &len); + + return hash_ipaddr(&my_addr) ; +} diff --git a/src/csocketclientitcp.h b/src/csocketclientitcp.h new file mode 100644 index 0000000..cfa877e --- /dev/null +++ b/src/csocketclientitcp.h @@ -0,0 +1,27 @@ +#ifndef _CSOCKETCLIENTITCP_H_ +#define _CSOCKETCLIENTITCP_H_ + +#include "csocketclient.h" + +#include // struct sockaddr_in + +class CSocketClientITCP : public CSocketClient +{ + private : + + struct sockaddr_in Server; + + public : + + CSocketClientITCP(); + + void Init(const char* IP, TPort port); + + bool _Configure() override; + + bool _Connect() override; + + int _GetID() override; +}; + +#endif diff --git a/src/csocketclientvtcp.cc b/src/csocketclientvtcp.cc new file mode 100644 index 0000000..82a7946 --- /dev/null +++ b/src/csocketclientvtcp.cc @@ -0,0 +1,66 @@ +#include // cout +#include //perror + +#include // ioctl +#include // open + +#include // INADDR_ANY +#include // close +#include // assert +#include // memset + +#include "csocketclientvtcp.h" +#include "tools.h" + +using namespace std; + +CSocketClientVTCP::CSocketClientVTCP() : CSocketClient() +{ +} + +void CSocketClientVTCP::Init(TPort port) +{ + memset(&Server, 0, sizeof(Server)); + Server.svm_family = AF_VSOCK; + Server.svm_port = port; + Server.svm_cid = 2; +} + +bool CSocketClientVTCP::_Configure() +{ + Master = socket(AF_VSOCK , SOCK_STREAM , 0); + + if( Master == SOCKET_ERROR ) + { + perror("CSocketClientVTCP::Configure : socket"); + return false; + } + + return true; +} + +bool CSocketClientVTCP::_Connect() +{ + return Connect((struct sockaddr*) &Server, sizeof(Server)); +} + +int CSocketClientVTCP::_GetID() +{ + int cid; + + int ioctl_fd = open("/dev/vsock", 0); + if (ioctl_fd < 0) + { + perror("Error : CSocketClientVHOST::GetID : open /dev/vsock :"); + return -1; + } + if( ioctl(ioctl_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, &cid) < 0 ) + { + perror("Error : CSocketClientVHOST::GetID : ioctl : Cannot get local CID :"); + close(ioctl_fd); + return -1; + } + + close(ioctl_fd); + return cid; +} diff --git a/src/csocketclientvtcp.h b/src/csocketclientvtcp.h new file mode 100644 index 0000000..44b3683 --- /dev/null +++ b/src/csocketclientvtcp.h @@ -0,0 +1,28 @@ +#ifndef _CSOCKETCLIENTVTCP_H_ +#define _CSOCKETCLIENTVTCP_H_ + +#include // struct sockaddr_in +#include // struct sockaddr_vm + +#include "csocketclient.h" + +class CSocketClientVTCP : public CSocketClient +{ + private : + + struct sockaddr_vm Server; + + public : + + CSocketClientVTCP(); + + void Init(TPort port); + + bool _Configure() override; + + bool _Connect() override; + + int _GetID() override; +}; + +#endif diff --git a/src/csocketserver.cc b/src/csocketserver.cc new file mode 100644 index 0000000..0c74dc3 --- /dev/null +++ b/src/csocketserver.cc @@ -0,0 +1,166 @@ +#include // cout +#include //perror +#include // memcpy +#include // assert + +#include // INADDR_ANY +#include +#include // struct sockaddr_vm + +#include "csocketserver.h" + +using namespace std; + +CSocketServer::CSocketServer(CListInfo* infoSockets) : CSocket() +{ + Init(0); + + if( infoSockets == NULL ) + { + InfoSockets = new CListInfo; + + ListInfoSelfManaged=true; + } + else + { + InfoSockets = infoSockets; + + ListInfoSelfManaged=false; + } +} + +CSocketServer::CSocketServer( const CSocketServer & socketServer ) : CSocket(socketServer) +{ + *this=socketServer; +} + +CSocketServer& CSocketServer::operator=(const CSocketServer& socketServer) +{ + if( this != &socketServer ) + { + // protect against invalid self-assignment + Init(socketServer.GetPort()); + + ListInfoSelfManaged=socketServer.ListInfoSelfManaged; + + if( ListInfoSelfManaged ) + { + if( InfoSockets != NULL ) + delete InfoSockets; + InfoSockets = new CListInfo(*(socketServer.InfoSockets)); + } + else + { + InfoSockets = socketServer.InfoSockets; + } + } + + // by convention, always return *this + return *this; +} + +void CSocketServer::Init(TPort port) +{ + Port=port; +} + +TPort CSocketServer::GetPort() const +{ + return Port; +} + +CSocketServer::~CSocketServer() +{ + for (auto& infoSocket : *InfoSockets) + infoSocket.Close(); + + delete InfoSockets; + + CSocket::Close(); +} + +bool CSocketServer::Listen() +{ + return _Listen(Master, Port); +} + +TDescriptor CSocketServer::Accept(TCID& cid) +{ + TDescriptor new_socket; + + new_socket = _Accept(Master, cid); + if( new_socket == SOCKET_ERROR ) + return SOCKET_ERROR; + + //add new socket to array of sockets + InfoSockets->push_back(CInfoSocket(new_socket)); + + return new_socket; +} + +TDescriptor CSocketServer::Accept() +{ + TCID cid; + + return Accept(cid); +} + +TDescriptor CSocketServer::GetSocketClient(TIndex index) const +{ + assert( index < InfoSockets->size() ); + + return (*InfoSockets)[index].GetDescriptor(); +} + +TDescriptor CSocketServer::operator[] (TIndex index) +{ + return GetSocketClient(index); +} + +TIndex CSocketServer::GetNumberClient() const +{ + return InfoSockets->size(); +} + +bool CSocketServer::IsEnable(TIndex index) +{ + assert( index < GetNumberClient() ); + + return (*InfoSockets)[index].IsEnable(); +} + +void CSocketServer::DisableClient(TIndex index) +{ + assert( index < InfoSockets->size() ); + + (*InfoSockets)[index].DisableIt(); +} + +void CSocketServer::CloseClient(TIndex index) +{ + assert( index < InfoSockets->size() ); + + (*InfoSockets)[index].Close(); + + InfoSockets->erase (InfoSockets->begin()+index); +} + +ssize_t CSocketServer::Send(TDescriptor descriptor, const char* data, ssize_t sizeOfData) +{ + return CSocket::Send(descriptor, data, sizeOfData); +} + +ssize_t CSocketServer::SendBigData(TDescriptor descriptor, const char* data, TMinimalSize sizeOfData) +{ + return CSocket::SendBigData(descriptor, data, sizeOfData); +} + +ssize_t CSocketServer::Read(TDescriptor descriptor, char* data, ssize_t sizeOfData) +{ + return CSocket::Read(descriptor, data, sizeOfData); +} + +ssize_t CSocketServer::ReadBigData(TDescriptor descriptor, CDynBuffer* data) +{ + return CSocket::ReadBigData(descriptor, data); +} diff --git a/src/csocketserver.h b/src/csocketserver.h new file mode 100644 index 0000000..793ecf7 --- /dev/null +++ b/src/csocketserver.h @@ -0,0 +1,63 @@ +#ifndef _CSOCKETSERVER_H_ +#define _CSOCKETSERVER_H_ + +#include "csocket.h" +#include "cinfosocket.h" +#include "clistinfo.h" +#include "types.h" // TIndex + +class CSocketServer : public CSocket +{ + protected : + + TPort Port; + + bool ListInfoSelfManaged; + CListInfo* InfoSockets; + + TDescriptor GetSocketClient(TIndex index) const; + + TDescriptor Accept(TCID& cid); + TDescriptor Accept(); + + explicit CSocketServer(CListInfo* infoSockets = NULL); + + CSocketServer(TSocket type, CListInfo* infoSockets = NULL); + + CSocketServer( const CSocketServer & socketServer ); + + ~CSocketServer(); + + CSocketServer& operator=(const CSocketServer& socketServer); + + TPort GetPort() const; + + void DisableClient(TIndex index); + + void CloseClient(TIndex index); + + ssize_t Send(TDescriptor descriptor, const char* data, ssize_t sizeOfData) override; + ssize_t SendBigData(TDescriptor descriptor, const char* data, TMinimalSize sizeOfData) override; + + ssize_t Read(TDescriptor descriptor, char* data, ssize_t sizeOfData) override; + ssize_t ReadBigData(TDescriptor descriptor, CDynBuffer* data) override; + + // virtual : + + virtual bool _Listen(TDescriptor& master, TPort port) = 0; + virtual TDescriptor _Accept(TDescriptor master, TCID& cid) = 0; + + public : + + TIndex GetNumberClient() const; + + TDescriptor operator[] (TIndex index); + + bool IsEnable(TIndex index); + + void Init(TPort port); + + bool Listen(); +}; + +#endif diff --git a/src/csocketserverfunctionitcp.cc b/src/csocketserverfunctionitcp.cc new file mode 100644 index 0000000..1b8fe99 --- /dev/null +++ b/src/csocketserverfunctionitcp.cc @@ -0,0 +1,95 @@ +#include // cout +#include //perror +#include // memcpy +#include // assert + +#include // INADDR_ANY +#include + +#include "csocket.h" // SOCKET_ERROR +#include "csocketserverfunctionitcp.h" +#include "tools.h" + +using namespace std; + +bool CSocketServerFunctionITCP::Configure(TDescriptor& master) +{ + //create a master socket + + master = socket(AF_INET , SOCK_STREAM , 0); + + if( master == SOCKET_ERROR ) + { + perror("CSocketServerFunctionITCP::Configure : socket"); + return false; + } + + return true; +} + +bool CSocketServerFunctionITCP::_Listen(TDescriptor& master, TPort port) +{ + if( ! Configure(master) ) + { + cerr<<"Error : CSocketServerFunctionITCP::_Listen : Configure"< // cout +#include //perror +#include // memset +#include // assert + +#include // INADDR_ANY +#include +#include // struct sockaddr_vm + +#include "csocket.h" // SOCKET_ERROR + +#include "csocketserverfunctionvtcp.h" + +using namespace std; + +bool CSocketServerFunctionVTCP::Configure(TDescriptor& master) +{ + //create a master socket + + master = socket(AF_VSOCK , SOCK_STREAM , 0); + + if( master == SOCKET_ERROR ) + { + perror("CSocketServerFunctionVTCP::_Configure : socket"); + return false; + } + + return true; +} + +bool CSocketServerFunctionVTCP::_Listen(TDescriptor& master, TPort port) +{ + if( ! Configure(master) ) + { + cerr<<"Error : CSocketServerFunctionVTCP::_Listen : Configure"<svm_cid; + + return new_socket; +} + diff --git a/src/csocketserverfunctionvtcp.h b/src/csocketserverfunctionvtcp.h new file mode 100644 index 0000000..e552cda --- /dev/null +++ b/src/csocketserverfunctionvtcp.h @@ -0,0 +1,20 @@ +#ifndef _CSOCKETSERVERFUNCTIONVTCP_H_ +#define _CSOCKETSERVERFUNCTIONVTCP_H_ + +#include "types.h" + +class CSocketServerFunctionVTCP +{ + private : + + bool Configure(TDescriptor& master); + + protected: + + bool _Listen(TDescriptor& master, TPort port); + + TDescriptor _Accept(TDescriptor master, TCID& cid); + +}; + +#endif diff --git a/src/cthread.cc b/src/cthread.cc new file mode 100644 index 0000000..df28dec --- /dev/null +++ b/src/cthread.cc @@ -0,0 +1,142 @@ +#include "cthread.h" +#include + +#include + +namespace intthread { + + +/*********************************************************/ + /* Global variables and functions */ +/********************************************************/ + +thread_local InterruptFlag this_thread_interrupt_flag ; + +void interruption_point(){ + + if(this_thread_interrupt_flag.is_set()) + { + throw thread_interrupted(); + } + +} + +/*********************************************************/ + /* InterruptFlag class definitions */ +/********************************************************/ + +InterruptFlag::InterruptFlag() +{ + _set = false ; +} + +void InterruptFlag::set(){ + + std::lock_guard guard(_mutex); + _set = true ; + +} + +bool InterruptFlag::is_set() { + + std::lock_guard guard(_mutex); + return _set ; + +} + + +/*********************************************************/ + /* InterruptibleThread class definitions */ +/********************************************************/ + + + +int InterruptibleThread::number_thread = 0 ; + +std::mutex InterruptibleThread::_number_thread_mutex ; + +InterruptibleThread::InterruptibleThread(){ + + count_thread(); + + +} + + +bool InterruptibleThread::started() +{ + + return _started ; +} + +void InterruptibleThread::interrupt(){ + + if (_interrupt_flag != nullptr){ + _interrupt_flag->set(); + + } + _started = false ; + +} + +void InterruptibleThread::join(){ + + _internal_thread.join(); + +} + +pthread_t InterruptibleThread::get_native_handle(){ + + return _internal_thread.native_handle(); +} + + +std::thread::id InterruptibleThread::get_id(){ + + + return _internal_thread.get_id(); +} + + +void InterruptibleThread::count_thread(){ + + std::unique_lock lk(_number_thread_mutex); + number_thread++; +} + +void InterruptibleThread::uncount_thread(){ + + std::unique_lock lk(_number_thread_mutex); + number_thread--; +} + +bool InterruptibleThread::all_thread_interrupted(){ + + std::unique_lock lk(_number_thread_mutex); + return (number_thread == 0); +} + + + + +/*********************************************************/ + /* AsyncTask class definitions */ +/********************************************************/ + + + +AsyncTask::AsyncTask(){ +} + + + +void AsyncTask::dead() { + + std::unique_lock lk(_mutex_condition); + InterruptibleThread::uncount_thread() ; + _condition.notify_all(); + lk.unlock(); + +} + +} diff --git a/src/cthread.h b/src/cthread.h new file mode 100644 index 0000000..045d911 --- /dev/null +++ b/src/cthread.h @@ -0,0 +1,127 @@ +#ifndef _CTHREAD_H_ +#define _CTHREAD_H_ + + +#include +#include +#include +#include +#include +//#include + +namespace intthread { + + +void interruption_point(); + +struct thread_interrupted{}; + +class InterruptFlag + +{ + private: + bool _set ; + std::mutex _mutex ; + + public: + InterruptFlag(); + + void set(); + bool is_set() ; + + +}; + + +class AsyncTask + +{ + protected : + + std::condition_variable _condition ; + std::mutex _mutex_condition ; + + public: + + AsyncTask(); + void dead() ; + +}; + + + +extern thread_local InterruptFlag this_thread_interrupt_flag ; + +class InterruptibleThread + + +{ + private: + + InterruptFlag* _interrupt_flag {nullptr} ; + std::thread _internal_thread ; + static int number_thread ; + static std::mutex _number_thread_mutex ; + bool _started {false} ; + + public: + + InterruptibleThread(); + + pthread_t get_native_handle(); + + + /* include with this version */ + /*template + void start(CLASS * obj , void (CLASS::* f)() ){ + + std::function< void(void)> _f = std::bind(f,*obj) ; + + std::promise p ; + _internal_thread = std::thread([_f,&p]{ + p.set_value(&this_thread_interrupt_flag); + _f(); + }); + _interrupt_flag = p.get_future().get(); + + }*/ + + bool started() ; + + template + void start(OBJECT * obj , FUNC f ){ + + + std::promise p ; + _internal_thread = std::thread([obj,f,&p]{ + p.set_value(&this_thread_interrupt_flag); + (obj->*f)(); + }); + _interrupt_flag = p.get_future().get(); + _started = true ; + + } + + + + void interrupt(); + void join(); + std::thread::id get_id(); + + + static bool all_thread_interrupted(); + + static void count_thread(); + + + static void uncount_thread(); + + + + + + +}; + +} // intthread space +#endif diff --git a/src/cwifi.cc b/src/cwifi.cc new file mode 100644 index 0000000..ff693c0 --- /dev/null +++ b/src/cwifi.cc @@ -0,0 +1,97 @@ +#include // log10 +#include // rand + +#include + +#include // (struct nlmsghdr *) + +#include "hwsim.h" // HWSIM_ATTR_FREQ +#include // genlmsg_parse + +#include "cwifi.h" + +//#include "config.h" + +const double ConstanteC=92.45; +const TFrequency DEFAULT_FREQUENCY=2412; // Hz + +const int MTU=2352; // Maximum Transmission Unit : 2352 (from include/linux/ieee80211.h) + +TFrequency CWifi::GetFrequency(struct nlmsghdr* nlh) +{ + /* we get the attributes*/ + struct nlattr *attrs[HWSIM_ATTR_FREQ + 1]; + genlmsg_parse(nlh, 0, attrs, HWSIM_ATTR_FREQ, NULL); + + /* we get frequence */ + if (attrs[HWSIM_ATTR_FREQ]) + return nla_get_u32(attrs[HWSIM_ATTR_FREQ]); + else + return DEFAULT_FREQUENCY; +} + +// distance : meter +// frequency : Hz +int CWifi::Attenuation(TDistance distance, TFrequency frequency) +{ + if( distance == 0 ) + return 0; + + // ConstanteC+20*log10(frequency/1000)+20*log10(distance/1000); + // ConstanteC+20*(log10(frequency)-log10(1000))+20*(log10(distance)-log10(1000)) + return ConstanteC+20*(log10(frequency)-3)+20*(log10(distance)-3); +} + +TPower CWifi::BoundedPower(int power) +{ + if( power < TPower_MIN ) + return TPower_MIN; + if( power > TPower_MAX ) + return TPower_MAX; + return power; +} + +bool CWifi::PacketIsLost(TPower signalLevel) +{ + //don't forget : signalLevel is negative + + int alea = rand() % 53 + 40; // between 40 and 92 + if( alea > -signalLevel ) + return false; + + return true; +} + +ssize_t CWifi::SendSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer) +{ +// cout<<"send power : "<Send(descriptor, reinterpret_cast(power), sizeof(TPower)); + if( val <= 0 ) + return val; + +// std::cout<<"send big data of size : "<Send(descriptor, buffer, sizeOfBuffer); +} + +ssize_t CWifi::RecvSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, CDynBuffer* buffer) +{ + int valread; + + // read the power + valread = socket->Read(descriptor, reinterpret_cast(power), sizeof(TPower)); + if ( valread <= 0 ) + return valread; + + // read the signal + // "nlmsg_len" (type "uint32_t") is the first attribut of the "struct nlmsghdr" in "libnl3/netlink/netlink-kernel.h" + ssize_t sizeRead = socket->ReadEqualSize(descriptor, buffer, 0, sizeof(struct nlmsghdr)); + if( sizeRead == SOCKET_ERROR ) + return SOCKET_ERROR; + + int sizeTotal=reinterpret_cast(buffer->GetBuffer())->nlmsg_len; + + if( sizeTotal > MTU ) // to avoid that a error packet overfulls the memory + return SOCKET_ERROR; + + return socket->ReadEqualSize(descriptor, buffer, sizeRead, sizeTotal); +} diff --git a/src/cwifi.h b/src/cwifi.h new file mode 100644 index 0000000..b7517f9 --- /dev/null +++ b/src/cwifi.h @@ -0,0 +1,25 @@ +#ifndef _WIFI_H_ +#define _WIFI_H_ + +#include "types.h" // TPower +#include "csocket.h" // CSocket + +class CWifi +{ + protected : + + TFrequency GetFrequency(struct nlmsghdr* nlh); + + // distance : meter + int Attenuation(TDistance distance, TFrequency frequency); + + // return power value between [TPower_MIN,TPower_MAX] + TPower BoundedPower(int power); + + bool PacketIsLost(TPower signalLevel); + + ssize_t SendSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer); + ssize_t RecvSignalWithSocket(CSocket* socket, TDescriptor descriptor, TPower* power, CDynBuffer* buffer); +}; + +#endif diff --git a/src/cwificlient.cc b/src/cwificlient.cc new file mode 100644 index 0000000..5adaaa4 --- /dev/null +++ b/src/cwificlient.cc @@ -0,0 +1 @@ +#include "cwificlient.h" diff --git a/src/cwificlient.h b/src/cwificlient.h new file mode 100644 index 0000000..80a99ff --- /dev/null +++ b/src/cwificlient.h @@ -0,0 +1,35 @@ +#ifndef _CWIFICLIENT_H_ +#define _CWIFICLIENT_H_ + +#include "ckernelwifi.h" +#include "csocketclient.h" +#include "cwifi.h" + +template +class CWifiClient : public CKernelWifi, public CWifi, public TypeCSocketClient +{ + bool _Connect(int* id) override + { + if( ! TypeCSocketClient::_Connect() ) + return false; + + if( ! Scheduler.AddNode(*this) ) + return false; + + *id=TypeCSocketClient::_GetID(); + + return true; + } + + ssize_t _SendSignal(TPower* power, const char* buffer, int sizeOfBuffer) override + { return SendSignalWithSocket(this, this->GetDescriptor(), power, buffer, sizeOfBuffer); } + + ssize_t _RecvSignal(TPower* power, CDynBuffer* buffer) override + { return RecvSignalWithSocket(this, this->GetDescriptor(), power, buffer); } + + void _Close() override { TypeCSocketClient::Close(); }; +}; + +#endif /* _CWIFICLIENT_H_ */ + + diff --git a/src/cwifiserver.cc b/src/cwifiserver.cc new file mode 100644 index 0000000..e3b7f1c --- /dev/null +++ b/src/cwifiserver.cc @@ -0,0 +1,267 @@ +#include // cout +#include //perror +#include // memcpy +#include // assert + +#include // struct sockaddr_in +#include // AF_VSOCK / AF_INET +#include // struct sockaddr_vm + +#include "cwifiserver.h" +#include "tools.h" +#include "config.h" // LOST_PACKET_BY_DEFAULT + +bool CanLostPackets=LOST_PACKET_BY_DEFAULT; + +using namespace std; + +CWifiServer::CWifiServer() : CSocketServer () +{ + DefaultValues(); + + InfoWifis = new CListInfo; + InfoWifisDeconnected = new CListInfo; +} + +CWifiServer::CWifiServer(CListInfo* infoSockets, CListInfo* infoWifis, CListInfo* infoWifisDeconnected) : CSocketServer (infoSockets) +{ + DefaultValues(); + + InfoWifis = infoWifis; + InfoWifisDeconnected = infoWifisDeconnected; +} + +CWifiServer::CWifiServer( const CWifiServer & wifiServer ) : CSocketServer(wifiServer), CWifi(wifiServer) +{ + *this=wifiServer; +} + +CWifiServer::~CWifiServer() +{ + if( ListInfoSelfManaged ) + { + delete InfoWifis; + delete InfoWifisDeconnected; + } +} + +CWifiServer& CWifiServer::operator=(const CWifiServer& wifiServer) +{ + if( this != &wifiServer ) + { + // protect against invalid self-assignment + MaxClientDeconnected=wifiServer.MaxClientDeconnected; + + if( ListInfoSelfManaged ) + { + if( InfoWifis != NULL ) + { + delete InfoWifis; + delete InfoWifisDeconnected; + } + InfoWifis = new CListInfo(*(wifiServer.InfoWifis)); + InfoWifisDeconnected = new CListInfo(*(wifiServer.InfoWifisDeconnected)); + } + else + { + InfoWifis = wifiServer.InfoWifis; + InfoWifisDeconnected = wifiServer.InfoWifisDeconnected; + } + } + + // by convention, always return *this + return *this; +} + +void CWifiServer::DefaultValues() +{ + MaxClientDeconnected=0; +} + +bool CWifiServer::Listen(TIndex maxClientDeconnected) +{ + MaxClientDeconnected=maxClientDeconnected; + + if( ! _Listen(Master, Port) ) + return false; + + return true; +} + +bool CWifiServer::RecoverInfosOfInfoWifiDeconnected(TCID cid, CCoordinate& coo, string& name) +{ + for (auto infoWifiDeconnected = InfoWifisDeconnected->begin(); infoWifiDeconnected != InfoWifisDeconnected->end(); ++infoWifiDeconnected) + { + if ( infoWifiDeconnected->GetCid() == cid ) + { + coo=*infoWifiDeconnected; + name=infoWifiDeconnected->GetName(); + + InfoWifisDeconnected->erase(infoWifiDeconnected); + + return true; + } + } + + return false; +} + +bool CWifiServer::RecoverInfosOfInfoWifi(TCID cid, CCoordinate& coo, string& name) +{ + int index=0; + for (auto& infoWifi : *InfoWifis) + { + if( IsEnable(index) ) + if( infoWifi.GetCid() == cid ) + { + coo=infoWifi; + name=infoWifi.GetName(); + + DisableClient(index); + + return true; + } + index++; + } + + return false; +} + +TDescriptor CWifiServer::Accept() +{ + TCID cid; + + TDescriptor new_socket = CSocketServer::Accept(cid); + if( new_socket == SOCKET_ERROR ) + return SOCKET_ERROR; + + CInfoWifi infoWifi; + + CCoordinate coo; + string name; + if( RecoverInfosOfInfoWifiDeconnected(cid,coo,name) || RecoverInfosOfInfoWifi(cid, coo,name) ) + { + infoWifi.Set(coo); + infoWifi.SetName(name); + } + + infoWifi.SetCid(cid); + + InfoWifis->push_back(infoWifi); + + return new_socket; +} + +void CWifiServer::ShowInfoWifi(TIndex index) +{ + assert( index < GetNumberClient() ); + + cout<<(*InfoWifis)[index]; +} + +void CWifiServer::CloseClient(TIndex index) +{ + assert( index < GetNumberClient() ); + + CSocketServer::CloseClient(index); + + // save the InfoWifi (the coordinate of the cid) + AddInfoWifiDeconnected( (*InfoWifis)[index] ); + + InfoWifis->erase(InfoWifis->begin()+index); +} + +void CWifiServer::CloseAllClient() +{ + // ( be careful : "TIndex i" is a **unsigned** int : i=0 ; i-1 != -1 but = 65534 ) + + TIndex nbre=GetNumberClient(); // because CloseClient changes the value of GetNumberClient() + for (TIndex i = 0; i < nbre; i++) + CloseClient(0); // we can Close the 0 because we use the shift +} + +ssize_t CWifiServer::SendSignal(TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer) +{ + return SendSignalWithSocket(this, descriptor, power, buffer, sizeOfBuffer); +} + +ssize_t CWifiServer::RecvSignal(TDescriptor descriptor, TPower* power, CDynBuffer* buffer) +{ + return RecvSignalWithSocket(this, descriptor, power, buffer); +} + +void CWifiServer::SendAllOtherClients(TIndex index,TPower power, const char* data, ssize_t sizeOfData) +{ + CCoordinate coo=(*InfoWifis)[index]; +// cout<<"Forward "<(GetFrequency( reinterpret_cast(const_cast(data)) )); + TPower signalLevel=BoundedPower(power-Attenuation(coo.DistanceWith((*InfoWifis)[i]),frequency)); + + if( ! CanLostPackets || ! PacketIsLost(signalLevel) ) + if( SendSignal((*InfoSockets)[i].GetDescriptor(), &signalLevel, data, sizeOfData) < 0 ) + (*InfoSockets)[i].DisableIt(); + } + } +} + +void CWifiServer::SendAllOtherClientsWithoutLoss(TIndex index, TPower power, const char* data, ssize_t sizeOfData) +{ + for (TIndex i = 0; i < GetNumberClient(); i++) + { + if( i != index ) + if( IsEnable(i) ) + if( SendSignal((*InfoSockets)[i].GetDescriptor(), &power, data, sizeOfData) < 0 ) + (*InfoSockets)[i].DisableIt(); + } +} + +void CWifiServer::SendAllClientsWithoutLoss(TPower power, const char* data, ssize_t sizeOfData) +{ + for (TIndex i = 0; i < GetNumberClient(); i++) + if( IsEnable(i) ) + if( SendSignal((*InfoSockets)[i].GetDescriptor(), &power, data, sizeOfData) < 0 ) + (*InfoSockets)[i].DisableIt(); +} + +CInfoWifi* CWifiServer::GetReferenceOnInfoWifiByCID(TCID cid) const +{ + for (auto& infoWifi : *InfoWifis) + { + if( infoWifi.GetCid() == cid ) + return &infoWifi; + } + + return NULL; +} + +CInfoWifi* CWifiServer::GetReferenceOnInfoWifiDeconnectedByCID(TCID cid) const +{ + for (auto& infoWifiDeconnected : *InfoWifisDeconnected) + { + if( infoWifiDeconnected.GetCid() == cid ) + return &infoWifiDeconnected; + } + + return NULL; +} + +CInfoWifi* CWifiServer::GetReferenceOnInfoWifiByIndex(TIndex index) const +{ + assert( index < GetNumberClient() ); + + return &((*InfoWifis)[index]); +} + +void CWifiServer::AddInfoWifiDeconnected(CInfoWifi infoWifi) +{ + if( InfoWifisDeconnected->size() >= MaxClientDeconnected ) + InfoWifisDeconnected->erase(InfoWifisDeconnected->begin()); + + InfoWifisDeconnected->push_back(infoWifi); +} diff --git a/src/cwifiserver.h b/src/cwifiserver.h new file mode 100644 index 0000000..40d45b1 --- /dev/null +++ b/src/cwifiserver.h @@ -0,0 +1,67 @@ +#ifndef _CWIFISERVER_H_ +#define _CWIFISERVER_H_ + +#include "csocketserver.h" +#include "cinfowifi.h" +#include "cwifi.h" + +extern bool CanLostPackets; + +class CWifiServer : public CSocketServer, public CWifi +{ + friend class CCTRLServer; + + TIndex MaxClientDeconnected; + + CListInfo* InfoWifis; + CListInfo* InfoWifisDeconnected; + + bool RecoverInfosOfInfoWifiDeconnected(TCID cid, CCoordinate& coo, string& name); + + bool RecoverInfosOfInfoWifi(TCID cid, CCoordinate& coo, string& name); + + void DefaultValues(); + + public : + + CWifiServer(); + + CWifiServer(CListInfo* infoSockets, CListInfo* infoWifis, CListInfo* infoWifisDeconnected); + + CWifiServer( const CWifiServer & wifiServer ); + + ~CWifiServer(); + + CWifiServer& operator=(const CWifiServer& wifiServer); + + bool Listen(TIndex maxClientDeconnected); + + TDescriptor Accept(); + + void ShowInfoWifi(TIndex index); + + void CloseClient(TIndex index); + + void CloseAllClient(); + + ssize_t SendSignal(TDescriptor descriptor, TPower* power, const char* buffer, int sizeOfBuffer); + + ssize_t RecvSignal(TDescriptor descriptor, TPower* power, CDynBuffer* buffer); + + void SendAllOtherClients(TIndex index,TPower power, const char* data, ssize_t sizeOfData); + + void SendAllOtherClientsWithoutLoss(TIndex index, TPower power, const char* data, ssize_t sizeOfData); + + void SendAllClientsWithoutLoss(TPower power, const char* data, ssize_t sizeOfData); + + CInfoWifi* GetReferenceOnInfoWifiByCID(TCID cid) const; + + CInfoWifi* GetReferenceOnInfoWifiDeconnectedByCID(TCID cid) const; + + CInfoWifi* GetReferenceOnInfoWifiByIndex(TIndex index) const; + + void AddInfoWifiDeconnected(CInfoWifi infoWifi); + +}; + +#endif diff --git a/src/cwifiserveritcp.cc b/src/cwifiserveritcp.cc new file mode 100644 index 0000000..1d4debc --- /dev/null +++ b/src/cwifiserveritcp.cc @@ -0,0 +1,19 @@ +#include"cwifiserveritcp.h" + +CWifiServerITCP::CWifiServerITCP() : CWifiServer() +{ +} + +CWifiServerITCP::CWifiServerITCP(CListInfo* infoSockets, CListInfo* infoWifis, CListInfo* infoWifisDeconnected) : CWifiServer(infoSockets, infoWifis, infoWifisDeconnected) +{ +} + +bool CWifiServerITCP::_Listen(TDescriptor& master, TPort port) +{ + return CSocketServerFunctionITCP::_Listen(master, port); +} + +TDescriptor CWifiServerITCP::_Accept(TDescriptor master, TCID& cid) +{ + return CSocketServerFunctionITCP::_Accept(master, cid); +} diff --git a/src/cwifiserveritcp.h b/src/cwifiserveritcp.h new file mode 100644 index 0000000..809a7a5 --- /dev/null +++ b/src/cwifiserveritcp.h @@ -0,0 +1,22 @@ +#ifndef _CWIFISERVERITCP_H_ +#define _CWIFISERVERITCP_H_ + +#include "csocketserverfunctionitcp.h" +#include "cwifiserver.h" + +class CWifiServerITCP : public CWifiServer, public CSocketServerFunctionITCP +{ + public: + + CWifiServerITCP(); + + CWifiServerITCP(CListInfo* infoSockets, CListInfo* infoWifis, CListInfo* infoWifisDeconnected); + + private: + + bool _Listen(TDescriptor& master, TPort port) override; + + TDescriptor _Accept(TDescriptor master, TCID& cid) override; +}; + +#endif diff --git a/src/cwifiservervtcp.cc b/src/cwifiservervtcp.cc new file mode 100644 index 0000000..a9d6c42 --- /dev/null +++ b/src/cwifiservervtcp.cc @@ -0,0 +1,16 @@ +#include"cwifiservervtcp.h" + +CWifiServerVTCP::CWifiServerVTCP(CListInfo* infoSockets, CListInfo* infoWifis, CListInfo* infoWifisDeconnected) : CWifiServer(infoSockets, infoWifis, infoWifisDeconnected) +{ +} + +bool CWifiServerVTCP::_Listen(TDescriptor& master, TPort port) +{ + return CSocketServerFunctionVTCP::_Listen(master, port); +} + +TDescriptor CWifiServerVTCP::_Accept(TDescriptor master, TCID& cid) +{ + return CSocketServerFunctionVTCP::_Accept(master, cid); +} + diff --git a/src/cwifiservervtcp.h b/src/cwifiservervtcp.h new file mode 100644 index 0000000..6a46178 --- /dev/null +++ b/src/cwifiservervtcp.h @@ -0,0 +1,20 @@ +#ifndef _CWIFISERVERVTCP_H_ +#define _CWIFISERVERVTCP_H_ + +#include "csocketserverfunctionvtcp.h" +#include "cwifiserver.h" + +class CWifiServerVTCP : public CWifiServer, public CSocketServerFunctionVTCP +{ + public: + + CWifiServerVTCP(CListInfo* infoSockets, CListInfo* infoWifis, CListInfo* infoWifisDeconnected); + + private : + + bool _Listen(TDescriptor& master, TPort port) override; + + TDescriptor _Accept(TDescriptor master, TCID& cid) override; +}; + +#endif diff --git a/src/cwirelessdevice.cc b/src/cwirelessdevice.cc new file mode 100644 index 0000000..b0bcb12 --- /dev/null +++ b/src/cwirelessdevice.cc @@ -0,0 +1,107 @@ +#include "cwirelessdevice.h" + +#include +#include + +#include + +#include + +const std::regex wlan("wlan[0-9]*"); + +WirelessDevice::WirelessDevice(){ + +} + +WirelessDevice::~WirelessDevice(){ + +} + +WirelessDevice::WirelessDevice(const std::string & name,int index ,int iftype ,const struct ether_addr & macaddr,int txpower):_name(name),_index(index),_iftype(iftype), _txpower(txpower), _macaddr(macaddr), _machwsim(macaddr) { + +// _machwsim.ether_addr_octet[0] |= 0x40 ; + +// std::memcpy(&_macaddr,&macaddr,ETH_ALEN); + +} + +WirelessDevice::WirelessDevice(const std::string & name,int index ,int iftype ,const struct ether_addr & macaddr,const struct ether_addr & machwsim,int txpower):_name(name),_index(index),_iftype(iftype), _txpower(txpower), _macaddr(macaddr), _machwsim(machwsim) { + +} + +std::string WirelessDevice::getName() const { + + return _name ; +} + +struct ether_addr WirelessDevice::getMacaddr() const { + + return _macaddr ; + +} + +void WirelessDevice::setMachwsim(const struct ether_addr & machwsim) { + + _machwsim = machwsim ; +// std::memcpy(&_macaddr,&macaddr,ETH_ALEN); +} + +struct ether_addr WirelessDevice::getMachwsim() const { + + return _machwsim ; +} + +bool WirelessDevice::checkif_wireless_device(){ + + if (std::regex_match(_name,wlan)) + return true ; + else + return false; +} + +int WirelessDevice::getIndex() const { + + return _index ; +} + +int WirelessDevice::getTxPower() const { + + return _txpower ; +} + +// friend functions + +std::ostream & operator<< ( std::ostream & os , const WirelessDevice & wdevice ){ + + char macstring[18]; + char machwsimstring[18]; + + sprintf(macstring, "%02X:%02X:%02X:%02X:%02X:%02X", + wdevice._macaddr.ether_addr_octet[0], wdevice._macaddr.ether_addr_octet[1], wdevice._macaddr.ether_addr_octet[2], + wdevice._macaddr.ether_addr_octet[3], wdevice._macaddr.ether_addr_octet[4], wdevice._macaddr.ether_addr_octet[5]); + + sprintf(machwsimstring, "%02X:%02X:%02X:%02X:%02X:%02X", + wdevice._machwsim.ether_addr_octet[0], wdevice._machwsim.ether_addr_octet[1], wdevice._machwsim.ether_addr_octet[2], + wdevice._machwsim.ether_addr_octet[3], wdevice._machwsim.ether_addr_octet[4], wdevice._machwsim.ether_addr_octet[5]); + + os << "name: " << wdevice._name << std::endl ; + + os << "index: " << wdevice._index << std::endl ; + + /* ARPHRD_ETHER normal, ARPHRD_IEEE80211_RADIOTAP as monitor */ + if (wdevice._iftype == ARPHRD_ETHER) + os << "iftype: ARPHRD_ETHER" << std::endl ; + else if (wdevice._iftype == ARPHRD_IEEE80211_RADIOTAP) + os << "iftype: ARPHRD_IEEE80211_RADIOTAP" << std::endl; + else + os << "iftype: UNKNOWN" << std::endl; + + os << "mac:" << macstring << std::endl ; + + os << "mac hwsim:" << machwsimstring << std::endl ; + + os << "Tx-Power : " << wdevice._txpower / 100 << "." << wdevice._txpower % 100 << "dBm" << std::endl ; + + return os ; +} + diff --git a/src/cwirelessdevice.h b/src/cwirelessdevice.h new file mode 100644 index 0000000..7c5d9cc --- /dev/null +++ b/src/cwirelessdevice.h @@ -0,0 +1,60 @@ +#ifndef _WIRELESSDEVICE_H +#define _WIRELESSDEVICE_H + +#include + +#include +#include + +class WirelessDevice { + + std::string _name; + int _index; + int _iftype; + //unsigned char _macaddr[ETH_ALEN]; + int _txpower ; + struct ether_addr _macaddr ; + struct ether_addr _machwsim = {0x00,0X00,0x00,0X00,0x00,0X00}; + + public: + + WirelessDevice(); + ~WirelessDevice(); + + /** + * \fn WirelessDevice(std::string n,int i,int t,const struct ether_addr & m,const struct ether_addr & h); + * \biref Constructor + * \param n - interface name + * i - index + * t - type + * m - wireless net device mac address + * h - wireless net device mac address in hwsim driver + */ + WirelessDevice(const std::string &,int,int,const struct ether_addr &,const struct ether_addr &,int); + + /** + * \fn WirelessDevice(std::string n,int i,int t,const struct ether_addr & m); + * \biref Constructor + * \param n - interface name + * i - index + * t - type + * m - wireless net device mac address + */ + WirelessDevice(const std::string &,int,int,const struct ether_addr &,int); + + friend std::ostream & operator<< ( std::ostream & , const WirelessDevice &); + + struct ether_addr getMacaddr() const ; + struct ether_addr getMachwsim() const ; + + void setMachwsim(const struct ether_addr &); + + std::string getName() const ; + + bool checkif_wireless_device(); + int getIndex() const ; + int getTxPower() const ; + +}; + +#endif diff --git a/src/cwirelessdevicelist.cc b/src/cwirelessdevicelist.cc new file mode 100644 index 0000000..467161e --- /dev/null +++ b/src/cwirelessdevicelist.cc @@ -0,0 +1,102 @@ +/** + * \file cwirelessdevicelist.cc + * \brief manage std::list of WirelessDevice objects + * \author + * \version + */ + +#include "cwirelessdevicelist.h" +#include +#include // std::transform + +WirelessDeviceList::WirelessDeviceList(){ + +} + +WirelessDeviceList::~WirelessDeviceList(){ + +} + +bool WirelessDeviceList::get_device_by_mac(WirelessDevice & wdev , struct ether_addr macaddr) { + + _listaccess.lock(); + for (auto & wd : _wdevices_list){ + + struct ether_addr mac = wd.second.getMacaddr() ; + if(std::memcmp(&mac,&macaddr,ETH_ALEN) == 0){ + wdev = wd.second ; + _listaccess.unlock(); + return true ; + } + } + _listaccess.unlock(); + + return false ; +} + +void WirelessDeviceList::add_device(const WirelessDevice & wdevice){ + + _listaccess.lock(); + + _wdevices_list[wdevice.getIndex()] = wdevice ; + + _listaccess.unlock(); +} + +void WirelessDeviceList::delete_device(const WirelessDevice & wdevice){ + + _listaccess.lock(); + + _wdevices_list.erase(wdevice.getIndex()) ; + + _listaccess.unlock(); +} + +void WirelessDeviceList::delete_device(int index){ + + _listaccess.lock(); + + _wdevices_list.erase(index); + + _listaccess.unlock(); +} + +std::vector & WirelessDeviceList::list_devices() { + + std::vector * list_wd = new std::vector(); + list_wd->reserve(_wdevices_list.size()); + + _listaccess.lock(); + + std::transform (_wdevices_list.begin(), + _wdevices_list.end(), + back_inserter(*list_wd), + [] (std::pair const & pair) + { + return pair.second; + } + ); + + _listaccess.unlock(); + + return *(list_wd) ; + +} + +/** friend functions */ + +std::ostream & operator<< ( std::ostream & os , WirelessDeviceList & wdlist ){ + + wdlist._listaccess.lock(); + + for (const auto & wd : wdlist._wdevices_list){ + + os << wd.second; + os << std::endl ; + } + + wdlist._listaccess.unlock(); + + return os ; +} + diff --git a/src/cwirelessdevicelist.h b/src/cwirelessdevicelist.h new file mode 100644 index 0000000..27c779f --- /dev/null +++ b/src/cwirelessdevicelist.h @@ -0,0 +1,85 @@ +/** + * \file cwirelessdevicelist.h + * \brief manage std::list of WirelessDevice objects + * \author + * \version + */ + +#ifndef _CWIRELESSDEVICELIST_H_ +#define _CWIRELESSDEVICELIST_H_ + +#include +#include +#include + +#include "cwirelessdevice.h" + +/** + * \class WirelessDeviceList + * \brief This class represents a std::list of WirelessDevice objects + */ +class WirelessDeviceList { + + /** + * \brief manage threads access to wdevices_list + */ + std::mutex _listaccess ; + + /** + * \brief list of existing wireless network interfaces + */ + std::map _wdevices_list; + + public: + + WirelessDeviceList(); + ~WirelessDeviceList(); + + /** + * \fn add_device(int) + * \brief Add to _wdevices_list a wireless network device + * \param wdevice Wireless network device + * \return void + */ + void add_device(const WirelessDevice & wdevice); + + /** + * \fn delete_device(int) + * \brief Remove from _wdevice_list a wireless network device by index + * \param index Ifindex of wireless network device + * \return void + */ + void delete_device(int index); + + /** + * \fn delete_device(const WirelessDevice & wdevice) + * \brief Remove from _wdevice_list a wireless network device by index + * \param wdevice wireless network device to remove from _wdevices_list + * \return void + */ + void delete_device(const WirelessDevice & wdevice); + + /** + * \fn list_devices() + * \brief Get a list of all wireless network devices + * \return std::vector List of all devices + */ + std::vector & list_devices() ; + + /** + * \fn get_device_by_mac(struct ether_addr macaddr) + * \brief Get a device related to mac address + * \param wdev : WirelessDevice to find + * \param macaddr : mac address to find + * \return true if found and false otherwise + */ + bool get_device_by_mac(WirelessDevice & wdev , struct ether_addr macaddr); + + /** + * \brief << operator overidden + */ + friend std::ostream & operator<< ( std::ostream & , WirelessDeviceList &); + +}; + +#endif diff --git a/src/hwsim.h b/src/hwsim.h new file mode 100644 index 0000000..93a931d --- /dev/null +++ b/src/hwsim.h @@ -0,0 +1,16 @@ +#ifndef _HWSIM_H_ +#define _HWSIM_H_ + +#include "types.h" + +#define __packed __attribute__((packed)) + +#define BIT(x) (1 << (x)) + +#include "mac80211_hwsim.h" + +#define VERSION_NR 1 + +#endif /* _HWSIM_H_ */ + + diff --git a/src/ieee80211.h b/src/ieee80211.h new file mode 100644 index 0000000..7447c93 --- /dev/null +++ b/src/ieee80211.h @@ -0,0 +1,8 @@ +#ifndef IEEE80211_H_ +#define IEEE80211_H_ + +// From Kernel : include/net/mac80211.h +#define IEEE80211_TX_MAX_RATES 4 + +#endif /* IEEE80211_H_ */ + diff --git a/src/mac80211_hwsim.h b/src/mac80211_hwsim.h new file mode 100644 index 0000000..f32fc3a --- /dev/null +++ b/src/mac80211_hwsim.h @@ -0,0 +1,344 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 + * Copyright (c) 2008, Jouni Malinen + * Copyright (c) 2011, Javier Lopez + * Copyright (C) 2020, 2022-2024 Intel Corporation + */ + +#ifndef __MAC80211_HWSIM_H +#define __MAC80211_HWSIM_H + +/** + * enum hwsim_tx_control_flags - flags to describe transmission info/status + * + * These flags are used to give the wmediumd extra information in order to + * modify its behavior for each frame + * + * @HWSIM_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. + * @HWSIM_TX_CTL_NO_ACK: tell the wmediumd not to wait for an ack + * @HWSIM_TX_STAT_ACK: Frame was acknowledged + * + */ +enum hwsim_tx_control_flags { + HWSIM_TX_CTL_REQ_TX_STATUS = BIT(0), + HWSIM_TX_CTL_NO_ACK = BIT(1), + HWSIM_TX_STAT_ACK = BIT(2), +}; + +/** + * DOC: Frame transmission/registration support + * + * Frame transmission and registration support exists to allow userspace + * entities such as wmediumd to receive and process all broadcasted + * frames from a mac80211_hwsim radio device. + * + * This allow user space applications to decide if the frame should be + * dropped or not and implement a wireless medium simulator at user space. + * + * Registration is done by sending a register message to the driver and + * will be automatically unregistered if the user application doesn't + * responds to sent frames. + * Once registered the user application has to take responsibility of + * broadcasting the frames to all listening mac80211_hwsim radio + * interfaces. + * + * For more technical details, see the corresponding command descriptions + * below. + */ + +/** + * enum hwsim_commands - supported hwsim commands + * + * @HWSIM_CMD_UNSPEC: unspecified command to catch errors + * + * @HWSIM_CMD_REGISTER: request to register and received all broadcasted + * frames by any mac80211_hwsim radio device. + * @HWSIM_CMD_FRAME: send/receive a broadcasted frame from/to kernel/user + * space, uses: + * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER, + * %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE, + * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional) + * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to + * kernel, uses: + * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, + * %HWSIM_ATTR_TX_INFO, %WSIM_ATTR_TX_INFO_FLAGS, + * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE + * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters, + * returns the radio ID (>= 0) or negative on errors, if successful + * then multicast the result, uses optional parameter: + * %HWSIM_ATTR_REG_STRICT_REG, %HWSIM_ATTR_SUPPORT_P2P_DEVICE, + * %HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, %HWSIM_ATTR_CHANNELS, + * %HWSIM_ATTR_NO_VIF, %HWSIM_ATTR_RADIO_NAME, %HWSIM_ATTR_USE_CHANCTX, + * %HWSIM_ATTR_REG_HINT_ALPHA2, %HWSIM_ATTR_REG_CUSTOM_REG, + * %HWSIM_ATTR_PERM_ADDR + * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted + * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses: + * %HWSIM_ATTR_RADIO_ID + * @HWSIM_CMD_ADD_MAC_ADDR: add a receive MAC address (given in the + * %HWSIM_ATTR_ADDR_RECEIVER attribute) to a device identified by + * %HWSIM_ATTR_ADDR_TRANSMITTER. This lets wmediumd forward frames + * to this receiver address for a given station. + * @HWSIM_CMD_DEL_MAC_ADDR: remove the MAC address again, the attributes + * are the same as to @HWSIM_CMD_ADD_MAC_ADDR. + * @HWSIM_CMD_START_PMSR: request to start peer measurement with the + * %HWSIM_ATTR_PMSR_REQUEST. Result will be sent back asynchronously + * with %HWSIM_CMD_REPORT_PMSR. + * @HWSIM_CMD_ABORT_PMSR: Abort previously started peer measurement. + * @HWSIM_CMD_REPORT_PMSR: Report peer measurement data. + * @__HWSIM_CMD_MAX: enum limit + */ +enum hwsim_commands { + HWSIM_CMD_UNSPEC, + HWSIM_CMD_REGISTER, + HWSIM_CMD_FRAME, + HWSIM_CMD_TX_INFO_FRAME, + HWSIM_CMD_NEW_RADIO, + HWSIM_CMD_DEL_RADIO, + HWSIM_CMD_GET_RADIO, + HWSIM_CMD_ADD_MAC_ADDR, + HWSIM_CMD_DEL_MAC_ADDR, + HWSIM_CMD_START_PMSR, + HWSIM_CMD_ABORT_PMSR, + HWSIM_CMD_REPORT_PMSR, + __HWSIM_CMD_MAX, +}; +#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) + +#define HWSIM_CMD_CREATE_RADIO HWSIM_CMD_NEW_RADIO +#define HWSIM_CMD_DESTROY_RADIO HWSIM_CMD_DEL_RADIO + +/** + * enum hwsim_attrs - hwsim netlink attributes + * + * @HWSIM_ATTR_UNSPEC: unspecified attribute to catch errors + * + * @HWSIM_ATTR_ADDR_RECEIVER: MAC address of the radio device that + * the frame is broadcasted to + * @HWSIM_ATTR_ADDR_TRANSMITTER: MAC address of the radio device that + * the frame was broadcasted from + * @HWSIM_ATTR_FRAME: Data array + * @HWSIM_ATTR_FLAGS: mac80211 transmission flags, used to process + * properly the frame at user space + * @HWSIM_ATTR_RX_RATE: estimated rx rate index for this frame at user + * space + * @HWSIM_ATTR_SIGNAL: estimated RX signal for this frame at user + * space + * @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array + * @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame + * @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_CREATE_RADIO + * command giving the number of channels supported by the new radio + * @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO + * only to destroy a radio + * @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatoro driver hint + * (nla string, length 2) + * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute) + * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute) + * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag) + * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO + * command to force use of channel contexts even when only a + * single channel is supported + * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO + * command to force radio removal when process that created the radio dies + * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666 + * @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio. + * @HWSIM_ATTR_PAD: padding attribute for 64-bit values, ignore + * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received. + * @HWSIM_ATTR_TX_INFO_FLAGS: additional flags for corresponding + * rates of %HWSIM_ATTR_TX_INFO + * @HWSIM_ATTR_PERM_ADDR: permanent mac address of new radio + * @HWSIM_ATTR_IFTYPE_SUPPORT: u32 attribute of supported interface types bits + * @HWSIM_ATTR_CIPHER_SUPPORT: u32 array of supported cipher types + * @HWSIM_ATTR_MLO_SUPPORT: claim MLO support (exact parameters TBD) for + * the new radio + * @HWSIM_ATTR_PMSR_SUPPORT: nested attribute used with %HWSIM_CMD_CREATE_RADIO + * to provide peer measurement capabilities. (nl80211_peer_measurement_attrs) + * @HWSIM_ATTR_PMSR_REQUEST: nested attribute used with %HWSIM_CMD_START_PMSR + * to provide details about peer measurement request (nl80211_peer_measurement_attrs) + * @HWSIM_ATTR_PMSR_RESULT: nested attributed used with %HWSIM_CMD_REPORT_PMSR + * to provide peer measurement result (nl80211_peer_measurement_attrs) + * @HWSIM_ATTR_MULTI_RADIO: Register multiple wiphy radios (flag). + * Adds one radio for each band. Number of supported channels will be set for + * each radio instead of for the wiphy. + * @__HWSIM_ATTR_MAX: enum limit + */ +enum hwsim_attrs { + HWSIM_ATTR_UNSPEC, + HWSIM_ATTR_ADDR_RECEIVER, + HWSIM_ATTR_ADDR_TRANSMITTER, + HWSIM_ATTR_FRAME, + HWSIM_ATTR_FLAGS, + HWSIM_ATTR_RX_RATE, + HWSIM_ATTR_SIGNAL, + HWSIM_ATTR_TX_INFO, + HWSIM_ATTR_COOKIE, + HWSIM_ATTR_CHANNELS, + HWSIM_ATTR_RADIO_ID, + HWSIM_ATTR_REG_HINT_ALPHA2, + HWSIM_ATTR_REG_CUSTOM_REG, + HWSIM_ATTR_REG_STRICT_REG, + HWSIM_ATTR_SUPPORT_P2P_DEVICE, + HWSIM_ATTR_USE_CHANCTX, + HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, + HWSIM_ATTR_RADIO_NAME, + HWSIM_ATTR_NO_VIF, + HWSIM_ATTR_FREQ, + HWSIM_ATTR_PAD, + HWSIM_ATTR_TX_INFO_FLAGS, + HWSIM_ATTR_PERM_ADDR, + HWSIM_ATTR_IFTYPE_SUPPORT, + HWSIM_ATTR_CIPHER_SUPPORT, + HWSIM_ATTR_MLO_SUPPORT, + HWSIM_ATTR_PMSR_SUPPORT, + HWSIM_ATTR_PMSR_REQUEST, + HWSIM_ATTR_PMSR_RESULT, + HWSIM_ATTR_MULTI_RADIO, + __HWSIM_ATTR_MAX, +}; +#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) + +/** + * struct hwsim_tx_rate - rate selection/status + * + * @idx: rate index to attempt to send with + * @count: number of tries in this rate before going to the next rate + * + * A value of -1 for @idx indicates an invalid rate and, if used + * in an array of retry rates, that no more rates should be tried. + * + * When used for transmit status reporting, the driver should + * always report the rate and number of retries used. + * + */ +struct hwsim_tx_rate { + s8 idx; + u8 count; +} __packed; + +/** + * enum hwsim_tx_rate_flags - per-rate flags set by the rate control algorithm. + * Inspired by structure mac80211_rate_control_flags. New flags may be + * appended, but old flags not deleted, to keep compatibility for + * userspace. + * + * These flags are set by the Rate control algorithm for each rate during tx, + * in the @flags member of struct ieee80211_tx_rate. + * + * @MAC80211_HWSIM_TX_RC_USE_RTS_CTS: Use RTS/CTS exchange for this rate. + * @MAC80211_HWSIM_TX_RC_USE_CTS_PROTECT: CTS-to-self protection is required. + * This is set if the current BSS requires ERP protection. + * @MAC80211_HWSIM_TX_RC_USE_SHORT_PREAMBLE: Use short preamble. + * @MAC80211_HWSIM_TX_RC_MCS: HT rate. + * @MAC80211_HWSIM_TX_RC_VHT_MCS: VHT MCS rate, in this case the idx field is + * split into a higher 4 bits (Nss) and lower 4 bits (MCS number) + * @MAC80211_HWSIM_TX_RC_GREEN_FIELD: Indicates whether this rate should be used + * in Greenfield mode. + * @MAC80211_HWSIM_TX_RC_40_MHZ_WIDTH: Indicates if the Channel Width should be + * 40 MHz. + * @MAC80211_HWSIM_TX_RC_80_MHZ_WIDTH: Indicates 80 MHz transmission + * @MAC80211_HWSIM_TX_RC_160_MHZ_WIDTH: Indicates 160 MHz transmission + * (80+80 isn't supported yet) + * @MAC80211_HWSIM_TX_RC_DUP_DATA: The frame should be transmitted on both of + * the adjacent 20 MHz channels, if the current channel type is + * NL80211_CHAN_HT40MINUS or NL80211_CHAN_HT40PLUS. + * @MAC80211_HWSIM_TX_RC_SHORT_GI: Short Guard interval should be used for this + * rate. + */ +enum hwsim_tx_rate_flags { + MAC80211_HWSIM_TX_RC_USE_RTS_CTS = BIT(0), + MAC80211_HWSIM_TX_RC_USE_CTS_PROTECT = BIT(1), + MAC80211_HWSIM_TX_RC_USE_SHORT_PREAMBLE = BIT(2), + + /* rate index is an HT/VHT MCS instead of an index */ + MAC80211_HWSIM_TX_RC_MCS = BIT(3), + MAC80211_HWSIM_TX_RC_GREEN_FIELD = BIT(4), + MAC80211_HWSIM_TX_RC_40_MHZ_WIDTH = BIT(5), + MAC80211_HWSIM_TX_RC_DUP_DATA = BIT(6), + MAC80211_HWSIM_TX_RC_SHORT_GI = BIT(7), + MAC80211_HWSIM_TX_RC_VHT_MCS = BIT(8), + MAC80211_HWSIM_TX_RC_80_MHZ_WIDTH = BIT(9), + MAC80211_HWSIM_TX_RC_160_MHZ_WIDTH = BIT(10), +}; + +/** + * struct hwsim_tx_rate_flag - rate selection/status + * + * @idx: rate index to attempt to send with + * @flags: the rate flags according to &enum hwsim_tx_rate_flags + * + * A value of -1 for @idx indicates an invalid rate and, if used + * in an array of retry rates, that no more rates should be tried. + * + * When used for transmit status reporting, the driver should + * always report the rate and number of retries used. + * + */ +struct hwsim_tx_rate_flag { + s8 idx; + u16 flags; +} __packed; + +/** + * DOC: Frame transmission support over virtio + * + * Frame transmission is also supported over virtio to allow communication + * with external entities. + */ + +/** + * enum hwsim_vqs - queues for virtio frame transmission + * + * @HWSIM_VQ_TX: send frames to external entity + * @HWSIM_VQ_RX: receive frames and transmission info reports + * @HWSIM_NUM_VQS: enum limit + */ +enum hwsim_vqs { + HWSIM_VQ_TX, + HWSIM_VQ_RX, + HWSIM_NUM_VQS, +}; + +/** + * enum hwsim_rate_info_attributes - bitrate information. + * + * Information about a receiving or transmitting bitrate + * that can be mapped to struct rate_info + * + * @__HWSIM_RATE_INFO_ATTR_INVALID: reserved, netlink attribute 0 is invalid + * @HWSIM_RATE_INFO_ATTR_FLAGS: bitflag of flags from &enum rate_info_flags + * @HWSIM_RATE_INFO_ATTR_MCS: mcs index if struct describes an HT/VHT/HE rate + * @HWSIM_RATE_INFO_ATTR_LEGACY: bitrate in 100kbit/s for 802.11abg + * @HWSIM_RATE_INFO_ATTR_NSS: number of streams (VHT & HE only) + * @HWSIM_RATE_INFO_ATTR_BW: bandwidth (from &enum rate_info_bw) + * @HWSIM_RATE_INFO_ATTR_HE_GI: HE guard interval (from &enum nl80211_he_gi) + * @HWSIM_RATE_INFO_ATTR_HE_DCM: HE DCM value + * @HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC: HE RU allocation (from &enum nl80211_he_ru_alloc, + * only valid if bw is %RATE_INFO_BW_HE_RU) + * @HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH: In case of EDMG the number of bonded channels (1-4) + * @HWSIM_RATE_INFO_ATTR_EHT_GI: EHT guard interval (from &enum nl80211_eht_gi) + * @HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC: EHT RU allocation (from &enum nl80211_eht_ru_alloc, + * only valid if bw is %RATE_INFO_BW_EHT_RU) + * @NUM_HWSIM_RATE_INFO_ATTRS: internal + * @HWSIM_RATE_INFO_ATTR_MAX: highest attribute number + */ +enum hwsim_rate_info_attributes { + __HWSIM_RATE_INFO_ATTR_INVALID, + + HWSIM_RATE_INFO_ATTR_FLAGS, + HWSIM_RATE_INFO_ATTR_MCS, + HWSIM_RATE_INFO_ATTR_LEGACY, + HWSIM_RATE_INFO_ATTR_NSS, + HWSIM_RATE_INFO_ATTR_BW, + HWSIM_RATE_INFO_ATTR_HE_GI, + HWSIM_RATE_INFO_ATTR_HE_DCM, + HWSIM_RATE_INFO_ATTR_HE_RU_ALLOC, + HWSIM_RATE_INFO_ATTR_N_BOUNDED_CH, + HWSIM_RATE_INFO_ATTR_EHT_GI, + HWSIM_RATE_INFO_ATTR_EHT_RU_ALLOC, + + /* keep last */ + NUM_HWSIM_RATE_INFO_ATTRS, + HWSIM_RATE_INFO_ATTR_MAX = NUM_HWSIM_RATE_INFO_ATTRS - 1 +}; + +#endif /* __MAC80211_HWSIM_H */ diff --git a/src/tools.cc b/src/tools.cc new file mode 100644 index 0000000..9c98aa2 --- /dev/null +++ b/src/tools.cc @@ -0,0 +1,71 @@ +#include // NULL +#include // struct sockaddr_in & inet_ntoa & ntohs + +#include "tools.h" + +#include // assert + +bool HashUsesPort=false; + +unsigned long hash_ipaddr(struct sockaddr_in* addr) +{ + unsigned long res; + + assert( addr != NULL ); + + res = (((addr->sin_addr.s_addr >> 24) & 0xff) * 256) + + (((addr->sin_addr.s_addr >> 16) & 0xff) * 256) + + (((addr->sin_addr.s_addr >> 8) & 0xff)* 256) + + (addr->sin_addr.s_addr & 0xff); + + if( HashUsesPort ) + res += addr->sin_port; + + return res; +} + +bool isInt(const char *str) { + + if( *str == '-' || *str == '+' ) + str++; + + while (*str) { + if( *str < '0' || *str > '9' ) + return false; + str++; + } + return true; +} + +bool isPositiveInt(const char *str) +{ + if( *str == '-' ) + return false; + + return isInt(str); +} + +bool isIntOrFloat(const char *str) { + bool seeDot=false; + bool seeDigit=false; + + if (*str == '-' || *str == '+') + str++; + + while (*str) { + if( *str == '.' ) + { + if( seeDot ) + return false; + seeDot=true; + } + else + { + if( *str < '0' || *str > '9' ) + return false; + seeDigit=true; + } + str++; + } + return seeDigit; +} diff --git a/src/tools.h b/src/tools.h new file mode 100644 index 0000000..f6f53ee --- /dev/null +++ b/src/tools.h @@ -0,0 +1,14 @@ +#ifndef _TOOLS_H_ +#define _TOOLS_H_ + +extern bool HashUsesPort; + +unsigned long hash_ipaddr(struct sockaddr_in* addr); + +bool isInt(const char *str); + +bool isPositiveInt(const char *str); + +bool isIntOrFloat(const char *str); + +#endif diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..db70605 --- /dev/null +++ b/src/types.h @@ -0,0 +1,54 @@ +#ifndef _TYPES_H_ +#define _TYPES_H_ + +#include + +typedef int8_t s8; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint64_t u64; +typedef int32_t s32; +typedef uint32_t u32; + +// int +typedef s32 TValue; + +// unsigned int +typedef u32 TCID; + +enum TOrder { + TORDER_NO, TORDER_LIST, TORDER_SHOW, TORDER_CHANGE_COORDINATE, TORDER_SETNAME, TORDER_PACKET_LOSS, TORDER_STATUS, TORDER_DISTANCE_BETWEEN_CID, TORDER_SET_SCALE, TORDER_CLOSE_ALL_CLIENT +}; + +// int +typedef s32 TDescriptor; + +// unsigned int +typedef u32 TIndex; + +// int +typedef s32 TSocket; +// AF_INET : use IP +// AF_VSOCK : use vsock + +// unsigned short +typedef u16 TPort; + +// char +typedef s8 TPower; // empirical observed values with int : [-123,20] +const TPower TPower_MAX=-10; // dBm is always negative. -10 is an empirical value +const TPower TPower_MIN=INT8_MIN; + +// double +typedef double TDistance; // in meters +typedef double TScale; + +// u32 +typedef u32 TFrequency; // Hz + +// unsigned short +typedef u16 TMinimalSize; + +typedef u8 TByte; + +#endif diff --git a/src/vwifi-add-interfaces.cc b/src/vwifi-add-interfaces.cc new file mode 100644 index 0000000..263ff6f --- /dev/null +++ b/src/vwifi-add-interfaces.cc @@ -0,0 +1,107 @@ +/* + From : https://android.googlesource.com/device/generic/goldfish/+/refs/heads/master/wifi/mac80211_create_radios/main.cpp + Licence http://www.apache.org/licenses/LICENSE-2.0 +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include // getuid + +#include "config_hwsim.h" +#include "addinterfaces.h" +#include "config.h" // DEFAULT_MAC_PREFIX + +int ParseInt(const char* str, int* result) +{ + return sscanf(str, "%d", result); +} + +int help(FILE* dst, const int ret) +{ + fprintf(dst, "%s", + "Usage:\n" + " vwifi-add-interfaces [-h] [-v] n_radios mac_prefix\n" + " vwifi-add-interfaces [--help] [--version] n_radios mac_prefix\n" + " where\n" + " n_radios - int, [1,100], e.g. 2\n" + " mac_prefix - xx:xx:xx:xx:xx (if n_radios > 1 then only the first 5 bytes are used\n" + " then all bytes are used)\n\n" + " vwifi-add-interfaces will create n_radios with MAC addresses xx:xx:xx:xx:xx:nn\n" + " where xx:xx:xx:xx:xx is the mac_prefix specified\n" + " and nn is incremented (from zero, and only if n_radios > 1)\n"); + return ret; +} + +int main(int argc, char* argv[]) +{ + int nRadios; + TByte macPrefix[ETH_ALEN]= {}; + + if( argc == 1 ) + return help(stdout,0); + + if( ! ParseAddress(DEFAULT_MAC_PREFIX,macPrefix) ) + return help(stderr, 6); + if( strlen(DEFAULT_MAC_PREFIX) <= 8 ) + { // if possible, randomize the 4th byte + srand(time(NULL)); + macPrefix[3]=rand()%100; + } + + int arg_idx = 1; + int arg_used = 1; + while (arg_idx < argc) + { + if( ! strcmp("-v", argv[arg_idx]) || ! strcmp("--version", argv[arg_idx]) ) + { + fprintf(stdout,"Version : %s\n",VERSION); + return 0; + } + if( ! strcmp("-h", argv[arg_idx]) || ! strcmp("--help", argv[arg_idx]) ) + { + return help(stdout,0); + } + if( argv[arg_idx][0] == '-' ) + { + fprintf(stderr,"Error : unknown parameter : %s\n",argv[arg_idx]); + return help(stderr, 1); + } + switch ( arg_used ) + { + case 1 : + if (!ParseInt(argv[arg_idx], &nRadios)) + return help(stderr, 2); + if (nRadios < 1) + return help(stderr, 3); + if (nRadios > 100) + return help(stderr, 4); + + arg_used++; + break; + case 2 : + if( strlen(argv[arg_idx]) > 17 ) + return help(stderr, 5); + if( ! ParseAddress(argv[arg_idx],macPrefix) ) + return help(stderr, 6); + + arg_used++; + break; + } + + arg_idx++; + } + + if( getuid() ) + { + fprintf(stderr,"Error : This program must be run as root!!\n"); + return 2; + } + + return ManageRadios(nRadios, macPrefix); +} diff --git a/src/vwifi-client.cc b/src/vwifi-client.cc new file mode 100644 index 0000000..e20f0d4 --- /dev/null +++ b/src/vwifi-client.cc @@ -0,0 +1,223 @@ +#include +#include +#include +#include // strcmp + +#include + +#include "config.h" // DEFAULT_WIFI_CLIENT_PORT_VHOST / DEFAULT_WIFI_CLIENT_PORT_INET +#include "tools.h" // isInt + +#include "cwificlient.h" +#ifdef ENABLE_VHOST +#include "csocketclientvtcp.h" +#endif +#include "csocketclientitcp.h" + +#include "addinterfaces.h" + +enum STATE { + + STARTED=1, + STOPPED , + SUSPENDED +}; + +CKernelWifi* wifiClient; + +enum STATE _state = STOPPED ; + + +void signal_handler(int signal_num) +{ + + switch(signal_num) + { + case SIGINT : + case SIGTERM : + case SIGQUIT : + + std::cout << signal_num << std::endl ; + wifiClient->stop() ; + _state = STOPPED ; + break ; + + case SIGTSTP: + + std::cout << "This signal is ignored" << std::endl ; + break ; + + + default : + std::cerr << "Signal not handled" << std::endl ; + + } + + std::cout << "OUT SWITCH" << std::endl ; +} + +void help() +{ +#ifdef ENABLE_VHOST + std::cout<<"Usage: vwifi-client [-h] [-v] [-s] [IP_ADDR] [-p PORT] [-u] [-n NUMBER_INTERFACE] [-m MAC_PREFIX]"< 100) + { + std::cerr<<"Error : NUMBER > 100"< 17 ) + { + std::cerr<<"Error : the MAC_PREFIX is too long"<; + static_cast*>(wifiClient)->Init(ip_addr.c_str(), port_number); + } + else + { + if( ip_addr.empty() ) + { // IP not set -> mode VHOST +#ifdef ENABLE_VHOST + if( ! port_number ) + port_number = DEFAULT_WIFI_CLIENT_PORT_VHOST; + + std::cout<<"Type : AF_VSOCK"<; + static_cast*>(wifiClient)->Init(port_number); +#else + std::cerr<<"Error : This program is not build with VHOST!!"<; + static_cast*>(wifiClient)->Init(ip_addr.c_str(), port_number); + } + } + + if(!wifiClient->start()) + std::cout << "Starting process aborted" << std::endl ; + + + + std::cout << "Good Bye (:-)" << std::endl ; + + _exit(EXIT_SUCCESS); + +} diff --git a/src/vwifi-ctrl.cc b/src/vwifi-ctrl.cc new file mode 100644 index 0000000..8ed537a --- /dev/null +++ b/src/vwifi-ctrl.cc @@ -0,0 +1,807 @@ +#include // cout + +#include //strlen + +#include "config.h" +#include "tools.h" // isInt isPositiveInt isIntOrFloat +#include "csocketclientitcp.h" +#include "types.h" +#include "ccoordinate.h" // CCoordinate +#include "cinfowifi.h" + +using namespace std; + +std::string IP_Ctrl = std::string(DEFAULT_ADDRESS_IP); +TPort Port_Ctrl = DEFAULT_CTRL_PORT; + +char* NameOfProg; + +void Help() +{ + cout<(&cid),sizeof(cid)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : GetCInfoWifi : socket.Read : cid"<(&coo),sizeof(coo)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : GetCInfoWifi : socket.Read : CCoordinate (cid:"<(&sizeName),sizeof(sizeName)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : GetCInfoWifi : socket.Read : size of name (cid:"< MAX_SIZE_NAME ) + { + cerr<<"Error : GetCInfoWifi : size of name > "< 0 ) + { + err=socket.Read(reinterpret_cast(strName),sizeName+1); // +1 : \0 + if( err == SOCKET_ERROR ) + { + cerr<<"Error : GetCInfoWifi : socket.Read : size of name (cid:"<SetCid(cid); + infoWifi->Set(coo); + + string name(strName); + infoWifi->SetName(name); + + return 0; +} + +int AskList() +{ + CSocketClientITCP socket; + + socket.Init(IP_Ctrl.c_str(),Port_Ctrl); + + if( ! socket.ConnectLoop() ) + { + cerr<<"Error : ls : socket.Connect error"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : ls : socket.Send : order"<(&number),sizeof(number)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : ls : socket.Read : number"<(&number),sizeof(number)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : ls : socket.Read : number"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : set : socket.Send : order"<(&cid),sizeof(cid)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : set : socket.Send : cid"<(&coo),sizeof(coo)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : set : socket.Send : "< MAX_SIZE_NAME ) + { + name.resize(MAX_SIZE_NAME); + sizeName=MAX_SIZE_NAME; + } + + cout<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : setname : socket.Send : order"<(&cid),sizeof(cid)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : setname : socket.Send : cid"<(&sizeName),sizeof(sizeName)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : setname : socket.Send : size of name"<(name.c_str()),sizeName+1); // +1 : \0 + if( err == SOCKET_ERROR ) + { + cerr<<"Error : setname : socket.Send : name"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : loss : socket.Send : order"<(&value),sizeof(value)); + if( err == SOCKET_ERROR ) + { + if ( value ) + cerr<<"Error : loss : socket.Send : yes"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : status : socket.Send : Order"<(&loss),sizeof(loss)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : status : socket.Read : Loss"<(&scale),sizeof(scale)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : status : socket.Read : scale"<(&port),sizeof(port)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : status : socket.Read : Port VHOST"<(&port),sizeof(port)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : status : socket.Read : Port INET"<(&size),sizeof(size)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : status : socket.Read : Size INET"<(&spyIsConnected),sizeof(spyIsConnected)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : status : socket.Read : spyIsConnected"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : show : socket.Send : Order"<(&loss),sizeof(loss)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : show : socket.Read : Loss"<(&scale),sizeof(scale)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : show : socket.Read : scale"<(&spyIsConnected),sizeof(spyIsConnected)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : show : socket.Read : spyIsConnected"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : distance : socket.Send : order"<(&cid1),sizeof(cid1)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : distance : socket.Send : cid 1"<(&cid2),sizeof(cid2)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : distance : socket.Send : cid 2"<(&codeError),sizeof(codeError)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : distance : socket.Read : codeError"<(&distance),sizeof(distance)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : distance : socket.Read : distance"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : scale : socket.Send : order"<(&scale),sizeof(scale)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : scale : socket.Send : scale"<(&order),sizeof(order)); + if( err == SOCKET_ERROR ) + { + cerr<<"Error : close : socket.Send : order"< + +#include +#include + + +MonitorWirelessDevice monitor ; + + +void signal_handler([[maybe_unused]] int signal_num) +{ + std::cout << __func__ << std::endl ; + monitor.stop(); +} + + + +int main (){ + + + /* Handle signals */ + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGQUIT, signal_handler); + signal(SIGHUP, SIG_IGN); + + + +/* struct ether_addr mac { 0xff, 0x00, 0x00,0x00, 0xfe, 0x00 }; + struct ether_addr mac3 { 0xaa, 0xbb, 0x00,0x00, 0xfe, 0x00 }; + + WirelessDevice wdevice("wlan0",4,5,mac); + std::cout << wdevice << std::endl ; + + WirelessDevice wdevice2 ; + wdevice2 = wdevice; + + wdevice.setMacaddr(mac3); + + std::cout << wdevice2 << std::endl ; + std::cout << wdevice << std::endl ; +*/ + + monitor.start(); + + pause(); + + std::cout << "end" << std::endl ; + + return 0 ; + +} diff --git a/src/vwifi-server.cc b/src/vwifi-server.cc new file mode 100644 index 0000000..2ddbb37 --- /dev/null +++ b/src/vwifi-server.cc @@ -0,0 +1,309 @@ +#include // cout + +#include // strcmp + +#include "config.h" +#include "tools.h" // isPositiveInt +#include "cwifiserveritcp.h" +#ifdef ENABLE_VHOST + #include "cwifiservervtcp.h" +#endif +#include "cctrlserver.h" +#include "cselect.h" +#include "cdynbuffer.h" + +using namespace std; + +CDynBuffer Buffer; // Buffer to stock received values +#ifdef ENABLE_VHOST +TPort Port_VHOST = DEFAULT_WIFI_CLIENT_PORT_VHOST; +#endif +TPort Port_TCP = DEFAULT_WIFI_CLIENT_PORT_INET; +TPort Port_Spy = DEFAULT_WIFI_SPY_PORT; +TPort Port_Ctrl = DEFAULT_CTRL_PORT; + +CSelect Scheduler; + +void RemoveClient(CWifiServer* srv, bool srvIsSpy, TIndex i, TDescriptor socket) +{ + if( ! srvIsSpy ) + { + cout<<"Client disconnected : "; srv->ShowInfoWifi(i) ; cout<GetReferenceOnInfoWifiByIndex(i)->GetCid() <CloseClient(i); + + //del master socket to set + Scheduler.DelNode(socket); +} + +void ForwardData(bool srcIsSpy, CWifiServer* src, CWifiServer* otherDst) +{ + int valread; + TPower power; + + for ( TIndex i = 0 ; i < src->GetNumberClient() ; ) + { + TDescriptor socket = (*src)[i]; + + if( ! src->IsEnable(i) ) + { + RemoveClient(src, srcIsSpy , i, socket); + + continue; + } + + if( Scheduler.DescriptorHasAction(socket) ) + { + //Check if it was for closing , and also read the + //incoming message + + valread=src->RecvSignal(socket,&power,&Buffer); + if( valread <=0 ) + { + RemoveClient(src, srcIsSpy , i, socket); + + continue; + } + + if( ! srcIsSpy ) + { + src->SendAllOtherClients(i,power,Buffer.GetBuffer(),valread); + otherDst->SendAllClientsWithoutLoss(power,Buffer.GetBuffer(),valread); + } + else + { + src->SendAllOtherClientsWithoutLoss(i,power,Buffer.GetBuffer(),valread); + otherDst->SendAllClientsWithoutLoss(power,Buffer.GetBuffer(),valread); + } + } + + i++; + } +} + +int vwifi_server() +{ + TDescriptor socket; + + CListInfo infoSockets; + CListInfo infoWifis; + CListInfo infoWifisDeconnected; + +#ifdef ENABLE_VHOST + CWifiServerVTCP wifiServerVTCP(&infoSockets,&infoWifis,&infoWifisDeconnected); + cout<<"CLIENT VHOST : "; + wifiServerVTCP.Init(Port_VHOST); + if( ! wifiServerVTCP.Listen(WIFI_MAX_DECONNECTED_CLIENT) ) + { + cerr<<"Error : wifiServerVTCP.Listen"<ShowInfoWifi(wifiServer->GetNumberClient()-1) ; cout<ShowInfoWifi(wifiServer->GetNumberClient()-1) ; cout<GetCid()<&2 echo -e "${CERROR}Error: Your GNS3 project must be open !!!${SansCouleur}" + exit 2 +fi + +if [ -z "$(pgrep 'vwifi-server')" ] +then + >&2 echo -e "${CERROR}Error: vwifi-server is not started !!!${SansCouleur}" + exit 2 +fi + +# récupère l'identifiant du projet +IdProjet=$(wget -q --user="$LOGIN" --password="$PASSWORD" "http://${SERVER}:3080/v2/projects" -O - | jq -M -r --unbuffered '.[] | select (.status=="opened") | .project_id') +if [ -z "${IdProjet}" ] +then + >&2 echo -e "${CERROR}Error: No project is open !!!${SansCouleur}" + exit 2 +fi + +# récupère la configuration du projet +ConfigProjectGNS3="$(mktemp fast-vwifi-update.XXXXXXXXXX --tmpdir=/tmp)" +wget -q --user="$LOGIN" --password="$PASSWORD" "http://${SERVER}:3080/v2/projects/${IdProjet}/nodes" -O "${ConfigProjectGNS3}" + +NbValue=0 +VMWithWifi=false + +IFS=$'\n' +for line in $(jq -M '.[] | select (.node_type=="qemu") | {name: .name, x: .x, y: .y, z: .z , option: .command_line} ' "${ConfigProjectGNS3}") +do + if [[ "${line}" =~ ^[[:space:]]+\"name\":.* ]] + then + ((NbValue++)) + # attention au decallage du print (?) + Name=$(echo "${line}" | awk -F '[:, ]' '{print $5}' | tr -d '"' ) + elif [[ "${line}" =~ ^[[:space:]]+\"x\":.* ]] + then + ((NbValue++)) + # attention au decallage du print (?) + X=$(echo "${line}" | awk -F '[:, ]' '{print $5}') + elif [[ "${line}" =~ ^[[:space:]]+\"y\":.* ]] + then + ((NbValue++)) + # attention au decallage du print (?) + Y=$(echo "${line}" | awk -F '[:, ]' '{print $5}') + elif [[ "${line}" =~ ^[[:space:]]+\"z\":.* ]] + then + ((NbValue++)) + # attention au decallage du print (?) + Z=$(echo "${line}" | awk -F '[:, ]' '{print $5}') + elif [[ "${line}" =~ ^[[:space:]]+\"option\":.* ]] + then + ((NbValue++)) + CID=$(echo "${line}" | grep -E -o 'id='${OptionVWifiQEmu}',guest-cid=[[:digit:]]+' | sed 's/id='${OptionVWifiQEmu}',guest-cid=//') + if [ -n "${CID}" ] + then + VMWithWifi=true + fi + fi + + if (( NbValue == 5 )) + then + NbValue=0 + if ${VMWithWifi} + then + echo "${CID}" "(${Name})" "${X}" "${Y}" "${Z}" + vwifi-ctrl setname "${CID}" "${Name}" > /dev/null + vwifi-ctrl set "${CID}" "${X}" "${Y}" "${Z}" > /dev/null + VMWithWifi=false + fi + fi +done + +rm -f "${ConfigProjectGNS3}" diff --git a/tools/start-vwifi-client.sh b/tools/start-vwifi-client.sh new file mode 100644 index 0000000..6f1e8f1 --- /dev/null +++ b/tools/start-vwifi-client.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +FOLDER_VWIFI='/hosthome/vwifi' + +DEFAULT_PREFIX_MAC_ADDRESS='74:F8:F6' + +# ------------------- + +cd "${FOLDER_VWIFI}" + +if (( $# == 0 )) +then + NbrWifi=2 +else + NbrWifi="$1" +fi + +if [ -e /sys/module/mac80211_hwsim ] +then + OldNbrWifi=$(cat /sys/module/mac80211_hwsim/parameters/radios) + if (( NbrWifi != OldNbrWifi )) + then + modprobe -r mac80211_hwsim + fi +fi + +modprobe mac80211_hwsim radios=0 + +hexchars="0123456789ABCDEF" +middle=$( for i in {1..4} ; do echo -n ${hexchars:$(( $RANDOM % 16 )):1} ; done | sed -e 's/\(..\)/:\1/g' ) +MAC_ADDRESS="${DEFAULT_PREFIX_MAC_ADDRESS}${middle}" + +./vwifi-add-interfaces "${NbrWifi}" "${MAC_ADDRESS}" + +if [ "$(tty)" = '/dev/ttyS0' ] +then + # In Console Mode -> Tmux can be usefull + if [ -v TMUX ] + then + # Already in tmux + ./vwifi-client + else + tmux new-session -s vwifi "bash --rcfile <(echo '. ~/.bashrc; ./vwifi-client')" ; detach &> /dev/null + + tmux attach -t vwifi + fi +else + ./vwifi-client +fi