├── hwsim ├── README.md ├── Makefile └── mac802154_hwsim.h ├── wmediumd ├── wmediumd_802154 ├── config.h ├── Makefile ├── wmediumd_dynamic.h ├── ieee802154.h ├── README.md ├── wserver.h ├── signal_table_ieee80211ax ├── wserver_messages_network.h ├── per.c ├── wmediumd.h ├── wmediumd_dynamic.c ├── wserver_messages_network.c ├── wserver_messages.c ├── wserver_messages.h ├── list.h ├── config.c ├── wserver.c └── wmediumd.c ├── .gitignore ├── tests ├── tree_error_prob.cfg ├── tree_fading.cfg ├── Makefile ├── tree.cfg ├── tree_interference.cfg ├── interference.sh └── signal_table_ieee80211ax ├── Makefile └── README.md /hwsim/README.md: -------------------------------------------------------------------------------- 1 | # Compiling 2 | 3 | ``` 4 | $ make 5 | ``` 6 | -------------------------------------------------------------------------------- /wmediumd/wmediumd_802154: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ramonfontes/wmediumd_802154/main/wmediumd/wmediumd_802154 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ko 2 | *.o 3 | modules.order 4 | Module.symvers 5 | snap 6 | .bash_history 7 | .vscode 8 | .dbus/session-bus 9 | .config/wireshark 10 | *.cmd 11 | *.mod* 12 | .local* 13 | -------------------------------------------------------------------------------- /hwsim/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += mac802154_hwsim.o 2 | 3 | all: 4 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 5 | clean: 6 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 7 | -------------------------------------------------------------------------------- /tests/tree_error_prob.cfg: -------------------------------------------------------------------------------- 1 | ifaces : 2 | { 3 | ids = [ 4 | "02:00:00:00:00:00:00:00", 5 | "02:00:00:00:00:00:00:01", 6 | "02:00:00:00:00:00:00:02" 7 | ]; 8 | enable_interference = true; 9 | }; 10 | 11 | model: 12 | { 13 | type = "prob"; 14 | default_prob = 0.0; 15 | links = ( 16 | (0, 1, 1.000000) 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /tests/tree_fading.cfg: -------------------------------------------------------------------------------- 1 | ifaces : 2 | { 3 | ids = [ 4 | "02:00:00:00:00:00:00:00", 5 | "02:00:00:00:00:00:00:01", 6 | "02:00:00:00:00:00:00:02" 7 | ]; 8 | enable_interference = true; 9 | }; 10 | 11 | 12 | model: 13 | { 14 | type = "snr" 15 | links = ( 16 | (0, 1, 10), 17 | (0, 2, 0) 18 | ); 19 | fading_coefficient = 1; 20 | }; 21 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -g -Wall -O2 2 | LDFLAGS = 3 | 4 | OBJECTS=../wmediumd/wserver_messages.o ../wmediumd/wserver_messages_network.o 5 | 6 | all: client_snr client_errprob 7 | 8 | client_snr: client_snr.o $(OBJECTS) 9 | $(CC) -o $@ $^ $(LDFLAGS) 10 | 11 | client_errprob: client_errprob.o $(OBJECTS) 12 | $(CC) -o $@ $^ $(LDFLAGS) 13 | 14 | clean: 15 | rm -f client_snr.o client_errprob.o client_snr client_errprob 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/sh 2 | MAKE = make 3 | SUBDIRS ?= wmediumd 4 | BIN = wmediumd/wmediumd_802154 5 | BINDIR = /usr/bin 6 | 7 | all: 8 | 9 | @for i in $(SUBDIRS); do \ 10 | echo "make all in $$i..."; \ 11 | (cd $$i; $(MAKE) all); done 12 | 13 | clean: 14 | 15 | @for i in $(SUBDIRS); do \ 16 | echo "Clearing in $$i..."; \ 17 | (cd $$i; $(MAKE) clean); done 18 | 19 | install: all 20 | install -m 0755 $(BIN) $(BINDIR) 21 | -------------------------------------------------------------------------------- /tests/tree.cfg: -------------------------------------------------------------------------------- 1 | ifaces : 2 | { 3 | ids = [ 4 | "02:00:00:00:00:00:00:00", 5 | "02:00:00:00:00:00:00:01", 6 | "02:00:00:00:00:00:00:02" 7 | ]; 8 | enable_interference = true; 9 | }; 10 | 11 | model: 12 | { 13 | type = "path_loss"; 14 | positions = ( 15 | (0.0, 0.0, 0.0), 16 | (10.0, 0.0, 0.0), 17 | (100.0, 0.0, 0.0) 18 | ); 19 | tx_powers = (15.0, 15.0, 15.0); 20 | model_name = "log_distance"; 21 | path_loss_exp = 4.0; 22 | xg = 0.0; 23 | }; 24 | -------------------------------------------------------------------------------- /tests/tree_interference.cfg: -------------------------------------------------------------------------------- 1 | ifaces : 2 | { 3 | ids = [ 4 | "02:00:00:00:00:00:00:00", 5 | "02:00:00:00:00:00:00:01", 6 | "02:00:00:00:00:00:00:02" 7 | ]; 8 | enable_interference = true; 9 | }; 10 | 11 | model: 12 | { 13 | type = "path_loss"; 14 | positions = ( 15 | (0.0, 0.0, 0.0), 16 | (10.0, 0.0, 0.0), 17 | (100.0, 0.0, 0.0) 18 | ); 19 | tx_powers = (15.0, 15.0, 15.0); 20 | model_name = "log_distance"; 21 | path_loss_exp = 4.0; 22 | xg = 0.0; 23 | }; 24 | -------------------------------------------------------------------------------- /wmediumd/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd, wireless medium simulator for mac80211_hwsim kernel module 3 | * Copyright (c) 2011 cozybit Inc. 4 | * 5 | * Author: Javier Lopez 6 | * Javier Cardona 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License 10 | * as published by the Free Software Foundation; either version 2 11 | * of the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 | * 02110-1301, USA. 22 | */ 23 | 24 | #ifndef CONFIG_H_ 25 | #define CONFIG_H_ 26 | 27 | int load_config(struct wmediumd *ctx, const char *file, const char *per_file, bool full_dynamic); 28 | int use_fixed_random_value(struct wmediumd *ctx); 29 | 30 | #endif /* CONFIG_H_ */ 31 | -------------------------------------------------------------------------------- /wmediumd/Makefile: -------------------------------------------------------------------------------- 1 | VERSION_STR="\"0.5\"" 2 | 3 | # Look for libnl libraries 4 | PKG_CONFIG ?= pkg-config 5 | NL2FOUND := $(shell $(PKG_CONFIG) --atleast-version=2 libnl-2.0 && echo Y) 6 | NL3FOUND := $(shell $(PKG_CONFIG) --atleast-version=3 libnl-3.0 && echo Y) 7 | NL31FOUND := $(shell $(PKG_CONFIG) --exact-version=3.1 libnl-3.1 && echo Y) 8 | NL3xFOUND := $(shell $(PKG_CONFIG) --atleast-version=3.2 libnl-3.0 && echo Y) 9 | 10 | CFLAGS = -g -std=gnu11 -Wall -Wextra -Wno-unused-parameter -O2 11 | LDFLAGS = -levent -lm 12 | 13 | ifeq ($(NL2FOUND),Y) 14 | CFLAGS += -DCONFIG_LIBNL20 15 | LDFLAGS += -lnl-genl 16 | NLLIBNAME = libnl-2.0 17 | endif 18 | 19 | ifeq ($(NL3xFOUND),Y) 20 | # libnl 3.2 might be found as 3.2 and 3.0 21 | NL3FOUND = N 22 | CFLAGS += -DCONFIG_LIBNL30 23 | LDFLAGS += -lnl-genl-3 24 | NLLIBNAME = libnl-3.0 25 | endif 26 | 27 | ifeq ($(NL3FOUND),Y) 28 | CFLAGS += -DCONFIG_LIBNL30 29 | LDFLAGS += -lnl-genl 30 | NLLIBNAME = libnl-3.0 31 | endif 32 | 33 | # nl-3.1 has a broken libnl-gnl-3.1.pc file 34 | # as show by pkg-config --debug --libs --cflags --exact-version=3.1 libnl-genl-3.1;echo $? 35 | ifeq ($(NL31FOUND),Y) 36 | CFLAGS += -DCONFIG_LIBNL30 37 | LDFLAGS += -lnl-genl 38 | NLLIBNAME = libnl-3.1 39 | endif 40 | 41 | ifeq ($(NLLIBNAME),) 42 | $(error Cannot find development files for any supported version of libnl) 43 | endif 44 | 45 | LDFLAGS += $(shell $(PKG_CONFIG) --libs $(NLLIBNAME)) 46 | CFLAGS += $(shell $(PKG_CONFIG) --cflags $(NLLIBNAME)) 47 | 48 | CFLAGS+=-DVERSION_STR=$(VERSION_STR) 49 | LDFLAGS+=-lconfig -lpthread 50 | OBJECTS=wmediumd.o wserver.o config.o per.o wmediumd_dynamic.o wserver_messages.o wserver_messages_network.o 51 | 52 | all: wmediumd_802154 53 | 54 | wmediumd_802154: $(OBJECTS) 55 | $(CC) -o $@ $(OBJECTS) $(LDFLAGS) 56 | 57 | clean: 58 | rm -f $(OBJECTS) wmediumd_802154 59 | -------------------------------------------------------------------------------- /wmediumd/wmediumd_dynamic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #ifndef WMEDIUMD_WMEDIUMD_DYNAMIC_H 22 | #define WMEDIUMD_WMEDIUMD_DYNAMIC_H 23 | 24 | #define SPECIFIC_MATRIX_MAX_SIZE_IDX (12) 25 | #define SPECIFIC_MATRIX_MAX_RATE_IDX (12) 26 | 27 | #include 28 | #include 29 | #include "wmediumd.h" 30 | 31 | typedef uint8_t u8; 32 | typedef int32_t i32; 33 | 34 | /** 35 | * Add a station 36 | * @param ctx The wmediumd context 37 | * @param addr The MAC address of the station 38 | * @return The station ID or a negative errno value 39 | */ 40 | int add_station(struct wmediumd *ctx, const u8 addr[]); 41 | 42 | /** 43 | * Delete a station 44 | * @param ctx The wmediumd context 45 | * @param station The station to delete 46 | * @return 0 on success otherwise a negative errno value 47 | */ 48 | int del_station(struct wmediumd *ctx, struct station *station); 49 | 50 | /** 51 | * Delete a station by its id 52 | * @param ctx The wmediumd context 53 | * @param id The ID of the station 54 | * @return 0 on success otherwise a negative errno value 55 | */ 56 | int del_station_by_id(struct wmediumd *ctx, const i32 id); 57 | 58 | /** 59 | * Delete a station by its address 60 | * @param ctx The wmediumd context 61 | * @param addr The MAC address of the station 62 | * @return 0 on success otherwise a negative errno value 63 | */ 64 | int del_station_by_mac(struct wmediumd *ctx, const u8 *addr); 65 | 66 | /** 67 | * Lock for the snr matrix/station list 68 | */ 69 | extern pthread_rwlock_t snr_lock; 70 | 71 | #endif //WMEDIUMD_WMEDIUMD_DYNAMIC_H 72 | -------------------------------------------------------------------------------- /tests/interference.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 sensor nodes in a tree topology 3 | # transmission between 0 and 2 fails due to excessive distance between them 4 | 5 | num_nodes=3 6 | session=wmediumd_802154 7 | subnet=10.10.10 8 | macfmt='02:00:00:00:00:00:00:%02x' 9 | 10 | . func 11 | 12 | if [[ $UID -ne 0 ]]; then 13 | echo "Sorry, run me as root." 14 | exit 1 15 | fi 16 | 17 | # we are now using a custom module 18 | #modprobe -r mac802154_hwsim 19 | #modprobe mac802154_hwsim 20 | 21 | for i in $(seq 0 $((num_nodes-1))); do 22 | addrs[$i]=$(printf "$macfmt" "$i") 23 | done 24 | 25 | tmux new -s $session -d 26 | 27 | rm /tmp/netns.pid.* 2>/dev/null 28 | i=0 29 | for addr in ${addrs[@]}; do 30 | phy=`addr2phy $addr` 31 | dev=`ls /sys/class/ieee802154/$phy/net` 32 | phys[$i]=$phy 33 | devs[$i]=$dev 34 | 35 | ip=${subnet}.$((10 + i)) 36 | 37 | # put this phy in own netns and tmux window, and start a mesh node 38 | win=$session:$((i+1)).0 39 | tmux new-window -t $session -n $ip 40 | 41 | # start netns 42 | pidfile=/tmp/netns.pid.$i 43 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 44 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 45 | 46 | # wait for netns to exist 47 | while [[ ! -e $pidfile ]]; do 48 | echo "Waiting for netns $i -- $pidfile" 49 | sleep 0.5 50 | done 51 | 52 | tmux send-keys -t $session:0.0 'iwpan phy '$phy' set netns `cat '$pidfile'`' C-m 53 | 54 | # wait for phy to exist in netns 55 | while [[ -e /sys/class/ieee80211/$phy ]]; do 56 | echo "Waiting for $phy to move to netns..." 57 | sleep 0.5 58 | done 59 | 60 | # start wpan 61 | tmux send-keys -t $win '. func' C-m 62 | tmux send-keys -t $win 'ip link add link wpan'$i' name pan'$i' type lowpan' C-m 63 | tmux send-keys -t $win 'iwpan dev wpan'$i' set pan_id 0xbeef' C-m 64 | tmux send-keys -t $win 'ip link set wpan'$i' up' C-m 65 | tmux send-keys -t $win 'ip link set pan'$i' up' C-m 66 | tmux send-keys -t $win 'ip -6 addr flush pan'$i'' C-m 67 | tmux send-keys -t $win 'ip -6 addr add fe80::'$((i+1))'/64 dev pan'$i'' C-m 68 | 69 | i=$((i+1)) 70 | done 71 | 72 | winct=$i 73 | 74 | tmux send-keys -t $session:0.0 'wpan-hwsim edge add 0 1 >/dev/null 2>&1' C-m 75 | tmux send-keys -t $session:0.0 'wpan-hwsim edge add 1 0 >/dev/null 2>&1' C-m 76 | 77 | tmux send-keys -t $session:0.0 'wpan-hwsim edge add 0 2 >/dev/null 2>&1' C-m 78 | tmux send-keys -t $session:0.0 'wpan-hwsim edge add 2 0 >/dev/null 2>&1' C-m 79 | 80 | tmux select-window -t $session:1 81 | tmux send-keys -t $session:1 'sleep 2; ping -c 2 fe80::2' C-m 82 | 83 | tmux select-window -t $session:1 84 | tmux send-keys -t $session:1 'sleep 2; ping -c 2 fe80::3' C-m 85 | 86 | # start wmediumd 87 | win=$session:$((winct+1)).0 88 | winct=$((winct+1)) 89 | #tmux new-window -a -t $session -n wmediumd_802154 90 | #tmux send-keys -t $win '../wmediumd/wmediumd_802154 -s -c diamond.cfg' C-m 91 | 92 | #tmux select-window -t $session:1 93 | #tmux send-keys -t $session:1 'sleep 2; ping -c 5 fe80::1' C-m 94 | 95 | tmux attach 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is the first attempt at implementing a wmediumd-like mechanism for `mac802154_hwsim`. The implementation will be developed while considering `tests/interference.sh` for testing. 4 | 5 | Patches submitted to the Linux Kernel: 6 | * [https://patchwork.kernel.org/project/linux-wpan/patch/20250603190506.6382-1-ramonreisfontes@gmail.com/](https://patchwork.kernel.org/project/linux-wpan/patch/20250603190506.6382-1-ramonreisfontes@gmail.com/) 7 | 8 | ## Wmediumd 9 | 10 | This is a wireless medium simulation tool for Linux, based on the netlink API 11 | implemented in the `mac802154_hwsim` kernel driver. Unlike the default in-kernel 12 | forwarding mode of `mac802154_hwsim`, wmediumd allows simulating frame loss and 13 | delay. 14 | 15 | This version is forked from an earlier version, hosted here: 16 | 17 | https://github.com/ramonfontes/wmediumd 18 | 19 | # Prerequisites 20 | 21 | First, you need a recent Linux kernel with the `mac802154_hwsim` module 22 | available. 23 | 24 | # Building 25 | 26 | Build the required modules and binaries: 27 | ``` 28 | $ cd wmediumd_802154 29 | $ make 30 | $ sudo make install 31 | ``` 32 | 33 | # Loading the modified kernel module 34 | 35 | If you're testing directly with a modified kernel module, you can load it manually: 36 | ``` 37 | $ cd hwsim 38 | $ make 39 | $ sudo modprobe mac802154_hwsim 40 | $ sudo rmmod mac802154_hwsim 41 | $ sudo insmod mac802154_hwsim.ko radios=3 42 | ``` 43 | 44 | # Using Wmediumd 45 | 46 | Navigate to the test directory: 47 | ``` 48 | cd tests 49 | ``` 50 | 51 | ## Terminal 1: Start the interference scenario 52 | 53 | This script sets up the simulated interfaces and initializes the test environment: 54 | ``` 55 | sudo ./interference.sh 56 | ``` 57 | 58 | ## Terminal 2: Launch wmediumd with the desired config 59 | 60 | Start the wmediumd_802154 daemon using socket mode and your chosen config file: 61 | ``` 62 | sudo wmediumd_802154 -s -c tree_interference.cfg 63 | ``` 64 | 65 | This command launches wmediumd_802154, which connects to the mac802154_hwsim module via netlink and simulates interference and packet loss between IEEE 802.15.4 virtual devices according to the configuration in tree.cfg. 66 | 67 | ## Terminal 1: Pinging virtual devices 68 | 69 | You can now test connectivity between the virtual sensors using IPv6 link-local addresses: 70 | 71 | Ping from sensor0 to sensor1: 72 | 73 | ``` 74 | ping -c 2 fe80::2 75 | PING fe80::2 (fe80::2) 56 data bytes 76 | 64 bytes from fe80::2%pan0: icmp_seq=1 ttl=64 time=2.33 ms 77 | 64 bytes from fe80::2%pan0: icmp_seq=2 ttl=64 time=1.77 ms 78 | 79 | --- fe80::2 ping statistics --- 80 | 2 packets transmitted, 2 received, 0% packet loss, time 1002ms 81 | rtt min/avg/max/mdev = 1.770/2.051/2.332/0.281 ms 82 | 83 | ``` 84 | 85 | Ping from sensor1 to sensor2: 86 | ``` 87 | ping -c 2 fe80::3 88 | PING fe80::3 (fe80::3) 56 data bytes 89 | ^C 90 | --- fe80::3 ping statistics --- 91 | 2 packets transmitted, 0 received, 100% packet loss, time 1054ms 92 | ``` 93 | 94 | # Running wmediumd_802154 with Mininet-WiFi 95 | 96 | [This script](https://github.com/intrig-unicamp/mininet-wifi/blob/master/examples/wmediumd_interference_lowpan.py) allows you to run wmediumd_802154 with a custom 802.15.4 network topology. -------------------------------------------------------------------------------- /wmediumd/ieee802154.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd, wireless medium simulator for mac80211_hwsim kernel module 3 | * Copyright (c) 2011 cozybit Inc. 4 | * 5 | * Author: Javier Lopez 6 | * Javier Cardona 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License 10 | * as published by the Free Software Foundation; either version 2 11 | * of the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 | * 02110-1301, USA. 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | typedef uint8_t u8; 28 | typedef uint16_t u16; 29 | typedef uint32_t u32; 30 | typedef uint64_t u64; 31 | 32 | #ifndef IEEE802154_H_ 33 | #define IEEE802154_H_ 34 | 35 | #define IEEE80211_AVAILABLE_RATES 12 36 | #define IEEE80211_TX_MAX_RATES 4 37 | #define IEEE80211_NUM_ACS 4 38 | 39 | #ifndef ETH_ALEN 40 | #define ETH_ALEN 8 41 | #endif 42 | 43 | #define IEEE802154_MAX_DATA_LEN 90 44 | 45 | #define FCTL_FTYPE 0x0c 46 | #define FCTL_TODS 0x01 47 | #define FCTL_FROMDS 0x02 48 | 49 | #define FTYPE_MGMT 0x00 50 | #define FTYPE_DATA 0x08 51 | 52 | #define STYPE_QOS_DATA 0x80 53 | 54 | #define QOS_CTL_TAG1D_MASK 0x07 55 | 56 | struct ieee802154_sechdr { 57 | #if defined(__LITTLE_ENDIAN_BITFIELD) 58 | u8 level:3, 59 | key_id_mode:2, 60 | reserved:3; 61 | #elif defined(__BIG_ENDIAN_BITFIELD) 62 | u8 reserved:3, 63 | key_id_mode:2, 64 | level:3; 65 | #endif 66 | u8 key_id; 67 | __le32 frame_counter; 68 | union { 69 | __le32 short_src; 70 | __le64 extended_src; 71 | }; 72 | }; 73 | 74 | 75 | struct ieee802154_addr { 76 | u8 mode; 77 | __le16 pan_id; 78 | union { 79 | __le16 short_addr; 80 | __le64 extended_addr; 81 | }; 82 | }; 83 | 84 | struct ieee802154_hdr_fc { 85 | u16 type:3, 86 | security_enabled:1, 87 | frame_pending:1, 88 | ack_request:1, 89 | intra_pan:1, 90 | reserved:3, 91 | dest_addr_mode:2, 92 | version:2, 93 | source_addr_mode:2; 94 | }; 95 | 96 | enum ieee80211_ac_number { 97 | IEEE80211_AC_VO = 0, 98 | IEEE80211_AC_VI = 1, 99 | IEEE80211_AC_BE = 2, 100 | IEEE80211_AC_BK = 3, 101 | }; 102 | 103 | static const enum ieee80211_ac_number ieee802_1d_to_ac[8] = { 104 | IEEE80211_AC_BE, 105 | IEEE80211_AC_BK, 106 | IEEE80211_AC_BK, 107 | IEEE80211_AC_BE, 108 | IEEE80211_AC_VI, 109 | IEEE80211_AC_VI, 110 | IEEE80211_AC_VO, 111 | IEEE80211_AC_VO 112 | }; 113 | 114 | struct ieee802154_hdr { 115 | struct ieee802154_hdr_fc fc; 116 | unsigned char seq; 117 | struct ieee802154_addr source; 118 | struct ieee802154_addr dest; 119 | struct ieee802154_sechdr sec; 120 | }; 121 | 122 | #endif /* IEEE802154_H_ */ 123 | -------------------------------------------------------------------------------- /wmediumd/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is a wireless medium simulation tool for Linux, based on the netlink API 4 | implemented in the `mac80211_hwsim` kernel driver. Unlike the default in-kernel 5 | forwarding mode of `mac80211_hwsim`, wmediumd allows simulating frame loss and 6 | delay. 7 | 8 | This version is forked from an earlier version, hosted here: 9 | 10 | https://github.com/cozybit/wmediumd 11 | 12 | # Building 13 | ``` 14 | cd wmediumd && make 15 | ``` 16 | 17 | # Using Wmediumd 18 | 19 | Starting wmediumd with an appropriate config file is enough to make frames 20 | pass through wmediumd: 21 | ``` 22 | sudo modprobe mac802154_hwsim radios=2 23 | sudo ./wmediumd/wmediumd -c tests/2node.cfg & 24 | # run some hwsim test 25 | ``` 26 | However, please see the next section on some potential pitfalls. 27 | 28 | A complete example using network namespaces is given at the end of 29 | this document. 30 | 31 | # Configuration 32 | 33 | Wmediumd supports multiple ways of configuring the wireless medium. 34 | 35 | ## Perfect medium 36 | 37 | With this configuration, all traffic flows between the configured interfaces, identified by their mac address: 38 | 39 | ``` 40 | ifaces : 41 | { 42 | ids = [ 43 | "02:00:00:00:00:00:00:00", 44 | "02:00:00:00:00:00:00:01", 45 | "02:00:00:00:00:00:00:02", 46 | "02:00:00:00:00:00:00:03" 47 | ]; 48 | }; 49 | ``` 50 | 51 | ## Path loss model 52 | 53 | The path loss model derives signal-to-noise and probabilities from the 54 | coordinates of each node. This is an example configuration file for it. 55 | 56 | ``` 57 | ifaces : {...}; 58 | model : 59 | { 60 | type = "path_loss"; 61 | positions = ( 62 | (-50.0, 0.0), 63 | ( 0.0, 40.0), 64 | ( 0.0, -70.0), 65 | ( 50.0, 0.0) 66 | ); 67 | tx_powers = (15.0, 15.0, 15.0, 15.0); 68 | 69 | model_name = "log_distance"; 70 | path_loss_exp = 3.5; 71 | xg = 0.0; 72 | }; 73 | ``` 74 | 75 | ## Per-link loss probability model 76 | 77 | You can simulate a slightly more realistic channel by assigning fixed error 78 | probabilities to each link. 79 | 80 | ``` 81 | ifaces : {...}; 82 | 83 | model: 84 | { 85 | type = "prob"; 86 | 87 | default_prob = 1.0; 88 | links = ( 89 | (0, 2, 0.000000), 90 | (2, 3, 0.000000) 91 | ); 92 | }; 93 | ``` 94 | 95 | The above configuration would assign 0% loss probability (perfect medium) to 96 | all frames flowing between nodes 0 and 2, and 100% loss probability to all 97 | other links. Unless both directions of a link are configured, the loss 98 | probability will be symmetric. 99 | 100 | This is a very simplistic model that does not take into account that losses 101 | depend on transmission rates and signal-to-noise ratio. For that, keep reading. 102 | 103 | ## Per-link signal-to-noise ratio (SNR) model 104 | 105 | You can model different signal-to-noise ratios for each link by including a 106 | list of link tuples in the form of (sensor1, sensor2, snr). 107 | 108 | ``` 109 | ifaces : {...}; 110 | 111 | model: 112 | { 113 | type = "snr" 114 | links = ( 115 | (0, 1, 10), 116 | (0, 2, 0) 117 | ); 118 | fading_coefficient = 1; 119 | }; 120 | ``` 121 | The snr will affect the maximum data rates that are successfully transmitted 122 | over the link. 123 | 124 | If only one direction of a link is configured, then the link will be 125 | symmetric. For asymmetric links, configure both directions, as in the 126 | above example where the path between 0 and 2 is usable in only one 127 | direction. 128 | 129 | The packet loss error probabilities are derived from this snr. See function 130 | `get_error_prob_from_snr()`. Or you can provide a packet-error-rate table like 131 | the one in `tests/signal_table_ieee80211ax` 132 | -------------------------------------------------------------------------------- /wmediumd/wserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #ifndef WMEDIUMD_SERVER_H 22 | #define WMEDIUMD_SERVER_H 23 | 24 | #include "wmediumd.h" 25 | #include "wserver_messages.h" 26 | 27 | struct request_ctx { 28 | struct wmediumd *ctx; 29 | int sock_fd; 30 | }; 31 | 32 | /** 33 | * Start the server using the given wmediumd context in a background task 34 | * @param ctx The wmediumd context 35 | * @return 0 on success 36 | */ 37 | int start_wserver(struct wmediumd *ctx); 38 | 39 | /** 40 | * Stop the server if active 41 | */ 42 | void stop_wserver(); 43 | 44 | /** 45 | * Handle a snr_update_request and pass it to wmediumd 46 | * @param ctx The request_ctx context 47 | * @param request The received request 48 | */ 49 | int handle_snr_update_request(struct request_ctx *ctx, const snr_update_request *request); 50 | 51 | /** 52 | * Handle a position_update_request and pass it to wmediumd 53 | * @param ctx The request_ctx context 54 | * @param request The received request 55 | */ 56 | int handle_position_update_request(struct request_ctx *ctx, const position_update_request *request); 57 | 58 | /** 59 | * Handle a txpower_update_request and pass it to wmediumd 60 | * @param ctx The request_ctx context 61 | * @param request The received request 62 | */ 63 | int handle_txpower_update_request(struct request_ctx *ctx, const txpower_update_request *request); 64 | 65 | /** 66 | * Handle a gaussian_random_update_request and pass it to wmediumd 67 | * @param ctx The request_ctx context 68 | * @param request The received request 69 | */ 70 | int handle_gaussian_random_update_request(struct request_ctx *ctx, const gaussian_random_update_request *request); 71 | 72 | /** 73 | * Handle a gain_update_request and pass it to wmediumd 74 | * @param ctx The request_ctx context 75 | * @param request The received request 76 | */ 77 | int handle_gain_update_request(struct request_ctx *ctx, const gain_update_request *request); 78 | 79 | /** 80 | * Handle a errprob_update_request and pass it to wmediumd 81 | * @param ctx The request_ctx context 82 | * @param request The received request 83 | */ 84 | int handle_errprob_update_request(struct request_ctx *ctx, const errprob_update_request *request); 85 | 86 | /** 87 | * Handle a specprob_update_request and pass it to wmediumd 88 | * @param ctx The request_ctx context 89 | * @param request The received request 90 | */ 91 | int handle_specprob_update_request(struct request_ctx *ctx, const specprob_update_request *request); 92 | 93 | /** 94 | * Handle a station_del_by_id_request and pass it to wmediumd 95 | * @param ctx The request_ctx context 96 | * @param request The received request 97 | */ 98 | int handle_delete_by_id_request(struct request_ctx *ctx, station_del_by_id_request *request); 99 | 100 | /** 101 | * Handle a station_del_by_mac_request and pass it to wmediumd 102 | * @param ctx The request_ctx context 103 | * @param request The received request 104 | */ 105 | int handle_delete_by_mac_request(struct request_ctx *ctx, station_del_by_mac_request *request); 106 | 107 | /** 108 | * Handle a station_add_request and pass it to wmediumd 109 | * @param ctx The request_ctx context 110 | * @param request The received request 111 | */ 112 | int handle_add_request(struct request_ctx *ctx, station_add_request *request); 113 | 114 | #endif //WMEDIUMD_SERVER_H 115 | -------------------------------------------------------------------------------- /hwsim/mac802154_hwsim.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAC802154_HWSIM_H 2 | #define __MAC802154_HWSIM_H 3 | 4 | 5 | #define IEEE802154_MAX_FRAME_LEN 127 6 | #define IEEE802154_MIN_HDR_LEN 3 7 | //#define IEEE802154_MAX_DATA_LEN (IEEE802154_PHY_FRAME_LEN - IEEE802154_MAX_HEADER_LEN) 8 | /** 9 | * enum hwsim_tx_control_flags - flags to describe transmission info/status 10 | * 11 | * These flags are used to give the wmediumd extra information in order to 12 | * modify its behavior for each frame 13 | * 14 | * @HWSIM_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. 15 | * @HWSIM_TX_CTL_NO_ACK: tell the wmediumd not to wait for an ack 16 | * @HWSIM_TX_STAT_ACK: Frame was acknowledged 17 | * 18 | */ 19 | enum hwsim_tx_control_flags { 20 | MAC802154_HWSIM_TX_CTL_REQ_TX_STATUS = BIT(0), 21 | MAC802154_HWSIM_TX_CTL_NO_ACK = BIT(1), 22 | MAC802154_HWSIM_TX_STAT_ACK = BIT(2), 23 | }; 24 | 25 | 26 | /* mac802154 hwsim netlink commands 27 | * @HWSIM_CMD_REGISTER: request to register and received all broadcasted 28 | * frames by any mac802154_hwsim radio device. 29 | * @MAC802154_HWSIM_CMD_UNSPEC: unspecified command to catch error 30 | * @MAC802154_HWSIM_CMD_GET_RADIO: fetch information about existing radios 31 | * @MAC802154_HWSIM_CMD_SET_RADIO: change radio parameters during runtime 32 | * @MAC802154_HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters 33 | * returns the radio ID (>= 0) or negative on errors, if successful 34 | * then multicast the result 35 | * @MAC802154_HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted 36 | * @MAC802154_HWSIM_CMD_GET_EDGE: fetch information about existing edges 37 | * @MAC802154_HWSIM_CMD_SET_EDGE: change edge parameters during runtime 38 | * @MAC802154_HWSIM_CMD_DEL_EDGE: delete edges between radios 39 | * @MAC802154_HWSIM_CMD_NEW_EDGE: create a new edge between two radios 40 | * @__MAC802154_HWSIM_CMD_MAX: enum limit 41 | */ 42 | enum { 43 | MAC802154_HWSIM_CMD_UNSPEC, 44 | 45 | MAC802154_HWSIM_CMD_GET_RADIO, 46 | MAC802154_HWSIM_CMD_SET_RADIO, 47 | MAC802154_HWSIM_CMD_NEW_RADIO, 48 | MAC802154_HWSIM_CMD_DEL_RADIO, 49 | 50 | MAC802154_HWSIM_CMD_GET_EDGE, 51 | MAC802154_HWSIM_CMD_SET_EDGE, 52 | MAC802154_HWSIM_CMD_DEL_EDGE, 53 | MAC802154_HWSIM_CMD_NEW_EDGE, 54 | MAC802154_HWSIM_CMD_REGISTER, 55 | MAC802154_HWSIM_CMD_FRAME, 56 | MAC802154_HWSIM_CMD_TX_INFO_FRAME, 57 | 58 | __MAC802154_HWSIM_CMD_MAX, 59 | }; 60 | 61 | #define MAC802154_HWSIM_CMD_MAX (__MAC802154_HWSIM_MAX - 1) 62 | 63 | /* mac802154 hwsim netlink attributes 64 | * 65 | * @MAC802154_HWSIM_ATTR_UNSPEC: unspecified attribute to catch error 66 | * @MAC802154_HWSIM_ATTR_RADIO_ID: u32 attribute to identify the radio 67 | * @MAC802154_HWSIM_ATTR_EDGE: nested attribute of edges 68 | * @MAC802154_HWSIM_ATTR_EDGES: list if nested attributes which contains the 69 | * edge information according the radio id 70 | * @__MAC802154_HWSIM_ATTR_MAX: enum limit 71 | */ 72 | enum { 73 | MAC802154_HWSIM_ATTR_UNSPEC, 74 | MAC802154_HWSIM_ATTR_RADIO_ID, 75 | MAC802154_HWSIM_ATTR_RADIO_EDGE, 76 | MAC802154_HWSIM_ATTR_RADIO_EDGES, 77 | MAC802154_HWSIM_ATTR_COOKIE, 78 | MAC802154_HWSIM_ATTR_PAD, 79 | MAC802154_HWSIM_ATTR_FRAME, 80 | MAC802154_HWSIM_ATTR_ADDR_TRANSMITTER, 81 | MAC802154_HWSIM_ATTR_ADDR_RECEIVER, 82 | MAC802154_HWSIM_ATTR_TX_INFO, 83 | MAC802154_HWSIM_ATTR_FLAGS, 84 | __MAC802154_HWSIM_ATTR_MAX, 85 | }; 86 | 87 | #define MAC802154_HWSIM_ATTR_MAX (__MAC802154_HWSIM_ATTR_MAX - 1) 88 | 89 | /* mac802154 hwsim edge netlink attributes 90 | * 91 | * @MAC802154_HWSIM_EDGE_ATTR_UNSPEC: unspecified attribute to catch error 92 | * @MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID: radio id where the edge points to 93 | * @MAC802154_HWSIM_EDGE_ATTR_LQI: LQI value which the endpoint radio will 94 | * receive for this edge 95 | * @__MAC802154_HWSIM_ATTR_MAX: enum limit 96 | */ 97 | enum { 98 | MAC802154_HWSIM_EDGE_ATTR_UNSPEC, 99 | MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID, 100 | MAC802154_HWSIM_EDGE_ATTR_LQI, 101 | __MAC802154_HWSIM_EDGE_ATTR_MAX, 102 | }; 103 | 104 | #define MAC802154_HWSIM_EDGE_ATTR_MAX (__MAC802154_HWSIM_EDGE_ATTR_MAX - 1) 105 | 106 | /** 107 | * DOC: Frame transmission support over virtio 108 | * 109 | * Frame transmission is also supported over virtio to allow communication 110 | * with external entities. 111 | */ 112 | 113 | /** 114 | * enum hwsim_vqs - queues for virtio frame transmission 115 | * 116 | * @HWSIM_VQ_TX: send frames to external entity 117 | * @HWSIM_VQ_RX: receive frames and transmission info reports 118 | * @HWSIM_NUM_VQS: enum limit 119 | */ 120 | enum hwsim_vqs { 121 | HWSIM_VQ_TX, 122 | HWSIM_VQ_RX, 123 | HWSIM_NUM_VQS, 124 | }; 125 | 126 | #endif /* __MAC802154_HWSIM_H */ -------------------------------------------------------------------------------- /wmediumd/signal_table_ieee80211ax: -------------------------------------------------------------------------------- 1 | # RSSI vs MCS vs PER table, based on 11-14-0571-12-00ax-evaluation-methodology.docx assuming No is -91dBm. 2 | # bitrate 1Mbps 2Mbps 5.5Mbps 11Mbps 6Mbps 9Mbps 12Mbps 18Mbps 24Mbps 36Mbps 48Mbps 54Mbps 3 | # RSSI [dBm] 0 1 2 3 4 5 6 7 8 9 10 11 4 | -100 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 5 | -99 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 6 | -98 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 7 | -97 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 8 | -96 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 9 | -95 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 10 | -94 0.529 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 11 | -93 0.0427 0.9194 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 12 | -92 0.0014 0.1765 0.529 1.00E+00 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 13 | -91 0.00E+00 0.0086 0.0427 1.00E+00 0.529 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 14 | -90 0.00E+00 0.0001 0.0014 0.9995 0.0427 0.529 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 15 | -89 0.00E+00 0.00E+00 0.00E+00 0.529 0.0014 0.0427 0.9997 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 16 | -88 0.00E+00 0.00E+00 0.00E+00 0.0427 0.00E+00 0.0014 0.5462 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 17 | -87 0.00E+00 0.00E+00 0.00E+00 0.0014 0.00E+00 0.00E+00 0.0439 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 18 | -86 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0016 0.9597 1.00E+00 1.00E+00 1.00E+00 1.00E+00 19 | -85 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.2239 1.00E+00 1.00E+00 1.00E+00 1.00E+00 20 | -84 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0117 0.8908 1.00E+00 1.00E+00 1.00E+00 21 | -83 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.2343 1.00E+00 1.00E+00 1.00E+00 22 | -82 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.024 1.00E+00 1.00E+00 1.00E+00 23 | -81 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 1.00E+00 1.00E+00 1.00E+00 24 | -80 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.979 1.00E+00 1.00E+00 25 | -79 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.3536 1.00E+00 1.00E+00 26 | -78 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0356 1.00E+00 1.00E+00 27 | -77 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0018 1.00E+00 1.00E+00 28 | -76 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.9496 1.00E+00 29 | -75 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.379 0.9981 30 | -74 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.061 0.6465 31 | -73 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0057 0.1343 32 | -72 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0004 0.0145 33 | -71 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0007 34 | -70 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 35 | -69 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 36 | -68 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 37 | -67 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 38 | -66 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 39 | -65 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 40 | -64 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 41 | -63 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 42 | -62 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 43 | -61 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 44 | -60 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 -------------------------------------------------------------------------------- /tests/signal_table_ieee80211ax: -------------------------------------------------------------------------------- 1 | # RSSI vs MCS vs PER table, based on 11-14-0571-12-00ax-evaluation-methodology.docx assuming No is -91dBm. 2 | # bitrate 1Mbps 2Mbps 5.5Mbps 11Mbps 6Mbps 9Mbps 12Mbps 18Mbps 24Mbps 36Mbps 48Mbps 54Mbps 3 | # RSSI [dBm] 0 1 2 3 4 5 6 7 8 9 10 11 4 | -100 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 5 | -99 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 6 | -98 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 7 | -97 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 8 | -96 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 9 | -95 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 10 | -94 0.529 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 11 | -93 0.0427 0.9194 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 12 | -92 0.0014 0.1765 0.529 1.00E+00 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 13 | -91 0.00E+00 0.0086 0.0427 1.00E+00 0.529 0.9995 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 14 | -90 0.00E+00 0.0001 0.0014 0.9995 0.0427 0.529 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 15 | -89 0.00E+00 0.00E+00 0.00E+00 0.529 0.0014 0.0427 0.9997 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 16 | -88 0.00E+00 0.00E+00 0.00E+00 0.0427 0.00E+00 0.0014 0.5462 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 17 | -87 0.00E+00 0.00E+00 0.00E+00 0.0014 0.00E+00 0.00E+00 0.0439 1.00E+00 1.00E+00 1.00E+00 1.00E+00 1.00E+00 18 | -86 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0016 0.9597 1.00E+00 1.00E+00 1.00E+00 1.00E+00 19 | -85 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.2239 1.00E+00 1.00E+00 1.00E+00 1.00E+00 20 | -84 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0117 0.8908 1.00E+00 1.00E+00 1.00E+00 21 | -83 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.2343 1.00E+00 1.00E+00 1.00E+00 22 | -82 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.024 1.00E+00 1.00E+00 1.00E+00 23 | -81 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 1.00E+00 1.00E+00 1.00E+00 24 | -80 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.979 1.00E+00 1.00E+00 25 | -79 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.3536 1.00E+00 1.00E+00 26 | -78 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0356 1.00E+00 1.00E+00 27 | -77 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0018 1.00E+00 1.00E+00 28 | -76 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.9496 1.00E+00 29 | -75 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.379 0.9981 30 | -74 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.061 0.6465 31 | -73 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0057 0.1343 32 | -72 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0004 0.0145 33 | -71 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.0007 34 | -70 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 35 | -69 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 36 | -68 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 37 | -67 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 38 | -66 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 39 | -65 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 40 | -64 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 41 | -63 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 42 | -62 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 43 | -61 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 44 | -60 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 0.00E+00 45 | -------------------------------------------------------------------------------- /wmediumd/wserver_messages_network.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #ifndef WMEDIUMD_WSERVER_MESSAGES_NETWORK_H 22 | #define WMEDIUMD_WSERVER_MESSAGES_NETWORK_H 23 | 24 | #include "wserver_messages.h" 25 | 26 | /** 27 | * Send bytes over a socket, repeat until all bytes are sent 28 | * @param sock The socket file descriptor 29 | * @param buf The pointer to the bytes 30 | * @param len The amount of bytes to send 31 | * @param shift The amount of bytes that should be skipped in the buffer 32 | * @param flags Flags for the send method 33 | * @return 0 on success, -1 on error, -2 on client disconnect 34 | */ 35 | int sendfull(int sock, const void *buf, size_t len, size_t shift, int flags); 36 | 37 | /** 38 | * Receive bytes from a socket, repeat until all bytes are read 39 | * @param sock The socket file descriptor 40 | * @param buf A pointer where to store the received bytes 41 | * @param len The amount of bytes to receive 42 | * @param shift The amount of bytes that should be skipped in the buffer 43 | * @param flags Flags for the recv method 44 | * @return 0 on success, -1 on error, -2 on client disconnect 45 | */ 46 | int recvfull(int sock, void *buf, size_t len, size_t shift, int flags); 47 | 48 | /** 49 | * Convert a wserver message from network to host byte order 50 | * @param elem The element to convert 51 | * @param type The struct type of the element 52 | */ 53 | #define hton_type(elem, type) \ 54 | hton_##type(elem); 55 | 56 | /** 57 | * Convert a wserver message from host to network byte order 58 | * @param elem The element to convert 59 | * @param type The struct type of the element 60 | */ 61 | #define ntoh_type(elem, type) \ 62 | ntoh_##type(elem); 63 | 64 | void hton_base(wserver_msg *elem); 65 | 66 | void hton_snr_update_request(snr_update_request *elem); 67 | 68 | void hton_snr_update_response(snr_update_response *elem); 69 | 70 | void hton_position_update_request(position_update_request *elem); 71 | 72 | void hton_position_update_response(position_update_response *elem); 73 | 74 | void hton_txpower_update_request(txpower_update_request *elem); 75 | 76 | void hton_txpower_update_response(txpower_update_response *elem); 77 | 78 | void hton_gaussian_random_update_request(gaussian_random_update_request *elem); 79 | 80 | void hton_gaussian_random_update_response(gaussian_random_update_response *elem); 81 | 82 | void hton_gain_update_request(gain_update_request *elem); 83 | 84 | void hton_gain_update_response(gain_update_response *elem); 85 | 86 | void hton_errprob_update_request(errprob_update_request *elem); 87 | 88 | void hton_errprob_update_response(errprob_update_response *elem); 89 | 90 | void hton_specprob_update_request(specprob_update_request *elem); 91 | 92 | void hton_specprob_update_response(specprob_update_response *elem); 93 | 94 | void hton_station_del_by_mac_request(station_del_by_mac_request *elem); 95 | 96 | void hton_station_del_by_mac_response(station_del_by_mac_response *elem); 97 | 98 | void hton_station_del_by_id_request(station_del_by_id_request *elem); 99 | 100 | void hton_station_del_by_id_response(station_del_by_id_response *elem); 101 | 102 | void hton_station_add_request(station_add_request *elem); 103 | 104 | void hton_station_add_response(station_add_response *elem); 105 | 106 | void hton_medium_update_request(medium_update_request *elem); 107 | 108 | void hton_medium_update_response(medium_update_response *elem); 109 | 110 | void ntoh_base(wserver_msg *elem); 111 | 112 | void ntoh_snr_update_request(snr_update_request *elem); 113 | 114 | void ntoh_snr_update_response(snr_update_response *elem); 115 | 116 | void ntoh_position_update_request(position_update_request *elem); 117 | 118 | void ntoh_position_update_response(position_update_response *elem); 119 | 120 | void ntoh_txpower_update_request(txpower_update_request *elem); 121 | 122 | void ntoh_txpower_update_response(txpower_update_response *elem); 123 | 124 | void ntoh_gaussian_random_update_request(gaussian_random_update_request *elem); 125 | 126 | void ntoh_gaussian_random_update_response(gaussian_random_update_response *elem); 127 | 128 | void ntoh_gain_update_request(gain_update_request *elem); 129 | 130 | void ntoh_gain_update_response(gain_update_response *elem); 131 | 132 | void ntoh_errprob_update_request(errprob_update_request *elem); 133 | 134 | void ntoh_errprob_update_response(errprob_update_response *elem); 135 | 136 | void ntoh_specprob_update_request(specprob_update_request *elem); 137 | 138 | void ntoh_specprob_update_response(specprob_update_response *elem); 139 | 140 | void ntoh_station_del_by_mac_request(station_del_by_mac_request *elem); 141 | 142 | void ntoh_station_del_by_mac_response(station_del_by_mac_response *elem); 143 | 144 | void ntoh_station_del_by_id_request(station_del_by_id_request *elem); 145 | 146 | void ntoh_station_del_by_id_response(station_del_by_id_response *elem); 147 | 148 | void ntoh_station_add_request(station_add_request *elem); 149 | 150 | void ntoh_station_add_response(station_add_response *elem); 151 | 152 | void ntoh_medium_update_request(medium_update_request *elem); 153 | 154 | void ntoh_medium_update_response(medium_update_response *elem); 155 | 156 | #endif //WMEDIUMD_WSERVER_MESSAGES_NETWORK_H 157 | -------------------------------------------------------------------------------- /wmediumd/per.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Generate packet error rates for OFDM rates given signal level and 3 | * packet length. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "wmediumd.h" 14 | 15 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 16 | 17 | /* Code rates for convolutional codes */ 18 | enum fec_rate { 19 | FEC_RATE_1_2, 20 | FEC_RATE_2_3, 21 | FEC_RATE_3_4, 22 | FEC_RATE_4_5, 23 | FEC_RATE_5_6, 24 | }; 25 | 26 | struct rate { 27 | int mbps; 28 | int mqam; 29 | enum fec_rate fec; 30 | }; 31 | 32 | /* 33 | * rate sets are defined in drivers/net/wireless/mac80211_hwsim.c#hwsim_rates. 34 | */ 35 | static struct rate rateset[] = { 36 | /* 37 | * XXX: 38 | * For rate = 1, 2, 5.5, 11 Mbps, we will use mqam and fec of closest 39 | * rate. Because these rates are not OFDM rate. 40 | */ 41 | { .mbps = 10, .mqam = 2, .fec = FEC_RATE_1_2 }, 42 | { .mbps = 20, .mqam = 2, .fec = FEC_RATE_1_2 }, 43 | { .mbps = 55, .mqam = 2, .fec = FEC_RATE_1_2 }, 44 | { .mbps = 110, .mqam = 4, .fec = FEC_RATE_1_2 }, 45 | { .mbps = 60, .mqam = 2, .fec = FEC_RATE_1_2 }, 46 | { .mbps = 90, .mqam = 2, .fec = FEC_RATE_3_4 }, 47 | { .mbps = 120, .mqam = 4, .fec = FEC_RATE_1_2 }, 48 | { .mbps = 180, .mqam = 4, .fec = FEC_RATE_3_4 }, 49 | { .mbps = 240, .mqam = 16, .fec = FEC_RATE_1_2 }, 50 | { .mbps = 360, .mqam = 16, .fec = FEC_RATE_3_4 }, 51 | { .mbps = 480, .mqam = 64, .fec = FEC_RATE_2_3 }, 52 | { .mbps = 540, .mqam = 64, .fec = FEC_RATE_3_4 }, 53 | }; 54 | static size_t rate_len = ARRAY_SIZE(rateset); 55 | 56 | static double n_choose_k(double n, double k) 57 | { 58 | int i; 59 | double c = 1; 60 | 61 | if (n < k || !k) 62 | return 0; 63 | 64 | if (k > n - k) 65 | k = n - k; 66 | 67 | for (i = 1; i <= k; i++) 68 | c *= (n - (k - i)) / i; 69 | 70 | return c; 71 | } 72 | 73 | static double dot(double *v1, double *v2, int len) 74 | { 75 | int i; 76 | double val = 0; 77 | 78 | for (i = 0; i < len; i++) 79 | val += v1[i] * v2[i]; 80 | 81 | return val; 82 | } 83 | 84 | /* 85 | * Compute bit error rate for BPSK at a given SNR. 86 | * See http://en.wikipedia.org/wiki/Phase-shift_keying 87 | */ 88 | static double bpsk_ber(double snr_db) 89 | { 90 | double snr = pow(10, (snr_db / 10.)); 91 | 92 | return .5 * erfc(sqrt(snr)); 93 | } 94 | 95 | /* 96 | * Compute bit error rate for M-QAM at a given SNR. 97 | * See http://www.dsplog.com/2012/01/01/symbol-error-rate-16qam-64qam-256qam/ 98 | */ 99 | static double mqam_ber(int m, double snr_db) 100 | { 101 | double k = sqrt(1. / ((2./3) * (m - 1))); 102 | double snr = pow(10, (snr_db / 10.)); 103 | double e = erfc(k * sqrt(snr)); 104 | double sqrtm = sqrt(m); 105 | 106 | double b = 2 * (1 - 1./sqrtm) * e; 107 | double c = (1 - 2./sqrtm + 1./m) * pow(e, 2); 108 | double ser = b - c; 109 | 110 | return ser / log2(m); 111 | } 112 | 113 | /* 114 | * Compute packet (frame) error rate given a length 115 | */ 116 | static double per(double ber, enum fec_rate rate, int frame_len) 117 | { 118 | /* free distances for each fec_rate */ 119 | int d_free[] = { 10, 6, 5 }; 120 | 121 | /* initial rate code coefficients */ 122 | double a_d[5][10] = { 123 | /* FEC_RATE_1_2 */ 124 | { 11, 0, 38, 0, 193, 0, 1331, 0, 7275, 0 }, 125 | /* FEC_RATE_2_3 */ 126 | { 1, 16, 48, 158, 642, 2435, 9174, 34701, 131533, 499312 }, 127 | /* FEC_RATE_3_4 */ 128 | { 8, 31, 160, 892, 4512, 23297, 120976, 624304, 3229885, 16721329 }, 129 | /* FEC_RATE_4_5 */ 130 | { 3, 24, 172, 1158, 7408, 48706, 319563, 2094852, 13737566, 90083445 }, 131 | /* FEC_RATE_5_6 */ 132 | { 14, 69, 654, 4996, 39677, 314973, 2503576, 19875546, 157824160, 1253169928 } 133 | }; 134 | 135 | double p_d[ARRAY_SIZE(a_d[0])] = {}; 136 | double rho = ber; 137 | double prob_uncorrected; 138 | int k; 139 | size_t i; 140 | 141 | for (i = 0; i < ARRAY_SIZE(p_d); i++) { 142 | double sum_prob = 0; 143 | int d = d_free[rate] + i; 144 | 145 | if (d & 1) { 146 | for (k = (d + 1)/2; k <= d; k++) 147 | sum_prob += n_choose_k(d, k) * pow(rho, k) * 148 | pow(1 - rho, d - k); 149 | } else { 150 | for (k = d/2 + 1; k <= d; k++) 151 | sum_prob += n_choose_k(d, k) * pow(rho, k) * 152 | pow(1 - rho, d - k); 153 | 154 | sum_prob += .5 * n_choose_k(d, d/2) * pow(rho, d/2) * 155 | pow(1 - rho, d/2); 156 | } 157 | 158 | p_d[i] = sum_prob; 159 | } 160 | 161 | prob_uncorrected = dot(p_d, a_d[rate], ARRAY_SIZE(a_d[rate])); 162 | if (prob_uncorrected > 1) 163 | prob_uncorrected = 1; 164 | 165 | return 1.0 - pow(1 - prob_uncorrected, 8 * frame_len); 166 | } 167 | 168 | double get_error_prob_from_snr(double snr, unsigned int rate_idx, u32 freq, 169 | int frame_len) 170 | { 171 | int m; 172 | enum fec_rate fec; 173 | double ber; 174 | 175 | if (snr <= 0.0) 176 | return 1.0; 177 | 178 | if (freq > 5000) 179 | rate_idx += 4; 180 | 181 | if (rate_idx >= rate_len) 182 | return 1.0; 183 | 184 | m = rateset[rate_idx].mqam; 185 | fec = rateset[rate_idx].fec; 186 | 187 | if (m == 2) 188 | ber = bpsk_ber(snr); 189 | else 190 | ber = mqam_ber(m, snr); 191 | 192 | return per(ber, fec, frame_len); 193 | } 194 | 195 | static double get_error_prob_from_per_matrix(struct wmediumd *ctx, double snr, 196 | unsigned int rate_idx, u32 freq, 197 | int frame_len, struct station *src, 198 | struct station *dst) 199 | { 200 | int signal_idx; 201 | 202 | signal_idx = snr + NOISE_LEVEL - ctx->per_matrix_signal_min; 203 | 204 | if (signal_idx < 0) 205 | return 1.0; 206 | 207 | if (signal_idx >= ctx->per_matrix_row_num) 208 | return 0.0; 209 | 210 | if (freq > 5000) 211 | rate_idx += 4; 212 | 213 | if (rate_idx >= rate_len) 214 | return 1.0; 215 | 216 | return ctx->per_matrix[signal_idx * rate_len + rate_idx]; 217 | } 218 | 219 | int read_per_file(struct wmediumd *ctx, const char *file_name) 220 | { 221 | FILE *fp; 222 | char line[256]; 223 | int signal; 224 | size_t i; 225 | float *temp; 226 | const char *files[] = {"ax"}; 227 | int size = strlen(file_name) + strlen(files[0]) + 1; 228 | char *filename = malloc(size); 229 | 230 | strcpy (filename, file_name); 231 | strcat (filename, files[0]); 232 | 233 | fp = fopen(filename, "r"); 234 | if (fp == NULL) { 235 | w_flogf(ctx, LOG_ERR, stderr, 236 | "fopen failed %s\n", strerror(errno)); 237 | return EXIT_FAILURE; 238 | } 239 | 240 | ctx->per_matrix_signal_min = 1000; 241 | while (fscanf(fp, "%s", line) != EOF){ 242 | if (line[0] == '#') { 243 | if (fgets(line, sizeof(line), fp) == NULL) { 244 | w_flogf(ctx, LOG_ERR, stderr, 245 | "Failed to read comment line\n"); 246 | return EXIT_FAILURE; 247 | } 248 | continue; 249 | } 250 | 251 | signal = atoi(line); 252 | if (ctx->per_matrix_signal_min > signal) 253 | ctx->per_matrix_signal_min = signal; 254 | 255 | if (signal - ctx->per_matrix_signal_min < 0) { 256 | w_flogf(ctx, LOG_ERR, stderr, 257 | "%s: invalid signal=%d\n", __func__, signal); 258 | return EXIT_FAILURE; 259 | } 260 | 261 | temp = realloc(ctx->per_matrix, sizeof(float) * rate_len * 262 | ++ctx->per_matrix_row_num); 263 | if (temp == NULL) { 264 | w_flogf(ctx, LOG_ERR, stderr, 265 | "Out of memory(PER file)\n"); 266 | return EXIT_FAILURE; 267 | } 268 | ctx->per_matrix = temp; 269 | 270 | for (i = 0; i < rate_len; i++) { 271 | if (fscanf(fp, "%f", &ctx->per_matrix[ 272 | (signal - ctx->per_matrix_signal_min) * 273 | rate_len + i]) == EOF) { 274 | w_flogf(ctx, LOG_ERR, stderr, 275 | "Not enough rate found\n"); 276 | return EXIT_FAILURE; 277 | } 278 | } 279 | } 280 | 281 | ctx->get_error_prob = get_error_prob_from_per_matrix; 282 | 283 | return EXIT_SUCCESS; 284 | } 285 | 286 | int index_to_rate(size_t index, u32 freq) 287 | { 288 | if (freq > 5000) 289 | index += 4; 290 | if (index >= rate_len) 291 | index = rate_len - 1; 292 | 293 | return rateset[index].mbps; 294 | } 295 | -------------------------------------------------------------------------------- /wmediumd/wmediumd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd, wireless medium simulator for mac80211_hwsim kernel module 3 | * Copyright (c) 2011 cozybit Inc. 4 | * 5 | * Author: Javier Lopez 6 | * Javier Cardona 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License 10 | * as published by the Free Software Foundation; either version 2 11 | * of the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 | * 02110-1301, USA. 22 | */ 23 | 24 | #ifndef WMEDIUMD_H_ 25 | #define WMEDIUMD_H_ 26 | 27 | #define MAC802154_HWSIM_TX_CTL_REQ_TX_STATUS 2 28 | #define MAC802154_HWSIM_TX_CTL_NO_ACK (1 << 1) 29 | #define MAC802154_HWSIM_TX_STAT_ACK (1 << 2) 30 | 31 | #define MAC802154_HWSIM_CMD_REGISTER 9 32 | #define MAC802154_HWSIM_CMD_FRAME 10 33 | #define MAC802154_HWSIM_CMD_TX_INFO_FRAME 11 34 | 35 | #define IEEE802154_ADDR_SHORT 2 36 | #define IEEE802154_ADDR_EXTENDED 3 37 | 38 | /* mac802154 hwsim netlink attributes 39 | * 40 | * @MAC802154_HWSIM_ATTR_UNSPEC: unspecified attribute to catch error 41 | * @MAC802154_HWSIM_ATTR_RADIO_ID: u32 attribute to identify the radio 42 | * @MAC802154_HWSIM_ATTR_EDGE: nested attribute of edges 43 | * @MAC802154_HWSIM_ATTR_EDGES: list if nested attributes which contains the 44 | * edge information according the radio id 45 | * @__MAC802154_HWSIM_ATTR_MAX: enum limit 46 | */ 47 | enum { 48 | MAC802154_HWSIM_ATTR_UNSPEC, 49 | MAC802154_HWSIM_ATTR_RADIO_ID, 50 | MAC802154_HWSIM_ATTR_RADIO_EDGE, 51 | MAC802154_HWSIM_ATTR_RADIO_EDGES, 52 | MAC802154_HWSIM_ATTR_COOKIE, 53 | MAC802154_HWSIM_ATTR_PAD, 54 | MAC802154_HWSIM_ATTR_FRAME, 55 | MAC802154_HWSIM_ATTR_ADDR_TRANSMITTER, 56 | MAC802154_HWSIM_ATTR_ADDR_RECEIVER, 57 | MAC802154_HWSIM_ATTR_TX_INFO, 58 | MAC802154_HWSIM_ATTR_FLAGS, 59 | __MAC802154_HWSIM_ATTR_MAX, 60 | }; 61 | #define MAC802154_HWSIM_ATTR_MAX (__MAC802154_HWSIM_ATTR_MAX - 1) 62 | 63 | /* mac802154 hwsim edge netlink attributes 64 | * 65 | * @MAC802154_HWSIM_EDGE_ATTR_UNSPEC: unspecified attribute to catch error 66 | * @MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID: radio id where the edge points to 67 | * @MAC802154_HWSIM_EDGE_ATTR_LQI: LQI value which the endpoint radio will 68 | * receive for this edge 69 | * @__MAC802154_HWSIM_ATTR_MAX: enum limit 70 | */ 71 | enum { 72 | MAC802154_HWSIM_EDGE_ATTR_UNSPEC, 73 | MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID, 74 | MAC802154_HWSIM_EDGE_ATTR_LQI, 75 | __MAC802154_HWSIM_EDGE_ATTR_MAX, 76 | }; 77 | 78 | #define MAC802154_HWSIM_EDGE_ATTR_MAX (__MAC802154_HWSIM_EDGE_ATTR_MAX - 1) 79 | 80 | #define VERSION_NR 1 81 | 82 | #define SNR_DEFAULT 30 83 | #define GAIN_DEFAULT 5 84 | #define GAUSS_RANDOM_DEFAULT 1 85 | #define HEIGHT_DEFAULT 1 86 | #define AP_DEFAULT 2 87 | #define MEDIUM_ID_DEFAULT 0 88 | #define EXTENDED_ADDR_LEN 8 89 | #define AP_DEFAULT_PORT 4001 90 | #define PAGE_SIZE 4096 91 | 92 | #include 93 | #include 94 | #include 95 | #include 96 | 97 | #include "list.h" 98 | #include "ieee802154.h" 99 | 100 | typedef uint8_t u8; 101 | typedef uint32_t u32; 102 | typedef uint64_t u64; 103 | 104 | #define TIME_FMT "%lld.%06lld" 105 | #define TIME_ARGS(a) ((unsigned long long)(a)->tv_sec), ((unsigned long long)(a)->tv_nsec/1000) 106 | 107 | #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" 108 | #define MAC_ARGS(a) a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7] 109 | 110 | #ifndef min 111 | #define min(x,y) ((x) < (y) ? (x) : (y)) 112 | #endif 113 | 114 | #define NOISE_LEVEL (-91) 115 | #define CCA_THRESHOLD (-90) 116 | #define ENABLE_MEDIUM_DETECTION true 117 | 118 | enum En_OperationMode 119 | { 120 | LOCAL, 121 | REMOTE 122 | }; 123 | 124 | struct wqueue { 125 | struct list_head frames; 126 | int cw_min; 127 | int cw_max; 128 | }; 129 | 130 | struct station { 131 | int index; 132 | u8 short_addr[16]; 133 | int addr_len; 134 | u8 extended_addr[64]; /* virtual interface mac address */ 135 | u8 hwaddr[8]; /* hardware address of hwsim radio */ 136 | double x, y, z; /* position of the station [m] */ 137 | double dir_x, dir_y; /* direction of the station [meter per MOVE_INTERVAL] */ 138 | int tx_power; /* transmission power [dBm] */ 139 | int gain; /* Antenna Gain [dBm] */ 140 | //int height; /* Antenna Height [m] */ 141 | int gRandom; /* Gaussian Random */ 142 | int isap; /* verify whether the node is ap */ 143 | double freq; /* frequency [Mhz] */ 144 | struct wqueue queues[IEEE80211_NUM_ACS]; 145 | struct list_head list; 146 | int medium_id; 147 | }; 148 | 149 | struct wmediumd { 150 | int op_mode; 151 | int timerfd; 152 | int net_sock; 153 | struct nl_sock *sock; 154 | bool enable_medium_detection; 155 | int num_stas; 156 | struct list_head pending_txinfo_frames; 157 | struct list_head stations; 158 | struct station **sta_array; 159 | int *snr_matrix; 160 | double *error_prob_matrix; 161 | double **station_err_matrix; 162 | struct intf_info *intf; 163 | struct timespec intf_updated; 164 | #define MOVE_INTERVAL (3) /* station movement interval [sec] */ 165 | struct timespec next_move; 166 | void *path_loss_param; 167 | float *per_matrix; 168 | int per_matrix_row_num; 169 | int per_matrix_signal_min; 170 | int fading_coefficient; 171 | int noise_threshold; 172 | 173 | struct nl_cb *cb; 174 | int family_id; 175 | 176 | int (*get_link_snr)(struct wmediumd *, struct station *, 177 | struct station *); 178 | double (*get_error_prob)(struct wmediumd *, double, unsigned int, u32, 179 | int, struct station *, struct station *); 180 | int (*calc_path_loss)(void *, struct station *, 181 | struct station *); 182 | void (*move_stations)(struct wmediumd *); 183 | int (*get_fading_signal)(struct wmediumd *); 184 | 185 | u8 log_lvl; 186 | }; 187 | 188 | struct hwsim_tx_rate { 189 | signed char idx; 190 | unsigned char count; 191 | }; 192 | 193 | struct frame { 194 | struct list_head list; /* frame queue list */ 195 | struct timespec expires; /* frame delivery (absolute) */ 196 | bool acked; 197 | u64 cookie; 198 | u32 freq; 199 | int flags; 200 | int lqi; 201 | int duration; 202 | int tx_rates_count; 203 | struct station *sender; 204 | uint8_t dest_mode; 205 | struct hwsim_tx_rate tx_rates[IEEE80211_TX_MAX_RATES]; 206 | size_t data_len; 207 | u8 data[0]; /* frame contents */ 208 | }; 209 | 210 | struct log_distance_model_param { 211 | double path_loss_exponent; 212 | double Xg; 213 | }; 214 | 215 | struct itu_model_param { 216 | int nFLOORS; 217 | int lF; 218 | int pL; 219 | }; 220 | 221 | struct log_normal_shadowing_model_param { 222 | int sL; 223 | double path_loss_exponent; 224 | }; 225 | 226 | struct free_space_model_param { 227 | int sL; 228 | }; 229 | 230 | struct two_ray_ground_model_param { 231 | int sL; 232 | }; 233 | 234 | struct intf_info { 235 | int lqi; 236 | int duration; 237 | double prob_col; 238 | }; 239 | 240 | void station_init_queues(struct station *station); 241 | double get_error_prob_from_snr(double snr, unsigned int rate_idx, u32 freq, 242 | int frame_len); 243 | bool timespec_before(struct timespec *t1, struct timespec *t2); 244 | int read_per_file(struct wmediumd *ctx, const char *file_name); 245 | int w_logf(struct wmediumd *ctx, u8 level, const char *format, ...); 246 | int w_flogf(struct wmediumd *ctx, u8 level, FILE *stream, const char *format, ...); 247 | int index_to_rate(size_t index, u32 freq); 248 | void detect_mediums(struct wmediumd *ctx, struct station *src, struct station *dest); 249 | 250 | #endif /* WMEDIUMD_H_ */ 251 | -------------------------------------------------------------------------------- /wmediumd/wmediumd_dynamic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include "wmediumd_dynamic.h" 25 | 26 | #define DEFAULT_DYNAMIC_SNR -10 27 | #define DEFAULT_DYNAMIC_ERRPROB 1.0 28 | #define DEFAULT_FULL_DYNAMIC_ERRPROB 1.0 29 | 30 | pthread_rwlock_t snr_lock = PTHREAD_RWLOCK_INITIALIZER; 31 | 32 | #define swap_matrix(matrix_ptr, oldsize, newsize, elem_type, backup_ptr) \ 33 | backup_ptr = malloc(sizeof(elem_type) * oldsize * oldsize); \ 34 | memcpy(backup_ptr, matrix_ptr, sizeof(elem_type) * oldsize * oldsize); \ 35 | free(matrix_ptr); \ 36 | matrix_ptr = malloc(sizeof(elem_type) * newsize * newsize); 37 | 38 | int add_station(struct wmediumd *ctx, const u8 addr[]) { 39 | struct station *sta_loop; 40 | list_for_each_entry(sta_loop, &ctx->stations, list) { 41 | if (memcmp(sta_loop->extended_addr, addr, ETH_ALEN) == 0) 42 | return -EEXIST; 43 | } 44 | 45 | pthread_rwlock_wrlock(&snr_lock); 46 | size_t oldnum = (size_t) ctx->num_stas; 47 | size_t newnum = oldnum + 1; 48 | 49 | // Save old matrix and init new matrix 50 | union { 51 | int *old_snr_matrix; 52 | double *old_errprob_matrix; 53 | double **old_station_err_matrix; 54 | } matrizes; 55 | int ret; 56 | if (ctx->station_err_matrix != NULL) { 57 | swap_matrix(ctx->station_err_matrix, oldnum, newnum, double*, matrizes.old_station_err_matrix); 58 | } else if (ctx->error_prob_matrix != NULL) { 59 | swap_matrix(ctx->error_prob_matrix, oldnum, newnum, double, matrizes.old_errprob_matrix); 60 | } else { 61 | swap_matrix(ctx->snr_matrix, oldnum, newnum, int, matrizes.old_snr_matrix); 62 | } 63 | 64 | // Copy old matrix 65 | for (size_t x = 0; x < oldnum; x++) { 66 | for (size_t y = 0; y < oldnum; y++) { 67 | if (ctx->station_err_matrix != NULL) { 68 | ctx->station_err_matrix[x * newnum + y] = matrizes.old_station_err_matrix[x * oldnum + y]; 69 | } else if (ctx->error_prob_matrix != NULL) { 70 | ctx->error_prob_matrix[x * newnum + y] = matrizes.old_errprob_matrix[x * oldnum + y]; 71 | } else { 72 | ctx->snr_matrix[x * newnum + y] = matrizes.old_snr_matrix[x * oldnum + y]; 73 | } 74 | } 75 | } 76 | 77 | // Fill last lines with default snr 78 | for (size_t x = 0; x < newnum; x++) { 79 | if (ctx->station_err_matrix != NULL) { 80 | ctx->station_err_matrix[x * newnum + oldnum] = malloc( 81 | SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX * sizeof(double)); 82 | for (int i = 0; i < SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX; i++) { 83 | ctx->station_err_matrix[x * newnum + oldnum][i] = DEFAULT_FULL_DYNAMIC_ERRPROB; 84 | } 85 | } else if (ctx->error_prob_matrix != NULL) { 86 | ctx->error_prob_matrix[x * newnum + oldnum] = DEFAULT_DYNAMIC_ERRPROB; 87 | } else { 88 | ctx->snr_matrix[x * newnum + oldnum] = DEFAULT_DYNAMIC_SNR; 89 | } 90 | } 91 | for (size_t y = 0; y < newnum; y++) { 92 | if (ctx->station_err_matrix != NULL) { 93 | ctx->station_err_matrix[oldnum * newnum + y] = malloc( 94 | SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX * sizeof(double)); 95 | for (int i = 0; i < SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX; i++) { 96 | ctx->station_err_matrix[oldnum * newnum + y][i] = DEFAULT_FULL_DYNAMIC_ERRPROB; 97 | } 98 | } else if (ctx->error_prob_matrix != NULL) { 99 | ctx->error_prob_matrix[oldnum * newnum + y] = DEFAULT_DYNAMIC_ERRPROB; 100 | } else { 101 | ctx->snr_matrix[oldnum * newnum + y] = DEFAULT_DYNAMIC_SNR; 102 | } 103 | } 104 | 105 | if (ctx->station_err_matrix != NULL) { 106 | free(matrizes.old_station_err_matrix); 107 | } else if (ctx->error_prob_matrix != NULL) { 108 | free(matrizes.old_errprob_matrix); 109 | } else { 110 | free(matrizes.old_snr_matrix); 111 | } 112 | 113 | // Init new station object 114 | struct station *station; 115 | station = malloc(sizeof(*station)); 116 | if (!station) { 117 | ret = -ENOMEM; 118 | goto out; 119 | } 120 | station->index = (int) oldnum; 121 | memcpy(station->extended_addr, addr, ETH_ALEN); 122 | memcpy(station->hwaddr, addr, ETH_ALEN); 123 | station->isap = AP_DEFAULT; 124 | station->gain = GAIN_DEFAULT; 125 | station->tx_power = SNR_DEFAULT; 126 | station->medium_id = MEDIUM_ID_DEFAULT; 127 | list_add_tail(&station->list, &ctx->stations); 128 | //realloc(ctx->sta_array, 1); 129 | ctx->sta_array[station->index] = station; 130 | ctx->num_stas = (int) newnum; 131 | ret = station->index; 132 | 133 | out: 134 | pthread_rwlock_unlock(&snr_lock); 135 | return ret; 136 | } 137 | 138 | int del_station(struct wmediumd *ctx, struct station *station) { 139 | if (ctx->num_stas == 0) { 140 | return -ENXIO; 141 | } 142 | size_t oldnum = (size_t) ctx->num_stas; 143 | size_t newnum = oldnum - 1; 144 | 145 | // Save old matrix and init new matrix 146 | union { 147 | int *old_snr_matrix; 148 | double *old_errprob_matrix; 149 | double **old_station_err_matrix; 150 | } matrizes; 151 | if (ctx->station_err_matrix != NULL) { 152 | swap_matrix(ctx->station_err_matrix, oldnum, newnum, double*, matrizes.old_station_err_matrix); 153 | } else if (ctx->error_prob_matrix != NULL) { 154 | swap_matrix(ctx->error_prob_matrix, oldnum, newnum, double, matrizes.old_errprob_matrix); 155 | } else { 156 | swap_matrix(ctx->snr_matrix, oldnum, newnum, int, matrizes.old_snr_matrix); 157 | } 158 | 159 | size_t index = (size_t) station->index; 160 | 161 | // Decreasing index of stations following deleted station 162 | struct station *sta_loop = station; 163 | list_for_each_entry_from(sta_loop, &ctx->stations, list) { 164 | sta_loop->index = sta_loop->index - 1; 165 | } 166 | 167 | if (ctx->station_err_matrix != NULL) { 168 | for (size_t x = 0; x < oldnum; x++) { 169 | // free old specific matrices 170 | if (matrizes.old_station_err_matrix[x * oldnum + index] != NULL) { 171 | free(matrizes.old_station_err_matrix[x * oldnum + index]); 172 | } 173 | } 174 | 175 | for (size_t y = 0; y < oldnum; y++) { 176 | if(y == index){ 177 | continue; 178 | } 179 | // free old specific matrices 180 | if (matrizes.old_station_err_matrix[index * oldnum + y] != NULL) { 181 | free(matrizes.old_station_err_matrix[index * oldnum + y]); 182 | } 183 | } 184 | } 185 | 186 | // Copy all values not related to deleted station 187 | int xnew = 0; 188 | for (size_t x = 0; x < oldnum; x++) { 189 | if (x == index) { 190 | continue; 191 | } 192 | int ynew = 0; 193 | for (size_t y = 0; y < oldnum; y++) { 194 | if (y == index) { 195 | continue; 196 | } 197 | if (ctx->station_err_matrix != NULL) { 198 | ctx->station_err_matrix[xnew * newnum + ynew] = matrizes.old_station_err_matrix[x * oldnum + y]; 199 | } else if (ctx->error_prob_matrix != NULL) { 200 | ctx->error_prob_matrix[xnew * newnum + ynew] = matrizes.old_errprob_matrix[x * oldnum + y]; 201 | } else { 202 | ctx->snr_matrix[xnew * newnum + ynew] = matrizes.old_snr_matrix[x * oldnum + y]; 203 | } 204 | ynew++; 205 | } 206 | xnew++; 207 | } 208 | 209 | if (ctx->station_err_matrix != NULL) { 210 | free(matrizes.old_station_err_matrix); 211 | } else if (ctx->error_prob_matrix != NULL) { 212 | free(matrizes.old_errprob_matrix); 213 | } else { 214 | free(matrizes.old_snr_matrix); 215 | } 216 | 217 | list_del(&station->list); 218 | ctx->num_stas = (int) newnum; 219 | 220 | free(station); 221 | return 0; 222 | } 223 | 224 | int del_station_by_id(struct wmediumd *ctx, const i32 id) { 225 | pthread_rwlock_wrlock(&snr_lock); 226 | int ret; 227 | struct station *station; 228 | list_for_each_entry(station, &ctx->stations, list) { 229 | if (station->index == id) { 230 | ret = del_station(ctx, station); 231 | goto out; 232 | } 233 | } 234 | 235 | out: 236 | ret = -ENODEV; 237 | pthread_rwlock_unlock(&snr_lock); 238 | return ret; 239 | } 240 | 241 | int del_station_by_mac(struct wmediumd *ctx, const u8 *addr) { 242 | pthread_rwlock_wrlock(&snr_lock); 243 | int ret; 244 | struct station *station; 245 | list_for_each_entry(station, &ctx->stations, list) { 246 | if (memcmp(addr, station->extended_addr, ETH_ALEN) == 0) { 247 | ret = del_station(ctx, station); 248 | goto out; 249 | } 250 | } 251 | ret = -ENODEV; 252 | 253 | out: 254 | pthread_rwlock_unlock(&snr_lock); 255 | return ret; 256 | } 257 | -------------------------------------------------------------------------------- /wmediumd/wserver_messages_network.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include "wserver_messages_network.h" 24 | 25 | 26 | int sendfull(int sock, const void *buf, size_t len, size_t shift, int flags) { 27 | size_t total = 0; 28 | size_t bytesleft = len; 29 | ssize_t currsent = 0; 30 | while (total < len) { 31 | currsent = send(sock, buf + shift + total, bytesleft, flags); 32 | if (currsent == -1) { 33 | if (errno == EPIPE || errno == ECONNRESET) { 34 | return WACTION_DISCONNECTED; 35 | } else { 36 | return -errno; 37 | } 38 | } 39 | total += currsent; 40 | bytesleft -= currsent; 41 | } 42 | return WACTION_CONTINUE; 43 | } 44 | 45 | int recvfull(int sock, void *buf, size_t len, size_t shift, int flags) { 46 | size_t total = 0; 47 | size_t bytesleft = len; 48 | ssize_t currrecv = 0; 49 | while (total < len) { 50 | currrecv = recv(sock, buf + shift + total, bytesleft, flags); 51 | if (currrecv == -1) { 52 | if (errno == EPIPE || errno == ECONNRESET) { 53 | return WACTION_DISCONNECTED; 54 | } else { 55 | return -errno; 56 | } 57 | } else if (currrecv == 0) { 58 | return WACTION_DISCONNECTED; 59 | } 60 | total += currrecv; 61 | bytesleft -= currrecv; 62 | } 63 | return WACTION_CONTINUE; 64 | } 65 | 66 | void htonu_wrapper(u32 *value) { 67 | *value = htonl(*value); 68 | } 69 | 70 | void ntohu_wrapper(u32 *value) { 71 | *value = ntohl(*value); 72 | } 73 | 74 | void htoni_wrapper(i32 *value) { 75 | *value = htonl(*value); 76 | } 77 | 78 | void ntohi_wrapper(i32 *value) { 79 | *value = ntohl(*value); 80 | } 81 | 82 | void hton_base(wserver_msg *elem) { 83 | UNUSED(elem); 84 | } 85 | 86 | void hton_snr_update_request(snr_update_request *elem) { 87 | hton_base(&elem->base); 88 | htoni_wrapper(&elem->snr); 89 | } 90 | 91 | void hton_snr_update_response(snr_update_response *elem) { 92 | hton_base(&elem->base); 93 | hton_snr_update_request(&elem->request); 94 | } 95 | 96 | void hton_position_update_request(position_update_request *elem) { 97 | hton_base(&elem->base); 98 | htoni_wrapper((int32_t*)&elem->posX); 99 | htoni_wrapper((int32_t*)&elem->posY); 100 | htoni_wrapper((int32_t*)&elem->posZ); 101 | } 102 | 103 | void hton_position_update_response(position_update_response *elem) { 104 | hton_base(&elem->base); 105 | hton_position_update_request(&elem->request); 106 | } 107 | 108 | void hton_txpower_update_request(txpower_update_request *elem) { 109 | hton_base(&elem->base); 110 | htoni_wrapper((int32_t*)&elem->txpower_); 111 | } 112 | 113 | void hton_txpower_update_response(txpower_update_response *elem) { 114 | hton_base(&elem->base); 115 | hton_txpower_update_request(&elem->request); 116 | } 117 | 118 | void hton_gaussian_random_update_request(gaussian_random_update_request *elem) { 119 | hton_base(&elem->base); 120 | htoni_wrapper((int32_t*)&elem->gaussian_random_); 121 | } 122 | 123 | void hton_gaussian_random_update_response(gaussian_random_update_response *elem) { 124 | hton_base(&elem->base); 125 | hton_gaussian_random_update_request(&elem->request); 126 | } 127 | 128 | void hton_gain_update_request(gain_update_request *elem) { 129 | hton_base(&elem->base); 130 | htoni_wrapper((int32_t*)&elem->gain_); 131 | } 132 | 133 | void hton_gain_update_response(gain_update_response *elem) { 134 | hton_base(&elem->base); 135 | hton_gain_update_request(&elem->request); 136 | } 137 | 138 | void hton_errprob_update_request(errprob_update_request *elem) { 139 | hton_base(&elem->base); 140 | htonu_wrapper(&elem->errprob); 141 | } 142 | 143 | void hton_errprob_update_response(errprob_update_response *elem) { 144 | hton_base(&elem->base); 145 | hton_errprob_update_request(&elem->request); 146 | } 147 | 148 | void hton_specprob_update_request(specprob_update_request *elem) { 149 | hton_base(&elem->base); 150 | for (int i = 0; i < SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX; i++) { 151 | htonu_wrapper(&elem->errprob[i]); 152 | } 153 | } 154 | 155 | void hton_specprob_update_response(specprob_update_response *elem) { 156 | hton_base(&elem->base); 157 | } 158 | 159 | void hton_station_del_by_mac_request(station_del_by_mac_request *elem) { 160 | hton_base(&elem->base); 161 | } 162 | 163 | void hton_station_del_by_mac_response(station_del_by_mac_response *elem) { 164 | hton_base(&elem->base); 165 | hton_station_del_by_mac_request(&elem->request); 166 | } 167 | 168 | void hton_station_del_by_id_request(station_del_by_id_request *elem) { 169 | hton_base(&elem->base); 170 | htoni_wrapper(&elem->id); 171 | } 172 | 173 | void hton_station_del_by_id_response(station_del_by_id_response *elem) { 174 | hton_base(&elem->base); 175 | hton_station_del_by_id_request(&elem->request); 176 | } 177 | 178 | void hton_station_add_request(station_add_request *elem) { 179 | hton_base(&elem->base); 180 | } 181 | 182 | void hton_station_add_response(station_add_response *elem) { 183 | hton_base(&elem->base); 184 | hton_station_add_request(&elem->request); 185 | htoni_wrapper(&elem->created_id); 186 | } 187 | 188 | void hton_medium_update_request(medium_update_request *elem) { 189 | hton_base(&elem->base); 190 | htoni_wrapper((int32_t*)&elem->medium_id_); 191 | } 192 | 193 | void hton_medium_update_response(medium_update_response *elem) { 194 | hton_base(&elem->base); 195 | hton_medium_update_request(&elem->request); 196 | } 197 | 198 | void ntoh_base(wserver_msg *elem) { 199 | UNUSED(elem); 200 | } 201 | 202 | void ntoh_snr_update_request(snr_update_request *elem) { 203 | ntoh_base(&elem->base); 204 | ntohi_wrapper(&elem->snr); 205 | } 206 | 207 | void ntoh_snr_update_response(snr_update_response *elem) { 208 | ntoh_base(&elem->base); 209 | ntoh_snr_update_request(&elem->request); 210 | } 211 | 212 | void ntoh_position_update_request(position_update_request *elem) { 213 | ntoh_base(&elem->base); 214 | ntohi_wrapper((int32_t*)&elem->posX); 215 | ntohi_wrapper((int32_t*)&elem->posY); 216 | ntohi_wrapper((int32_t*)&elem->posZ); 217 | } 218 | 219 | void ntoh_position_update_response(position_update_response *elem) { 220 | ntoh_base(&elem->base); 221 | ntoh_position_update_request(&elem->request); 222 | } 223 | 224 | void ntoh_txpower_update_request(txpower_update_request *elem) { 225 | ntoh_base(&elem->base); 226 | ntohi_wrapper((int32_t*)&elem->txpower_); 227 | } 228 | 229 | void ntoh_txpower_update_response(txpower_update_response *elem) { 230 | ntoh_base(&elem->base); 231 | ntoh_txpower_update_request(&elem->request); 232 | } 233 | 234 | void ntoh_gaussian_random_update_request(gaussian_random_update_request *elem) { 235 | ntoh_base(&elem->base); 236 | ntohi_wrapper((int32_t*)&elem->gaussian_random_); 237 | } 238 | 239 | void ntoh_gaussian_random_update_response(gaussian_random_update_response *elem) { 240 | ntoh_base(&elem->base); 241 | ntoh_gaussian_random_update_request(&elem->request); 242 | } 243 | 244 | void ntoh_gain_update_request(gain_update_request *elem) { 245 | ntoh_base(&elem->base); 246 | ntohi_wrapper((int32_t*)&elem->gain_); 247 | } 248 | 249 | void ntoh_gain_update_response(gain_update_response *elem) { 250 | ntoh_base(&elem->base); 251 | ntoh_gain_update_request(&elem->request); 252 | } 253 | 254 | void ntoh_errprob_update_request(errprob_update_request *elem) { 255 | ntoh_base(&elem->base); 256 | ntohu_wrapper(&elem->errprob); 257 | } 258 | 259 | void ntoh_errprob_update_response(errprob_update_response *elem) { 260 | ntoh_base(&elem->base); 261 | ntoh_errprob_update_request(&elem->request); 262 | } 263 | 264 | void ntoh_specprob_update_request(specprob_update_request *elem) { 265 | ntoh_base(&elem->base); 266 | for (int i = 0; i < SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX; i++) { 267 | ntohu_wrapper(&elem->errprob[i]); 268 | } 269 | } 270 | 271 | void ntoh_specprob_update_response(specprob_update_response *elem) { 272 | ntoh_base(&elem->base); 273 | } 274 | 275 | void ntoh_station_del_by_mac_request(station_del_by_mac_request *elem) { 276 | ntoh_base(&elem->base); 277 | } 278 | 279 | void ntoh_station_del_by_mac_response(station_del_by_mac_response *elem) { 280 | ntoh_base(&elem->base); 281 | ntoh_station_del_by_mac_request(&elem->request); 282 | } 283 | 284 | void ntoh_station_del_by_id_request(station_del_by_id_request *elem) { 285 | ntoh_base(&elem->base); 286 | ntohi_wrapper(&elem->id); 287 | } 288 | 289 | void ntoh_station_del_by_id_response(station_del_by_id_response *elem) { 290 | ntoh_base(&elem->base); 291 | ntoh_station_del_by_id_request(&elem->request); 292 | } 293 | 294 | void ntoh_station_add_request(station_add_request *elem) { 295 | ntoh_base(&elem->base); 296 | } 297 | 298 | void ntoh_station_add_response(station_add_response *elem) { 299 | ntoh_base(&elem->base); 300 | ntoh_station_add_request(&elem->request); 301 | ntohi_wrapper(&elem->created_id); 302 | } 303 | 304 | void ntoh_medium_update_request(medium_update_request *elem) { 305 | ntoh_base(&elem->base); 306 | ntohi_wrapper((int32_t*)&elem->medium_id_); 307 | } 308 | 309 | void ntoh_medium_update_response(medium_update_response *elem) { 310 | ntoh_base(&elem->base); 311 | ntoh_medium_update_request(&elem->request); 312 | } -------------------------------------------------------------------------------- /wmediumd/wserver_messages.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include "wserver_messages.h" 24 | #include "wserver_messages_network.h" 25 | 26 | 27 | #define align_send_msg(sock_fd, elem, type, typeint) \ 28 | type tosend; \ 29 | *((u8 *) elem) = typeint; \ 30 | memcpy(&tosend, elem, sizeof(type)); \ 31 | hton_type(&tosend, type);\ 32 | return sendfull(sock_fd, &tosend, sizeof(type), 0, MSG_NOSIGNAL); 33 | 34 | #define align_recv_msg(sock_fd, elem, elemtype, typeint) \ 35 | int ret; \ 36 | ret = recvfull(sock_fd, elem, sizeof(elemtype) - sizeof(wserver_msg), sizeof(wserver_msg), 0); \ 37 | ntoh_type(elem, elemtype); \ 38 | elem->base.type = typeint; \ 39 | return ret; 40 | 41 | 42 | int send_snr_update_request(int sock, const snr_update_request *elem) { 43 | align_send_msg(sock, elem, snr_update_request, WSERVER_SNR_UPDATE_REQUEST_TYPE) 44 | } 45 | 46 | int send_snr_update_response(int sock, const snr_update_response *elem) { 47 | align_send_msg(sock, elem, snr_update_response, WSERVER_SNR_UPDATE_RESPONSE_TYPE) 48 | } 49 | 50 | int send_position_update_request(int sock, const position_update_request *elem) { 51 | align_send_msg(sock, elem, position_update_request, WSERVER_POSITION_UPDATE_REQUEST_TYPE) 52 | } 53 | 54 | int send_position_update_response(int sock, const position_update_response *elem) { 55 | align_send_msg(sock, elem, position_update_response, WSERVER_POSITION_UPDATE_RESPONSE_TYPE) 56 | } 57 | 58 | int send_txpower_update_request(int sock, const txpower_update_request *elem) { 59 | align_send_msg(sock, elem, txpower_update_request, WSERVER_TXPOWER_UPDATE_REQUEST_TYPE) 60 | } 61 | 62 | int send_txpower_update_response(int sock, const txpower_update_response *elem) { 63 | align_send_msg(sock, elem, txpower_update_response, WSERVER_TXPOWER_UPDATE_RESPONSE_TYPE) 64 | } 65 | 66 | int send_gaussian_random_update_request(int sock, const gaussian_random_update_request *elem) { 67 | align_send_msg(sock, elem, gaussian_random_update_request, WSERVER_GAUSSIAN_RANDOM_UPDATE_REQUEST_TYPE) 68 | } 69 | 70 | int send_gaussian_random_update_response(int sock, const gaussian_random_update_response *elem) { 71 | align_send_msg(sock, elem, gaussian_random_update_response, WSERVER_GAUSSIAN_RANDOM_UPDATE_RESPONSE_TYPE) 72 | } 73 | 74 | int send_gain_update_request(int sock, const gain_update_request *elem) { 75 | align_send_msg(sock, elem, gain_update_request, WSERVER_GAIN_UPDATE_REQUEST_TYPE) 76 | } 77 | 78 | int send_gain_update_response(int sock, const gain_update_response *elem) { 79 | align_send_msg(sock, elem, gain_update_response, WSERVER_GAIN_UPDATE_RESPONSE_TYPE) 80 | } 81 | 82 | int send_errprob_update_request(int sock, const errprob_update_request *elem) { 83 | align_send_msg(sock, elem, errprob_update_request, WSERVER_ERRPROB_UPDATE_REQUEST_TYPE) 84 | } 85 | 86 | int send_errprob_update_response(int sock, const errprob_update_response *elem) { 87 | align_send_msg(sock, elem, errprob_update_response, WSERVER_ERRPROB_UPDATE_RESPONSE_TYPE) 88 | } 89 | 90 | int send_specprob_update_request(int sock, const specprob_update_request *elem) { 91 | align_send_msg(sock, elem, specprob_update_request, WSERVER_SPECPROB_UPDATE_REQUEST_TYPE) 92 | } 93 | 94 | int send_specprob_update_response(int sock, const specprob_update_response *elem) { 95 | align_send_msg(sock, elem, specprob_update_response, WSERVER_SPECPROB_UPDATE_RESPONSE_TYPE) 96 | } 97 | 98 | int send_station_del_by_mac_request(int sock, const station_del_by_mac_request *elem) { 99 | align_send_msg(sock, elem, station_del_by_mac_request, WSERVER_DEL_BY_MAC_REQUEST_TYPE) 100 | } 101 | 102 | int send_station_del_by_mac_response(int sock, const station_del_by_mac_response *elem) { 103 | align_send_msg(sock, elem, station_del_by_mac_response, WSERVER_DEL_BY_MAC_RESPONSE_TYPE) 104 | } 105 | 106 | int send_station_del_by_id_request(int sock, const station_del_by_id_request *elem) { 107 | align_send_msg(sock, elem, station_del_by_id_request, WSERVER_DEL_BY_ID_REQUEST_TYPE) 108 | } 109 | 110 | int send_station_del_by_id_response(int sock, const station_del_by_id_response *elem) { 111 | align_send_msg(sock, elem, station_del_by_id_response, WSERVER_DEL_BY_ID_RESPONSE_TYPE) 112 | } 113 | 114 | int send_station_add_request(int sock, const station_add_request *elem) { 115 | align_send_msg(sock, elem, station_add_request, WSERVER_ADD_REQUEST_TYPE) 116 | } 117 | 118 | int send_station_add_response(int sock, const station_add_response *elem) { 119 | align_send_msg(sock, elem, station_add_response, WSERVER_ADD_RESPONSE_TYPE) 120 | } 121 | 122 | int send_medium_update_request(int sock, const medium_update_request *elem) { 123 | align_send_msg(sock, elem, medium_update_request , WSERVER_MEDIUM_UPDATE_REQUEST_TYPE) 124 | } 125 | 126 | int send_medium_update_response(int sock, const medium_update_response *elem) { 127 | align_send_msg(sock, elem, medium_update_response , WSERVER_MEDIUM_UPDATE_RESPONSE_TYPE) 128 | } 129 | 130 | int recv_snr_update_request(int sock, snr_update_request *elem) { 131 | align_recv_msg(sock, elem, snr_update_request, WSERVER_SNR_UPDATE_REQUEST_TYPE) 132 | } 133 | 134 | int recv_snr_update_response(int sock, snr_update_response *elem) { 135 | align_recv_msg(sock, elem, snr_update_response, WSERVER_SNR_UPDATE_RESPONSE_TYPE) 136 | } 137 | 138 | int recv_position_update_request(int sock, position_update_request *elem) { 139 | align_recv_msg(sock, elem, position_update_request, WSERVER_POSITION_UPDATE_REQUEST_TYPE) 140 | } 141 | 142 | int recv_position_update_response(int sock, position_update_response *elem) { 143 | align_recv_msg(sock, elem, position_update_response, WSERVER_POSITION_UPDATE_RESPONSE_TYPE) 144 | } 145 | 146 | int recv_txpower_update_request(int sock, txpower_update_request *elem) { 147 | align_recv_msg(sock, elem, txpower_update_request, WSERVER_TXPOWER_UPDATE_REQUEST_TYPE) 148 | } 149 | 150 | int recv_txpower_update_response(int sock, txpower_update_response *elem) { 151 | align_recv_msg(sock, elem, txpower_update_response, WSERVER_TXPOWER_UPDATE_RESPONSE_TYPE) 152 | } 153 | 154 | int recv_gaussian_random_update_request(int sock, gaussian_random_update_request *elem) { 155 | align_recv_msg(sock, elem, gaussian_random_update_request, WSERVER_GAUSSIAN_RANDOM_UPDATE_REQUEST_TYPE) 156 | } 157 | 158 | int recv_gaussian_random_update_response(int sock, gaussian_random_update_response *elem) { 159 | align_recv_msg(sock, elem, gaussian_random_update_response, WSERVER_GAUSSIAN_RANDOM_UPDATE_RESPONSE_TYPE) 160 | } 161 | 162 | int recv_gain_update_request(int sock, gain_update_request *elem) { 163 | align_recv_msg(sock, elem, gain_update_request, WSERVER_GAIN_UPDATE_REQUEST_TYPE) 164 | } 165 | 166 | int recv_gain_update_response(int sock, gain_update_response *elem) { 167 | align_recv_msg(sock, elem, gain_update_response, WSERVER_GAIN_UPDATE_RESPONSE_TYPE) 168 | } 169 | 170 | int recv_errprob_update_request(int sock, errprob_update_request *elem) { 171 | align_recv_msg(sock, elem, errprob_update_request, WSERVER_ERRPROB_UPDATE_REQUEST_TYPE) 172 | } 173 | 174 | int recv_errprob_update_response(int sock, errprob_update_response *elem) { 175 | align_recv_msg(sock, elem, errprob_update_response, WSERVER_ERRPROB_UPDATE_RESPONSE_TYPE) 176 | } 177 | 178 | int recv_specprob_update_request(int sock, specprob_update_request *elem) { 179 | align_recv_msg(sock, elem, specprob_update_request, WSERVER_SPECPROB_UPDATE_REQUEST_TYPE) 180 | } 181 | 182 | int recv_specprob_update_response(int sock, specprob_update_response *elem) { 183 | align_recv_msg(sock, elem, specprob_update_response, WSERVER_SPECPROB_UPDATE_RESPONSE_TYPE) 184 | } 185 | 186 | int recv_station_del_by_mac_request(int sock, station_del_by_mac_request *elem) { 187 | align_recv_msg(sock, elem, station_del_by_mac_request, WSERVER_DEL_BY_MAC_REQUEST_TYPE) 188 | } 189 | 190 | int recv_station_del_by_mac_response(int sock, station_del_by_mac_response *elem) { 191 | align_recv_msg(sock, elem, station_del_by_mac_response, WSERVER_DEL_BY_MAC_RESPONSE_TYPE) 192 | } 193 | 194 | int recv_station_del_by_id_request(int sock, station_del_by_id_request *elem) { 195 | align_recv_msg(sock, elem, station_del_by_id_request, WSERVER_DEL_BY_ID_REQUEST_TYPE) 196 | } 197 | 198 | int recv_station_del_by_id_response(int sock, station_del_by_id_response *elem) { 199 | align_recv_msg(sock, elem, station_del_by_id_response, WSERVER_DEL_BY_ID_RESPONSE_TYPE) 200 | } 201 | 202 | int recv_station_add_request(int sock, station_add_request *elem) { 203 | align_recv_msg(sock, elem, station_add_request, WSERVER_ADD_REQUEST_TYPE) 204 | } 205 | 206 | int recv_station_add_response(int sock, station_add_response *elem) { 207 | align_recv_msg(sock, elem, station_add_response, WSERVER_ADD_RESPONSE_TYPE) 208 | } 209 | 210 | int recv_medium_update_request(int sock, medium_update_request *elem) { 211 | align_recv_msg(sock, elem, medium_update_request , WSERVER_MEDIUM_UPDATE_REQUEST_TYPE) 212 | } 213 | 214 | int recv_medium_update_response(int sock, medium_update_response *elem) { 215 | align_recv_msg(sock, elem, medium_update_response , WSERVER_MEDIUM_UPDATE_RESPONSE_TYPE) 216 | } 217 | 218 | int wserver_recv_msg_base(int sock_fd, wserver_msg *base, int *recv_type) { 219 | int ret = recvfull(sock_fd, base, sizeof(wserver_msg), 0, 0); 220 | if (ret) { 221 | return ret; 222 | } 223 | ntoh_base(base); 224 | *recv_type = base->type; 225 | hton_base(base); 226 | return 0; 227 | } 228 | 229 | ssize_t get_msg_size_by_type(int type) { 230 | switch (type) { 231 | case WSERVER_SHUTDOWN_REQUEST_TYPE: 232 | return sizeof(wserver_msg); 233 | case WSERVER_SNR_UPDATE_REQUEST_TYPE: 234 | return sizeof(snr_update_request); 235 | case WSERVER_SNR_UPDATE_RESPONSE_TYPE: 236 | return sizeof(snr_update_response); 237 | case WSERVER_DEL_BY_MAC_REQUEST_TYPE: 238 | return sizeof(station_del_by_mac_request); 239 | case WSERVER_DEL_BY_MAC_RESPONSE_TYPE: 240 | return sizeof(station_del_by_mac_response); 241 | case WSERVER_DEL_BY_ID_REQUEST_TYPE: 242 | return sizeof(station_del_by_id_request); 243 | case WSERVER_DEL_BY_ID_RESPONSE_TYPE: 244 | return sizeof(station_del_by_id_response); 245 | case WSERVER_ADD_REQUEST_TYPE: 246 | return sizeof(station_add_request); 247 | case WSERVER_ADD_RESPONSE_TYPE: 248 | return sizeof(station_add_response); 249 | case WSERVER_ERRPROB_UPDATE_REQUEST_TYPE: 250 | return sizeof(errprob_update_request); 251 | case WSERVER_ERRPROB_UPDATE_RESPONSE_TYPE: 252 | return sizeof(errprob_update_response); 253 | case WSERVER_POSITION_UPDATE_REQUEST_TYPE: 254 | return sizeof(position_update_request); 255 | case WSERVER_POSITION_UPDATE_RESPONSE_TYPE: 256 | return sizeof(position_update_response); 257 | case WSERVER_TXPOWER_UPDATE_REQUEST_TYPE: 258 | return sizeof(txpower_update_request); 259 | case WSERVER_TXPOWER_UPDATE_RESPONSE_TYPE: 260 | return sizeof(txpower_update_response); 261 | case WSERVER_GAIN_UPDATE_REQUEST_TYPE: 262 | return sizeof(gain_update_request); 263 | case WSERVER_GAIN_UPDATE_RESPONSE_TYPE: 264 | return sizeof(gain_update_response); 265 | case WSERVER_MEDIUM_UPDATE_REQUEST_TYPE: 266 | return sizeof(medium_update_request); 267 | case WSERVER_MEDIUM_UPDATE_RESPONSE_TYPE: 268 | return sizeof(medium_update_response); 269 | default: 270 | return -1; 271 | } 272 | } 273 | 274 | double custom_fixed_point_to_floating_point(u32 fixed_point) { 275 | u32 SHIFT_AMOUNT = 31; 276 | u32 SHIFT_MASK = 0x7fffffff; // ((1 << SHIFT_AMOUNT) - 1) 277 | return ((double) (fixed_point & SHIFT_MASK) / (1 << SHIFT_AMOUNT)) + (fixed_point >> SHIFT_AMOUNT); 278 | } 279 | 280 | u32 custom_floating_point_to_fixed_point(double floating_point) { 281 | unsigned int SHIFT_AMOUNT = 31; 282 | u32 beforecomma = (unsigned int) floating_point; 283 | u32 aftercomma = (unsigned int) ((floating_point - beforecomma) * (1 << SHIFT_AMOUNT)); 284 | return (beforecomma << SHIFT_AMOUNT) + aftercomma; 285 | } 286 | -------------------------------------------------------------------------------- /wmediumd/wserver_messages.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #ifndef WMEDIUMD_WSERVER_MESSAGES_H 22 | #define WMEDIUMD_WSERVER_MESSAGES_H 23 | 24 | #include 25 | #include 26 | #include "ieee802154.h" 27 | 28 | #define WACTION_CONTINUE 0 /* Operation successful, continue */ 29 | #define WACTION_ERROR 1 /* Error occured, disconnect client */ 30 | #define WACTION_DISCONNECTED 2 /* Client has disconnected */ 31 | #define WACTION_CLOSE 3 /* Close the server */ 32 | 33 | #define WUPDATE_SUCCESS 0 /* update of SNR successful */ 34 | #define WUPDATE_INTF_NOTFOUND 1 /* unknown interface */ 35 | #define WUPDATE_INTF_DUPLICATE 2 /* interface already exists */ 36 | #define WUPDATE_WRONG_MODE 3 /* tried to update snr in errprob mode or vice versa */ 37 | 38 | /* Socket location following FHS guidelines: 39 | * http://www.pathname.com/fhs/pub/fhs-2.3.html#PURPOSE46 */ 40 | #define WSERVER_SOCKET_PATH "/var/run/wmediumd_802154.sock" 41 | 42 | #define WSERVER_SHUTDOWN_REQUEST_TYPE 0 43 | #define WSERVER_SNR_UPDATE_REQUEST_TYPE 1 44 | #define WSERVER_SNR_UPDATE_RESPONSE_TYPE 2 45 | #define WSERVER_DEL_BY_MAC_REQUEST_TYPE 3 46 | #define WSERVER_DEL_BY_MAC_RESPONSE_TYPE 4 47 | #define WSERVER_DEL_BY_ID_REQUEST_TYPE 5 48 | #define WSERVER_DEL_BY_ID_RESPONSE_TYPE 6 49 | #define WSERVER_ADD_REQUEST_TYPE 7 50 | #define WSERVER_ADD_RESPONSE_TYPE 8 51 | #define WSERVER_ERRPROB_UPDATE_REQUEST_TYPE 9 52 | #define WSERVER_ERRPROB_UPDATE_RESPONSE_TYPE 10 53 | #define WSERVER_SPECPROB_UPDATE_REQUEST_TYPE 11 54 | #define WSERVER_SPECPROB_UPDATE_RESPONSE_TYPE 12 55 | #define WSERVER_POSITION_UPDATE_REQUEST_TYPE 13 56 | #define WSERVER_POSITION_UPDATE_RESPONSE_TYPE 14 57 | #define WSERVER_TXPOWER_UPDATE_REQUEST_TYPE 15 58 | #define WSERVER_TXPOWER_UPDATE_RESPONSE_TYPE 16 59 | #define WSERVER_GAIN_UPDATE_REQUEST_TYPE 17 60 | #define WSERVER_GAIN_UPDATE_RESPONSE_TYPE 18 61 | #define WSERVER_HEIGHT_UPDATE_REQUEST_TYPE 19 62 | #define WSERVER_HEIGHT_UPDATE_RESPONSE_TYPE 20 63 | #define WSERVER_GAUSSIAN_RANDOM_UPDATE_REQUEST_TYPE 21 64 | #define WSERVER_GAUSSIAN_RANDOM_UPDATE_RESPONSE_TYPE 22 65 | #define WSERVER_MEDIUM_UPDATE_REQUEST_TYPE 23 66 | #define WSERVER_MEDIUM_UPDATE_RESPONSE_TYPE 24 67 | 68 | #define SPECIFIC_MATRIX_MAX_SIZE_IDX (12) 69 | #define SPECIFIC_MATRIX_MAX_RATE_IDX (12) 70 | 71 | #define MULTIMEDIUM_MAX_STATION_NUMBER 250 72 | 73 | #ifndef __packed 74 | #define __packed __attribute__((packed)) 75 | #endif 76 | 77 | typedef uint8_t u8; 78 | typedef int32_t i32; 79 | typedef float f32; 80 | typedef uint32_t u32; 81 | 82 | /* 83 | * Macro for unused parameters 84 | */ 85 | #ifndef UNUSED 86 | #define UNUSED(x) (void)(x) 87 | #endif 88 | 89 | typedef struct __packed { 90 | u8 type; 91 | } wserver_msg; 92 | 93 | typedef struct __packed { 94 | wserver_msg base; 95 | u8 from_addr[ETH_ALEN]; 96 | u8 to_addr[ETH_ALEN]; 97 | i32 snr; 98 | } snr_update_request; 99 | 100 | typedef struct __packed { 101 | wserver_msg base; 102 | snr_update_request request; 103 | u8 update_result; 104 | } snr_update_response; 105 | 106 | typedef struct __packed { 107 | wserver_msg base; 108 | u8 sta_addr[ETH_ALEN]; 109 | f32 posX; 110 | f32 posY; 111 | f32 posZ; 112 | } position_update_request; 113 | 114 | typedef struct __packed { 115 | wserver_msg base; 116 | position_update_request request; 117 | u8 update_result; 118 | } position_update_response; 119 | 120 | typedef struct __packed { 121 | wserver_msg base; 122 | u8 sta_addr[ETH_ALEN]; 123 | i32 txpower_; 124 | } txpower_update_request; 125 | 126 | typedef struct __packed { 127 | wserver_msg base; 128 | txpower_update_request request; 129 | u8 update_result; 130 | } txpower_update_response; 131 | 132 | typedef struct __packed { 133 | wserver_msg base; 134 | u8 sta_addr[ETH_ALEN]; 135 | f32 gaussian_random_; 136 | } gaussian_random_update_request; 137 | 138 | typedef struct __packed { 139 | wserver_msg base; 140 | gaussian_random_update_request request; 141 | u8 update_result; 142 | } gaussian_random_update_response; 143 | 144 | typedef struct __packed { 145 | wserver_msg base; 146 | u8 sta_addr[ETH_ALEN]; 147 | i32 gain_; 148 | } gain_update_request; 149 | 150 | typedef struct __packed { 151 | wserver_msg base; 152 | gain_update_request request; 153 | u8 update_result; 154 | } gain_update_response; 155 | 156 | typedef struct __packed { 157 | wserver_msg base; 158 | u8 sta_addr[ETH_ALEN]; 159 | i32 height_; 160 | } height_update_request; 161 | 162 | typedef struct __packed { 163 | wserver_msg base; 164 | height_update_request request; 165 | u8 update_result; 166 | } height_update_response; 167 | 168 | typedef struct __packed { 169 | wserver_msg base; 170 | u8 from_addr[ETH_ALEN]; 171 | u8 to_addr[ETH_ALEN]; 172 | u32 errprob; 173 | } errprob_update_request; 174 | 175 | typedef struct __packed { 176 | wserver_msg base; 177 | errprob_update_request request; 178 | u8 update_result; 179 | } errprob_update_response; 180 | 181 | typedef struct __packed { 182 | wserver_msg base; 183 | u8 from_addr[ETH_ALEN]; 184 | u8 to_addr[ETH_ALEN]; 185 | u32 errprob[SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX]; 186 | } specprob_update_request; 187 | 188 | typedef struct __packed { 189 | wserver_msg base; 190 | u8 from_addr[ETH_ALEN]; 191 | u8 to_addr[ETH_ALEN]; 192 | u8 update_result; 193 | } specprob_update_response; 194 | 195 | typedef struct __packed { 196 | wserver_msg base; 197 | u8 addr[ETH_ALEN]; 198 | } station_del_by_mac_request; 199 | 200 | typedef struct __packed { 201 | wserver_msg base; 202 | station_del_by_mac_request request; 203 | u8 update_result; 204 | } station_del_by_mac_response; 205 | 206 | typedef struct __packed { 207 | wserver_msg base; 208 | i32 id; 209 | } station_del_by_id_request; 210 | 211 | typedef struct __packed { 212 | wserver_msg base; 213 | station_del_by_id_request request; 214 | u8 update_result; 215 | } station_del_by_id_response; 216 | 217 | typedef struct __packed { 218 | wserver_msg base; 219 | u8 addr[ETH_ALEN]; 220 | } station_add_request; 221 | 222 | typedef struct __packed { 223 | wserver_msg base; 224 | station_add_request request; 225 | i32 created_id; 226 | u8 update_result; 227 | } station_add_response; 228 | 229 | typedef struct __packed { 230 | wserver_msg base; 231 | u8 sta_addr[ETH_ALEN]; 232 | i32 medium_id_; 233 | } medium_update_request; 234 | 235 | typedef struct __packed { 236 | wserver_msg base; 237 | medium_update_request request; 238 | u8 update_result; 239 | } medium_update_response; 240 | 241 | /** 242 | * Receive the wserver_msg from a socket 243 | * @param sock_fd The socket file descriptor 244 | * @param base Where to store the wserver_msg 245 | * @param recv_type The received WSERVER_*_TYPE 246 | * @return A positive WACTION_* constant, or a negative errno value 247 | */ 248 | int wserver_recv_msg_base(int sock_fd, wserver_msg *base, int *recv_type); 249 | 250 | /** 251 | * Send a wserver message to a socket 252 | * @param sock_fd The socket file descriptor 253 | * @param elem The message to send 254 | * @param type The response type struct 255 | * @return 0 on success 256 | */ 257 | #define wserver_send_msg(sock_fd, elem, type) \ 258 | send_##type(sock_fd, elem) 259 | 260 | /** 261 | * Receive a wserver msg from a socket 262 | * @param sock_fd The socket file descriptor 263 | * @param elem Where to store the msg 264 | * @param type The response type struct 265 | * @return A positive WACTION_* constant, or a negative errno value 266 | */ 267 | #define wserver_recv_msg(sock_fd, elem, type) \ 268 | recv_##type(sock_fd, elem) 269 | 270 | /** 271 | * Get the size of a request/response based on its type 272 | * @param type The WSERVER_*_TYPE 273 | * @return The size or -1 if not found 274 | */ 275 | ssize_t get_msg_size_by_type(int type); 276 | 277 | int send_snr_update_request(int sock, const snr_update_request *elem); 278 | 279 | int send_snr_update_response(int sock, const snr_update_response *elem); 280 | 281 | int send_position_update_request(int sock, const position_update_request *elem); 282 | 283 | int send_position_update_response(int sock, const position_update_response *elem); 284 | 285 | int send_txpower_update_request(int sock, const txpower_update_request *elem); 286 | 287 | int send_txpower_update_response(int sock, const txpower_update_response *elem); 288 | 289 | int send_gaussian_random_update_request(int sock, const gaussian_random_update_request *elem); 290 | 291 | int send_gaussian_random_update_response(int sock, const gaussian_random_update_response *elem); 292 | 293 | int send_gain_update_request(int sock, const gain_update_request *elem); 294 | 295 | int send_gain_update_response(int sock, const gain_update_response *elem); 296 | 297 | int send_height_update_request(int sock, const height_update_request *elem); 298 | 299 | int send_height_update_response(int sock, const height_update_response *elem); 300 | 301 | int send_errprob_update_request(int sock, const errprob_update_request *elem); 302 | 303 | int send_errprob_update_response(int sock, const errprob_update_response *elem); 304 | 305 | int send_specprob_update_request(int sock, const specprob_update_request *elem); 306 | 307 | int send_specprob_update_response(int sock, const specprob_update_response *elem); 308 | 309 | int send_station_del_by_mac_request(int sock, const station_del_by_mac_request *elem); 310 | 311 | int send_station_del_by_mac_response(int sock, const station_del_by_mac_response *elem); 312 | 313 | int send_station_del_by_id_request(int sock, const station_del_by_id_request *elem); 314 | 315 | int send_station_del_by_id_response(int sock, const station_del_by_id_response *elem); 316 | 317 | int send_station_add_request(int sock, const station_add_request *elem); 318 | 319 | int send_station_add_response(int sock, const station_add_response *elem); 320 | 321 | int send_medium_update_request(int sock, const medium_update_request *elem); 322 | 323 | int send_medium_update_response(int sock, const medium_update_response *elem); 324 | 325 | int recv_snr_update_request(int sock, snr_update_request *elem); 326 | 327 | int recv_snr_update_response(int sock, snr_update_response *elem); 328 | 329 | int recv_position_update_request(int sock, position_update_request *elem); 330 | 331 | int recv_position_update_response(int sock, position_update_response *elem); 332 | 333 | int recv_txpower_update_request(int sock, txpower_update_request *elem); 334 | 335 | int recv_txpower_update_response(int sock, txpower_update_response *elem); 336 | 337 | int recv_gaussian_random_update_request(int sock, gaussian_random_update_request *elem); 338 | 339 | int recv_gaussian_random_update_response(int sock, gaussian_random_update_response *elem); 340 | 341 | int recv_gain_update_request(int sock, gain_update_request *elem); 342 | 343 | int recv_gain_update_response(int sock, gain_update_response *elem); 344 | 345 | int recv_height_update_request(int sock, height_update_request *elem); 346 | 347 | int recv_height_update_response(int sock, height_update_response *elem); 348 | 349 | int recv_errprob_update_request(int sock, errprob_update_request *elem); 350 | 351 | int recv_errprob_update_response(int sock, errprob_update_response *elem); 352 | 353 | int recv_specprob_update_request(int sock, specprob_update_request *elem); 354 | 355 | int recv_specprob_update_response(int sock, specprob_update_response *elem); 356 | 357 | int recv_station_del_by_mac_request(int sock, station_del_by_mac_request *elem); 358 | 359 | int recv_station_del_by_mac_response(int sock, station_del_by_mac_response *elem); 360 | 361 | int recv_station_del_by_id_request(int sock, station_del_by_id_request *elem); 362 | 363 | int recv_station_del_by_id_response(int sock, station_del_by_id_response *elem); 364 | 365 | int recv_station_add_request(int sock, station_add_request *elem); 366 | 367 | int recv_station_add_response(int sock, station_add_response *elem); 368 | 369 | int recv_medium_update_request(int sock, medium_update_request *elem); 370 | 371 | int recv_medium_update_response(int sock, medium_update_response *elem); 372 | 373 | double custom_fixed_point_to_floating_point(u32 fixed_point); 374 | 375 | u32 custom_floating_point_to_fixed_point(double floating_point); 376 | 377 | #endif //WMEDIUMD_WSERVER_MESSAGES_H 378 | -------------------------------------------------------------------------------- /wmediumd/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIST_H 2 | #define _LIST_H 3 | 4 | /* Stripped down implementation of linked list taken 5 | * from the Linux Kernel. 6 | */ 7 | 8 | /* 9 | * Simple doubly linked list implementation. 10 | * 11 | * Some of the internal functions ("__xxx") are useful when 12 | * manipulating whole lists rather than single entries, as 13 | * sometimes we already know the next/prev entries and we can 14 | * generate better code by using them directly rather than 15 | * using the generic single-entry routines. 16 | */ 17 | 18 | struct list_head { 19 | struct list_head *next, *prev; 20 | }; 21 | 22 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 23 | 24 | #define LIST_HEAD(name) \ 25 | struct list_head name = LIST_HEAD_INIT(name) 26 | 27 | static inline void INIT_LIST_HEAD(struct list_head *list) 28 | { 29 | list->next = list; 30 | list->prev = list; 31 | } 32 | 33 | /* 34 | * Insert a new entry between two known consecutive entries. 35 | * 36 | * This is only for internal list manipulation where we know 37 | * the prev/next entries already! 38 | */ 39 | static inline void __list_add(struct list_head *new, 40 | struct list_head *prev, 41 | struct list_head *next) 42 | { 43 | next->prev = new; 44 | new->next = next; 45 | new->prev = prev; 46 | prev->next = new; 47 | } 48 | 49 | /** 50 | * list_add - add a new entry 51 | * @new: new entry to be added 52 | * @head: list head to add it after 53 | * 54 | * Insert a new entry after the specified head. 55 | * This is good for implementing stacks. 56 | */ 57 | static inline void list_add(struct list_head *new, struct list_head *head) 58 | { 59 | __list_add(new, head, head->next); 60 | } 61 | 62 | /** 63 | * list_add_tail - add a new entry 64 | * @new: new entry to be added 65 | * @head: list head to add it before 66 | * 67 | * Insert a new entry before the specified head. 68 | * This is useful for implementing queues. 69 | */ 70 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 71 | { 72 | __list_add(new, head->prev, head); 73 | } 74 | 75 | /* 76 | * Delete a list entry by making the prev/next entries 77 | * point to each other. 78 | * 79 | * This is only for internal list manipulation where we know 80 | * the prev/next entries already! 81 | */ 82 | static inline void __list_del(struct list_head *prev, struct list_head *next) 83 | { 84 | next->prev = prev; 85 | prev->next = next; 86 | } 87 | 88 | #define POISON_POINTER_DELTA 0 89 | #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) 90 | #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) 91 | 92 | /** 93 | * list_empty - tests whether a list is empty 94 | * @head: the list to test. 95 | */ 96 | static inline int list_empty(const struct list_head *head) 97 | { 98 | return head->next == head; 99 | } 100 | 101 | /** 102 | * list_del - deletes entry from list. 103 | * @entry: the element to delete from the list. 104 | * Note: list_empty() on entry does not return true after this, the entry is 105 | * in an undefined state. 106 | */ 107 | static inline void __list_del_entry(struct list_head *entry) 108 | { 109 | __list_del(entry->prev, entry->next); 110 | } 111 | 112 | static inline void list_del(struct list_head *entry) 113 | { 114 | __list_del(entry->prev, entry->next); 115 | entry->next = LIST_POISON1; 116 | entry->prev = LIST_POISON2; 117 | } 118 | 119 | /** 120 | * list_entry - get the struct for this entry 121 | * @ptr: the &struct list_head pointer. 122 | * @type: the type of the struct this is embedded in. 123 | * @member: the name of the list_struct within the struct. 124 | */ 125 | #define list_entry(ptr, type, member) \ 126 | container_of(ptr, type, member) 127 | 128 | /** 129 | * list_first_entry - get the first element from a list 130 | * @ptr: the list head to take the element from. 131 | * @type: the type of the struct this is embedded in. 132 | * @member: the name of the list_struct within the struct. 133 | * 134 | * Note, that list is expected to be not empty. 135 | */ 136 | #define list_first_entry(ptr, type, member) \ 137 | list_entry((ptr)->next, type, member) 138 | 139 | /** 140 | * list_last_entry - get the last element from a list 141 | * @ptr: the list head to take the element from. 142 | * @type: the type of the struct this is embedded in. 143 | * @member: the name of the list_struct within the struct. 144 | * 145 | * Note, that list is expected to be not empty. 146 | */ 147 | #define list_last_entry(ptr, type, member) \ 148 | list_entry((ptr)->prev, type, member) 149 | 150 | /** 151 | * list_first_entry_or_null - get the first element from a list 152 | * @ptr: the list head to take the element from. 153 | * @type: the type of the struct this is embedded in. 154 | * @member: the name of the list_struct within the struct. 155 | * 156 | * Note that if the list is empty, it returns NULL. 157 | */ 158 | #define list_first_entry_or_null(ptr, type, member) \ 159 | (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) 160 | 161 | /** 162 | * list_last_entry_or_null - get the last element from a list 163 | * @ptr: the list head to take the element from. 164 | * @type: the type of the struct this is embedded in. 165 | * @member: the name of the list_struct within the struct. 166 | * 167 | * Note that if the list is empty, it returns NULL. 168 | */ 169 | #define list_last_entry_or_null(ptr, type, member) \ 170 | (!list_empty(ptr) ? list_last_entry(ptr, type, member) : NULL) 171 | 172 | /** 173 | * list_next_entry - get the next element in list 174 | * @pos: the type * to cursor 175 | * @member: the name of the list_struct within the struct. 176 | */ 177 | #define list_next_entry(pos, member) \ 178 | list_entry((pos)->member.next, typeof(*(pos)), member) 179 | 180 | /** 181 | * list_prev_entry - get the prev element in list 182 | * @pos: the type * to cursor 183 | * @member: the name of the list_struct within the struct. 184 | */ 185 | #define list_prev_entry(pos, member) \ 186 | list_entry((pos)->member.prev, typeof(*(pos)), member) 187 | 188 | /** 189 | * list_for_each - iterate over a list 190 | * @pos: the &struct list_head to use as a loop cursor. 191 | * @head: the head for your list. 192 | */ 193 | #define list_for_each(pos, head) \ 194 | for (pos = (head)->next; pos != (head); pos = pos->next) 195 | 196 | /** 197 | * list_for_each_prev - iterate over a list backwards 198 | * @pos: the &struct list_head to use as a loop cursor. 199 | * @head: the head for your list. 200 | */ 201 | #define list_for_each_prev(pos, head) \ 202 | for (pos = (head)->prev; pos != (head); pos = pos->prev) 203 | 204 | /** 205 | * list_for_each_safe - iterate over a list safe against removal of list entry 206 | * @pos: the &struct list_head to use as a loop cursor. 207 | * @n: another &struct list_head to use as temporary storage 208 | * @head: the head for your list. 209 | */ 210 | #define list_for_each_safe(pos, n, head) \ 211 | for (pos = (head)->next, n = pos->next; pos != (head); \ 212 | pos = n, n = pos->next) 213 | 214 | /** 215 | * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry 216 | * @pos: the &struct list_head to use as a loop cursor. 217 | * @n: another &struct list_head to use as temporary storage 218 | * @head: the head for your list. 219 | */ 220 | #define list_for_each_prev_safe(pos, n, head) \ 221 | for (pos = (head)->prev, n = pos->prev; \ 222 | pos != (head); \ 223 | pos = n, n = pos->prev) 224 | 225 | /** 226 | * list_for_each_entry - iterate over list of given type 227 | * @pos: the type * to use as a loop cursor. 228 | * @head: the head for your list. 229 | * @member: the name of the list_struct within the struct. 230 | */ 231 | #define list_for_each_entry(pos, head, member) \ 232 | for (pos = list_first_entry(head, typeof(*pos), member); \ 233 | &pos->member != (head); \ 234 | pos = list_next_entry(pos, member)) 235 | 236 | /** 237 | * list_for_each_entry_reverse - iterate backwards over list of given type. 238 | * @pos: the type * to use as a loop cursor. 239 | * @head: the head for your list. 240 | * @member: the name of the list_struct within the struct. 241 | */ 242 | #define list_for_each_entry_reverse(pos, head, member) \ 243 | for (pos = list_last_entry(head, typeof(*pos), member); \ 244 | &pos->member != (head); \ 245 | pos = list_prev_entry(pos, member)) 246 | 247 | /** 248 | * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() 249 | * @pos: the type * to use as a start point 250 | * @head: the head of the list 251 | * @member: the name of the list_struct within the struct. 252 | * 253 | * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). 254 | */ 255 | #define list_prepare_entry(pos, head, member) \ 256 | ((pos) ? : list_entry(head, typeof(*pos), member)) 257 | 258 | /** 259 | * list_for_each_entry_continue - continue iteration over list of given type 260 | * @pos: the type * to use as a loop cursor. 261 | * @head: the head for your list. 262 | * @member: the name of the list_struct within the struct. 263 | * 264 | * Continue to iterate over list of given type, continuing after 265 | * the current position. 266 | */ 267 | #define list_for_each_entry_continue(pos, head, member) \ 268 | for (pos = list_next_entry(pos, member); \ 269 | &pos->member != (head); \ 270 | pos = list_next_entry(pos, member)) 271 | 272 | /** 273 | * list_for_each_entry_continue_reverse - iterate backwards from the given point 274 | * @pos: the type * to use as a loop cursor. 275 | * @head: the head for your list. 276 | * @member: the name of the list_struct within the struct. 277 | * 278 | * Start to iterate over list of given type backwards, continuing after 279 | * the current position. 280 | */ 281 | #define list_for_each_entry_continue_reverse(pos, head, member) \ 282 | for (pos = list_prev_entry(pos, member); \ 283 | &pos->member != (head); \ 284 | pos = list_prev_entry(pos, member)) 285 | 286 | /** 287 | * list_for_each_entry_from - iterate over list of given type from the current point 288 | * @pos: the type * to use as a loop cursor. 289 | * @head: the head for your list. 290 | * @member: the name of the list_struct within the struct. 291 | * 292 | * Iterate over list of given type, continuing from current position. 293 | */ 294 | #define list_for_each_entry_from(pos, head, member) \ 295 | for (; &pos->member != (head); \ 296 | pos = list_next_entry(pos, member)) 297 | 298 | /** 299 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry 300 | * @pos: the type * to use as a loop cursor. 301 | * @n: another type * to use as temporary storage 302 | * @head: the head for your list. 303 | * @member: the name of the list_struct within the struct. 304 | */ 305 | #define list_for_each_entry_safe(pos, n, head, member) \ 306 | for (pos = list_first_entry(head, typeof(*pos), member), \ 307 | n = list_next_entry(pos, member); \ 308 | &pos->member != (head); \ 309 | pos = n, n = list_next_entry(n, member)) 310 | 311 | /** 312 | * list_for_each_entry_safe_continue - continue list iteration safe against removal 313 | * @pos: the type * to use as a loop cursor. 314 | * @n: another type * to use as temporary storage 315 | * @head: the head for your list. 316 | * @member: the name of the list_struct within the struct. 317 | * 318 | * Iterate over list of given type, continuing after current point, 319 | * safe against removal of list entry. 320 | */ 321 | #define list_for_each_entry_safe_continue(pos, n, head, member) \ 322 | for (pos = list_next_entry(pos, member), \ 323 | n = list_next_entry(pos, member); \ 324 | &pos->member != (head); \ 325 | pos = n, n = list_next_entry(n, member)) 326 | 327 | /** 328 | * list_for_each_entry_safe_from - iterate over list from current point safe against removal 329 | * @pos: the type * to use as a loop cursor. 330 | * @n: another type * to use as temporary storage 331 | * @head: the head for your list. 332 | * @member: the name of the list_struct within the struct. 333 | * 334 | * Iterate over list of given type from current point, safe against 335 | * removal of list entry. 336 | */ 337 | #define list_for_each_entry_safe_from(pos, n, head, member) \ 338 | for (n = list_next_entry(pos, member); \ 339 | &pos->member != (head); \ 340 | pos = n, n = list_next_entry(n, member)) 341 | 342 | /** 343 | * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal 344 | * @pos: the type * to use as a loop cursor. 345 | * @n: another type * to use as temporary storage 346 | * @head: the head for your list. 347 | * @member: the name of the list_struct within the struct. 348 | * 349 | * Iterate backwards over list of given type, safe against removal 350 | * of list entry. 351 | */ 352 | #define list_for_each_entry_safe_reverse(pos, n, head, member) \ 353 | for (pos = list_last_entry(head, typeof(*pos), member), \ 354 | n = list_prev_entry(pos, member); \ 355 | &pos->member != (head); \ 356 | pos = n, n = list_prev_entry(n, member)) 357 | 358 | /** 359 | * list_safe_reset_next - reset a stale list_for_each_entry_safe loop 360 | * @pos: the loop cursor used in the list_for_each_entry_safe loop 361 | * @n: temporary storage used in list_for_each_entry_safe 362 | * @member: the name of the list_struct within the struct. 363 | * 364 | * list_safe_reset_next is not safe to use in general if the list may be 365 | * modified concurrently (eg. the lock is dropped in the loop body). An 366 | * exception to this is if the cursor element (pos) is pinned in the list, 367 | * and list_safe_reset_next is called after re-taking the lock and before 368 | * completing the current iteration of the loop body. 369 | */ 370 | #define list_safe_reset_next(pos, n, member) \ 371 | n = list_next_entry(pos, member) 372 | 373 | #ifndef offsetof 374 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 375 | #endif 376 | 377 | /** 378 | * container_of - cast a member of a structure out to the containing structure 379 | * @ptr: the pointer to the member. 380 | * @type: the type of the container struct this is embedded in. 381 | * @member: the name of the member within the struct. 382 | * 383 | */ 384 | #define container_of(ptr, type, member) ({ \ 385 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 386 | (type *)( (char *)__mptr - offsetof(type,member) );}) 387 | 388 | #endif 389 | -------------------------------------------------------------------------------- /wmediumd/config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd, wireless medium simulator for mac80211_hwsim kernel module 3 | * Copyright (c) 2011 cozybit Inc. 4 | * 5 | * Author: Javier Lopez 6 | * Javier Cardona 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License 10 | * as published by the Free Software Foundation; either version 2 11 | * of the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 | * 02110-1301, USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "wmediumd.h" 32 | 33 | static void string_to_mac_address(const char *str, u8 *addr) 34 | { 35 | int a[8]; 36 | 37 | sscanf(str, "%x:%x:%x:%x:%x:%x:%x:%x", 38 | &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]); 39 | 40 | addr[0] = (u8) a[0]; 41 | addr[1] = (u8) a[1]; 42 | addr[2] = (u8) a[2]; 43 | addr[3] = (u8) a[3]; 44 | addr[4] = (u8) a[4]; 45 | addr[5] = (u8) a[5]; 46 | addr[6] = (u8) a[6]; 47 | addr[7] = (u8) a[7]; 48 | } 49 | 50 | static int get_link_snr_default(struct wmediumd *ctx, struct station *sender, 51 | struct station *receiver) 52 | { 53 | return SNR_DEFAULT; 54 | } 55 | 56 | static int get_link_snr_from_snr_matrix(struct wmediumd *ctx, 57 | struct station *sender, 58 | struct station *receiver) 59 | { 60 | return ctx->snr_matrix[sender->index * ctx->num_stas + receiver->index]; 61 | } 62 | 63 | static double _get_error_prob_from_snr(struct wmediumd *ctx, double snr, 64 | unsigned int rate_idx, u32 freq, 65 | int frame_len, struct station *src, 66 | struct station *dst) 67 | { 68 | return get_error_prob_from_snr(snr, rate_idx, freq, frame_len); 69 | } 70 | 71 | static double get_error_prob_from_matrix(struct wmediumd *ctx, double snr, 72 | unsigned int rate_idx, u32 freq, 73 | int frame_len, struct station *src, 74 | struct station *dst) 75 | { 76 | if (dst == NULL) // dst is multicast. returned value will not be used. 77 | return 0.0; 78 | 79 | return ctx->error_prob_matrix[ctx->num_stas * src->index + dst->index]; 80 | } 81 | 82 | int use_fixed_random_value(struct wmediumd *ctx) 83 | { 84 | return ctx->error_prob_matrix != NULL || ctx->station_err_matrix != NULL; 85 | } 86 | 87 | #define FREQ_1CH (2.412e9) // [Hz] 88 | #define SPEED_LIGHT (2.99792458e8) // [meter/sec] 89 | /* 90 | * Calculate path loss based on a free-space path loss 91 | * 92 | * This function returns path loss [dBm]. 93 | */ 94 | static int calc_path_loss_free_space(void *model_param, 95 | struct station *dst, struct station *src) 96 | { 97 | struct free_space_model_param *param; 98 | double PL, d, denominator, numerator, lambda; 99 | double f = src->freq * pow(10,6); 100 | 101 | if (f < 0.1) 102 | f = FREQ_1CH; 103 | 104 | param = model_param; 105 | 106 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 107 | (src->y - dst->y) * (src->y - dst->y) + 108 | (src->z - dst->z) * (src->z - dst->z)); 109 | 110 | /* 111 | * Calculate PL0 with Free-space path loss in decibels 112 | * 113 | * 20 * log10 * (4 * M_PI * d * f / c) 114 | * d: distance [meter] 115 | * f: frequency [Hz] 116 | * c: speed of light in a vacuum [meter/second] 117 | * 118 | * https://en.wikipedia.org/wiki/Free-space_path_loss 119 | */ 120 | lambda = SPEED_LIGHT / f; 121 | denominator = pow(lambda, 2); 122 | numerator = pow((4.0 * M_PI * d), 2) * param->sL; 123 | PL = 10.0 * log10(numerator / denominator); 124 | return PL; 125 | } 126 | /* 127 | * Calculate path loss based on a log distance model 128 | * 129 | * This function returns path loss [dBm]. 130 | */ 131 | static int calc_path_loss_log_distance(void *model_param, 132 | struct station *dst, struct station *src) 133 | { 134 | struct log_distance_model_param *param; 135 | double PL, PL0, d; 136 | double f = src->freq * pow(10,6); 137 | 138 | if (f < 0.1) 139 | f = FREQ_1CH; 140 | 141 | param = model_param; 142 | 143 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 144 | (src->y - dst->y) * (src->y - dst->y) + 145 | (src->z - dst->z) * (src->z - dst->z)); 146 | 147 | /* 148 | * Calculate PL0 with Free-space path loss in decibels 149 | * 150 | * 20 * log10 * (4 * M_PI * d * f / c) 151 | * d: distance [meter] 152 | * f: frequency [Hz] 153 | * c: speed of light in a vacuum [meter/second] 154 | * 155 | * https://en.wikipedia.org/wiki/Free-space_path_loss 156 | */ 157 | PL0 = 20.0 * log10(4.0 * M_PI * 1.0 * f / SPEED_LIGHT); 158 | 159 | /* 160 | * Calculate signal strength with Log-distance path loss model 161 | * https://en.wikipedia.org/wiki/Log-distance_path_loss_model 162 | */ 163 | PL = PL0 + 10.0 * param->path_loss_exponent * log10(d) + param->Xg; 164 | 165 | return PL; 166 | } 167 | /* 168 | * Calculate path loss based on a itu model 169 | * 170 | * This function returns path loss [dBm]. 171 | */ 172 | static int calc_path_loss_itu(void *model_param, 173 | struct station *dst, struct station *src) 174 | { 175 | struct itu_model_param *param; 176 | double PL, d; 177 | double f = src->freq; 178 | int N=28, pL; 179 | 180 | if (f < 0.1) 181 | f = FREQ_1CH; 182 | 183 | param = model_param; 184 | pL = param->pL; 185 | 186 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 187 | (src->y - dst->y) * (src->y - dst->y) + 188 | (src->z - dst->z) * (src->z - dst->z)); 189 | 190 | if (d>16) 191 | N=38; 192 | if (pL!=0) 193 | N=pL; 194 | /* 195 | * Calculate signal strength with ITU path loss model 196 | * Power Loss Coefficient Based on the Paper 197 | * Site-Specific Validation of ITU Indoor Path Loss Model at 2.4 GHz 198 | * from Theofilos Chrysikos, Giannis Georgopoulos and Stavros Kotsopoulos 199 | * LF: floor penetration loss factor 200 | * nFLOORS: number of floors 201 | */ 202 | 203 | PL = 20.0 * log10(f) + N * log10(d) + param->lF * param->nFLOORS - 28; 204 | return PL; 205 | } 206 | /* 207 | * Calculate path loss based on a log-normal shadowing model 208 | * 209 | * This function returns path loss [dBm]. 210 | */ 211 | static int calc_path_loss_log_normal_shadowing(void *model_param, 212 | struct station *dst, struct station *src) 213 | { 214 | struct log_normal_shadowing_model_param *param; 215 | double PL, PL0, d; 216 | double f = src->freq * pow(10,6); 217 | double gRandom = src->gRandom; 218 | 219 | if (f < 0.1) 220 | f = FREQ_1CH; 221 | 222 | param = model_param; 223 | 224 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 225 | (src->y - dst->y) * (src->y - dst->y) + 226 | (src->z - dst->z) * (src->z - dst->z)); 227 | 228 | /* 229 | * Calculate PL0 with Free-space path loss in decibels 230 | * 231 | * 20 * log10 * (4 * M_PI * d * f / c) 232 | * d: distance [meter] 233 | * f: frequency [Hz] 234 | * c: speed of light in a vacuum [meter/second] 235 | * 236 | * https://en.wikipedia.org/wiki/Free-space_path_loss 237 | */ 238 | PL0 = 20.0 * log10(4.0 * M_PI * 1.0 * f / SPEED_LIGHT); 239 | 240 | /* 241 | * Calculate signal strength with Log-distance path loss model + gRandom (Gaussian random variable) 242 | * https://en.wikipedia.org/wiki/Log-distance_path_loss_model 243 | */ 244 | PL = PL0 + 10.0 * param->path_loss_exponent * log10(d) - gRandom; 245 | return PL; 246 | } 247 | /* 248 | * Calculate path loss based on a two ray ground model 249 | * 250 | * This function returns path loss [dBm]. 251 | */ 252 | static int calc_path_loss_two_ray_ground(void *model_param, 253 | struct station *dst, struct station *src) 254 | { 255 | //struct two_ray_ground_model_param *param; 256 | double PL, d; 257 | double f = 20 * 1000000; //frequency in Hz 258 | double lambda = SPEED_LIGHT / f; 259 | int ht = 1; 260 | int hr = 1; 261 | double dCross = (4 * M_PI * ht * hr) / (lambda / 1000); 262 | 263 | //param = model_param; 264 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 265 | (src->y - dst->y) * (src->y - dst->y) + 266 | (src->z - dst->z) * (src->z - dst->z)); 267 | 268 | if (d < dCross){ 269 | PL = calc_path_loss_free_space(model_param, dst, src); 270 | return PL; 271 | } 272 | else{ 273 | double numerator = src->tx_power * src->gain * dst->gain * pow(ht, 2) * pow(hr, 2); 274 | double denominator = pow(d, 4); 275 | PL = (numerator / denominator); 276 | return PL; 277 | } 278 | } 279 | 280 | /* Existing link is from from -> to; copy to other dir */ 281 | static void mirror_link(struct wmediumd *ctx, int from, int to) 282 | { 283 | ctx->snr_matrix[ctx->num_stas * to + from] = 284 | ctx->snr_matrix[ctx->num_stas * from + to]; 285 | 286 | if (ctx->error_prob_matrix) { 287 | ctx->error_prob_matrix[ctx->num_stas * to + from] = 288 | ctx->error_prob_matrix[ctx->num_stas * from + to]; 289 | } 290 | } 291 | 292 | static void recalc_path_loss(struct wmediumd *ctx) 293 | { 294 | int start, end, path_loss, gains, txpower, lqi; 295 | 296 | for (start = 0; start < ctx->num_stas; start++) { 297 | for (end = 0; end < ctx->num_stas; end++) { 298 | if (start == end) 299 | continue; 300 | txpower = ctx->sta_array[start]->tx_power; 301 | if (ctx->sta_array[end]->isap == 1) 302 | txpower = ctx->sta_array[end]->tx_power; 303 | 304 | path_loss = ctx->calc_path_loss(ctx->path_loss_param, 305 | ctx->sta_array[end], ctx->sta_array[start]); 306 | gains = txpower + ctx->sta_array[start]->gain + ctx->sta_array[end]->gain; 307 | lqi = gains - path_loss - ctx->noise_threshold; 308 | ctx->snr_matrix[ctx->num_stas * start + end] = lqi; 309 | ctx->snr_matrix[ctx->num_stas * end + start] = lqi; 310 | } 311 | } 312 | } 313 | 314 | static void move_stations_to_direction(struct wmediumd *ctx) 315 | { 316 | struct station *station; 317 | struct timespec now; 318 | 319 | clock_gettime(CLOCK_MONOTONIC, &now); 320 | if (!timespec_before(&ctx->next_move, &now)) 321 | return; 322 | 323 | list_for_each_entry(station, &ctx->stations, list) { 324 | station->x += station->dir_x; 325 | station->y += station->dir_y; 326 | } 327 | recalc_path_loss(ctx); 328 | 329 | clock_gettime(CLOCK_MONOTONIC, &ctx->next_move); 330 | ctx->next_move.tv_sec += MOVE_INTERVAL; 331 | } 332 | 333 | static void move_stations_donothing(struct wmediumd *ctx) 334 | { 335 | } 336 | 337 | static int parse_path_loss(struct wmediumd *ctx, config_t *cf) 338 | { 339 | struct station *station; 340 | const config_setting_t *positions, *position; 341 | const config_setting_t *directions, *direction; 342 | const config_setting_t *tx_powers, *model; 343 | const config_setting_t *isnodeaps; 344 | const char *path_loss_model_name; 345 | 346 | positions = config_lookup(cf, "model.positions"); 347 | if (!positions) { 348 | w_flogf(ctx, LOG_ERR, stderr, 349 | "No positions found in model\n"); 350 | return -EINVAL; 351 | } 352 | if (config_setting_length(positions) != ctx->num_stas) { 353 | w_flogf(ctx, LOG_ERR, stderr, 354 | "Specify %d positions\n", ctx->num_stas); 355 | return -EINVAL; 356 | } 357 | 358 | directions = config_lookup(cf, "model.directions"); 359 | if (directions) { 360 | if (config_setting_length(directions) != ctx->num_stas) { 361 | w_flogf(ctx, LOG_ERR, stderr, 362 | "Specify %d directions\n", ctx->num_stas); 363 | return -EINVAL; 364 | } 365 | ctx->move_stations = move_stations_to_direction; 366 | } 367 | 368 | tx_powers = config_lookup(cf, "model.tx_powers"); 369 | if (!tx_powers) { 370 | w_flogf(ctx, LOG_ERR, stderr, 371 | "No tx_powers found in model\n"); 372 | return -EINVAL; 373 | } 374 | if (config_setting_length(tx_powers) != ctx->num_stas) { 375 | w_flogf(ctx, LOG_ERR, stderr, 376 | "Specify %d tx_powers\n", ctx->num_stas); 377 | return -EINVAL; 378 | } 379 | 380 | isnodeaps = config_lookup(cf, "model.isnodeaps"); 381 | 382 | model = config_lookup(cf, "model"); 383 | if (config_setting_lookup_string(model, "model_name", 384 | &path_loss_model_name) != CONFIG_TRUE) { 385 | w_flogf(ctx, LOG_ERR, stderr, "Specify model_name\n"); 386 | return -EINVAL; 387 | } 388 | if (strncmp(path_loss_model_name, "log_distance", 389 | sizeof("log_distance")) == 0) { 390 | struct log_distance_model_param *param; 391 | ctx->calc_path_loss = calc_path_loss_log_distance; 392 | param = malloc(sizeof(*param)); 393 | if (!param) { 394 | w_flogf(ctx, LOG_ERR, stderr, 395 | "Out of memory(path_loss_param)\n"); 396 | return -EINVAL; 397 | } 398 | 399 | if (config_setting_lookup_float(model, "path_loss_exp", 400 | ¶m->path_loss_exponent) != CONFIG_TRUE) { 401 | w_flogf(ctx, LOG_ERR, stderr, 402 | "path_loss_exponent not found\n"); 403 | return -EINVAL; 404 | } 405 | 406 | if (config_setting_lookup_float(model, "xg", 407 | ¶m->Xg) != CONFIG_TRUE) { 408 | w_flogf(ctx, LOG_ERR, stderr, "xg not found\n"); 409 | return -EINVAL; 410 | } 411 | ctx->path_loss_param = param; 412 | } 413 | else if (strncmp(path_loss_model_name, "free_space", 414 | sizeof("free_space")) == 0) { 415 | struct free_space_model_param *param; 416 | ctx->calc_path_loss = calc_path_loss_free_space; 417 | param = malloc(sizeof(*param)); 418 | if (!param) { 419 | w_flogf(ctx, LOG_ERR, stderr, 420 | "Out of memory(path_loss_param)\n"); 421 | return -EINVAL; 422 | } 423 | 424 | if (config_setting_lookup_int(model, "sL", 425 | ¶m->sL) != CONFIG_TRUE) { 426 | w_flogf(ctx, LOG_ERR, stderr, 427 | "system loss not found\n"); 428 | return -EINVAL; 429 | } 430 | ctx->path_loss_param = param; 431 | } 432 | else if (strncmp(path_loss_model_name, "log_normal_shadowing", 433 | sizeof("log_normal_shadowing")) == 0) { 434 | struct log_normal_shadowing_model_param *param; 435 | ctx->calc_path_loss = calc_path_loss_log_normal_shadowing; 436 | param = malloc(sizeof(*param)); 437 | if (!param) { 438 | w_flogf(ctx, LOG_ERR, stderr, 439 | "Out of memory(path_loss_param)\n"); 440 | return -EINVAL; 441 | } 442 | 443 | if (config_setting_lookup_int(model, "sL", 444 | ¶m->sL) != CONFIG_TRUE) { 445 | w_flogf(ctx, LOG_ERR, stderr, 446 | "system loss not found\n"); 447 | return -EINVAL; 448 | } 449 | 450 | if (config_setting_lookup_float(model, "path_loss_exp", 451 | ¶m->path_loss_exponent) != CONFIG_TRUE) { 452 | w_flogf(ctx, LOG_ERR, stderr, 453 | "path_loss_exponent not found\n"); 454 | return -EINVAL; 455 | } 456 | ctx->path_loss_param = param; 457 | } 458 | else if (strncmp(path_loss_model_name, "two_ray_ground", 459 | sizeof("two_ray_ground")) == 0) { 460 | struct two_ray_ground_model_param *param; 461 | ctx->calc_path_loss = calc_path_loss_two_ray_ground; 462 | param = malloc(sizeof(*param)); 463 | if (!param) { 464 | w_flogf(ctx, LOG_ERR, stderr, 465 | "Out of memory(path_loss_param)\n"); 466 | return -EINVAL; 467 | } 468 | 469 | if (config_setting_lookup_int(model, "sL", 470 | ¶m->sL) != CONFIG_TRUE) { 471 | w_flogf(ctx, LOG_ERR, stderr, 472 | "system loss not found\n"); 473 | return -EINVAL; 474 | } 475 | ctx->path_loss_param = param; 476 | } 477 | else if (strncmp(path_loss_model_name, "itu", 478 | sizeof("itu")) == 0) { 479 | struct itu_model_param *param; 480 | ctx->calc_path_loss = calc_path_loss_itu; 481 | param = malloc(sizeof(*param)); 482 | if (!param) { 483 | w_flogf(ctx, LOG_ERR, stderr, 484 | "Out of memory(path_loss_param)\n"); 485 | return -EINVAL; 486 | } 487 | 488 | if (config_setting_lookup_int(model, "nFLOORS", 489 | ¶m->nFLOORS) != CONFIG_TRUE) { 490 | w_flogf(ctx, LOG_ERR, stderr, 491 | "nFLOORS not found\n"); 492 | return -EINVAL; 493 | } 494 | 495 | if (config_setting_lookup_int(model, "lF", 496 | ¶m->lF) != CONFIG_TRUE) { 497 | w_flogf(ctx, LOG_ERR, stderr, "LF not found\n"); 498 | return -EINVAL; 499 | } 500 | 501 | if (config_setting_lookup_int(model, "pL", 502 | ¶m->pL) != CONFIG_TRUE) { 503 | w_flogf(ctx, LOG_ERR, stderr, "PL not found\n"); 504 | return -EINVAL; 505 | } 506 | ctx->path_loss_param = param; 507 | } 508 | else { 509 | w_flogf(ctx, LOG_ERR, stderr, "No path loss model found\n"); 510 | return -EINVAL; 511 | } 512 | 513 | list_for_each_entry(station, &ctx->stations, list) { 514 | position = config_setting_get_elem(positions, station->index); 515 | if (config_setting_length(position) != 3) { 516 | w_flogf(ctx, LOG_ERR, stderr, 517 | "Invalid position: expected (double,double,double)\n"); 518 | return -EINVAL; 519 | } 520 | station->x = config_setting_get_float_elem(position, 0); 521 | station->y = config_setting_get_float_elem(position, 1); 522 | station->z = config_setting_get_float_elem(position, 2); 523 | 524 | if (directions) { 525 | direction = config_setting_get_elem(directions, 526 | station->index); 527 | if (config_setting_length(direction) != 2) { 528 | w_flogf(ctx, LOG_ERR, stderr, 529 | "Invalid direction: expected (double,double)\n"); 530 | return -EINVAL; 531 | } 532 | station->dir_x = config_setting_get_float_elem( 533 | direction, 0); 534 | station->dir_y = config_setting_get_float_elem( 535 | direction, 1); 536 | } 537 | 538 | station->tx_power = config_setting_get_float_elem( 539 | tx_powers, station->index); 540 | if (isnodeaps) { 541 | station->isap = config_setting_get_int_elem( 542 | isnodeaps, station->index); 543 | } 544 | } 545 | 546 | recalc_path_loss(ctx); 547 | 548 | return 0; 549 | } 550 | 551 | static double pseudo_normal_distribution(void) 552 | { 553 | int i; 554 | double normal = -6.0; 555 | 556 | for (i = 0; i < 12; i++) 557 | normal += drand48(); 558 | 559 | return normal; 560 | } 561 | 562 | static int _get_fading_signal(struct wmediumd *ctx) 563 | { 564 | return ctx->fading_coefficient * pseudo_normal_distribution(); 565 | } 566 | 567 | static int get_no_fading_signal(struct wmediumd *ctx) 568 | { 569 | return 0; 570 | } 571 | 572 | /* 573 | * Loads a config file into memory 574 | */ 575 | int load_config(struct wmediumd *ctx, const char *file, const char *per_file, bool full_dynamic) 576 | { 577 | config_t cfg, *cf; 578 | const config_setting_t *ids, *links, *model_type; 579 | const config_setting_t *error_probs = NULL, *error_prob; 580 | const config_setting_t *enable_interference; 581 | const config_setting_t *fading_coefficient, *noise_threshold, *default_prob; 582 | const config_setting_t *mediums, *medium_data,*interface_data, *medium_detection; 583 | int count_ids, count_mediums, count_interfaces, station_id, i, j; 584 | int start, end, snr; 585 | struct station *station; 586 | const char *model_type_str; 587 | float default_prob_value = 0.0; 588 | bool *link_map = NULL; 589 | 590 | if (full_dynamic) { 591 | ctx->sta_array = malloc(0); 592 | ctx->num_stas = 0; 593 | ctx->intf = NULL; 594 | ctx->get_fading_signal = get_no_fading_signal; 595 | ctx->fading_coefficient = 0; 596 | ctx->move_stations = move_stations_donothing; 597 | ctx->snr_matrix = malloc(0); 598 | ctx->per_matrix = NULL; 599 | ctx->per_matrix_row_num = 0; 600 | ctx->error_prob_matrix = NULL; 601 | ctx->get_link_snr = get_link_snr_default; 602 | ctx->station_err_matrix = malloc(0); 603 | return 0; 604 | } 605 | ctx->station_err_matrix = NULL; 606 | 607 | /*initialize the config file*/ 608 | cf = &cfg; 609 | config_init(cf); 610 | 611 | /*read the file*/ 612 | if (!config_read_file(cf, file)) { 613 | w_logf(ctx, LOG_ERR, "Error loading file %s at line:%d, reason: %s\n", 614 | file, 615 | config_error_line(cf), 616 | config_error_text(cf)); 617 | config_destroy(cf); 618 | return -EIO; 619 | } 620 | 621 | ids = config_lookup(cf, "ifaces.ids"); 622 | if (!ids) { 623 | w_logf(ctx, LOG_ERR, "ids not found in config file\n"); 624 | return -EIO; 625 | } 626 | count_ids = config_setting_length(ids); 627 | 628 | w_logf(ctx, LOG_NOTICE, "#_if = %d\n", count_ids); 629 | 630 | /* Fill the mac_addr */ 631 | ctx->sta_array = malloc(sizeof(struct station *) * count_ids); 632 | if (!ctx->sta_array) { 633 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory(sta_array)!\n"); 634 | return -ENOMEM; 635 | } 636 | for (i = 0; i < count_ids; i++) { 637 | u8 addr[8]; 638 | const char *str = config_setting_get_string_elem(ids, i); 639 | string_to_mac_address(str, addr); 640 | 641 | station = malloc(sizeof(*station)); 642 | if (!station) { 643 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory!\n"); 644 | return -ENOMEM; 645 | } 646 | station->index = i; 647 | memcpy(station->extended_addr, addr, 8); 648 | memcpy(station->hwaddr, addr, 8); 649 | station->tx_power = SNR_DEFAULT; 650 | station->gain = GAIN_DEFAULT; 651 | station->gRandom = GAUSS_RANDOM_DEFAULT; 652 | station->isap = AP_DEFAULT; 653 | station->medium_id = MEDIUM_ID_DEFAULT; 654 | station_init_queues(station); 655 | list_add_tail(&station->list, &ctx->stations); 656 | ctx->sta_array[i] = station; 657 | 658 | w_logf(ctx, LOG_NOTICE, "Added sensor %d: " MAC_FMT "\n", i, MAC_ARGS(addr)); 659 | } 660 | ctx->num_stas = count_ids; 661 | 662 | enable_interference = config_lookup(cf, "ifaces.enable_interference"); 663 | if (enable_interference && 664 | config_setting_get_bool(enable_interference)) { 665 | ctx->intf = calloc(ctx->num_stas * ctx->num_stas, 666 | sizeof(struct intf_info)); 667 | if (!ctx->intf) { 668 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory(intf)\n"); 669 | return -ENOMEM; 670 | } 671 | for (i = 0; i < ctx->num_stas; i++) 672 | for (j = 0; j < ctx->num_stas; j++) 673 | ctx->intf[i * ctx->num_stas + j].lqi = 200; 674 | } else { 675 | ctx->intf = NULL; 676 | } 677 | 678 | noise_threshold = 679 | config_lookup(cf, "model.noise_threshold"); 680 | if (noise_threshold && 681 | config_setting_get_int(noise_threshold) < 0) { 682 | ctx->get_fading_signal = _get_fading_signal; 683 | ctx->noise_threshold = 684 | config_setting_get_int(noise_threshold); 685 | } else { 686 | ctx->noise_threshold = NOISE_LEVEL; 687 | } 688 | 689 | 690 | fading_coefficient = 691 | config_lookup(cf, "model.fading_coefficient"); 692 | if (fading_coefficient && 693 | config_setting_get_int(fading_coefficient) > 0) { 694 | ctx->get_fading_signal = _get_fading_signal; 695 | ctx->fading_coefficient = 696 | config_setting_get_int(fading_coefficient); 697 | } else { 698 | ctx->get_fading_signal = get_no_fading_signal; 699 | ctx->fading_coefficient = 0; 700 | } 701 | 702 | ctx->move_stations = move_stations_donothing; 703 | 704 | /* create link quality matrix */ 705 | ctx->snr_matrix = calloc(sizeof(int), count_ids * count_ids); 706 | if (!ctx->snr_matrix) { 707 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory!\n"); 708 | return -ENOMEM; 709 | } 710 | /* set default snrs */ 711 | for (i = 0; i < count_ids * count_ids; i++) 712 | ctx->snr_matrix[i] = SNR_DEFAULT; 713 | 714 | links = config_lookup(cf, "ifaces.links"); 715 | if (!links) { 716 | model_type = config_lookup(cf, "model.type"); 717 | if (model_type) { 718 | model_type_str = config_setting_get_string(model_type); 719 | if (memcmp("snr", model_type_str, strlen("snr")) == 0) { 720 | links = config_lookup(cf, "model.links"); 721 | } else if (memcmp("prob", model_type_str, 722 | strlen("prob")) == 0) { 723 | error_probs = config_lookup(cf, "model.links"); 724 | } else if (memcmp("path_loss", model_type_str, 725 | strlen("path_loss")) == 0) { 726 | /* calculate signal from positions */ 727 | if (parse_path_loss(ctx, cf)) 728 | goto fail; 729 | } 730 | } 731 | } 732 | mediums = config_lookup(cf, "ifaces.medium_array"); 733 | if (mediums) { 734 | count_mediums = config_setting_length(mediums); 735 | for (i = 0; i < count_mediums; i++) { 736 | medium_data = config_setting_get_elem(mediums, i); 737 | count_interfaces = config_setting_length(medium_data); 738 | for (j = 0; j < count_interfaces; j++) { 739 | interface_data = config_setting_get_elem(medium_data, j); 740 | station_id = config_setting_get_int(interface_data); 741 | ctx->sta_array[station_id]->medium_id = i+1; 742 | } 743 | } 744 | } 745 | medium_detection = config_lookup(cf, "ifaces.enable_medium_detection"); 746 | if (medium_detection) { 747 | ctx->enable_medium_detection =config_setting_get_bool(enable_interference); 748 | }else{ 749 | ctx->enable_medium_detection = ENABLE_MEDIUM_DETECTION; 750 | } 751 | 752 | if (per_file && error_probs) { 753 | w_flogf(ctx, LOG_ERR, stderr, 754 | "per_file and error_probs could not be used at the same time\n"); 755 | goto fail; 756 | } 757 | 758 | ctx->get_link_snr = get_link_snr_from_snr_matrix; 759 | ctx->get_error_prob = _get_error_prob_from_snr; 760 | 761 | ctx->per_matrix = NULL; 762 | ctx->per_matrix_row_num = 0; 763 | if (per_file && read_per_file(ctx, per_file)) 764 | goto fail; 765 | 766 | ctx->error_prob_matrix = NULL; 767 | if (error_probs) { 768 | ctx->error_prob_matrix = calloc(sizeof(double), 769 | count_ids * count_ids); 770 | if (!ctx->error_prob_matrix) { 771 | w_flogf(ctx, LOG_ERR, stderr, 772 | "Out of memory(error_prob_matrix)\n"); 773 | goto fail; 774 | } 775 | 776 | ctx->get_link_snr = get_link_snr_default; 777 | ctx->get_error_prob = get_error_prob_from_matrix; 778 | 779 | default_prob = config_lookup(cf, "model.default_prob"); 780 | if (default_prob) { 781 | default_prob_value = config_setting_get_float( 782 | default_prob); 783 | if (default_prob_value < 0.0 || 784 | default_prob_value > 1.0) { 785 | w_flogf(ctx, LOG_ERR, stderr, 786 | "model.default_prob should be in [0.0, 1.0]\n"); 787 | goto fail; 788 | } 789 | } 790 | } 791 | 792 | link_map = calloc(sizeof(bool), count_ids * count_ids); 793 | if (!link_map) { 794 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory\n"); 795 | goto fail; 796 | } 797 | 798 | /* read snr values */ 799 | for (i = 0; links && i < config_setting_length(links); i++) { 800 | config_setting_t *link; 801 | 802 | link = config_setting_get_elem(links, i); 803 | if (config_setting_length(link) != 3) { 804 | w_flogf(ctx, LOG_ERR, stderr, "Invalid link: expected (int,int,int)\n"); 805 | goto fail; 806 | } 807 | start = config_setting_get_int_elem(link, 0); 808 | end = config_setting_get_int_elem(link, 1); 809 | snr = config_setting_get_int_elem(link, 2); 810 | 811 | if (start < 0 || start >= ctx->num_stas || 812 | end < 0 || end >= ctx->num_stas) { 813 | w_flogf(ctx, LOG_ERR, stderr, "Invalid link [%d,%d,%d]: index out of range\n", 814 | start, end, snr); 815 | goto fail; 816 | } 817 | ctx->snr_matrix[ctx->num_stas * start + end] = snr; 818 | link_map[ctx->num_stas * start + end] = true; 819 | } 820 | 821 | /* initialize with default_prob */ 822 | for (start = 0; error_probs && start < ctx->num_stas; start++) 823 | for (end = start + 1; end < ctx->num_stas; end++) { 824 | ctx->error_prob_matrix[ctx->num_stas * 825 | start + end] = 826 | ctx->error_prob_matrix[ctx->num_stas * 827 | end + start] = default_prob_value; 828 | } 829 | 830 | /* read error probabilities */ 831 | for (i = 0; error_probs && 832 | i < config_setting_length(error_probs); i++) { 833 | float error_prob_value; 834 | 835 | error_prob = config_setting_get_elem(error_probs, i); 836 | if (config_setting_length(error_prob) != 3) { 837 | w_flogf(ctx, LOG_ERR, stderr, "Invalid error probability: expected (int,int,float)\n"); 838 | goto fail; 839 | } 840 | 841 | start = config_setting_get_int_elem(error_prob, 0); 842 | end = config_setting_get_int_elem(error_prob, 1); 843 | error_prob_value = config_setting_get_float_elem(error_prob, 2); 844 | 845 | if (start < 0 || start >= ctx->num_stas || 846 | end < 0 || end >= ctx->num_stas || 847 | error_prob_value < 0.0 || error_prob_value > 1.0) { 848 | w_flogf(ctx, LOG_ERR, stderr, "Invalid error probability [%d,%d,%f]\n", 849 | start, end, error_prob_value); 850 | goto fail; 851 | } 852 | ctx->error_prob_matrix[ctx->num_stas * start + end] = 853 | error_prob_value; 854 | link_map[ctx->num_stas * start + end] = true; 855 | } 856 | 857 | /* 858 | * If any links are specified in only one direction, mirror them, 859 | * making them symmetric. If specified in both directions they 860 | * can be asymmetric. 861 | */ 862 | for (i = 0; i < ctx->num_stas; i++) { 863 | for (j = 0; j < ctx->num_stas; j++) { 864 | if (i == j) 865 | continue; 866 | 867 | if (link_map[ctx->num_stas * i + j] && 868 | !link_map[ctx->num_stas * j + i]) { 869 | mirror_link(ctx, i, j); 870 | } 871 | } 872 | } 873 | 874 | free(link_map); 875 | config_destroy(cf); 876 | return 0; 877 | 878 | fail: 879 | free(ctx->snr_matrix); 880 | free(ctx->error_prob_matrix); 881 | config_destroy(cf); 882 | return -EINVAL; 883 | } 884 | -------------------------------------------------------------------------------- /wmediumd/wserver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd_server - server for on-the-fly modifications for wmediumd 3 | * Copyright (c) 2016, Patrick Grosse 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public License 7 | * as published by the Free Software Foundation; either version 2 8 | * of the License, or (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | * 02110-1301, USA. 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "wserver.h" 33 | #include "wmediumd_dynamic.h" 34 | #include "wserver_messages.h" 35 | 36 | 37 | #define LOG_PREFIX "W_SRV: " 38 | 39 | /** 40 | * Global listen socket 41 | */ 42 | static int listen_soc; 43 | 44 | /** 45 | * Global thread 46 | */ 47 | static pthread_t server_thread; 48 | 49 | /** 50 | * Event base for server events 51 | */ 52 | static struct event_base *server_event_base; 53 | 54 | /** 55 | * Stores the old sig handler for SIGINT 56 | */ 57 | static __sighandler_t old_sig_handler; 58 | 59 | /** 60 | * Handle the SIGINT signal 61 | * @param param The param passed to by signal() 62 | */ 63 | void handle_sigint(int param) { 64 | UNUSED(param); 65 | stop_wserver(); 66 | exit(EXIT_SUCCESS); 67 | } 68 | 69 | /* Existing link is from from -> to; copy to other dir */ 70 | static void mirror_link_(struct request_ctx *ctx, int from, int to, int signal) 71 | { 72 | ctx->ctx->snr_matrix[ctx->ctx->num_stas * to + from] = signal; 73 | ctx->ctx->snr_matrix[ctx->ctx->num_stas * from + to] = signal; 74 | } 75 | 76 | 77 | static void calc_signal(struct request_ctx *ctx) 78 | { 79 | int txpower, path_loss, gains, signal, from, to; 80 | 81 | for (from = 0; from < ctx->ctx->num_stas; from++) { 82 | for (to = 0; to < ctx->ctx->num_stas; to++) { 83 | if (from == to) 84 | continue; 85 | txpower = ctx->ctx->sta_array[from]->tx_power; 86 | if (ctx->ctx->sta_array[to]->isap == 1) 87 | txpower = ctx->ctx->sta_array[to]->tx_power; 88 | path_loss = ctx->ctx->calc_path_loss(ctx->ctx->path_loss_param, 89 | ctx->ctx->sta_array[to], ctx->ctx->sta_array[from]); 90 | gains = (txpower + ctx->ctx->sta_array[from]->gain + ctx->ctx->sta_array[to]->gain); 91 | signal = gains - path_loss - ctx->ctx->noise_threshold; 92 | mirror_link_(ctx, from, to, signal); 93 | } 94 | } 95 | } 96 | 97 | /** 98 | * Create the listening socket 99 | * @param ctx The wmediumd context 100 | * @return The FD of the socket 101 | */ 102 | int create_listen_socket(struct wmediumd *ctx) { 103 | int soc = socket(AF_UNIX, SOCK_STREAM, 0); 104 | if (soc < 0) { 105 | w_logf(ctx, LOG_ERR, LOG_PREFIX "Socket not created: %s\n", strerror(errno)); 106 | return -1; 107 | } 108 | w_logf(ctx, LOG_DEBUG, LOG_PREFIX "Socket created\n"); 109 | 110 | int unlnk_ret = unlink(WSERVER_SOCKET_PATH); 111 | if (unlnk_ret != 0 && errno != ENOENT) { 112 | w_logf(ctx, LOG_ERR, LOG_PREFIX "Cannot remove old UNIX socket at '\" WSERVER_SOCKET_PATH \"': %s\n", 113 | strerror(errno)); 114 | close(soc); 115 | return -1; 116 | } 117 | struct sockaddr_un saddr = {AF_UNIX, WSERVER_SOCKET_PATH}; 118 | int retval = bind(soc, (struct sockaddr *) &saddr, sizeof(saddr)); 119 | if (retval < 0) { 120 | w_logf(ctx, LOG_ERR, LOG_PREFIX "Bind failed: %s\n", strerror(errno)); 121 | close(soc); 122 | return -1; 123 | } 124 | w_logf(ctx, LOG_DEBUG, LOG_PREFIX "Bound to UNIX socket '" WSERVER_SOCKET_PATH "'\n"); 125 | 126 | retval = listen(soc, 10); 127 | if (retval < 0) { 128 | w_logf(ctx, LOG_ERR, LOG_PREFIX "Listen failed: %s\n", strerror(errno)); 129 | close(soc); 130 | return -1; 131 | } 132 | 133 | return soc; 134 | } 135 | 136 | /** 137 | * Accept incoming connections 138 | * @param listen_soc The FD of the server socket 139 | * @return The FD of the client socket 140 | */ 141 | int accept_connection(int listen_soc) { 142 | struct sockaddr_in claddr; 143 | socklen_t claddr_size = sizeof(claddr); 144 | 145 | int soc = accept(listen_soc, (struct sockaddr *) &claddr, &claddr_size); 146 | if (soc < 0) { 147 | return -1; 148 | } 149 | return soc; 150 | } 151 | 152 | int handle_snr_update_request(struct request_ctx *ctx, const snr_update_request *request) { 153 | snr_update_response response; 154 | response.request = *request; 155 | 156 | if (ctx->ctx->snr_matrix != NULL) { 157 | struct station *sender = NULL; 158 | struct station *receiver = NULL; 159 | struct station *station; 160 | 161 | pthread_rwlock_wrlock(&snr_lock); 162 | 163 | list_for_each_entry(station, &ctx->ctx->stations, list) { 164 | if (memcmp(&request->from_addr, station->extended_addr, ETH_ALEN) == 0) { 165 | sender = station; 166 | } 167 | if (memcmp(&request->to_addr, station->extended_addr, ETH_ALEN) == 0) { 168 | receiver = station; 169 | } 170 | } 171 | 172 | if (!sender || !receiver) { 173 | w_logf(ctx->ctx, LOG_WARNING, 174 | LOG_PREFIX "Could not perform SNR update from=" MAC_FMT ", to=" MAC_FMT ", snr=%d; station(s) not found\n", 175 | MAC_ARGS(request->from_addr), MAC_ARGS(request->to_addr), request->snr); 176 | response.update_result = WUPDATE_INTF_NOTFOUND; 177 | } else { 178 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX "Performing SNR update: from=" MAC_FMT ", to=" MAC_FMT ", snr=%d\n", 179 | MAC_ARGS(sender->extended_addr), MAC_ARGS(receiver->extended_addr), request->snr); 180 | 181 | mirror_link_(ctx, sender->index, receiver->index, request->snr); 182 | response.update_result = WUPDATE_SUCCESS; 183 | } 184 | pthread_rwlock_unlock(&snr_lock); 185 | } else { 186 | response.update_result = WUPDATE_WRONG_MODE; 187 | } 188 | int ret = wserver_send_msg(ctx->sock_fd, &response, snr_update_response); 189 | if (ret < 0) { 190 | w_logf(ctx->ctx, LOG_ERR, "Error on SNR update response: %s\n", strerror(abs(ret))); 191 | return WACTION_ERROR; 192 | } 193 | return ret; 194 | } 195 | 196 | int handle_position_update_request(struct request_ctx *ctx, const position_update_request *request) { 197 | position_update_response response; 198 | response.request = *request; 199 | 200 | if (ctx->ctx->error_prob_matrix == NULL) { 201 | struct station *sender = NULL; 202 | struct station *station; 203 | 204 | pthread_rwlock_wrlock(&snr_lock); 205 | 206 | list_for_each_entry(station, &ctx->ctx->stations, list) { 207 | if (memcmp(&request->sta_addr, station->extended_addr, ETH_ALEN) == 0) { 208 | sender = station; 209 | sender->x = request->posX; 210 | sender->y = request->posY; 211 | sender->z = request->posZ; 212 | } 213 | } 214 | 215 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX "Performing Position update: for=" MAC_FMT ", position=%f,%f,%f\n", 216 | MAC_ARGS(request->sta_addr), request->posX, request->posY, request->posZ); 217 | 218 | calc_signal(ctx); 219 | response.update_result = WUPDATE_SUCCESS; 220 | 221 | pthread_rwlock_unlock(&snr_lock); 222 | } else { 223 | response.update_result = WUPDATE_WRONG_MODE; 224 | } 225 | int ret = wserver_send_msg(ctx->sock_fd, &response, position_update_response); 226 | return ret; 227 | } 228 | 229 | int handle_txpower_update_request(struct request_ctx *ctx, const txpower_update_request *request) { 230 | txpower_update_response response; 231 | response.request = *request; 232 | 233 | if (ctx->ctx->error_prob_matrix == NULL) { 234 | struct station *sender = NULL; 235 | struct station *station; 236 | 237 | pthread_rwlock_wrlock(&snr_lock); 238 | 239 | list_for_each_entry(station, &ctx->ctx->stations, list) { 240 | if (memcmp(&request->sta_addr, station->extended_addr, ETH_ALEN) == 0) { 241 | sender = station; 242 | sender->tx_power = request->txpower_; 243 | } 244 | } 245 | 246 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX "Performing TxPower update: for=" MAC_FMT ", txpower=%d\n", 247 | MAC_ARGS(request->sta_addr), request->txpower_); 248 | 249 | calc_signal(ctx); 250 | response.update_result = WUPDATE_SUCCESS; 251 | 252 | pthread_rwlock_unlock(&snr_lock); 253 | } else { 254 | response.update_result = WUPDATE_WRONG_MODE; 255 | } 256 | int ret = wserver_send_msg(ctx->sock_fd, &response, txpower_update_response); 257 | return ret; 258 | } 259 | 260 | int handle_gaussian_random_update_request(struct request_ctx *ctx, const gaussian_random_update_request *request) { 261 | gaussian_random_update_response response; 262 | response.request = *request; 263 | 264 | if (ctx->ctx->error_prob_matrix == NULL) { 265 | struct station *sender = NULL; 266 | struct station *station; 267 | 268 | pthread_rwlock_wrlock(&snr_lock); 269 | 270 | list_for_each_entry(station, &ctx->ctx->stations, list) { 271 | if (memcmp(&request->sta_addr, station->extended_addr, ETH_ALEN) == 0) { 272 | sender = station; 273 | sender->gRandom = request->gaussian_random_; 274 | } 275 | } 276 | 277 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX "Performing Gaussian Random update: for=" MAC_FMT ", gRandom=%d\n", 278 | MAC_ARGS(request->sta_addr), request->gaussian_random_); 279 | 280 | calc_signal(ctx); 281 | response.update_result = WUPDATE_SUCCESS; 282 | 283 | pthread_rwlock_unlock(&snr_lock); 284 | } else { 285 | response.update_result = WUPDATE_WRONG_MODE; 286 | } 287 | int ret = wserver_send_msg(ctx->sock_fd, &response, gaussian_random_update_response); 288 | return ret; 289 | } 290 | 291 | int handle_gain_update_request(struct request_ctx *ctx, const gain_update_request *request) { 292 | gain_update_response response; 293 | response.request = *request; 294 | 295 | if (ctx->ctx->error_prob_matrix == NULL) { 296 | struct station *sender = NULL; 297 | struct station *station; 298 | 299 | pthread_rwlock_wrlock(&snr_lock); 300 | 301 | list_for_each_entry(station, &ctx->ctx->stations, list) { 302 | if (memcmp(&request->sta_addr, station->extended_addr, ETH_ALEN) == 0) { 303 | sender = station; 304 | sender->gain = request->gain_; 305 | } 306 | } 307 | 308 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX "Performing Gain update: for=" MAC_FMT ", gain=%d\n", 309 | MAC_ARGS(request->sta_addr), request->gain_); 310 | 311 | calc_signal(ctx); 312 | response.update_result = WUPDATE_SUCCESS; 313 | 314 | pthread_rwlock_unlock(&snr_lock); 315 | } else { 316 | response.update_result = WUPDATE_WRONG_MODE; 317 | } 318 | int ret = wserver_send_msg(ctx->sock_fd, &response, gain_update_response); 319 | return ret; 320 | } 321 | 322 | 323 | int handle_errprob_update_request(struct request_ctx *ctx, const errprob_update_request *request) { 324 | errprob_update_response response; 325 | response.request = *request; 326 | 327 | if (ctx->ctx->error_prob_matrix != NULL) { 328 | struct station *sender = NULL; 329 | struct station *receiver = NULL; 330 | struct station *station; 331 | 332 | pthread_rwlock_wrlock(&snr_lock); 333 | 334 | list_for_each_entry(station, &ctx->ctx->stations, list) { 335 | if (memcmp(&request->from_addr, station->extended_addr, ETH_ALEN) == 0) { 336 | sender = station; 337 | } 338 | if (memcmp(&request->to_addr, station->extended_addr, ETH_ALEN) == 0) { 339 | receiver = station; 340 | } 341 | } 342 | 343 | double errprob = custom_fixed_point_to_floating_point(request->errprob); 344 | 345 | if (!sender || !receiver) { 346 | w_logf(ctx->ctx, LOG_WARNING, 347 | LOG_PREFIX "Could not perform ERRPROB update from=" MAC_FMT ", to=" MAC_FMT ", errprob=%f; station(s) not found\n", 348 | MAC_ARGS(request->from_addr), MAC_ARGS(request->to_addr), errprob); 349 | response.update_result = WUPDATE_INTF_NOTFOUND; 350 | } else { 351 | w_logf(ctx->ctx, LOG_NOTICE, 352 | LOG_PREFIX "Performing ERRPROB update: from=" MAC_FMT ", to=" MAC_FMT ", errprob=%f\n", 353 | MAC_ARGS(sender->extended_addr), MAC_ARGS(receiver->extended_addr), errprob); 354 | ctx->ctx->error_prob_matrix[sender->index * ctx->ctx->num_stas + receiver->index] = errprob; 355 | ctx->ctx->error_prob_matrix[receiver->index * ctx->ctx->num_stas + sender->index] = errprob; 356 | response.update_result = WUPDATE_SUCCESS; 357 | } 358 | pthread_rwlock_unlock(&snr_lock); 359 | } else { 360 | response.update_result = WUPDATE_WRONG_MODE; 361 | } 362 | int ret = wserver_send_msg(ctx->sock_fd, &response, errprob_update_response); 363 | if (ret < 0) { 364 | w_logf(ctx->ctx, LOG_ERR, "Error on ERRPROB update response: %s\n", strerror(abs(ret))); 365 | return WACTION_ERROR; 366 | } 367 | return ret; 368 | } 369 | 370 | int handle_specprob_update_request(struct request_ctx *ctx, const specprob_update_request *request) { 371 | specprob_update_response response; 372 | memcpy(response.from_addr, request->from_addr, ETH_ALEN); 373 | memcpy(response.to_addr, request->to_addr, ETH_ALEN); 374 | 375 | if (ctx->ctx->station_err_matrix != NULL) { 376 | struct station *sender = NULL; 377 | struct station *receiver = NULL; 378 | struct station *station; 379 | 380 | pthread_rwlock_wrlock(&snr_lock); 381 | 382 | list_for_each_entry(station, &ctx->ctx->stations, list) { 383 | if (memcmp(&request->from_addr, station->extended_addr, ETH_ALEN) == 0) { 384 | sender = station; 385 | } 386 | if (memcmp(&request->to_addr, station->extended_addr, ETH_ALEN) == 0) { 387 | receiver = station; 388 | } 389 | } 390 | 391 | if (!sender || !receiver) { 392 | //w_logf(ctx->ctx, LOG_WARNING, 393 | // LOG_PREFIX "Could not perform SPECPROB update from=" MAC_FMT ", to=" MAC_FMT "; station(s) not found\n", 394 | // MAC_ARGS(request->from_addr), MAC_ARGS(request->to_addr)); 395 | response.update_result = WUPDATE_INTF_NOTFOUND; 396 | } else { 397 | //w_logf(ctx->ctx, LOG_NOTICE, 398 | // LOG_PREFIX "Performing SPECPROB update: from=" MAC_FMT ", to=" MAC_FMT "\n", 399 | // MAC_ARGS(sender->addr), MAC_ARGS(receiver->addr)); 400 | double *specific_mat = malloc(sizeof(double) * SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX); 401 | if (!specific_mat) { 402 | w_logf(ctx->ctx, LOG_ERR, "Error during allocation of memory in handle_specprob_update_request wmediumd/wserver.c\n"); 403 | // should be different type of error here 404 | response.update_result = WUPDATE_WRONG_MODE; 405 | goto out; 406 | } 407 | for (int i = 0; i < SPECIFIC_MATRIX_MAX_SIZE_IDX * SPECIFIC_MATRIX_MAX_RATE_IDX; i++) { 408 | specific_mat[i] = custom_fixed_point_to_floating_point(request->errprob[i]); 409 | } 410 | if (ctx->ctx->station_err_matrix[sender->index * ctx->ctx->num_stas + receiver->index] != NULL) { 411 | free(ctx->ctx->station_err_matrix[sender->index * ctx->ctx->num_stas + receiver->index]); 412 | } 413 | ctx->ctx->station_err_matrix[sender->index * ctx->ctx->num_stas + receiver->index] = specific_mat; 414 | response.update_result = WUPDATE_SUCCESS; 415 | } 416 | out: 417 | pthread_rwlock_unlock(&snr_lock); 418 | } else { 419 | response.update_result = WUPDATE_WRONG_MODE; 420 | } 421 | int ret = wserver_send_msg(ctx->sock_fd, &response, specprob_update_response); 422 | if (ret < 0) { 423 | w_logf(ctx->ctx, LOG_ERR, "Error on SPECPROB update response: %s\n", strerror(abs(ret))); 424 | return WACTION_ERROR; 425 | } 426 | return ret; 427 | } 428 | 429 | int handle_delete_by_id_request(struct request_ctx *ctx, station_del_by_id_request *request) { 430 | station_del_by_id_response response; 431 | response.request = *request; 432 | int ret = del_station_by_id(ctx->ctx, request->id); 433 | if (ret) { 434 | if (ret == -ENODEV) { 435 | w_logf(ctx->ctx, LOG_WARNING, LOG_PREFIX 436 | "Station with ID %d could not be found\n", request->id); 437 | response.update_result = WUPDATE_INTF_NOTFOUND; 438 | } else { 439 | w_logf(ctx->ctx, LOG_ERR, "Error on delete by id request: %s\n", strerror(abs(ret))); 440 | return WACTION_ERROR; 441 | } 442 | } else { 443 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX 444 | "Station with ID %d successfully deleted\n", request->id); 445 | response.update_result = WUPDATE_SUCCESS; 446 | } 447 | ret = wserver_send_msg(ctx->sock_fd, &response, station_del_by_id_response); 448 | if (ret < 0) { 449 | w_logf(ctx->ctx, LOG_ERR, "Error on delete by id response: %s\n", strerror(abs(ret))); 450 | return WACTION_ERROR; 451 | } 452 | return ret; 453 | } 454 | 455 | int handle_delete_by_mac_request(struct request_ctx *ctx, station_del_by_mac_request *request) { 456 | station_del_by_mac_response response; 457 | response.request = *request; 458 | int ret = del_station_by_mac(ctx->ctx, request->addr); 459 | if (ret) { 460 | if (ret == -ENODEV) { 461 | w_logf(ctx->ctx, LOG_WARNING, LOG_PREFIX 462 | "Station with MAC " MAC_FMT " could not be found\n", MAC_ARGS(request->addr)); 463 | response.update_result = WUPDATE_INTF_NOTFOUND; 464 | } else { 465 | w_logf(ctx->ctx, LOG_ERR, "Error %d on delete by mac request: %s\n", ret, strerror(abs(ret))); 466 | return WACTION_ERROR; 467 | } 468 | } else { 469 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX 470 | "Station with MAC " MAC_FMT " successfully deleted\n", MAC_ARGS(request->addr)); 471 | response.update_result = WUPDATE_SUCCESS; 472 | } 473 | ret = wserver_send_msg(ctx->sock_fd, &response, station_del_by_mac_response); 474 | if (ret < 0) { 475 | w_logf(ctx->ctx, LOG_ERR, "Error on delete by mac response: %s\n", strerror(abs(ret))); 476 | return WACTION_ERROR; 477 | } 478 | return ret; 479 | } 480 | 481 | int handle_add_request(struct request_ctx *ctx, station_add_request *request) { 482 | int ret = add_station(ctx->ctx, request->addr); 483 | station_add_response response; 484 | response.request = *request; 485 | if (ret < 0) { 486 | if (ret == -EEXIST) { 487 | w_logf(ctx->ctx, LOG_WARNING, LOG_PREFIX 488 | "Station with MAC " MAC_FMT " already exists\n", MAC_ARGS(request->addr)); 489 | response.created_id = 0; 490 | response.update_result = WUPDATE_INTF_DUPLICATE; 491 | } else { 492 | w_logf(ctx->ctx, LOG_ERR, "Error on add request: %s\n", strerror(abs(ret))); 493 | return WACTION_ERROR; 494 | } 495 | } else { 496 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX 497 | "Added station with MAC " MAC_FMT " and ID %d\n", MAC_ARGS(request->addr), ret); 498 | response.created_id = ret; 499 | response.update_result = WUPDATE_SUCCESS; 500 | } 501 | ret = wserver_send_msg(ctx->sock_fd, &response, station_add_response); 502 | if (ret < 0) { 503 | w_logf(ctx->ctx, LOG_ERR, "Error on add response: %s\n", strerror(abs(ret))); 504 | return WACTION_ERROR; 505 | } 506 | return ret; 507 | } 508 | 509 | int handle_medium_update_request(struct request_ctx *ctx, const medium_update_request *request) { 510 | medium_update_response response; 511 | response.request = *request; 512 | struct station *sender = NULL; 513 | struct station *station; 514 | 515 | list_for_each_entry(station, &ctx->ctx->stations, list) { 516 | if (memcmp(&request->sta_addr, station->extended_addr, ETH_ALEN) == 0) { 517 | sender = station; 518 | } 519 | } 520 | w_logf(ctx->ctx, LOG_NOTICE, LOG_PREFIX "Performing Medium update: for=" MAC_FMT " to #%d\n", 521 | MAC_ARGS(request->sta_addr), request->medium_id_); 522 | if(sender!=NULL){ 523 | response.update_result = WUPDATE_SUCCESS; 524 | pthread_rwlock_wrlock(&snr_lock); 525 | sender->medium_id = request->medium_id_; 526 | pthread_rwlock_unlock(&snr_lock); 527 | }else{ 528 | response.update_result = WUPDATE_INTF_NOTFOUND; 529 | } 530 | 531 | int ret = wserver_send_msg(ctx->sock_fd, &response, medium_update_response); 532 | return ret; 533 | } 534 | 535 | int parse_recv_msg_rest_error(struct wmediumd *ctx, int value) { 536 | if (value > 0) { 537 | return value; 538 | } else { 539 | w_logf(ctx, LOG_ERR, "Error on receive msg rest: %s\n", strerror(abs(value))); 540 | return WACTION_ERROR; 541 | } 542 | } 543 | 544 | int receive_handle_request(struct request_ctx *ctx) { 545 | wserver_msg base; 546 | int recv_type; 547 | int ret = wserver_recv_msg_base(ctx->sock_fd, &base, &recv_type); 548 | if (ret > 0) { 549 | return ret; 550 | } else if (ret < 0) { 551 | w_logf(ctx->ctx, LOG_ERR, "Error on receive base request: %s\n", strerror(abs(ret))); 552 | return WACTION_ERROR; 553 | } 554 | if (recv_type == WSERVER_SHUTDOWN_REQUEST_TYPE) { 555 | return WACTION_CLOSE; 556 | } else if (recv_type == WSERVER_SNR_UPDATE_REQUEST_TYPE) { 557 | snr_update_request request; 558 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, snr_update_request))) { 559 | return parse_recv_msg_rest_error(ctx->ctx, ret); 560 | } else { 561 | return handle_snr_update_request(ctx, &request); 562 | } 563 | } else if (recv_type == WSERVER_ERRPROB_UPDATE_REQUEST_TYPE) { 564 | errprob_update_request request; 565 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, errprob_update_request))) { 566 | return parse_recv_msg_rest_error(ctx->ctx, ret); 567 | } else { 568 | return handle_errprob_update_request(ctx, &request); 569 | } 570 | } else if (recv_type == WSERVER_SPECPROB_UPDATE_REQUEST_TYPE) { 571 | specprob_update_request request; 572 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, specprob_update_request))) { 573 | return parse_recv_msg_rest_error(ctx->ctx, ret); 574 | } else { 575 | return handle_specprob_update_request(ctx, &request); 576 | } 577 | } else if (recv_type == WSERVER_DEL_BY_MAC_REQUEST_TYPE) { 578 | station_del_by_mac_request request; 579 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, station_del_by_mac_request))) { 580 | return parse_recv_msg_rest_error(ctx->ctx, ret); 581 | } else { 582 | return handle_delete_by_mac_request(ctx, &request); 583 | } 584 | } else if (recv_type == WSERVER_DEL_BY_ID_REQUEST_TYPE) { 585 | station_del_by_id_request request; 586 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, station_del_by_id_request))) { 587 | return parse_recv_msg_rest_error(ctx->ctx, ret); 588 | } else { 589 | return handle_delete_by_id_request(ctx, &request); 590 | } 591 | } else if (recv_type == WSERVER_ADD_REQUEST_TYPE) { 592 | station_add_request request; 593 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, station_add_request))) { 594 | return parse_recv_msg_rest_error(ctx->ctx, ret); 595 | } else { 596 | return handle_add_request(ctx, &request); 597 | } 598 | } else if (recv_type == WSERVER_POSITION_UPDATE_REQUEST_TYPE) { 599 | position_update_request request; 600 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, position_update_request))) { 601 | return parse_recv_msg_rest_error(ctx->ctx, ret); 602 | } else { 603 | return handle_position_update_request(ctx, &request); 604 | } 605 | } else if (recv_type == WSERVER_TXPOWER_UPDATE_REQUEST_TYPE) { 606 | txpower_update_request request; 607 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, txpower_update_request))) { 608 | return parse_recv_msg_rest_error(ctx->ctx, ret); 609 | } else { 610 | return handle_txpower_update_request(ctx, &request); 611 | } 612 | } else if (recv_type == WSERVER_GAIN_UPDATE_REQUEST_TYPE) { 613 | gain_update_request request; 614 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, gain_update_request))) { 615 | return parse_recv_msg_rest_error(ctx->ctx, ret); 616 | } else { 617 | return handle_gain_update_request(ctx, &request); 618 | } 619 | } else if (recv_type == WSERVER_GAUSSIAN_RANDOM_UPDATE_REQUEST_TYPE) { 620 | gaussian_random_update_request request; 621 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, gaussian_random_update_request))) { 622 | return parse_recv_msg_rest_error(ctx->ctx, ret); 623 | } else { 624 | return handle_gaussian_random_update_request(ctx, &request); 625 | } 626 | } else if (recv_type == WSERVER_MEDIUM_UPDATE_REQUEST_TYPE) { 627 | medium_update_request request; 628 | if ((ret = wserver_recv_msg(ctx->sock_fd, &request, medium_update_request))) { 629 | return parse_recv_msg_rest_error(ctx->ctx, ret); 630 | } else { 631 | return handle_medium_update_request(ctx, &request); 632 | } 633 | } 634 | else { 635 | return -1; 636 | } 637 | } 638 | 639 | struct accept_context { 640 | struct wmediumd *wctx; 641 | int server_socket; 642 | int client_socket; 643 | pthread_t *thread; 644 | }; 645 | 646 | void *handle_accepted_connection(void *d_ptr) { 647 | struct accept_context *actx = d_ptr; 648 | struct request_ctx rctx; 649 | rctx.ctx = actx->wctx; 650 | rctx.sock_fd = actx->client_socket; 651 | w_logf(rctx.ctx, LOG_INFO, LOG_PREFIX "Client connected\n"); 652 | while (1) { 653 | int action_resp; 654 | w_logf(rctx.ctx, LOG_INFO, LOG_PREFIX "Waiting for request...\n"); 655 | action_resp = receive_handle_request(&rctx); 656 | if (action_resp == WACTION_DISCONNECTED) { 657 | w_logf(rctx.ctx, LOG_INFO, LOG_PREFIX "Client has disconnected\n"); 658 | break; 659 | } else if (action_resp == WACTION_ERROR) { 660 | w_logf(rctx.ctx, LOG_INFO, LOG_PREFIX "Disconnecting client because of error\n"); 661 | break; 662 | } else if (action_resp == WACTION_CLOSE) { 663 | w_logf(rctx.ctx, LOG_INFO, LOG_PREFIX "Closing server\n"); 664 | event_base_loopbreak(server_event_base); 665 | break; 666 | } 667 | } 668 | close(rctx.sock_fd); 669 | free(actx); 670 | return NULL; 671 | } 672 | 673 | void on_listen_event(int fd, short what, void *wctx) { 674 | UNUSED(fd); 675 | UNUSED(what); 676 | struct accept_context *actx = malloc(sizeof(struct accept_context)); 677 | if (!actx) { 678 | w_logf(wctx, LOG_ERR, "Error during allocation of memory in on_listen_event wmediumd/wserver.c\n"); 679 | return; 680 | } 681 | 682 | actx->wctx = wctx; 683 | actx->server_socket = fd; 684 | actx->thread = malloc(sizeof(pthread_t)); 685 | if (!actx->thread) { 686 | w_logf(wctx, LOG_ERR, "Error during allocation of memory in on_listen_event wmediumd/wserver.c\n"); 687 | free(actx); 688 | return; 689 | } 690 | 691 | actx->client_socket = accept_connection(actx->server_socket); 692 | if (actx->client_socket < 0) { 693 | w_logf(actx->wctx, LOG_ERR, LOG_PREFIX "Accept failed: %s\n", strerror(errno)); 694 | } else { 695 | pthread_create(actx->thread, NULL, handle_accepted_connection, actx); 696 | } 697 | } 698 | 699 | /** 700 | * Run the server using the given wmediumd context 701 | * @param ctx The wmediumd context 702 | * @return NULL, required for pthread 703 | */ 704 | void *run_wserver(void *ctx) { 705 | struct event *accept_event; 706 | 707 | old_sig_handler = signal(SIGINT, handle_sigint); 708 | 709 | listen_soc = create_listen_socket(ctx); 710 | if (listen_soc < 0) { 711 | return NULL; 712 | } 713 | w_logf(ctx, LOG_DEBUG, LOG_PREFIX "Listening for incoming connection\n"); 714 | evutil_make_socket_nonblocking(listen_soc); 715 | server_event_base = event_base_new(); 716 | accept_event = event_new(server_event_base, listen_soc, EV_READ | EV_PERSIST, on_listen_event, ctx); 717 | event_add(accept_event, NULL); 718 | 719 | w_logf(ctx, LOG_DEBUG, LOG_PREFIX "Waiting for client to connect...\n"); 720 | event_base_dispatch(server_event_base); 721 | 722 | event_free(accept_event); 723 | event_base_free(server_event_base); 724 | stop_wserver(); 725 | return NULL; 726 | } 727 | 728 | int start_wserver(struct wmediumd *ctx) { 729 | return pthread_create(&server_thread, NULL, run_wserver, ctx); 730 | } 731 | 732 | void stop_wserver() { 733 | signal(SIGINT, old_sig_handler); 734 | pthread_cancel(server_thread); 735 | pthread_detach(server_thread); 736 | printf("\n" LOG_PREFIX "shutting down wserver\n"); 737 | close(listen_soc); 738 | unlink(WSERVER_SOCKET_PATH); 739 | } 740 | -------------------------------------------------------------------------------- /wmediumd/wmediumd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * wmediumd, wireless medium simulator for mac802154_hwsim kernel module 3 | * Copyright (c) 2025 Ramon Fontes. 4 | * 5 | * Author: Javier Lopez 6 | * Javier Cardona 7 | * 8 | * This program is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU General Public License 10 | * as published by the Free Software Foundation; either version 2 11 | * of the License, or (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 | * 02110-1301, USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "wmediumd.h" 43 | #include "ieee802154.h" 44 | #include "config.h" 45 | #include "wserver.h" 46 | #include "wmediumd_dynamic.h" 47 | #include "wserver_messages.h" 48 | 49 | struct sockaddr_in serverAddr, clientAddr; 50 | socklen_t len; 51 | void* out_buf; 52 | char in_buf[PAGE_SIZE]; 53 | static bool is_ap = true; 54 | 55 | 56 | #if __BYTE_ORDER == __LITTLE_ENDIAN 57 | #define le16_to_cpu(x) (x) 58 | #else 59 | #define le16_to_cpu(x) __bswap_16(x) 60 | #endif 61 | 62 | static inline int div_round(int a, int b) 63 | { 64 | return (a + b - 1) / b; 65 | } 66 | 67 | static inline int pkt_duration(struct wmediumd *ctx, int len, int rate) 68 | { 69 | /* preamble + signal + t_sym * n_sym, rate in 100 kbps */ 70 | return 16 + 4 + 4 * div_round((16 + 8 * len + 6) * 10, 4 * rate); 71 | } 72 | 73 | int w_logf(struct wmediumd *ctx, u8 level, const char *format, ...) 74 | { 75 | va_list(args); 76 | va_start(args, format); 77 | if (ctx->log_lvl >= level) { 78 | return vprintf(format, args); 79 | } 80 | return -1; 81 | } 82 | 83 | int w_flogf(struct wmediumd *ctx, u8 level, FILE *stream, const char *format, ...) 84 | { 85 | va_list(args); 86 | va_start(args, format); 87 | if (ctx->log_lvl >= level) { 88 | return vfprintf(stream, format, args); 89 | } 90 | return -1; 91 | } 92 | 93 | static void wqueue_init(struct wqueue *wqueue, int cw_min, int cw_max) 94 | { 95 | INIT_LIST_HEAD(&wqueue->frames); 96 | wqueue->cw_min = cw_min; 97 | wqueue->cw_max = cw_max; 98 | } 99 | 100 | void station_init_queues(struct station *station) 101 | { 102 | wqueue_init(&station->queues[IEEE80211_AC_BK], 15, 1023); 103 | wqueue_init(&station->queues[IEEE80211_AC_BE], 15, 1023); 104 | wqueue_init(&station->queues[IEEE80211_AC_VI], 7, 15); 105 | wqueue_init(&station->queues[IEEE80211_AC_VO], 3, 7); 106 | } 107 | 108 | bool timespec_before(struct timespec *t1, struct timespec *t2) 109 | { 110 | return t1->tv_sec < t2->tv_sec || 111 | (t1->tv_sec == t2->tv_sec && t1->tv_nsec < t2->tv_nsec); 112 | } 113 | 114 | void timespec_add_usec(struct timespec *t, int usec) 115 | { 116 | t->tv_nsec += usec * 1000; 117 | if (t->tv_nsec >= 1000000000) { 118 | t->tv_sec++; 119 | t->tv_nsec -= 1000000000; 120 | } 121 | } 122 | 123 | // a - b = c 124 | static int timespec_sub(struct timespec *a, struct timespec *b, 125 | struct timespec *c) 126 | { 127 | c->tv_sec = a->tv_sec - b->tv_sec; 128 | 129 | if (a->tv_nsec < b->tv_nsec) { 130 | c->tv_sec--; 131 | c->tv_nsec = 1000000000 + a->tv_nsec - b->tv_nsec; 132 | } else { 133 | c->tv_nsec = a->tv_nsec - b->tv_nsec; 134 | } 135 | 136 | return 0; 137 | } 138 | 139 | void rearm_timer(struct wmediumd *ctx) 140 | { 141 | struct timespec min_expires; 142 | struct itimerspec expires; 143 | struct station *station; 144 | struct frame *frame; 145 | int i; 146 | 147 | bool set_min_expires = false; 148 | 149 | /* 150 | * Iterate over all the interfaces to find the next frame that 151 | * will be delivered, and set the timerfd accordingly. 152 | */ 153 | list_for_each_entry(station, &ctx->stations, list) { 154 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { 155 | frame = list_first_entry_or_null(&station->queues[i].frames, 156 | struct frame, list); 157 | 158 | if (frame && (!set_min_expires || 159 | timespec_before(&frame->expires, 160 | &min_expires))) { 161 | set_min_expires = true; 162 | min_expires = frame->expires; 163 | } 164 | } 165 | } 166 | 167 | if (set_min_expires) { 168 | memset(&expires, 0, sizeof(expires)); 169 | expires.it_value = min_expires; 170 | timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &expires, 171 | NULL); 172 | } 173 | } 174 | 175 | static inline bool frame_is_mgmt(struct frame *frame) 176 | { 177 | u8 fctl = frame->data[0]; // first byte of FCF 178 | u8 ftype = fctl & FCTL_FTYPE; 179 | 180 | return ftype == 0x00 || ftype == 0x03; // Beacon or MAC Command 181 | } 182 | 183 | static inline bool frame_is_data(struct frame *frame) 184 | { 185 | u8 fctl = frame->data[0]; // first byte of FCF 186 | u8 ftype = fctl & FCTL_FTYPE; // separate 3 first bits 187 | 188 | return ftype == 0x01; // 0x01 == Data 189 | } 190 | 191 | static double dBm_to_milliwatt(int decibel_intf) 192 | { 193 | #define INTF_LIMIT (31) 194 | int intf_diff = NOISE_LEVEL - decibel_intf; 195 | 196 | if (intf_diff >= INTF_LIMIT) 197 | return 0.001; 198 | 199 | if (intf_diff <= -INTF_LIMIT) 200 | return 1000.0; 201 | 202 | return pow(10.0, -intf_diff / 10.0); 203 | } 204 | 205 | static double milliwatt_to_dBm(double value) 206 | { 207 | return 10.0 * log10(value); 208 | } 209 | 210 | static int set_interference_duration(struct wmediumd *ctx, int src_idx, 211 | int duration, int lqi) 212 | { 213 | int i, medium_id; 214 | 215 | if (!ctx->intf) 216 | return 0; 217 | 218 | if (lqi >= CCA_THRESHOLD) 219 | return 0; 220 | 221 | medium_id = ctx->sta_array[src_idx]->medium_id; 222 | for (i = 0; i < ctx->num_stas; i++) { 223 | if (medium_id != ctx->sta_array[i]->medium_id) 224 | continue; 225 | ctx->intf[ctx->num_stas * src_idx + i].duration += duration; 226 | // use only latest value 227 | ctx->intf[ctx->num_stas * src_idx + i].lqi = lqi; 228 | } 229 | 230 | return 1; 231 | } 232 | 233 | static int get_signal_offset_by_interference(struct wmediumd *ctx, int src_idx, 234 | int dst_idx) 235 | { 236 | int i, medium_id; 237 | double intf_power; 238 | 239 | if (!ctx->intf) 240 | return 0; 241 | 242 | intf_power = 0.0; 243 | medium_id = ctx->sta_array[dst_idx]->medium_id; 244 | for (i = 0; i < ctx->num_stas; i++) { 245 | if (i == src_idx || i == dst_idx) 246 | continue; 247 | if (medium_id != ctx->sta_array[i]->medium_id) 248 | continue; 249 | if (drand48() < ctx->intf[i * ctx->num_stas + dst_idx].prob_col) 250 | intf_power += dBm_to_milliwatt( 251 | ctx->intf[i * ctx->num_stas + dst_idx].lqi); 252 | } 253 | 254 | if (intf_power <= 1.0) 255 | return 0; 256 | 257 | return (int)(milliwatt_to_dBm(intf_power) + 0.5); 258 | } 259 | 260 | bool is_802154_broadcast(struct ieee802154_addr *addr) { 261 | if (addr->mode == IEEE802154_ADDR_SHORT && 262 | le16_to_cpu(addr->short_addr) == 0xFFFF) { 263 | return true; 264 | } 265 | 266 | return false; 267 | } 268 | 269 | struct station *get_station_by_addr(struct wmediumd *ctx, u8 *addr, size_t addr_len) 270 | { 271 | struct station *station; 272 | 273 | list_for_each_entry(station, &ctx->stations, list) { 274 | 275 | if (addr_len == 2) { 276 | if (memcmp(station->short_addr, addr, 2) == 0) 277 | return station; 278 | } else if (addr_len == 8) { 279 | if (memcmp(station->extended_addr, addr, 8) == 0) 280 | return station; 281 | } 282 | } 283 | return NULL; 284 | } 285 | 286 | void detect_mediums(struct wmediumd *ctx, struct station *src, struct station *dest) { 287 | int medium_id; 288 | if (!ctx->enable_medium_detection){ 289 | return; 290 | } 291 | if(src->isap& !dest->isap){ 292 | // AP-STA Connection 293 | medium_id = -src->index-1; 294 | }else if((!src->isap)& dest->isap){ 295 | // STA-AP Connection 296 | medium_id = -dest->index-1; 297 | }else{ 298 | // AP-AP Connection 299 | // STA-STA Connection 300 | // TODO: Detect adhoc and mesh groups 301 | return; 302 | } 303 | if (medium_id!=src->medium_id){ 304 | w_logf(ctx, LOG_DEBUG, "Setting medium id of " MAC_FMT "(%d|%s) to %d.\n", 305 | MAC_ARGS(src->extended_addr), src->index, src->isap ? "AP" : "Sta", 306 | medium_id); 307 | src-> medium_id = medium_id; 308 | } 309 | if(medium_id!=dest->medium_id){ 310 | w_logf(ctx, LOG_DEBUG, "Setting medium id of " MAC_FMT "(%d|%s) to %d.\n", 311 | MAC_ARGS(dest->extended_addr), dest->index, dest->isap ? "AP" : "Sta", 312 | medium_id); 313 | dest-> medium_id = medium_id; 314 | } 315 | } 316 | 317 | void print_extended_addr(u8 *addr) { 318 | printf("Extended Address: "); 319 | for (int i = 0; i < 8; i++) { 320 | printf("%02X", addr[i]); 321 | if (i < 7) printf(":"); 322 | } 323 | printf("\n"); 324 | } 325 | 326 | 327 | void queue_frame(struct wmediumd *ctx, struct station *station, 328 | struct frame *frame, char *data, int dest_addr_len) 329 | { 330 | struct ieee802154_hdr *hdr = (void *)frame->data; 331 | struct timespec now, target; 332 | struct wqueue *queue; 333 | //struct frame *tail; 334 | struct station *tmpsta, *deststa; 335 | int send_time; 336 | int cw; 337 | double error_prob; 338 | bool is_acked = false; 339 | bool noack = false; 340 | int i, j; 341 | int rate_idx; 342 | //int ac; 343 | 344 | /* TODO configure phy parameters */ 345 | int slot_time = 9; 346 | int sifs = 16; 347 | int difs = 2 * slot_time + sifs; 348 | 349 | int retries = 0; 350 | 351 | clock_gettime(CLOCK_MONOTONIC, &now); 352 | 353 | int ack_time_usec = pkt_duration(ctx, 14, index_to_rate(0, frame->freq)) + 354 | sifs; 355 | 356 | /* 357 | * To determine a frame's expiration time, we compute the 358 | * number of retries we might have to make due to radio conditions 359 | * or contention, and add backoff time accordingly. To that, we 360 | * add the expiration time of the previous frame in the queue. 361 | */ 362 | 363 | //ac = frame_select_queue_802154(frame); 364 | queue = &station->queues[0]; 365 | 366 | /* try to "send" this frame at each of the rates in the rateset */ 367 | send_time = 0; 368 | 369 | //cw = queue->cw_min; 370 | int snr = SNR_DEFAULT; 371 | 372 | u8 dest[8]; 373 | for (int i = 0; i < 8; i++) 374 | dest[i] = frame->data[5 + 7 - i]; 375 | 376 | uint8_t *ptr = (uint8_t *)hdr; 377 | 378 | uint16_t fcf = ptr[0] | (ptr[1] << 8); // Get FCF 379 | 380 | // Search for the mode 381 | uint8_t dest_mode = (fcf >> 10) & 0x3; 382 | 383 | if (dest_mode == IEEE802154_ADDR_SHORT) 384 | deststa = NULL; 385 | else 386 | deststa = get_station_by_addr(ctx, dest, 8); 387 | 388 | if (deststa) { 389 | w_logf(ctx, LOG_DEBUG, "Packet from " MAC_FMT "(%d|%s) to " MAC_FMT "(%d|%s)\n", 390 | MAC_ARGS(station->extended_addr), station->index, station->isap ? "AP" : "Sta", 391 | MAC_ARGS(deststa->extended_addr), deststa->index, deststa->isap ? "AP" : "Sta"); 392 | detect_mediums(ctx,station,deststa); 393 | snr = ctx->get_link_snr(ctx, station, deststa) - 394 | get_signal_offset_by_interference(ctx, 395 | station->index, deststa->index); 396 | snr += ctx->get_fading_signal(ctx); 397 | } 398 | 399 | frame->lqi = snr + NOISE_LEVEL; 400 | 401 | noack = frame_is_mgmt(frame); // || is_802154_broadcast(dest); 402 | double choice = -3.14; 403 | 404 | if (use_fixed_random_value(ctx)) 405 | choice = drand48(); 406 | 407 | for (i = 0; i < frame->tx_rates_count && !is_acked; i++) { 408 | 409 | rate_idx = frame->tx_rates[i].idx; 410 | 411 | /* no more rates in MRR */ 412 | if (rate_idx < 0) 413 | break; 414 | 415 | error_prob = ctx->get_error_prob(ctx, snr, rate_idx, 416 | frame->freq, frame->data_len, 417 | station, deststa); 418 | 419 | for (j = 0; j < frame->tx_rates[i].count; j++) { 420 | send_time += difs + pkt_duration(ctx, frame->data_len, 421 | index_to_rate(rate_idx, frame->freq)); 422 | 423 | retries++; 424 | 425 | /* skip ack/backoff/retries for noack frames */ 426 | if (noack) { 427 | is_acked = true; 428 | break; 429 | } 430 | 431 | /* TODO TXOPs */ 432 | 433 | /* backoff */ 434 | if (j > 0) { 435 | send_time += (cw * slot_time) / 2; 436 | cw = (cw << 1) + 1; 437 | if (cw > queue->cw_max) 438 | cw = queue->cw_max; 439 | } 440 | if (!use_fixed_random_value(ctx)) 441 | choice = drand48(); 442 | if (choice > error_prob) { 443 | is_acked = true; 444 | break; 445 | } 446 | send_time += ack_time_usec; 447 | } 448 | } 449 | 450 | is_acked = true; 451 | if (is_acked) { 452 | //frame->tx_rates[i-1].count = j + 1; 453 | //for (; i < frame->tx_rates_count; i++) { 454 | // frame->tx_rates[i].idx = -1; 455 | // frame->tx_rates[i].count = -1; 456 | //} 457 | frame->flags |= MAC802154_HWSIM_TX_STAT_ACK; 458 | } 459 | 460 | /* 461 | * delivery time starts after any equal or higher prio frame 462 | * (or now, if none). 463 | */ 464 | 465 | target = now; 466 | list_for_each_entry(tmpsta, &ctx->stations, list) { 467 | 468 | if (station->medium_id == tmpsta->medium_id) { 469 | w_logf(ctx, LOG_DEBUG, "Sta " MAC_FMT " medium is also #%d\n", MAC_ARGS(tmpsta->extended_addr), 470 | tmpsta->medium_id); 471 | /* for (i = 0; i <= ac; i++) { 472 | tail = list_last_entry_or_null(&tmpsta->queues[i].frames, 473 | struct frame, list);inver 474 | if (tail && timespec_before(&target, &tail->expires)) 475 | target = tail->expires; 476 | }*/ 477 | } else { 478 | w_logf(ctx, LOG_DEBUG, "Sta " MAC_FMT " medium is not #%d, it is #%d\n", MAC_ARGS(tmpsta->extended_addr), 479 | station->medium_id, tmpsta->medium_id); 480 | } 481 | } 482 | 483 | timespec_add_usec(&target, send_time); 484 | frame->duration = send_time; 485 | frame->expires = target; 486 | 487 | list_add_tail(&frame->list, &queue->frames); 488 | 489 | rearm_timer(ctx); 490 | 491 | } 492 | 493 | /* 494 | * Report transmit status to the kernel. 495 | */ 496 | static int send_tx_info_frame_nl(struct wmediumd *ctx, struct frame *frame) 497 | { 498 | struct ieee802154_hdr *hdr = (void *)frame->data; 499 | struct nl_sock *sock = ctx->sock; 500 | struct nl_msg *msg; 501 | struct nlattr *edge_nest; 502 | struct station *deststa; 503 | int ret; 504 | 505 | u32 radio_id = frame->sender->index; 506 | 507 | u8 dest[8]; 508 | for (int i = 0; i < 8; i++) 509 | dest[i] = frame->data[5 + 7 - i]; 510 | 511 | uint8_t *ptr = (uint8_t *)hdr; 512 | 513 | uint16_t fcf = ptr[0] | (ptr[1] << 8); // Get FCF 514 | 515 | // Search for the mode 516 | uint8_t dest_mode = (fcf >> 10) & 0x3; 517 | 518 | if (dest_mode == IEEE802154_ADDR_SHORT) 519 | deststa = NULL; 520 | else 521 | deststa = get_station_by_addr(ctx, dest, 8); 522 | 523 | msg = nlmsg_alloc(); 524 | if (!msg) { 525 | w_logf(ctx, LOG_ERR, "Error allocating new message MSG!\n"); 526 | return -1; 527 | } 528 | 529 | if (!deststa) 530 | goto out; 531 | 532 | if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id, 533 | 0, NLM_F_REQUEST, MAC802154_HWSIM_CMD_TX_INFO_FRAME, 534 | VERSION_NR) == NULL) { 535 | w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__); 536 | ret = -1; 537 | goto out; 538 | } 539 | 540 | if (nla_put_u32(msg, MAC802154_HWSIM_ATTR_RADIO_ID, radio_id)) { 541 | w_logf(ctx, LOG_ERR, "%s: Failed to set RADIO_ID\n", __func__); 542 | ret = -1; 543 | goto out; 544 | } 545 | 546 | edge_nest = nla_nest_start(msg, MAC802154_HWSIM_ATTR_RADIO_EDGE); 547 | if (!edge_nest) { 548 | w_logf(ctx, LOG_ERR, "%s: Failed to start RADIO_EDGE\n", __func__); 549 | ret = -1; 550 | goto out; 551 | } 552 | 553 | if (nla_put_u32(msg, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID, deststa->index) || 554 | nla_put_u8(msg, MAC802154_HWSIM_EDGE_ATTR_LQI, 250)) { 555 | w_logf(ctx, LOG_ERR, "%s: Failed to fill EDGE attrs\n", __func__); 556 | ret = -1; 557 | goto out; 558 | } 559 | nla_nest_end(msg, edge_nest); 560 | 561 | /*if (nla_put(msg, MAC802154_HWSIM_ATTR_ADDR_TRANSMITTER, EXTENDED_ADDR_LEN, 562 | frame->sender->hwaddr) || 563 | nla_put_u32(msg, MAC802154_HWSIM_ATTR_FLAGS, frame->flags) || 564 | nla_put_u64(msg, MAC802154_HWSIM_ATTR_COOKIE, frame->cookie)) { 565 | w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__); 566 | ret = -1; 567 | goto out; 568 | }*/ 569 | 570 | ret = nl_send_auto_complete(sock, msg); 571 | if (ret < 0) { 572 | w_logf(ctx, LOG_ERR, "%s: nl_send_auto failed\n", __func__); 573 | ret = -1; 574 | goto out; 575 | } 576 | //nl_msg_dump(msg, stdout); 577 | ret = 0; 578 | out: 579 | nlmsg_free(msg); 580 | return ret; 581 | } 582 | 583 | /* 584 | * Report transmit status to the transmitter. 585 | */ 586 | static int send_tx_info_frame(struct wmediumd *ctx, struct frame *frame) 587 | { 588 | if (ctx->op_mode == LOCAL) 589 | return send_tx_info_frame_nl(ctx, frame); 590 | 591 | int numBytes, ret; 592 | 593 | if (is_ap){ 594 | numBytes = sendto(ctx->net_sock, frame, sizeof(*frame), 0, (struct sockaddr*)&clientAddr, len); 595 | if (numBytes < 0){ 596 | w_flogf(ctx, LOG_ERR, stderr, "Failed to send xmit info to station: %s", strerror(errno)); 597 | ret = -1; 598 | goto out; 599 | } 600 | } 601 | else{ 602 | numBytes = sendto(ctx->net_sock, frame, sizeof(*frame), 0, (struct sockaddr*)&serverAddr, len); 603 | if (numBytes < 0){ 604 | w_flogf(ctx, LOG_ERR, stderr, "Failed to send xmit info to AP station: %s", strerror(errno)); 605 | ret = -1; 606 | goto out; 607 | } 608 | } 609 | ret = 0; 610 | 611 | out: 612 | return ret; 613 | } 614 | 615 | /* 616 | * Send a data frame to the kernel for reception at a specific radio. 617 | */ 618 | int send_cloned_frame_msg(struct wmediumd *ctx, struct station *dst, 619 | u8 *data, int data_len, int rate_idx, int lqi, 620 | int freq) 621 | { 622 | struct nl_msg *msg; 623 | struct nl_sock *sock = ctx->sock; 624 | int ret; 625 | 626 | size_t addr_len = 0; 627 | uint8_t *ptr = data; 628 | 629 | uint16_t fcf = ptr[0] | (ptr[1] << 8); 630 | ptr += 2; 631 | 632 | uint8_t seq = *ptr++; 633 | (void)seq; 634 | 635 | uint8_t dest_mode = (fcf >> 10) & 0x3; 636 | 637 | if (dest_mode) { 638 | ptr += 2; 639 | 640 | if (dest_mode == IEEE802154_ADDR_SHORT) { 641 | addr_len = 2; 642 | } else if (dest_mode == IEEE802154_ADDR_EXTENDED) { 643 | addr_len = 8; 644 | } 645 | } 646 | 647 | msg = nlmsg_alloc(); 648 | if (!msg) { 649 | w_logf(ctx, LOG_ERR, "Error allocating new message MSG!\n"); 650 | return -1; 651 | } 652 | 653 | if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id, 654 | 0, NLM_F_REQUEST, MAC802154_HWSIM_CMD_FRAME, 655 | VERSION_NR) == NULL) { 656 | w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__); 657 | ret = -1; 658 | goto out; 659 | } 660 | 661 | u8 hwaddr[8]; 662 | if (addr_len == 2) { 663 | uint16_t short_addr = le16_to_cpu(dst->short_addr); 664 | hwaddr[0] = short_addr & 0xff; 665 | hwaddr[1] = (short_addr >> 8) & 0xff; 666 | } else if (addr_len == 8) { 667 | for (int i = 0; i < 8; i++) { 668 | hwaddr[i] = dst->extended_addr[7 - i]; 669 | } 670 | } 671 | 672 | if (nla_put(msg, MAC802154_HWSIM_ATTR_ADDR_RECEIVER, addr_len, hwaddr) || 673 | nla_put(msg, MAC802154_HWSIM_ATTR_FRAME, data_len, data)) { 674 | w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__); 675 | ret = -1; 676 | goto out; 677 | } 678 | 679 | ret = nl_send_auto_complete(sock, msg); 680 | if (ret < 0) { 681 | w_logf(ctx, LOG_ERR, "%s: nl_send_auto failed\n", __func__); 682 | ret = -1; 683 | goto out; 684 | } 685 | 686 | ret = 0; 687 | //nl_msg_dump(msg, stdout); 688 | 689 | out: 690 | nlmsg_free(msg); 691 | return ret; 692 | } 693 | 694 | void deliver_frame(struct wmediumd *ctx, struct frame *frame) 695 | { 696 | struct ieee802154_hdr *hdr = (void *) frame->data; 697 | struct station *station; 698 | u8 *src = frame->sender->extended_addr; 699 | 700 | if (frame->flags & MAC802154_HWSIM_TX_STAT_ACK) { 701 | /* rx the frame on the dest interface */ 702 | 703 | list_for_each_entry(station, &ctx->stations, list) { 704 | 705 | if (memcmp(src, station->extended_addr, EXTENDED_ADDR_LEN) == 0) 706 | continue; 707 | 708 | int rate_idx; 709 | 710 | u16 dest = NULL; 711 | 712 | uint64_t *addr64 = (uint64_t *)&hdr->dest.extended_addr; 713 | uint64_t shifted = (*addr64) << 40; 714 | uint8_t *shifted_bytes = (uint8_t *)&shifted; 715 | uint8_t inverted_addr[8]; 716 | 717 | if (is_802154_broadcast(station->short_addr)){ 718 | dest = 0XFFFF; 719 | } 720 | else { 721 | for (int i = 0; i < 8; i++) { 722 | inverted_addr[i] = shifted_bytes[7 - i]; 723 | } 724 | dest = inverted_addr; 725 | } 726 | 727 | uint8_t *ptr = (uint8_t *)hdr; 728 | 729 | uint16_t fcf = ptr[0] | (ptr[1] << 8); // Get FCF 730 | 731 | ptr += 2; 732 | 733 | uint8_t seq = *ptr++; 734 | (void)seq; 735 | 736 | // Search for the modes 737 | uint8_t dest_mode = (fcf >> 10) & 0x3; 738 | 739 | if (dest_mode == IEEE802154_ADDR_SHORT){ 740 | dest = 0xFFFF; 741 | int snr, lqi; 742 | double error_prob; 743 | 744 | /* 745 | * we may or may not receive this based on 746 | * reverse link from sender -- check for 747 | * each receiver. 748 | */ 749 | snr = ctx->get_link_snr(ctx, frame->sender, 750 | station); 751 | snr += ctx->get_fading_signal(ctx); 752 | lqi = snr + NOISE_LEVEL; 753 | 754 | if (lqi < CCA_THRESHOLD) 755 | continue; 756 | 757 | if (set_interference_duration(ctx, 758 | frame->sender->index, frame->duration, 759 | lqi)) 760 | continue; 761 | 762 | snr -= get_signal_offset_by_interference(ctx, 763 | frame->sender->index, station->index); 764 | rate_idx = frame->tx_rates[0].idx; 765 | error_prob = ctx->get_error_prob(ctx, 766 | (double)snr, rate_idx, frame->freq, 767 | frame->data_len, frame->sender, 768 | station); 769 | 770 | if (drand48() <= error_prob) { 771 | w_logf(ctx, LOG_DEBUG, "Dropped mcast from " 772 | MAC_FMT " to " MAC_FMT " at receiver\n", 773 | MAC_ARGS(src), MAC_ARGS(station->extended_addr)); 774 | continue; 775 | } 776 | 777 | send_cloned_frame_msg(ctx, station, 778 | frame->data, 779 | frame->data_len, 780 | rate_idx, lqi, 781 | frame->freq); 782 | } else if (dest_mode == IEEE802154_ADDR_EXTENDED) { 783 | 784 | if (set_interference_duration(ctx, 785 | frame->sender->index, frame->duration, 786 | frame->lqi)) 787 | continue; 788 | 789 | rate_idx = frame->tx_rates[0].idx; 790 | send_cloned_frame_msg(ctx, station, 791 | frame->data, 792 | frame->data_len, 793 | rate_idx, frame->lqi, 794 | frame->freq); 795 | } 796 | } 797 | } else 798 | set_interference_duration(ctx, frame->sender->index, 799 | frame->duration, frame->lqi); 800 | 801 | send_tx_info_frame(ctx, frame); 802 | 803 | free(frame); 804 | } 805 | 806 | void deliver_expired_frames_queue(struct wmediumd *ctx, 807 | struct list_head *queue, 808 | struct timespec *now) 809 | { 810 | struct frame *frame, *tmp; 811 | 812 | list_for_each_entry_safe(frame, tmp, queue, list) { 813 | if (timespec_before(&frame->expires, now)) { 814 | list_del(&frame->list); 815 | deliver_frame(ctx, frame); 816 | } else { 817 | break; 818 | } 819 | } 820 | } 821 | 822 | void deliver_expired_frames(struct wmediumd *ctx) 823 | { 824 | struct timespec now, _diff; 825 | struct station *station; 826 | 827 | struct list_head *l,*rand_it,*rand_start; 828 | int i, j, duration; 829 | int sta1_medium_id; 830 | 831 | clock_gettime(CLOCK_MONOTONIC, &now); 832 | 833 | int rand_start_cnt = rand() % ctx->num_stas; 834 | 835 | // Find the randomized starting point in the list 836 | rand_start = &ctx->stations; 837 | for (i = 0; i < rand_start_cnt; i++) { 838 | rand_start = rand_start->next; 839 | } 840 | 841 | list_for_each(rand_it, rand_start) { 842 | //skip if we iterate over head 843 | if(rand_it == &ctx->stations) 844 | continue; 845 | station = list_entry(rand_it, struct station, list); 846 | int q_ct[IEEE80211_NUM_ACS] = {}; 847 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { 848 | list_for_each(l, &station->queues[i].frames) { 849 | q_ct[i]++; 850 | } 851 | } 852 | 853 | for (i = 0; i < IEEE80211_NUM_ACS; i++) 854 | deliver_expired_frames_queue(ctx, &station->queues[i].frames, &now); 855 | } 856 | w_logf(ctx, LOG_DEBUG, "\n\n"); 857 | 858 | if (!ctx->intf) 859 | return; 860 | 861 | timespec_sub(&now, &ctx->intf_updated, &_diff); 862 | duration = (_diff.tv_sec * 1000000) + (_diff.tv_nsec / 1000); 863 | if (duration < 10000) // calc per 10 msec 864 | return; 865 | 866 | // update interference 867 | for (i = 0; i < ctx->num_stas; i++){ 868 | sta1_medium_id = ctx->sta_array[i]->medium_id; 869 | for (j = 0; j < ctx->num_stas; j++) { 870 | if (i == j) 871 | continue; 872 | if (sta1_medium_id != ctx->sta_array[j]->medium_id) 873 | continue; 874 | // probability is used for next calc 875 | ctx->intf[i * ctx->num_stas + j].prob_col = 876 | ctx->intf[i * ctx->num_stas + j].duration / 877 | (double)duration; 878 | ctx->intf[i * ctx->num_stas + j].duration = 0; 879 | } 880 | } 881 | 882 | clock_gettime(CLOCK_MONOTONIC, &ctx->intf_updated); 883 | } 884 | 885 | void print_data(const uint8_t *data, size_t len) { 886 | printf("Conteúdo de data (%zu bytes):\n", len); 887 | for (size_t i = 0; i < len; i++) { 888 | printf("%02x ", data[i]); 889 | if ((i + 1) % 16 == 0) printf("\n"); 890 | } 891 | printf("\n"); 892 | } 893 | 894 | 895 | static int process_recvd_data(struct wmediumd *ctx, struct nlmsghdr *nlh) 896 | { 897 | struct nlattr *attrs[MAC802154_HWSIM_ATTR_MAX+1]; 898 | /* generic netlink header*/ 899 | struct genlmsghdr *gnlh = nlmsg_data(nlh); 900 | 901 | struct station *sender; 902 | struct frame *frame; 903 | struct ieee802154_hdr *hdr; 904 | u8 *src; 905 | u8 src_addr_len = 0; 906 | u8 dest_addr_len = 0; 907 | uint8_t src_buf[8]; 908 | 909 | if (gnlh->cmd == MAC802154_HWSIM_CMD_FRAME) { 910 | 911 | pthread_rwlock_rdlock(&snr_lock); 912 | /* we get the attributes*/ 913 | genlmsg_parse(nlh, 0, attrs, MAC802154_HWSIM_ATTR_MAX, NULL); 914 | 915 | if (attrs[MAC802154_HWSIM_ATTR_ADDR_TRANSMITTER]) { 916 | 917 | u8 *hwaddr = (u8 *)nla_data(attrs[MAC802154_HWSIM_ATTR_ADDR_TRANSMITTER]); 918 | 919 | unsigned int data_len = 920 | nla_len(attrs[MAC802154_HWSIM_ATTR_FRAME]); 921 | char *data = (char *)nla_data(attrs[MAC802154_HWSIM_ATTR_FRAME]); 922 | unsigned int flags = 923 | nla_get_u32(attrs[MAC802154_HWSIM_ATTR_FLAGS]); 924 | 925 | u64 cookie = nla_get_u64(attrs[MAC802154_HWSIM_ATTR_COOKIE]); 926 | 927 | uint8_t *ptr = (uint8_t *)data; 928 | 929 | uint16_t fcf = ptr[0] | (ptr[1] << 8); // Get FCF 930 | ptr += 2; 931 | 932 | uint8_t seq = *ptr++; 933 | (void)seq; 934 | 935 | // Search for the modes 936 | uint8_t dest_mode = (fcf >> 10) & 0x3; 937 | uint8_t src_mode = (fcf >> 14) & 0x3; 938 | 939 | // PAN ID Compression bit 940 | bool panid_compression = fcf & (1 << 6); 941 | 942 | hdr = (struct ieee802154_hdr *)data; 943 | uint8_t dest_pan[2]; 944 | memcpy(dest_pan, ptr, 2); 945 | uint16_t dest_pan_id = dest_pan[0] | (dest_pan[1] << 8); 946 | ptr += 2; 947 | 948 | if (dest_mode == IEEE802154_ADDR_SHORT) { 949 | dest_addr_len = 2; 950 | 951 | uint16_t short_addr = ptr[0] | (ptr[1] << 8); 952 | ptr += 2; 953 | 954 | w_logf(ctx, LOG_DEBUG, "Dest (short): %04x, PAN ID: %04x\n", 955 | short_addr, dest_pan_id); 956 | 957 | } else if (dest_mode == IEEE802154_ADDR_EXTENDED) { 958 | dest_addr_len = 8; 959 | 960 | uint8_t addr_[8]; 961 | for (int i = 0; i < 8; i++) 962 | addr_[i] = ptr[7 - i]; // reverse 963 | 964 | ptr += 8; 965 | 966 | w_logf(ctx, LOG_DEBUG, "Dest (extended): %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, PAN ID: %04x\n", 967 | addr_[7], addr_[6], addr_[5], addr_[4], 968 | addr_[3], addr_[2], addr_[1], addr_[0], 969 | hdr->dest.pan_id); 970 | } 971 | 972 | // If panid_compression is false, read source PAN ID 973 | if (src_mode) { 974 | 975 | if (!panid_compression) { 976 | uint8_t src_pan[2]; 977 | memcpy(src_pan, ptr, 2); 978 | ptr += 2; 979 | } 980 | else 981 | if (fcf & (1 << 6)) 982 | w_logf(ctx, LOG_DEBUG, "Source PAN ID omitted due to Intra-PAN compression\n"); 983 | 984 | if (src_mode == IEEE802154_ADDR_SHORT) { 985 | uint16_t short_addr = ptr[0] | (ptr[1] << 8); 986 | ptr += 2; 987 | 988 | src_buf[0] = short_addr & 0xFF; 989 | src_buf[1] = (short_addr >> 8) & 0xFF; 990 | src_addr_len = 2; 991 | 992 | src = src_buf; 993 | } else if (src_mode == IEEE802154_ADDR_EXTENDED) { 994 | for (int i = 0; i < 8; i++) 995 | src_buf[i] = ptr[7 - i]; 996 | ptr += 8; 997 | 998 | src_addr_len = 8; 999 | src = src_buf; 1000 | 1001 | w_logf(ctx, LOG_DEBUG, "Source (extended): %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", 1002 | src_buf[7], src_buf[6], src_buf[5], src_buf[4], src_buf[3], src_buf[2], src_buf[1], src_buf[0]); 1003 | } 1004 | } 1005 | 1006 | if (data_len < 23) 1007 | goto out; 1008 | 1009 | sender = get_station_by_addr(ctx, src, src_addr_len); 1010 | 1011 | if (!sender) { 1012 | w_flogf(ctx, LOG_ERR, stderr, "Unable to find sender station " MAC_FMT "\n", MAC_ARGS(src)); 1013 | goto out; 1014 | } 1015 | 1016 | memcpy(sender->hwaddr, hwaddr, src_addr_len); 1017 | 1018 | frame = malloc(sizeof(*frame) + data_len); 1019 | if (!frame) 1020 | goto out; 1021 | 1022 | memcpy(frame->data, data, data_len); 1023 | frame->data_len = data_len; 1024 | frame->flags = flags; 1025 | frame->cookie = cookie; 1026 | //frame->freq = freq; 1027 | frame->sender = sender; 1028 | queue_frame(ctx, sender, frame, data, dest_addr_len); 1029 | } 1030 | out: 1031 | pthread_rwlock_unlock(&snr_lock); 1032 | return 0; 1033 | 1034 | } 1035 | return 0; 1036 | } 1037 | 1038 | static 1039 | int nl_err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg) 1040 | { 1041 | struct genlmsghdr *gnlh = nlmsg_data(&nlerr->msg); 1042 | struct wmediumd *ctx = arg; 1043 | 1044 | w_flogf(ctx, LOG_ERR, stderr, "nl: cmd %d, seq %d: %s\n", gnlh->cmd, 1045 | nlerr->msg.nlmsg_seq, strerror(abs(nlerr->error))); 1046 | 1047 | return NL_SKIP; 1048 | } 1049 | 1050 | struct frame* construct_tx_info_frame(struct wmediumd *ctx, struct nlmsghdr *nlh) 1051 | { 1052 | //struct nlattr *attrs[MAC802154_HWSIM_ATTR_MAX+1]; 1053 | struct genlmsghdr *gnlh = nlmsg_data(nlh); 1054 | 1055 | //struct station *sender; 1056 | //struct frame *frame = NULL; 1057 | //struct ieee802154_hdr *hdr; 1058 | 1059 | if (gnlh->cmd == MAC802154_HWSIM_CMD_FRAME){ 1060 | /* genlmsg_parse(nlh, 0, attrs, HWSIM_ATTR_MAX, NULL); 1061 | u8 *hwaddr = (u8 *)nla_data(attrs[MAC802154_HWSIM_ATTR_ADDR_TRANSMITTER]); 1062 | u64 cookie = nla_get_u64(attrs[MAC802154_HWSIM_ATTR_COOKIE]); 1063 | char *data = (char *)nla_data(attrs[MAC802154_HWSIM_ATTR_FRAME]); 1064 | 1065 | hdr = (struct ieee80211_hdr *)data; 1066 | 1067 | sender = get_station_by_addr(ctx, hdr->addr2); 1068 | if (!sender) { 1069 | w_flogf(ctx, LOG_ERR, stderr, "%s: Unable to find sender station " MAC_FMT "\n", __FUNCTION__, MAC_ARGS(hdr->addr2)); 1070 | goto out; 1071 | } 1072 | memcpy(sender->hwaddr, hwaddr, EXTENDED_ADDR_LEN); 1073 | 1074 | frame = malloc(sizeof(struct frame)); 1075 | if (!frame) 1076 | goto out; 1077 | 1078 | frame->cookie = cookie; 1079 | frame->sender = sender;*/ 1080 | } 1081 | 1082 | //out: 1083 | // return frame; 1084 | } 1085 | 1086 | /* 1087 | * Handle events from the kernel. Process CMD_FRAME events and queue them 1088 | * for later delivery with the scheduler. 1089 | */ 1090 | static int process_messages_cb(struct nl_msg *msg, void *arg) 1091 | { 1092 | struct nlmsghdr *nlh = nlmsg_hdr(msg); 1093 | struct wmediumd* ctx = (struct wmediumd*)arg; 1094 | 1095 | if (ctx->op_mode == LOCAL) 1096 | return process_recvd_data(ctx, nlh); 1097 | 1098 | int numBytes, ret; 1099 | 1100 | out_buf = malloc(nlh->nlmsg_len); 1101 | memcpy(out_buf, nlh, nlh->nlmsg_len); 1102 | 1103 | if (is_ap){ 1104 | numBytes = sendto(ctx->net_sock, out_buf, nlh->nlmsg_len, 0, (struct sockaddr*)&clientAddr, len); 1105 | if (numBytes < 0){ 1106 | w_flogf(ctx, LOG_ERR, stderr, "Failed to send data to station: %s", strerror(errno)); 1107 | ret = -1; 1108 | goto out; 1109 | } 1110 | } 1111 | else{ 1112 | numBytes = sendto(ctx->net_sock, out_buf, nlh->nlmsg_len, 0, (struct sockaddr*)&serverAddr, len); 1113 | if (numBytes < 0){ 1114 | w_flogf(ctx, LOG_ERR, stderr, "Failed to send data to AP station: %s", strerror(errno)); 1115 | ret = -1; 1116 | goto out; 1117 | } 1118 | } 1119 | ret = 0; 1120 | struct frame* tx_frame = construct_tx_info_frame(ctx, nlh); 1121 | if (tx_frame != NULL) 1122 | list_add_tail(&tx_frame->list, &ctx->pending_txinfo_frames); 1123 | 1124 | out: 1125 | free(out_buf); 1126 | return ret; 1127 | } 1128 | 1129 | /* 1130 | * Register with the kernel to start receiving new frames. 1131 | */ 1132 | int send_register_msg(struct wmediumd *ctx) 1133 | { 1134 | struct nl_sock *sock = ctx->sock; 1135 | struct nl_msg *msg; 1136 | int ret; 1137 | 1138 | msg = nlmsg_alloc(); 1139 | if (!msg) { 1140 | w_logf(ctx, LOG_ERR, "Error allocating new message MSG!\n"); 1141 | return -1; 1142 | } 1143 | 1144 | if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id, 1145 | 0, NLM_F_REQUEST, MAC802154_HWSIM_CMD_REGISTER, 1146 | VERSION_NR) == NULL) { 1147 | w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__); 1148 | ret = -1; 1149 | goto out; 1150 | } 1151 | 1152 | ret = nl_send_auto_complete(sock, msg); 1153 | if (ret < 0) { 1154 | w_logf(ctx, LOG_ERR, "%s: nl_send_auto failed\n", __func__); 1155 | ret = -1; 1156 | goto out; 1157 | } 1158 | ret = 0; 1159 | 1160 | out: 1161 | nlmsg_free(msg); 1162 | return ret; 1163 | } 1164 | 1165 | static void net_sock_event_cb(int fd, short what, void *data) 1166 | { 1167 | struct wmediumd *ctx = data; 1168 | int numBytes; 1169 | struct frame* pending_frame; 1170 | struct frame tx_info_frame; 1171 | bzero(in_buf, PAGE_SIZE); 1172 | 1173 | if (is_ap){ 1174 | numBytes = recvfrom(fd, in_buf, PAGE_SIZE, 0, (struct sockaddr*)&clientAddr, &len); 1175 | if (numBytes < 0){ 1176 | w_flogf(ctx, LOG_ERR, stderr, "Failed to receive data from station: %s", strerror(errno)); 1177 | return; 1178 | } 1179 | } 1180 | else{ 1181 | numBytes = recvfrom(fd, in_buf, PAGE_SIZE, 0, (struct sockaddr*)&serverAddr, &len); 1182 | if (numBytes < 0){ 1183 | w_flogf(ctx, LOG_ERR, stderr, "Failed to receive data from AP station: %s", strerror(errno)); 1184 | return; 1185 | } 1186 | } 1187 | /* First check if the received message is for transmit status */ 1188 | memcpy(&tx_info_frame, in_buf, sizeof(struct frame)); 1189 | list_for_each_entry(pending_frame, &ctx->pending_txinfo_frames, list) 1190 | { 1191 | if (pending_frame->cookie == tx_info_frame.cookie){ 1192 | pending_frame->flags = tx_info_frame.flags; 1193 | pending_frame->lqi = tx_info_frame.lqi; 1194 | pending_frame->tx_rates_count = tx_info_frame.tx_rates_count; 1195 | memcpy(pending_frame->tx_rates, tx_info_frame.tx_rates, 1196 | pending_frame->tx_rates_count * sizeof(struct hwsim_tx_rate)); 1197 | send_tx_info_frame_nl(ctx, pending_frame); 1198 | list_del(&pending_frame->list); 1199 | free(pending_frame); 1200 | return; 1201 | } 1202 | } 1203 | process_recvd_data(ctx, (struct nlmsghdr*)in_buf); 1204 | } 1205 | 1206 | static void sock_event_cb(int fd, short what, void *data) 1207 | { 1208 | struct wmediumd *ctx = data; 1209 | 1210 | nl_recvmsgs_default(ctx->sock); 1211 | } 1212 | 1213 | /* 1214 | * Setup netlink socket and callbacks. 1215 | */ 1216 | static int init_netlink(struct wmediumd *ctx) 1217 | { 1218 | struct nl_sock *sock; 1219 | int ret; 1220 | 1221 | ctx->cb = nl_cb_alloc(NL_CB_CUSTOM); 1222 | if (!ctx->cb) { 1223 | w_logf(ctx, LOG_ERR, "Error allocating netlink callbacks\n"); 1224 | return -1; 1225 | } 1226 | 1227 | sock = nl_socket_alloc_cb(ctx->cb); 1228 | if (!sock) { 1229 | w_logf(ctx, LOG_ERR, "Error allocating netlink socket\n"); 1230 | return -1; 1231 | } 1232 | 1233 | ctx->sock = sock; 1234 | 1235 | ret = genl_connect(sock); 1236 | if (ret < 0) { 1237 | w_logf(ctx, LOG_ERR, "Error connecting netlink socket ret=%d\n", ret); 1238 | return -1; 1239 | } 1240 | 1241 | ctx->family_id = genl_ctrl_resolve(sock, "MAC802154_HWSIM"); 1242 | if (ctx->family_id < 0) { 1243 | w_logf(ctx, LOG_ERR, "Family MAC802154_HWSIM not registered\n"); 1244 | return -1; 1245 | } 1246 | 1247 | nl_cb_set(ctx->cb, NL_CB_MSG_IN, NL_CB_CUSTOM, process_messages_cb, ctx); 1248 | nl_cb_err(ctx->cb, NL_CB_CUSTOM, nl_err_cb, ctx); 1249 | 1250 | return 0; 1251 | } 1252 | 1253 | int init_remote_connection(struct wmediumd* ctx, char* ap_ipaddr) 1254 | { 1255 | int numBytes, ret = 0; 1256 | 1257 | ctx->net_sock = socket(AF_INET, SOCK_DGRAM, 0); 1258 | if (ctx->net_sock < 0){ 1259 | w_flogf(ctx, LOG_ERR, stderr, "Failed to open socket: %s\n", strerror(errno)); 1260 | ret = -1; 1261 | goto out; 1262 | } 1263 | 1264 | bzero(&serverAddr, sizeof(serverAddr)); 1265 | serverAddr.sin_family = AF_INET; 1266 | serverAddr.sin_port = htons(AP_DEFAULT_PORT); 1267 | len = sizeof(struct sockaddr_in); 1268 | 1269 | /* AP server configuration */ 1270 | if (ap_ipaddr == NULL){ 1271 | serverAddr.sin_addr.s_addr = INADDR_ANY; 1272 | if (bind(ctx->net_sock, (struct sockaddr *)&serverAddr, len) < 0){ 1273 | w_flogf(ctx, LOG_ERR, stderr, "Failed to bind socket: %s\n", strerror(errno)); 1274 | ret = -1; 1275 | goto out; 1276 | } 1277 | w_logf(ctx, LOG_INFO, "Waiting for station machine to connect\n"); 1278 | 1279 | /* Wait until station machine connects. This is primarily meant to get the client details */ 1280 | numBytes = recvfrom(ctx->net_sock, in_buf, 5, 0, (struct sockaddr*)&clientAddr, &len); 1281 | if (numBytes < 0){ 1282 | w_flogf(ctx, LOG_ERR, stderr, "Failed to receive initiate command from client: %s\n", strerror(errno)); 1283 | ret = -1; 1284 | goto out; 1285 | } 1286 | w_logf(ctx, LOG_NOTICE, "Station machine connected successfully\n"); 1287 | } 1288 | else{ 1289 | struct hostent *server = NULL; 1290 | server = gethostbyname(ap_ipaddr); 1291 | if (server == NULL){ 1292 | w_flogf(ctx, LOG_ERR, stderr, "No host with the given hostname exists\n"); 1293 | ret = -1; 1294 | goto out; 1295 | } 1296 | bcopy((char*)server->h_addr_list[0], (char*)&serverAddr.sin_addr.s_addr, server->h_length); 1297 | 1298 | /* The client must send a message first for the server to know the client address details */ 1299 | const char* initiate_comm = "start"; 1300 | numBytes = sendto(ctx->net_sock, initiate_comm, strlen(initiate_comm), 0, (const struct sockaddr*)&serverAddr, len); 1301 | if (numBytes < 0){ 1302 | w_flogf(ctx, LOG_ERR, stderr, "Failed to send initiate message: %s\n", strerror(errno)); 1303 | ret = -1; 1304 | goto out; 1305 | } 1306 | w_logf(ctx, LOG_INFO, "Initiate communication command sent to access point machine\n"); 1307 | } 1308 | 1309 | out: 1310 | return ret; 1311 | } 1312 | 1313 | /* 1314 | * Print the CLI help 1315 | */ 1316 | void print_help(int exval) 1317 | { 1318 | printf("wmediumd v%s - a wireless medium simulator\n", VERSION_STR); 1319 | printf("wmediumd [-h] [-V] [-a AP_ADDR] [-s] [-l LOG_LVL] [-x FILE] -c FILE\n\n"); 1320 | 1321 | printf(" -h print this help and exit\n"); 1322 | printf(" -V print version and exit\n\n"); 1323 | 1324 | printf(" -l LOG_LVL set the logging level\n"); 1325 | printf(" LOG_LVL: RFC 5424 severity, values 0 - 7\n"); 1326 | printf(" >= 3: errors are logged\n"); 1327 | printf(" >= 5: startup msgs are logged\n"); 1328 | printf(" >= 6: dropped packets are logged (default)\n"); 1329 | printf(" == 7: all packets will be logged\n"); 1330 | printf(" -c FILE set input config file\n"); 1331 | printf(" -x FILE set input PER file\n"); 1332 | printf(" -s start the server on a socket\n"); 1333 | printf(" -d use the dynamic complex mode\n"); 1334 | printf(" (server only with matrices for each connection)\n"); 1335 | printf(" -a AP_ADDR Set remote operation mode to associate remotely\n"); 1336 | printf(" AP_ADDR: IPv4 address or hostname of AP machine\n"); 1337 | printf(" \"localhost\" if current machine is AP\n"); 1338 | 1339 | exit(exval); 1340 | } 1341 | 1342 | static void timer_cb(int fd, short what, void *data) 1343 | { 1344 | struct wmediumd *ctx = data; 1345 | uint64_t u; 1346 | 1347 | pthread_rwlock_rdlock(&snr_lock); 1348 | read(fd, &u, sizeof(u)); 1349 | ctx->move_stations(ctx); 1350 | deliver_expired_frames(ctx); 1351 | rearm_timer(ctx); 1352 | pthread_rwlock_unlock(&snr_lock); 1353 | } 1354 | 1355 | int main(int argc, char *argv[]) 1356 | { 1357 | int opt; 1358 | struct event ev_cmd, net_ev; 1359 | struct event ev_timer; 1360 | struct wmediumd ctx; 1361 | char *config_file = NULL; 1362 | char *per_file = NULL; 1363 | char* ap_ip = NULL; 1364 | 1365 | setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 1366 | 1367 | if (argc == 1) { 1368 | fprintf(stderr, "This program needs arguments....\n\n"); 1369 | print_help(EXIT_FAILURE); 1370 | } 1371 | 1372 | ctx.log_lvl = 6; 1373 | unsigned long int parse_log_lvl; 1374 | char* parse_end_token; 1375 | bool start_server = false; 1376 | bool full_dynamic = false; 1377 | 1378 | while ((opt = getopt(argc, argv, "hVc:l:x:sda:")) != -1) { 1379 | switch (opt) { 1380 | case 'h': 1381 | print_help(EXIT_SUCCESS); 1382 | break; 1383 | case 'V': 1384 | printf("wmediumd v%s - a wireless medium simulator " 1385 | "for mac802154_hwsim\n", VERSION_STR); 1386 | exit(EXIT_SUCCESS); 1387 | break; 1388 | case 'c': 1389 | config_file = optarg; 1390 | break; 1391 | case 'x': 1392 | printf("Input packet error rate file: %s\n", optarg); 1393 | per_file = optarg; 1394 | break; 1395 | case ':': 1396 | printf("wmediumd: Error - Option `%c' " 1397 | "needs a value\n\n", optopt); 1398 | print_help(EXIT_FAILURE); 1399 | break; 1400 | case 'l': 1401 | parse_log_lvl = strtoul(optarg, &parse_end_token, 10); 1402 | if ((parse_log_lvl == ULONG_MAX && errno == ERANGE) || 1403 | optarg == parse_end_token || parse_log_lvl > 7) { 1404 | printf("wmediumd: Error - Invalid RFC 5424 severity level: " 1405 | "%s\n\n", optarg); 1406 | print_help(EXIT_FAILURE); 1407 | } 1408 | ctx.log_lvl = parse_log_lvl; 1409 | break; 1410 | case 'd': 1411 | full_dynamic = true; 1412 | break; 1413 | case 's': 1414 | start_server = true; 1415 | break; 1416 | case 'a': 1417 | ap_ip = optarg; 1418 | ctx.op_mode = REMOTE; 1419 | is_ap = strcmp(ap_ip, "localhost") == 0; 1420 | break; 1421 | case '?': 1422 | printf("wmediumd: Error - No such option: " 1423 | "`%c'\n\n", optopt); 1424 | print_help(EXIT_FAILURE); 1425 | break; 1426 | } 1427 | 1428 | } 1429 | 1430 | if (optind < argc) 1431 | print_help(EXIT_FAILURE); 1432 | 1433 | if (ap_ip == NULL) 1434 | ctx.op_mode = LOCAL; 1435 | 1436 | if (full_dynamic) { 1437 | if (config_file) { 1438 | printf("%s: cannot use dynamic complex mode with config file\n", argv[0]); 1439 | print_help(EXIT_FAILURE); 1440 | } 1441 | 1442 | if (!start_server) { 1443 | printf("%s: dynamic complex mode requires the server option\n", argv[0]); 1444 | print_help(EXIT_FAILURE); 1445 | } 1446 | 1447 | w_logf(&ctx, LOG_NOTICE, "Using dynamic complex mode instead of config file\n"); 1448 | } else { 1449 | if (!config_file) { 1450 | printf("%s: config file must be supplied\n", argv[0]); 1451 | print_help(EXIT_FAILURE); 1452 | } 1453 | 1454 | w_logf(&ctx, LOG_NOTICE, "Input configuration file: %s\n", config_file); 1455 | } 1456 | INIT_LIST_HEAD(&ctx.stations); 1457 | if (load_config(&ctx, config_file, per_file, full_dynamic)) 1458 | return EXIT_FAILURE; 1459 | 1460 | /* init libevent */ 1461 | event_init(); 1462 | 1463 | if (ctx.op_mode == REMOTE){ 1464 | INIT_LIST_HEAD(&ctx.pending_txinfo_frames); 1465 | if (init_remote_connection(&ctx, is_ap ? NULL : ap_ip) < 0) 1466 | return EXIT_FAILURE; 1467 | event_set(&net_ev, ctx.net_sock, EV_READ | EV_PERSIST, net_sock_event_cb, &ctx); 1468 | event_add(&net_ev, NULL); 1469 | } 1470 | 1471 | /* init netlink */ 1472 | if (init_netlink(&ctx) < 0) 1473 | return EXIT_FAILURE; 1474 | 1475 | event_set(&ev_cmd, nl_socket_get_fd(ctx.sock), EV_READ | EV_PERSIST, 1476 | sock_event_cb, &ctx); 1477 | event_add(&ev_cmd, NULL); 1478 | 1479 | /* setup timers */ 1480 | ctx.timerfd = timerfd_create(CLOCK_MONOTONIC, 0); 1481 | clock_gettime(CLOCK_MONOTONIC, &ctx.intf_updated); 1482 | clock_gettime(CLOCK_MONOTONIC, &ctx.next_move); 1483 | ctx.next_move.tv_sec += MOVE_INTERVAL; 1484 | event_set(&ev_timer, ctx.timerfd, EV_READ | EV_PERSIST, timer_cb, &ctx); 1485 | event_add(&ev_timer, NULL); 1486 | 1487 | /* register for new frames */ 1488 | if (send_register_msg(&ctx) == 0) { 1489 | w_logf(&ctx, LOG_NOTICE, "REGISTER SENT!\n"); 1490 | } 1491 | 1492 | if (start_server == true) 1493 | start_wserver(&ctx); 1494 | 1495 | /* enter libevent main loop */ 1496 | event_dispatch(); 1497 | 1498 | if (start_server == true) 1499 | stop_wserver(); 1500 | 1501 | free(ctx.sock); 1502 | free(ctx.cb); 1503 | free(ctx.intf); 1504 | free(ctx.per_matrix); 1505 | 1506 | return EXIT_SUCCESS; 1507 | } --------------------------------------------------------------------------------