├── .gitignore ├── tests ├── 2node.cfg ├── Makefile ├── example_config_for_multimedium.cfg ├── test-001.sh ├── func ├── diamond.sh ├── diamond_error_prob.sh ├── diamond_per_matrix.sh ├── diamond_fading.sh ├── n-linear-mesh.sh ├── diamond_log_distance.sh ├── diamond_direction.sh ├── interference.sh ├── signal_table_ieee80211ax ├── client_snr.c ├── client_errprob.c └── client_specprob.c ├── Makefile ├── wmediumd ├── config.h ├── Makefile ├── ieee80211.h ├── wmediumd_dynamic.h ├── wserver.h ├── wserver_messages_network.h ├── wmediumd.h ├── wmediumd_dynamic.c ├── wserver_messages_network.c ├── per.c ├── wserver_messages.c ├── wserver_messages.h ├── list.h ├── config.c └── wserver.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | wmediumd/wmediumd 3 | tests/client_snr 4 | tests/client_errprob 5 | tests/client_specprob 6 | -------------------------------------------------------------------------------- /tests/2node.cfg: -------------------------------------------------------------------------------- 1 | ifaces : 2 | { 3 | count = 2; 4 | ids = ["02:00:00:00:00:00", "02:00:00:00:01:00" ]; 5 | }; 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/sh 2 | MAKE = make 3 | SUBDIRS ?= wmediumd tests 4 | BIN = wmediumd/wmediumd 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/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 | -------------------------------------------------------------------------------- /tests/example_config_for_multimedium.cfg: -------------------------------------------------------------------------------- 1 | ifaces: 2 | { 3 | ids = [ 4 | "02:00:00:00:00:00", 5 | "02:00:00:00:01:00", 6 | "02:00:00:00:02:00", 7 | "02:00:00:00:03:00", 8 | "02:00:00:00:04:00", 9 | "02:00:00:00:05:00", 10 | "02:00:00:00:06:00", 11 | "02:00:00:00:07:00", 12 | "02:00:00:00:08:00" 13 | ]; 14 | medium_array = ((0, 1, 6), (2, 3, 7), (4, 5, 8)); 15 | enable_interference = true; 16 | }; 17 | model: 18 | { 19 | type = "path_loss"; 20 | positions = ( 21 | (192.0, 384.0, 0.0), 22 | (237.0, 443.0, 0.0), 23 | (1493.0, 150.0, 0.0), 24 | (1374.0, 656.0, 0.0), 25 | (2393.0, 350.0, 0.0), 26 | (2374.0, 426.0, 0.0), 27 | (337.0, 424.0, 0.0), 28 | (1368.0, 391.0, 0.0), 29 | (2368.0, 391.0, 0.0) 30 | ); 31 | fading_coefficient = 0; 32 | noise_threshold = -91; 33 | isnodeaps = (0, 0, 0, 0, 0, 0, 1, 1, 1); 34 | tx_powers = (14, 14, 14, 14, 14, 14, 14, 14, 14); 35 | model_name = "log_distance"; 36 | path_loss_exp = 3.0; 37 | xg = 0.0; 38 | }; -------------------------------------------------------------------------------- /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 53 | 54 | wmediumd: $(OBJECTS) 55 | $(CC) -o $@ $(OBJECTS) $(LDFLAGS) 56 | 57 | clean: 58 | rm -f $(OBJECTS) wmediumd 59 | -------------------------------------------------------------------------------- /wmediumd/ieee80211.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 IEEE80211_H_ 25 | #define IEEE80211_H_ 26 | 27 | #define IEEE80211_AVAILABLE_RATES 12 28 | #define IEEE80211_TX_MAX_RATES 4 29 | #define IEEE80211_NUM_ACS 4 30 | 31 | #ifndef ETH_ALEN 32 | #define ETH_ALEN 6 33 | #endif 34 | 35 | #define FCTL_FTYPE 0x0c 36 | #define FCTL_TODS 0x01 37 | #define FCTL_FROMDS 0x02 38 | 39 | #define FTYPE_MGMT 0x00 40 | #define FTYPE_DATA 0x08 41 | 42 | #define STYPE_QOS_DATA 0x80 43 | 44 | #define QOS_CTL_TAG1D_MASK 0x07 45 | 46 | enum ieee80211_ac_number { 47 | IEEE80211_AC_VO = 0, 48 | IEEE80211_AC_VI = 1, 49 | IEEE80211_AC_BE = 2, 50 | IEEE80211_AC_BK = 3, 51 | }; 52 | 53 | static const enum ieee80211_ac_number ieee802_1d_to_ac[8] = { 54 | IEEE80211_AC_BE, 55 | IEEE80211_AC_BK, 56 | IEEE80211_AC_BK, 57 | IEEE80211_AC_BE, 58 | IEEE80211_AC_VI, 59 | IEEE80211_AC_VI, 60 | IEEE80211_AC_VO, 61 | IEEE80211_AC_VO 62 | }; 63 | 64 | struct ieee80211_hdr { 65 | unsigned char frame_control[2]; 66 | unsigned char duration_id[2]; 67 | unsigned char addr1[ETH_ALEN]; 68 | unsigned char addr2[ETH_ALEN]; 69 | unsigned char addr3[ETH_ALEN]; 70 | unsigned char seq_ctrl[2]; 71 | unsigned char addr4[ETH_ALEN]; 72 | }; 73 | 74 | #endif /* IEEE80211_H_ */ 75 | -------------------------------------------------------------------------------- /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/test-001.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SUBNET=10.10.10 4 | NUM_PHYS=2 5 | 6 | if [[ $UID -ne 0 ]]; then 7 | echo "Sorry, run me as root." 8 | exit 1 9 | fi 10 | 11 | function cleanup() { 12 | echo "Cleaning up!" 13 | # restore default routing rules 14 | echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore 15 | for i in `seq 0 $NUM_PHYS`; do 16 | prio=$((i+10)) 17 | prio2=$((256+prio)) 18 | tbl=$prio2 19 | 20 | ip rule del priority $prio2 2> /dev/null 21 | ip rule del priority $prio 2> /dev/null 22 | ip route flush table $tbl 2> /dev/null 23 | done 24 | ip rule del priority 1000 25 | ip rule add priority 0 table local 26 | 27 | # kill whatever we started 28 | killall wmediumd 29 | } 30 | 31 | trap 'cleanup' INT TERM EXIT 32 | 33 | modprobe -r mac80211_hwsim 34 | modprobe mac80211_hwsim radios=$NUM_PHYS 35 | 36 | # routing-based send-to-self (Patrick McHardy) 37 | # lower priority of kernel local table 38 | ip rule add priority 1000 lookup local 39 | ip rule del priority 0 &>/dev/null 40 | 41 | # only arp reply for self 42 | echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore 43 | 44 | i=0 45 | # Assume most recently modified phys are hwsim phys (hence the ls -t) 46 | for phy in `ls -t /sys/class/ieee80211 | head -$NUM_PHYS`; do 47 | # The usual stuff 48 | dev=`ls /sys/class/ieee80211/$phy/device/net` 49 | ip=${SUBNET}.$((10 + i)) 50 | 51 | ip link set $dev down 52 | ip link set address 42:00:00:00:0${i}:00 dev $dev 53 | iw dev $dev set type mesh 54 | iw dev $dev set channel 36 55 | ip link set $dev up 56 | iw dev $dev mesh join meshtest 57 | 58 | ip addr flush dev $dev 59 | ip addr add $ip/24 dev $dev 60 | 61 | # set up local delivery 62 | prio=$((i+10)) 63 | prio2=$((256+prio)) 64 | tbl=$prio2 65 | 66 | # incoming traffic to us delivered via local table 67 | echo 1 > /proc/sys/net/ipv4/conf/$dev/accept_local 68 | ip rule del priority $prio 2> /dev/null 69 | ip rule add priority $prio iif $dev lookup local 70 | 71 | # outgoing frames with our ip will be generated on our interface 72 | # and go over the wire. 73 | ip rule del priority $prio2 2> /dev/null 74 | ip rule add priority $prio2 from $ip table $tbl 75 | ip route flush table $tbl 2> /dev/null 76 | ip route add default dev $dev table $tbl 77 | 78 | i=$((i+1)) 79 | done 80 | 81 | # enable wmediumd 82 | ../wmediumd/wmediumd -c 2node.cfg > wmediumd.log & 83 | 84 | # see if we can establish a mesh path 85 | ping -i 1 -c 5 -I ${SUBNET}.10 ${SUBNET}.11 || { echo FAIL; exit 1; } 86 | 87 | echo PASS 88 | -------------------------------------------------------------------------------- /tests/func: -------------------------------------------------------------------------------- 1 | function freq_to_chan { 2 | local freq=$1 3 | 4 | if [[ $freq -ge 2412 && $freq -le 2472 ]]; then 5 | band="11g" 6 | chan=$(( ($freq - 2412) / 5 + 1 )) 7 | else 8 | band="11a" 9 | chan=$(( ($freq - 5000) / 5 )) 10 | fi 11 | echo "$chan $band" 12 | } 13 | 14 | 15 | function meshup-iw { 16 | local if=$1 17 | local meshid=$2 18 | local freq=$3 19 | local ip=$4 20 | 21 | ip link set $if down 22 | iw dev $if set type mp 23 | ip link set $if up 24 | iw dev $if mesh join $meshid freq $freq 25 | ip addr add $ip/24 dev $if 2>/dev/null 26 | } 27 | 28 | function meshup-wpas-open { 29 | local if=$1 30 | local meshid=$2 31 | local freq=$3 32 | local ip=$4 33 | 34 | ip link set $if down 35 | iw dev $if set type mp 36 | ip link set $if up 37 | 38 | cat< /tmp/wpas-$if.conf 39 | network={ 40 | ssid="wmediumd-mesh" 41 | mode=5 42 | frequency=$freq 43 | key_mgmt=NONE 44 | } 45 | EOM 46 | wpa_supplicant -i $if -c /tmp/wpas-$if.conf & 47 | ip addr add $ip/24 dev $if 2>/dev/null 48 | } 49 | 50 | function meshup-wpas { 51 | local if=$1; 52 | local meshid=$2; 53 | local freq=$3; 54 | local ip=$4; 55 | 56 | ip link set $if down 57 | iw dev $if set type mp 58 | ip link set $if up 59 | 60 | cat< /tmp/wpas-$if.conf 61 | network={ 62 | ssid="wmediumd-mesh-sec" 63 | mode=5 64 | frequency=$freq 65 | key_mgmt=SAE 66 | psk="some passphrase" 67 | } 68 | EOM 69 | wpa_supplicant -i $if -c /tmp/wpas-$if.conf & 70 | ip addr add $ip/24 dev $if 2>/dev/null 71 | } 72 | 73 | function meshup-authsae { 74 | local if=$1; 75 | local meshid=$2; 76 | local freq=$3; 77 | local ip=$4; 78 | 79 | ip link set $if down 80 | iw dev $if set type mp 81 | ip link set $if up 82 | 83 | chan_params=$(freq_to_chan $freq) 84 | read -ra ch <<< "$chan_params" 85 | 86 | cat< /tmp/authsae-$if.conf 87 | authsae: 88 | { 89 | sae: 90 | { 91 | debug = 480; 92 | password = "some passphrase"; 93 | group = [19, 26, 21, 25, 20]; 94 | blacklist = 5; 95 | thresh = 5; 96 | lifetime = 3600; 97 | }; 98 | meshd: 99 | { 100 | meshid = "wmediumd-mesh-sec"; 101 | interface = "wlan0"; 102 | passive = 0; 103 | secured = 1; 104 | debug = 1; 105 | mediaopt = 1; 106 | band = "${ch[1]}"; 107 | channel = ${ch[0]}; 108 | }; 109 | }; 110 | EOM 111 | meshd-nl80211 -i $if -c /tmp/authsae-$if.conf & 112 | ip addr add $ip/24 dev $if 2>/dev/null 113 | } 114 | 115 | function addr2phy { 116 | local addr=$1; 117 | grep -l $addr /sys/class/ieee80211/phy*/macaddress | \ 118 | awk -F '/' '{print $(NF-1)}' 119 | } 120 | -------------------------------------------------------------------------------- /tests/diamond.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 4 mesh nodes in a diamond topology 3 | # paths must go through one of two intermediate nodes. 4 | 5 | num_nodes=4 6 | session=wmediumd 7 | subnet=10.10.10 8 | macfmt='02:00:00:00:%02x:00' 9 | 10 | . func 11 | 12 | if [[ $UID -ne 0 ]]; then 13 | echo "Sorry, run me as root." 14 | exit 1 15 | fi 16 | 17 | modprobe -r mac80211_hwsim 18 | modprobe mac80211_hwsim radios=$num_nodes 19 | 20 | for i in `seq 0 $((num_nodes-1))`; do 21 | addrs[$i]=`printf $macfmt $i` 22 | done 23 | 24 | cat <<__EOM > diamond.cfg 25 | ifaces : 26 | { 27 | ids = [ 28 | "02:00:00:00:00:00", 29 | "02:00:00:00:01:00", 30 | "02:00:00:00:02:00", 31 | "02:00:00:00:03:00" 32 | ]; 33 | 34 | links = ( 35 | (0, 1, 10), 36 | (0, 2, 20), 37 | (0, 3, 0), 38 | (1, 2, 30), 39 | (1, 3, 10), 40 | (2, 3, 20) 41 | ); 42 | }; 43 | __EOM 44 | 45 | tmux new -s $session -d 46 | 47 | rm /tmp/netns.pid.* 2>/dev/null 48 | i=0 49 | for addr in ${addrs[@]}; do 50 | phy=`addr2phy $addr` 51 | dev=`ls /sys/class/ieee80211/$phy/device/net` 52 | phys[$i]=$phy 53 | devs[$i]=$dev 54 | 55 | ip=${subnet}.$((10 + i)) 56 | 57 | # put this phy in own netns and tmux window, and start a mesh node 58 | win=$session:$((i+1)).0 59 | tmux new-window -t $session -n $ip 60 | 61 | # start netns 62 | pidfile=/tmp/netns.pid.$i 63 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 64 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 65 | 66 | # wait for netns to exist 67 | while [[ ! -e $pidfile ]]; do 68 | echo "Waiting for netns $i -- $pidfile" 69 | sleep 0.5 70 | done 71 | 72 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 73 | 74 | # wait for phy to exist in netns 75 | while [[ -e /sys/class/ieee80211/$phy ]]; do 76 | echo "Waiting for $phy to move to netns..." 77 | sleep 0.5 78 | done 79 | 80 | # start mesh node 81 | tmux send-keys -t $win '. func' C-m 82 | tmux send-keys -t $win 'meshup-iw '$dev' diamond 2412 '$ip C-m 83 | 84 | i=$((i+1)) 85 | done 86 | winct=$i 87 | 88 | # start wmediumd 89 | win=$session:$((winct+1)).0 90 | winct=$((winct+1)) 91 | tmux new-window -a -t $session -n wmediumd 92 | tmux send-keys -t $win '../wmediumd/wmediumd -c diamond.cfg' C-m 93 | 94 | # start iperf server on 10.10.10.13 95 | tmux send-keys -t $session:4 'iperf -s' C-m 96 | 97 | # enable monitor 98 | tmux send-keys -t $session:0 'ip link set hwsim0 up' C-m 99 | 100 | tmux select-window -t $session:1 101 | tmux send-keys -t $session:1 'ping -c 5 10.10.10.13' C-m 102 | tmux send-keys -t $session:1 'iperf -c 10.10.10.13 -i 5 -t 120' 103 | 104 | tmux attach 105 | -------------------------------------------------------------------------------- /tests/diamond_error_prob.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 4 mesh nodes in a diamond topology 3 | # paths must go through one of two intermediate nodes. 4 | 5 | num_nodes=4 6 | session=wmediumd 7 | subnet=10.10.10 8 | macfmt='02:00:00:00:%02x:00' 9 | 10 | . func 11 | 12 | if [[ $UID -ne 0 ]]; then 13 | echo "Sorry, run me as root." 14 | exit 1 15 | fi 16 | 17 | modprobe -r mac80211_hwsim 18 | modprobe mac80211_hwsim radios=$num_nodes 19 | 20 | for i in `seq 0 $((num_nodes-1))`; do 21 | addrs[$i]=`printf $macfmt $i` 22 | done 23 | 24 | cat <<__EOM > diamond.cfg 25 | ifaces : 26 | { 27 | ids = [ 28 | "02:00:00:00:00:00", 29 | "02:00:00:00:01:00", 30 | "02:00:00:00:02:00", 31 | "02:00:00:00:03:00" 32 | ]; 33 | }; 34 | 35 | model: 36 | { 37 | type = "prob"; 38 | 39 | default_prob = 1.0; 40 | links = ( 41 | (0, 2, 0.000000), 42 | (2, 3, 0.000000) 43 | ); 44 | }; 45 | __EOM 46 | 47 | tmux new -s $session -d 48 | 49 | rm /tmp/netns.pid.* 2>/dev/null 50 | i=0 51 | for addr in ${addrs[@]}; do 52 | phy=`addr2phy $addr` 53 | dev=`ls /sys/class/ieee80211/$phy/device/net` 54 | phys[$i]=$phy 55 | devs[$i]=$dev 56 | 57 | ip=${subnet}.$((10 + i)) 58 | 59 | # put this phy in own netns and tmux window, and start a mesh node 60 | win=$session:$((i+1)).0 61 | tmux new-window -t $session -n $ip 62 | 63 | # start netns 64 | pidfile=/tmp/netns.pid.$i 65 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 66 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 67 | 68 | # wait for netns to exist 69 | while [[ ! -e $pidfile ]]; do 70 | echo "Waiting for netns $i -- $pidfile" 71 | sleep 0.5 72 | done 73 | 74 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 75 | 76 | # wait for phy to exist in netns 77 | while [[ -e /sys/class/ieee80211/$phy ]]; do 78 | echo "Waiting for $phy to move to netns..." 79 | sleep 0.5 80 | done 81 | 82 | # start mesh node 83 | tmux send-keys -t $win '. func' C-m 84 | tmux send-keys -t $win 'meshup-iw '$dev' diamond 2412 '$ip C-m 85 | 86 | i=$((i+1)) 87 | done 88 | winct=$i 89 | 90 | # start wmediumd 91 | win=$session:$((winct+1)).0 92 | winct=$((winct+1)) 93 | tmux new-window -a -t $session -n wmediumd 94 | tmux send-keys -t $win '../wmediumd/wmediumd -c diamond.cfg' C-m 95 | 96 | # start iperf server on 10.10.10.13 97 | tmux send-keys -t $session:4 'iperf -s' C-m 98 | 99 | # enable monitor 100 | tmux send-keys -t $session:0 'ip link set hwsim0 up' C-m 101 | 102 | tmux select-window -t $session:1 103 | tmux send-keys -t $session:1 'ping -c 5 10.10.10.13' C-m 104 | tmux send-keys -t $session:1 'iperf -c 10.10.10.13 -i 5 -t 120' 105 | 106 | tmux attach 107 | -------------------------------------------------------------------------------- /tests/diamond_per_matrix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 4 mesh nodes in a diamond topology 3 | # paths must go through one of two intermediate nodes. 4 | 5 | num_nodes=4 6 | session=wmediumd 7 | subnet=10.10.10 8 | macfmt='02:00:00:00:%02x:00' 9 | 10 | . func 11 | 12 | if [[ $UID -ne 0 ]]; then 13 | echo "Sorry, run me as root." 14 | exit 1 15 | fi 16 | 17 | modprobe -r mac80211_hwsim 18 | modprobe mac80211_hwsim radios=$num_nodes 19 | 20 | for i in `seq 0 $((num_nodes-1))`; do 21 | addrs[$i]=`printf $macfmt $i` 22 | done 23 | 24 | cat <<__EOM > diamond.cfg 25 | ifaces : 26 | { 27 | ids = [ 28 | "02:00:00:00:00:00", 29 | "02:00:00:00:01:00", 30 | "02:00:00:00:02:00", 31 | "02:00:00:00:03:00" 32 | ]; 33 | 34 | links = ( 35 | (0, 1, 10), 36 | (0, 2, 20), 37 | (0, 3, 0), 38 | (1, 2, 30), 39 | (1, 3, 10), 40 | (2, 3, 20) 41 | ); 42 | }; 43 | __EOM 44 | 45 | tmux new -s $session -d 46 | 47 | rm /tmp/netns.pid.* 2>/dev/null 48 | i=0 49 | for addr in ${addrs[@]}; do 50 | phy=`addr2phy $addr` 51 | dev=`ls /sys/class/ieee80211/$phy/device/net` 52 | phys[$i]=$phy 53 | devs[$i]=$dev 54 | 55 | ip=${subnet}.$((10 + i)) 56 | 57 | # put this phy in own netns and tmux window, and start a mesh node 58 | win=$session:$((i+1)).0 59 | tmux new-window -t $session -n $ip 60 | 61 | # start netns 62 | pidfile=/tmp/netns.pid.$i 63 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 64 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 65 | 66 | # wait for netns to exist 67 | while [[ ! -e $pidfile ]]; do 68 | echo "Waiting for netns $i -- $pidfile" 69 | sleep 0.5 70 | done 71 | 72 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 73 | 74 | # wait for phy to exist in netns 75 | while [[ -e /sys/class/ieee80211/$phy ]]; do 76 | echo "Waiting for $phy to move to netns..." 77 | sleep 0.5 78 | done 79 | 80 | # start mesh node 81 | tmux send-keys -t $win '. func' C-m 82 | tmux send-keys -t $win 'meshup-iw '$dev' diamond 2412 '$ip C-m 83 | 84 | i=$((i+1)) 85 | done 86 | winct=$i 87 | 88 | # start wmediumd 89 | win=$session:$((winct+1)).0 90 | winct=$((winct+1)) 91 | tmux new-window -a -t $session -n wmediumd 92 | tmux send-keys -t $win '../wmediumd/wmediumd -c diamond.cfg -x signal_table_ieee80211ax' C-m 93 | 94 | # start iperf server on 10.10.10.13 95 | tmux send-keys -t $session:4 'iperf -s' C-m 96 | 97 | # enable monitor 98 | tmux send-keys -t $session:0 'ip link set hwsim0 up' C-m 99 | 100 | tmux select-window -t $session:1 101 | tmux send-keys -t $session:1 'ping -c 5 10.10.10.13' C-m 102 | tmux send-keys -t $session:1 'iperf -c 10.10.10.13 -i 5 -t 120' 103 | 104 | tmux attach 105 | -------------------------------------------------------------------------------- /tests/diamond_fading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 4 mesh nodes in a diamond topology 3 | # paths must go through one of two intermediate nodes. 4 | 5 | num_nodes=4 6 | session=wmediumd 7 | subnet=10.10.10 8 | macfmt='02:00:00:00:%02x:00' 9 | 10 | . func 11 | 12 | if [[ $UID -ne 0 ]]; then 13 | echo "Sorry, run me as root." 14 | exit 1 15 | fi 16 | 17 | modprobe -r mac80211_hwsim 18 | modprobe mac80211_hwsim radios=$num_nodes 19 | 20 | for i in `seq 0 $((num_nodes-1))`; do 21 | addrs[$i]=`printf $macfmt $i` 22 | done 23 | 24 | cat <<__EOM > diamond.cfg 25 | ifaces : 26 | { 27 | ids = [ 28 | "02:00:00:00:00:00", 29 | "02:00:00:00:01:00", 30 | "02:00:00:00:02:00", 31 | "02:00:00:00:03:00" 32 | ]; 33 | }; 34 | 35 | model: 36 | { 37 | type = "snr" 38 | links = ( 39 | (0, 1, 10), 40 | (0, 2, 20), 41 | (0, 3, 0), 42 | (1, 2, 30), 43 | (1, 3, 10), 44 | (2, 3, 20) 45 | ); 46 | fading_coefficient = 1; 47 | }; 48 | __EOM 49 | 50 | tmux new -s $session -d 51 | 52 | rm /tmp/netns.pid.* 2>/dev/null 53 | i=0 54 | for addr in ${addrs[@]}; do 55 | phy=`addr2phy $addr` 56 | dev=`ls /sys/class/ieee80211/$phy/device/net` 57 | phys[$i]=$phy 58 | devs[$i]=$dev 59 | 60 | ip=${subnet}.$((10 + i)) 61 | 62 | # put this phy in own netns and tmux window, and start a mesh node 63 | win=$session:$((i+1)).0 64 | tmux new-window -t $session -n $ip 65 | 66 | # start netns 67 | pidfile=/tmp/netns.pid.$i 68 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 69 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 70 | 71 | # wait for netns to exist 72 | while [[ ! -e $pidfile ]]; do 73 | echo "Waiting for netns $i -- $pidfile" 74 | sleep 0.5 75 | done 76 | 77 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 78 | 79 | # wait for phy to exist in netns 80 | while [[ -e /sys/class/ieee80211/$phy ]]; do 81 | echo "Waiting for $phy to move to netns..." 82 | sleep 0.5 83 | done 84 | 85 | # start mesh node 86 | tmux send-keys -t $win '. func' C-m 87 | tmux send-keys -t $win 'meshup-iw '$dev' diamond 2412 '$ip C-m 88 | 89 | i=$((i+1)) 90 | done 91 | winct=$i 92 | 93 | # start wmediumd 94 | win=$session:$((winct+1)).0 95 | winct=$((winct+1)) 96 | tmux new-window -a -t $session -n wmediumd 97 | tmux send-keys -t $win '../wmediumd/wmediumd -c diamond.cfg' C-m 98 | 99 | # start iperf server on 10.10.10.13 100 | tmux send-keys -t $session:4 'iperf -s' C-m 101 | 102 | # enable monitor 103 | tmux send-keys -t $session:0 'ip link set hwsim0 up' C-m 104 | 105 | tmux select-window -t $session:1 106 | tmux send-keys -t $session:1 'ping -c 5 10.10.10.13' C-m 107 | tmux send-keys -t $session:1 'iperf -c 10.10.10.13 -i 5 -t 120' 108 | 109 | tmux attach 110 | -------------------------------------------------------------------------------- /tests/n-linear-mesh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # run multiple mesh nodes in a linear topology 3 | # each node is in the same coverage area, so 4 | # total throughput is divided by n. 5 | 6 | num_nodes=${1:-4} 7 | daemon=${2:-iw} 8 | 9 | session=wmediumd 10 | subnet=10.10.10 11 | macfmt='02:00:00:00:%02x:00' 12 | 13 | . func 14 | 15 | if [[ $UID -ne 0 ]]; then 16 | echo "Sorry, run me as root." 17 | exit 1 18 | fi 19 | 20 | modprobe -r mac80211_hwsim 21 | modprobe mac80211_hwsim radios=$num_nodes 22 | 23 | for i in `seq 0 $((num_nodes-1))`; do 24 | addrs[$i]=`printf $macfmt $i` 25 | done 26 | 27 | echo "ifaces: { count = $num_nodes; ids = [" > linear.cfg 28 | for addr in "${addrs[@]}"; do 29 | echo -n '"'$addr'"' >> linear.cfg 30 | if [[ $addr != ${addrs[$((num_nodes-1))]} ]]; then 31 | echo ", " >> linear.cfg 32 | fi 33 | done 34 | echo "]; }" >> linear.cfg 35 | 36 | tmux new -s $session -d 37 | 38 | rm /tmp/netns.pid.* 2>/dev/null 39 | i=0 40 | for addr in ${addrs[@]}; do 41 | phy=`addr2phy $addr` 42 | dev=`ls /sys/class/ieee80211/$phy/device/net` 43 | phys[$i]=$phy 44 | devs[$i]=$dev 45 | 46 | ip=${subnet}.$((10 + i)) 47 | 48 | # put this phy in own netns and tmux window, and start a mesh node 49 | win=$session:$((i+1)).0 50 | tmux new-window -t $session -n $ip 51 | 52 | # start netns 53 | pidfile=/tmp/netns.pid.$i 54 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 55 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 56 | 57 | # wait for netns to exist 58 | while [[ ! -e $pidfile ]]; do 59 | echo "Waiting for netns $i -- $pidfile" 60 | sleep 0.5 61 | done 62 | 63 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 64 | 65 | # wait for phy to exist in netns 66 | while [[ -e /sys/class/ieee80211/$phy ]]; do 67 | echo "Waiting for $phy to move to netns..." 68 | sleep 0.5 69 | done 70 | 71 | # start mesh node 72 | tmux send-keys -t $win '. func' C-m 73 | tmux send-keys -t $win 'meshup-'$daemon ' ' $dev' linear 2412 '$ip C-m 74 | 75 | i=$((i+1)) 76 | done 77 | winct=$i 78 | 79 | # wait a few beacon periods for everyone to discover each other 80 | sleep 3 81 | 82 | # force a linear topology 83 | for i in `seq 0 $((${#addrs[@]} - 1))`; do 84 | win=$session:$((i+1)).0 85 | addr=${addrs[$i]} 86 | dev=${devs[$i]} 87 | 88 | for j in `seq 0 $((${#addrs[@]} - 1))`; do 89 | oaddr=${addrs[$j]} 90 | if [[ $j -lt $((i-1)) || $j -gt $((i+1)) ]]; then 91 | tmux send-keys -t $win 'iw dev '$dev' station set '$oaddr' plink_action block' C-m 92 | fi 93 | done 94 | done 95 | 96 | # start wmediumd 97 | win=$session:$((winct+1)).0 98 | winct=$((winct+1)) 99 | tmux new-window -t $session -n wmediumd 100 | tmux send-keys -t $win '../wmediumd/wmediumd -c linear.cfg' C-m 101 | 102 | tmux attach 103 | -------------------------------------------------------------------------------- /tests/diamond_log_distance.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 4 mesh nodes in a diamond topology 3 | # paths must go through one of two intermediate nodes. 4 | 5 | num_nodes=4 6 | session=wmediumd 7 | subnet=10.10.10 8 | macfmt='02:00:00:00:%02x:00' 9 | 10 | . func 11 | 12 | if [[ $UID -ne 0 ]]; then 13 | echo "Sorry, run me as root." 14 | exit 1 15 | fi 16 | 17 | modprobe -r mac80211_hwsim 18 | modprobe mac80211_hwsim radios=$num_nodes 19 | 20 | for i in `seq 0 $((num_nodes-1))`; do 21 | addrs[$i]=`printf $macfmt $i` 22 | done 23 | 24 | cat <<__EOM > diamond.cfg 25 | ifaces : 26 | { 27 | ids = [ 28 | "02:00:00:00:00:00", 29 | "02:00:00:00:01:00", 30 | "02:00:00:00:02:00", 31 | "02:00:00:00:03:00" 32 | ]; 33 | }; 34 | 35 | model : 36 | { 37 | type = "path_loss"; 38 | positions = ( 39 | (-50.0, 0.0), 40 | ( 0.0, 10.0), 41 | ( 0.0, 0.0), 42 | ( 50.0, 0.0) 43 | ); 44 | tx_powers = (15.0, 15.0, 15.0, 15.0); 45 | 46 | model_name = "log_distance"; 47 | path_loss_exp = 3.5; 48 | xg = 0.0; 49 | }; 50 | __EOM 51 | 52 | tmux new -s $session -d 53 | 54 | rm /tmp/netns.pid.* 2>/dev/null 55 | i=0 56 | for addr in ${addrs[@]}; do 57 | phy=`addr2phy $addr` 58 | dev=`ls /sys/class/ieee80211/$phy/device/net` 59 | phys[$i]=$phy 60 | devs[$i]=$dev 61 | 62 | ip=${subnet}.$((10 + i)) 63 | 64 | # put this phy in own netns and tmux window, and start a mesh node 65 | win=$session:$((i+1)).0 66 | tmux new-window -t $session -n $ip 67 | 68 | # start netns 69 | pidfile=/tmp/netns.pid.$i 70 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 71 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 72 | 73 | # wait for netns to exist 74 | while [[ ! -e $pidfile ]]; do 75 | echo "Waiting for netns $i -- $pidfile" 76 | sleep 0.5 77 | done 78 | 79 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 80 | 81 | # wait for phy to exist in netns 82 | while [[ -e /sys/class/ieee80211/$phy ]]; do 83 | echo "Waiting for $phy to move to netns..." 84 | sleep 0.5 85 | done 86 | 87 | # start mesh node 88 | tmux send-keys -t $win '. func' C-m 89 | tmux send-keys -t $win 'meshup-iw '$dev' diamond 2412 '$ip C-m 90 | 91 | i=$((i+1)) 92 | done 93 | winct=$i 94 | 95 | # start wmediumd 96 | win=$session:$((winct+1)).0 97 | winct=$((winct+1)) 98 | tmux new-window -a -t $session -n wmediumd 99 | tmux send-keys -t $win '../wmediumd/wmediumd -c diamond.cfg' C-m 100 | 101 | # start iperf server on 10.10.10.13 102 | tmux send-keys -t $session:4 'iperf -s' C-m 103 | 104 | # enable monitor 105 | tmux send-keys -t $session:0 'ip link set hwsim0 up' C-m 106 | 107 | tmux select-window -t $session:1 108 | tmux send-keys -t $session:1 'ping -c 5 10.10.10.13' C-m 109 | tmux send-keys -t $session:1 'iperf -c 10.10.10.13 -i 5 -t 120' 110 | 111 | tmux attach 112 | -------------------------------------------------------------------------------- /tests/diamond_direction.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 4 mesh nodes in a diamond topology 3 | # node 1 and 2 moves along with y axis 4 | # ping will be lost until switching node 1 to node 2 5 | 6 | num_nodes=4 7 | session=wmediumd 8 | subnet=10.10.10 9 | macfmt='02:00:00:00:%02x:00' 10 | 11 | . func 12 | 13 | if [[ $UID -ne 0 ]]; then 14 | echo "Sorry, run me as root." 15 | exit 1 16 | fi 17 | 18 | modprobe -r mac80211_hwsim 19 | modprobe mac80211_hwsim radios=$num_nodes 20 | 21 | for i in `seq 0 $((num_nodes-1))`; do 22 | addrs[$i]=`printf $macfmt $i` 23 | done 24 | 25 | cat <<__EOM > diamond.cfg 26 | ifaces : 27 | { 28 | ids = [ 29 | "02:00:00:00:00:00", 30 | "02:00:00:00:01:00", 31 | "02:00:00:00:02:00", 32 | "02:00:00:00:03:00" 33 | ]; 34 | }; 35 | 36 | model : 37 | { 38 | type = "path_loss"; 39 | positions = ( 40 | (-50.0, 0.0), 41 | ( 0.0, 40.0), 42 | ( 0.0, -70.0), 43 | ( 50.0, 0.0) 44 | ); 45 | directions = ( 46 | ( 0.0, 0.0), 47 | ( 0.0, 10.0), 48 | ( 0.0, 10.0), 49 | ( 0.0, 0.0) 50 | ); 51 | tx_powers = (15.0, 15.0, 15.0, 15.0); 52 | 53 | model_name = "log_distance"; 54 | path_loss_exp = 3.5; 55 | xg = 0.0; 56 | }; 57 | __EOM 58 | 59 | tmux new -s $session -d 60 | 61 | rm /tmp/netns.pid.* 2>/dev/null 62 | i=0 63 | for addr in ${addrs[@]}; do 64 | phy=`addr2phy $addr` 65 | dev=`ls /sys/class/ieee80211/$phy/device/net` 66 | phys[$i]=$phy 67 | devs[$i]=$dev 68 | 69 | ip=${subnet}.$((10 + i)) 70 | 71 | # put this phy in own netns and tmux window, and start a mesh node 72 | win=$session:$((i+1)).0 73 | tmux new-window -t $session -n $ip 74 | 75 | # start netns 76 | pidfile=/tmp/netns.pid.$i 77 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 78 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 79 | 80 | # wait for netns to exist 81 | while [[ ! -e $pidfile ]]; do 82 | echo "Waiting for netns $i -- $pidfile" 83 | sleep 0.5 84 | done 85 | 86 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 87 | 88 | # wait for phy to exist in netns 89 | while [[ -e /sys/class/ieee80211/$phy ]]; do 90 | echo "Waiting for $phy to move to netns..." 91 | sleep 0.5 92 | done 93 | 94 | # start mesh node 95 | tmux send-keys -t $win '. func' C-m 96 | tmux send-keys -t $win 'meshup-iw '$dev' diamond 2412 '$ip C-m 97 | 98 | i=$((i+1)) 99 | done 100 | winct=$i 101 | 102 | # start wmediumd 103 | win=$session:$((winct+1)).0 104 | winct=$((winct+1)) 105 | tmux new-window -a -t $session -n wmediumd 106 | 107 | tmux send-keys -t $win '../wmediumd/wmediumd -c diamond.cfg' C-m 108 | 109 | # enable monitor 110 | tmux send-keys -t $session:0 'ip link set hwsim0 up' C-m 111 | 112 | tmux select-window -t $session:1 113 | tmux send-keys -t $session:1 'ping -c 15 10.10.10.13' C-m 114 | 115 | tmux attach 116 | -------------------------------------------------------------------------------- /tests/interference.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 mesh nodes in a linear topology 3 | # 4 additional mesh nodes exists to prevent transmission 4 | # When enable_interference=true, ping always fails. 5 | # (This test is not perfect because of random values) 6 | 7 | num_nodes=7 8 | session=wmediumd 9 | subnet=10.10.10 10 | macfmt='02:00:00:00:%02x:00' 11 | 12 | . func 13 | 14 | if [[ $UID -ne 0 ]]; then 15 | echo "Sorry, run me as root." 16 | exit 1 17 | fi 18 | 19 | modprobe -r mac80211_hwsim 20 | modprobe mac80211_hwsim radios=$num_nodes 21 | 22 | for i in `seq 0 $((num_nodes-1))`; do 23 | addrs[$i]=`printf $macfmt $i` 24 | done 25 | 26 | cat <<__EOM > diamond.cfg 27 | ifaces : 28 | { 29 | ids = [ 30 | "02:00:00:00:00:00", 31 | "02:00:00:00:01:00", 32 | "02:00:00:00:02:00", 33 | "02:00:00:00:03:00", 34 | "02:00:00:00:04:00", 35 | "02:00:00:00:05:00", 36 | "02:00:00:00:06:00" 37 | ]; 38 | enable_interference = true; 39 | }; 40 | 41 | path_loss : 42 | { 43 | positions = ( 44 | (-70.0, 0.0), 45 | ( 0.0, 0.0), 46 | ( 70.0, 0.0), 47 | (130.0, -2.0), 48 | (130.0, -1.0), 49 | (130.0, 2.0), 50 | (130.0, 1.0) 51 | ); 52 | tx_powers = (15.0, 15.0, 15.0, 11.0, 11.0, 11.0, 11.0); 53 | model_params = ("log_distance", 3.5, 0.0); 54 | }; 55 | __EOM 56 | 57 | tmux new -s $session -d 58 | 59 | rm /tmp/netns.pid.* 2>/dev/null 60 | i=0 61 | for addr in ${addrs[@]}; do 62 | phy=`addr2phy $addr` 63 | dev=`ls /sys/class/ieee80211/$phy/device/net` 64 | phys[$i]=$phy 65 | devs[$i]=$dev 66 | 67 | ip=${subnet}.$((10 + i)) 68 | 69 | # put this phy in own netns and tmux window, and start a mesh node 70 | win=$session:$((i+1)).0 71 | tmux new-window -t $session -n $ip 72 | 73 | # start netns 74 | pidfile=/tmp/netns.pid.$i 75 | tmux send-keys -t $win 'lxc-unshare -s NETWORK /bin/bash' C-m 76 | tmux send-keys -t $win 'echo $$ > '$pidfile C-m 77 | 78 | # wait for netns to exist 79 | while [[ ! -e $pidfile ]]; do 80 | echo "Waiting for netns $i -- $pidfile" 81 | sleep 0.5 82 | done 83 | 84 | tmux send-keys -t $session:0.0 'iw phy '$phy' set netns `cat '$pidfile'`' C-m 85 | 86 | # wait for phy to exist in netns 87 | while [[ -e /sys/class/ieee80211/$phy ]]; do 88 | echo "Waiting for $phy to move to netns..." 89 | sleep 0.5 90 | done 91 | 92 | # start mesh node 93 | tmux send-keys -t $win '. func' C-m 94 | tmux send-keys -t $win 'meshup-iw '$dev' diamond 2412 '$ip C-m 95 | 96 | i=$((i+1)) 97 | done 98 | winct=$i 99 | 100 | # start wmediumd 101 | win=$session:$((winct+1)).0 102 | winct=$((winct+1)) 103 | tmux new-window -a -t $session -n wmediumd 104 | tmux send-keys -t $win '../wmediumd/wmediumd -c diamond.cfg' C-m 105 | 106 | # start iperf server on 10.10.10.14 107 | tmux send-keys -t $session:5 'iperf -s' C-m 108 | # start iperf server on 10.10.10.16 109 | tmux send-keys -t $session:7 'iperf -s' C-m 110 | 111 | # enable monitor 112 | tmux send-keys -t $session:0 'ip link set hwsim0 up' C-m 113 | 114 | tmux send-keys -t $session:4 'sleep 2; iperf -u -b 100000000 -c 10.10.10.14 -t 6' C-m 115 | tmux send-keys -t $session:6 'sleep 2; iperf -u -b 100000000 -c 10.10.10.16 -t 6' C-m 116 | 117 | tmux select-window -t $session:1 118 | tmux send-keys -t $session:1 'sleep 2; ping -c 5 10.10.10.12' C-m 119 | 120 | tmux attach 121 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests/client_snr.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 "../wmediumd/wserver_messages.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | #define send_request(connection_soc, request, type) \ 29 | { \ 30 | int ret = wserver_send_msg(connection_soc, request, type); \ 31 | if (ret < 0) { \ 32 | perror("error while sending"); \ 33 | close(connection_soc); \ 34 | exit(EXIT_FAILURE); \ 35 | } \ 36 | printf("sent request\n"); \ 37 | } 38 | 39 | 40 | #define receive_response(connection_soc, response, elemtype, typeint) \ 41 | { \ 42 | wserver_msg base; \ 43 | int recv_type; \ 44 | int ret = wserver_recv_msg_base(connection_soc, &base, &recv_type); \ 45 | if (ret < 0) { \ 46 | perror("error while receiving"); \ 47 | close(connection_soc); \ 48 | exit(EXIT_FAILURE); \ 49 | } \ 50 | if (recv_type != typeint) { \ 51 | fprintf(stderr, "Received invalid request of type %d", recv_type); \ 52 | close(connection_soc); \ 53 | exit(EXIT_FAILURE); \ 54 | } \ 55 | ret = wserver_recv_msg(connection_soc, response, elemtype); \ 56 | if (ret < 0) { \ 57 | perror("error while receiving"); \ 58 | close(connection_soc); \ 59 | exit(EXIT_FAILURE); \ 60 | } \ 61 | printf("received response of type %d\n", typeint); \ 62 | } 63 | 64 | void string_to_mac_address(const char *str, u8 *addr) { 65 | int a[ETH_ALEN]; 66 | 67 | sscanf(str, "%x:%x:%x:%x:%x:%x", 68 | &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); 69 | 70 | addr[0] = (u8) a[0]; 71 | addr[1] = (u8) a[1]; 72 | addr[2] = (u8) a[2]; 73 | addr[3] = (u8) a[3]; 74 | addr[4] = (u8) a[4]; 75 | addr[5] = (u8) a[5]; 76 | } 77 | 78 | int main() { 79 | int create_socket; 80 | struct sockaddr_un address; 81 | if ((create_socket = socket(AF_UNIX, SOCK_STREAM, 0)) > 0) { 82 | printf("Socket has been created\n"); 83 | } else { 84 | perror("Socket creation failed"); 85 | return EXIT_FAILURE; 86 | } 87 | address.sun_family = AF_LOCAL; 88 | strcpy(address.sun_path, WSERVER_SOCKET_PATH); 89 | if (connect(create_socket, 90 | (struct sockaddr *) &address, 91 | sizeof(address)) == 0) { 92 | printf("Connected to server\n"); 93 | 94 | printf("==== station add\n"); 95 | station_add_request request; 96 | string_to_mac_address("02:00:00:00:02:00", request.addr); 97 | send_request(create_socket, &request, station_add_request); 98 | station_add_response response; 99 | receive_response(create_socket, &response, station_add_response, WSERVER_ADD_RESPONSE_TYPE); 100 | printf("answer was: %d\n", response.update_result); 101 | 102 | printf("==== snr update 1\n"); 103 | snr_update_request request2; 104 | string_to_mac_address("02:00:00:00:01:00", request2.from_addr); 105 | string_to_mac_address("02:00:00:00:02:00", request2.to_addr); 106 | request2.snr = 15; 107 | send_request(create_socket, &request2, snr_update_request); 108 | snr_update_response response2; 109 | receive_response(create_socket, &response2, snr_update_response, WSERVER_SNR_UPDATE_RESPONSE_TYPE); 110 | printf("answer was: %d\n", response2.update_result); 111 | 112 | printf("==== snr update 2\n"); 113 | snr_update_request request3; 114 | string_to_mac_address("02:00:00:00:02:00", request3.from_addr); 115 | string_to_mac_address("02:00:00:00:01:00", request3.to_addr); 116 | request3.snr = 15; 117 | send_request(create_socket, &request3, snr_update_request); 118 | snr_update_response response3; 119 | receive_response(create_socket, &response3, snr_update_response, WSERVER_SNR_UPDATE_RESPONSE_TYPE); 120 | printf("answer was: %d\n", response3.update_result); 121 | 122 | 123 | printf("==== station del\n"); 124 | station_del_by_mac_request request4; 125 | string_to_mac_address("02:00:00:00:02:00", request4.addr); 126 | send_request(create_socket, &request4, station_del_by_mac_request); 127 | station_del_by_mac_response response4; 128 | receive_response(create_socket, &response4, station_del_by_mac_response, WSERVER_DEL_BY_MAC_RESPONSE_TYPE); 129 | printf("answer was: %d\n", response4.update_result); 130 | 131 | close(create_socket); 132 | printf("socket closed\n"); 133 | return EXIT_SUCCESS; 134 | } else { 135 | perror("Server connection failed"); 136 | return EXIT_FAILURE; 137 | } 138 | } -------------------------------------------------------------------------------- /tests/client_errprob.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 "../wmediumd/wserver_messages.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | #define send_request(connection_soc, request, type) \ 29 | { \ 30 | int ret = wserver_send_msg(connection_soc, request, type); \ 31 | if (ret < 0) { \ 32 | perror("error while sending"); \ 33 | close(connection_soc); \ 34 | exit(EXIT_FAILURE); \ 35 | } \ 36 | printf("sent request\n"); \ 37 | } 38 | 39 | 40 | #define receive_response(connection_soc, response, elemtype, typeint) \ 41 | { \ 42 | wserver_msg base; \ 43 | int recv_type; \ 44 | int ret = wserver_recv_msg_base(connection_soc, &base, &recv_type); \ 45 | if (ret < 0) { \ 46 | perror("error while receiving"); \ 47 | close(connection_soc); \ 48 | exit(EXIT_FAILURE); \ 49 | } \ 50 | if (recv_type != typeint) { \ 51 | fprintf(stderr, "Received invalid request of type %d", recv_type); \ 52 | close(connection_soc); \ 53 | exit(EXIT_FAILURE); \ 54 | } \ 55 | ret = wserver_recv_msg(connection_soc, response, elemtype); \ 56 | if (ret < 0) { \ 57 | perror("error while receiving"); \ 58 | close(connection_soc); \ 59 | exit(EXIT_FAILURE); \ 60 | } \ 61 | printf("received response of type %d\n", typeint); \ 62 | } 63 | 64 | void string_to_mac_address(const char *str, u8 *addr) { 65 | int a[ETH_ALEN]; 66 | 67 | sscanf(str, "%x:%x:%x:%x:%x:%x", 68 | &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); 69 | 70 | addr[0] = (u8) a[0]; 71 | addr[1] = (u8) a[1]; 72 | addr[2] = (u8) a[2]; 73 | addr[3] = (u8) a[3]; 74 | addr[4] = (u8) a[4]; 75 | addr[5] = (u8) a[5]; 76 | } 77 | 78 | int main() { 79 | int create_socket; 80 | struct sockaddr_un address; 81 | if ((create_socket = socket(AF_UNIX, SOCK_STREAM, 0)) > 0) { 82 | printf("Socket has been created\n"); 83 | } else { 84 | perror("Socket creation failed"); 85 | return EXIT_FAILURE; 86 | } 87 | address.sun_family = AF_LOCAL; 88 | strcpy(address.sun_path, WSERVER_SOCKET_PATH); 89 | if (connect(create_socket, 90 | (struct sockaddr *) &address, 91 | sizeof(address)) == 0) { 92 | printf("Connected to server\n"); 93 | 94 | printf("==== station add\n"); 95 | station_add_request request; 96 | string_to_mac_address("02:00:00:00:02:00", request.addr); 97 | send_request(create_socket, &request, station_add_request); 98 | station_add_response response; 99 | receive_response(create_socket, &response, station_add_response, WSERVER_ADD_RESPONSE_TYPE); 100 | printf("answer was: %d\n", response.update_result); 101 | 102 | printf("==== errprob update 1\n"); 103 | errprob_update_request request2; 104 | string_to_mac_address("02:00:00:00:01:00", request2.from_addr); 105 | string_to_mac_address("02:00:00:00:02:00", request2.to_addr); 106 | request2.errprob = custom_floating_point_to_fixed_point(0.7); 107 | send_request(create_socket, &request2, errprob_update_request); 108 | errprob_update_response response2; 109 | receive_response(create_socket, &response2, errprob_update_response, WSERVER_ERRPROB_UPDATE_RESPONSE_TYPE); 110 | printf("answer was: %d\n", response2.update_result); 111 | 112 | printf("==== errprob update 2\n"); 113 | errprob_update_request request3; 114 | string_to_mac_address("02:00:00:00:02:00", request3.from_addr); 115 | string_to_mac_address("02:00:00:00:01:00", request3.to_addr); 116 | request3.errprob = custom_floating_point_to_fixed_point(0.5); 117 | send_request(create_socket, &request3, errprob_update_request); 118 | errprob_update_response response3; 119 | receive_response(create_socket, &response3, errprob_update_response, WSERVER_ERRPROB_UPDATE_RESPONSE_TYPE); 120 | printf("answer was: %d\n", response3.update_result); 121 | 122 | 123 | printf("==== station del\n"); 124 | station_del_by_mac_request request4; 125 | string_to_mac_address("02:00:00:00:02:00", request4.addr); 126 | send_request(create_socket, &request4, station_del_by_mac_request); 127 | station_del_by_mac_response response4; 128 | receive_response(create_socket, &response4, station_del_by_mac_response, WSERVER_DEL_BY_MAC_RESPONSE_TYPE); 129 | printf("answer was: %d\n", response4.update_result); 130 | 131 | close(create_socket); 132 | printf("socket closed\n"); 133 | return EXIT_SUCCESS; 134 | } else { 135 | perror("Server connection failed"); 136 | return EXIT_FAILURE; 137 | } 138 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | # Prerequisites 13 | 14 | First, you need a recent Linux kernel with the `mac80211_hwsim` module 15 | available. If you do not have this module, you may be able to build it using 16 | the [backports project](https://backports.wiki.kernel.org/index.php/Main_Page). 17 | 18 | Wmediumd requires libnl3.0. 19 | 20 | # Building 21 | ``` 22 | cd wmediumd && make 23 | ``` 24 | 25 | # Using Wmediumd 26 | 27 | Starting wmediumd with an appropriate config file is enough to make frames 28 | pass through wmediumd: 29 | ``` 30 | sudo modprobe mac80211_hwsim radios=2 31 | sudo ./wmediumd/wmediumd -c tests/2node.cfg & 32 | # run some hwsim test 33 | ``` 34 | However, please see the next section on some potential pitfalls. 35 | 36 | A complete example using network namespaces is given at the end of 37 | this document. 38 | 39 | # Configuration 40 | 41 | Wmediumd supports multiple ways of configuring the wireless medium. 42 | 43 | ## Perfect medium 44 | 45 | With this configuration, all traffic flows between the configured interfaces, identified by their mac address: 46 | 47 | ``` 48 | ifaces : 49 | { 50 | ids = [ 51 | "02:00:00:00:00:00", 52 | "02:00:00:00:01:00", 53 | "02:00:00:00:02:00", 54 | "02:00:00:00:03:00" 55 | ]; 56 | }; 57 | ``` 58 | 59 | ## Per-link loss probability model 60 | 61 | You can simulate a slightly more realistic channel by assigning fixed error 62 | probabilities to each link. 63 | 64 | ``` 65 | ifaces : 66 | { 67 | ids = [ 68 | "02:00:00:00:00:00", 69 | "02:00:00:00:01:00", 70 | "02:00:00:00:02:00", 71 | "02:00:00:00:03:00" 72 | ]; 73 | }; 74 | 75 | model: 76 | { 77 | type = "prob"; 78 | 79 | default_prob = 1.0; 80 | links = ( 81 | (0, 2, 0.000000), 82 | (2, 3, 0.000000) 83 | ); 84 | }; 85 | ``` 86 | 87 | The above configuration would assign 0% loss probability (perfect medium) to 88 | all frames flowing between nodes 0 and 2, and 100% loss probability to all 89 | other links. Unless both directions of a link are configured, the loss 90 | probability will be symmetric. 91 | 92 | This is a very simplistic model that does not take into account that losses 93 | depend on transmission rates and signal-to-noise ratio. For that, keep reading. 94 | 95 | ## Per-link signal-to-noise ratio (SNR) model 96 | 97 | You can model different signal-to-noise ratios for each link by including a 98 | list of link tuples in the form of (sta1, sta2, snr). 99 | 100 | ``` 101 | ifaces : 102 | { 103 | ids = [ 104 | "02:00:00:00:00:00", 105 | "02:00:00:00:01:00", 106 | "02:00:00:00:02:00", 107 | "02:00:00:00:03:00" 108 | ]; 109 | 110 | links = ( 111 | (0, 1, 0), 112 | (0, 2, 0), 113 | (2, 0, 10), 114 | (0, 3, 0), 115 | (1, 2, 30), 116 | (1, 3, 10), 117 | (2, 3, 20) 118 | ); 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 | 133 | ## Path loss model 134 | 135 | The path loss model derives signal-to-noise and probabilities from the 136 | coordinates of each node. This is an example configuration file for it. 137 | 138 | ``` 139 | ifaces : {...}; 140 | model : 141 | { 142 | type = "path_loss"; 143 | positions = ( 144 | (-50.0, 0.0), 145 | ( 0.0, 40.0), 146 | ( 0.0, -70.0), 147 | ( 50.0, 0.0) 148 | ); 149 | directions = ( 150 | ( 0.0, 0.0), 151 | ( 0.0, 10.0), 152 | ( 0.0, 10.0), 153 | ( 0.0, 0.0) 154 | ); 155 | tx_powers = (15.0, 15.0, 15.0, 15.0); 156 | 157 | model_name = "log_distance"; 158 | path_loss_exp = 3.5; 159 | xg = 0.0; 160 | }; 161 | ``` 162 | 163 | ## Gotchas 164 | 165 | ### Allowable MAC addresses 166 | 167 | The kernel only allows wmediumd to work on the second available hardware 168 | address, which has bit 6 set in the most significant octet 169 | (i.e. 42:00:00:xx:xx:xx, not 02:00:00:xx:xx:xx). Set this appropriately 170 | using 'ip link set address'. 171 | 172 | This issue was fixed in commit cd37a90b2a417e5882414e19954eeed174aa4d29 173 | in Linux, released in kernel 4.1.0. 174 | 175 | ### Rates 176 | 177 | wmediumd's rate table is currently hardcoded to 802.11a OFDM rates. 178 | Therefore, either operate wmediumd networks in 5 GHz channels, or supply 179 | a rateset for the BSS with no CCK rates. 180 | 181 | ### Send-to-self 182 | 183 | By default, traffic between local devices in Linux will not go over 184 | the wire / wireless medium. This is true of vanilla hwsim as well. 185 | In order to make this happen, you need to either run the hwsim interfaces 186 | in separate network namespaces, or you need to set up routing rules with 187 | the hwsim devices at a higher priority than local forwarding. 188 | 189 | `tests/test-001.sh` contains an example of the latter setup. 190 | 191 | # Example session 192 | 193 | The following sequence of commands establishes a two-node mesh using network 194 | namespaces. 195 | ``` 196 | sudo modprobe -r mac80211_hwsim 197 | sudo modprobe mac80211_hwsim 198 | sudo ./wmediumd/wmediumd -c ./tests/2node.cfg 199 | 200 | # in window 2 201 | sudo lxc-unshare -s NETWORK bash 202 | ps | grep bash # note pid 203 | 204 | # in window 1 205 | sudo iw phy phy2 set netns $pid 206 | 207 | sudo ip link set wlan1 down 208 | sudo iw dev wlan1 set type mp 209 | sudo ip link set addr 42:00:00:00:00:00 dev wlan1 210 | sudo ip link set wlan1 up 211 | sudo ip addr add 10.10.10.1/24 dev wlan1 212 | sudo iw dev wlan1 set channel 149 213 | sudo iw dev wlan1 mesh join meshabc 214 | 215 | # in window 2 216 | ip link set lo 217 | 218 | sudo ip link set wlan2 down 219 | sudo iw dev wlan2 set type mp 220 | sudo ip link set addr 42:00:00:00:01:00 dev wlan2 221 | sudo ip link set wlan2 up 222 | sudo ip addr add 10.10.10.2/24 dev wlan2 223 | sudo iw dev wlan2 set channel 149 224 | sudo iw dev wlan2 mesh join meshabc 225 | 226 | iperf -u -s -i 10 -B 10.10.10.2 227 | 228 | # in window 1 229 | iperf -u -c 10.10.10.2 -b 100M -i 10 -t 120 230 | ``` 231 | -------------------------------------------------------------------------------- /tests/client_specprob.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 "../wmediumd/wserver_messages.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | #define send_request(connection_soc, request, type) \ 29 | { \ 30 | int ret = wserver_send_msg(connection_soc, request, type); \ 31 | if (ret < 0) { \ 32 | perror("error while sending"); \ 33 | close(connection_soc); \ 34 | exit(EXIT_FAILURE); \ 35 | } \ 36 | printf("sent request\n"); \ 37 | } 38 | 39 | 40 | #define receive_response(connection_soc, response, elemtype, typeint) \ 41 | { \ 42 | wserver_msg base; \ 43 | int recv_type; \ 44 | int ret = wserver_recv_msg_base(connection_soc, &base, &recv_type); \ 45 | if (ret < 0) { \ 46 | perror("error while receiving"); \ 47 | close(connection_soc); \ 48 | exit(EXIT_FAILURE); \ 49 | } \ 50 | if (recv_type != typeint) { \ 51 | fprintf(stderr, "Received invalid request of type %d", recv_type); \ 52 | close(connection_soc); \ 53 | exit(EXIT_FAILURE); \ 54 | } \ 55 | ret = wserver_recv_msg(connection_soc, response, elemtype); \ 56 | if (ret < 0) { \ 57 | perror("error while receiving"); \ 58 | close(connection_soc); \ 59 | exit(EXIT_FAILURE); \ 60 | } \ 61 | printf("received response of type %d\n", typeint); \ 62 | } 63 | 64 | void string_to_mac_address(const char *str, u8 *addr) { 65 | int a[ETH_ALEN]; 66 | 67 | sscanf(str, "%x:%x:%x:%x:%x:%x", 68 | &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); 69 | 70 | addr[0] = (u8) a[0]; 71 | addr[1] = (u8) a[1]; 72 | addr[2] = (u8) a[2]; 73 | addr[3] = (u8) a[3]; 74 | addr[4] = (u8) a[4]; 75 | addr[5] = (u8) a[5]; 76 | } 77 | 78 | int main() { 79 | int create_socket; 80 | struct sockaddr_un address; 81 | if ((create_socket = socket(AF_UNIX, SOCK_STREAM, 0)) > 0) { 82 | printf("Socket has been created\n"); 83 | } else { 84 | perror("Socket creation failed"); 85 | return EXIT_FAILURE; 86 | } 87 | address.sun_family = AF_LOCAL; 88 | strcpy(address.sun_path, WSERVER_SOCKET_PATH); 89 | if (connect(create_socket, 90 | (struct sockaddr *) &address, 91 | sizeof(address)) == 0) { 92 | printf("Connected to server\n"); 93 | 94 | printf("==== station add\n"); 95 | station_add_request request; 96 | string_to_mac_address("02:00:00:00:02:00", request.addr); 97 | send_request(create_socket, &request, station_add_request); 98 | station_add_response response; 99 | receive_response(create_socket, &response, station_add_response, WSERVER_ADD_RESPONSE_TYPE); 100 | printf("answer was: %d\n", response.update_result); 101 | 102 | printf("==== station add2\n"); 103 | station_add_request request2; 104 | string_to_mac_address("02:00:00:00:01:00", request2.addr); 105 | send_request(create_socket, &request2, station_add_request); 106 | station_add_response response2; 107 | receive_response(create_socket, &response2, station_add_response, WSERVER_ADD_RESPONSE_TYPE); 108 | printf("answer was: %d\n", response2.update_result); 109 | 110 | printf("==== specprob update 1\n"); 111 | specprob_update_request request3; 112 | string_to_mac_address("02:00:00:00:01:00", request3.from_addr); 113 | string_to_mac_address("02:00:00:00:02:00", request3.to_addr); 114 | double errprobs[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 115 | 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 116 | 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.40, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 117 | 0.47, 0.48, 0.49, 0.50, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 118 | 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.70, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 119 | 0.77, 0.78, 0.79, 0.80, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.90, 0.91, 120 | 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 0.100, 0.101, 0.102, 0.103, 0.104, 0.105, 121 | 0.106, 0.107, 0.108, 0.109, 0.110, 0.111, 0.112, 0.113, 0.114, 0.115, 0.116, 0.117, 0.118, 122 | 0.119, 0.120, 0.121, 0.122, 0.123, 0.124, 0.125, 0.126, 0.127, 0.128, 0.129, 0.130, 0.131, 123 | 0.132, 0.133, 0.134, 0.135, 0.136, 0.137, 0.138, 0.139, 0.140, 0.141, 0.142, 0.143, 0.144}; 124 | u32 fixedpoint[144]; 125 | for (int i = 0; i < 144; i++) { 126 | fixedpoint[i] = custom_floating_point_to_fixed_point(errprobs[i]); 127 | } 128 | memcpy(request3.errprob, fixedpoint, sizeof(u32) * 144); 129 | send_request(create_socket, &request3, specprob_update_request); 130 | specprob_update_response response3; 131 | receive_response(create_socket, &response3, specprob_update_response, WSERVER_SPECPROB_UPDATE_RESPONSE_TYPE); 132 | printf("answer was: %d\n", response3.update_result); 133 | 134 | printf("==== station del\n"); 135 | station_del_by_mac_request request4; 136 | string_to_mac_address("02:00:00:00:02:00", request4.addr); 137 | send_request(create_socket, &request4, station_del_by_mac_request); 138 | station_del_by_mac_response response4; 139 | receive_response(create_socket, &response4, station_del_by_mac_response, WSERVER_DEL_BY_MAC_RESPONSE_TYPE); 140 | printf("answer was: %d\n", response4.update_result); 141 | 142 | printf("==== station del2\n"); 143 | station_del_by_mac_request request5; 144 | string_to_mac_address("02:00:00:00:01:00", request5.addr); 145 | send_request(create_socket, &request5, station_del_by_mac_request); 146 | station_del_by_mac_response response5; 147 | receive_response(create_socket, &response5, station_del_by_mac_response, WSERVER_DEL_BY_MAC_RESPONSE_TYPE); 148 | printf("answer was: %d\n", response5.update_result); 149 | 150 | close(create_socket); 151 | printf("socket closed\n"); 152 | return EXIT_SUCCESS; 153 | } else { 154 | perror("Server connection failed"); 155 | return EXIT_FAILURE; 156 | } 157 | } -------------------------------------------------------------------------------- /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 HWSIM_TX_CTL_REQ_TX_STATUS 1 28 | #define HWSIM_TX_CTL_NO_ACK (1 << 1) 29 | #define HWSIM_TX_STAT_ACK (1 << 2) 30 | 31 | #define HWSIM_CMD_REGISTER 1 32 | #define HWSIM_CMD_FRAME 2 33 | #define HWSIM_CMD_TX_INFO_FRAME 3 34 | 35 | /** 36 | * enum hwsim_attrs - hwsim netlink attributes 37 | * 38 | * @HWSIM_ATTR_UNSPEC: unspecified attribute to catch errors 39 | * 40 | * @HWSIM_ATTR_ADDR_RECEIVER: MAC address of the radio device that 41 | * the frame is broadcasted to 42 | * @HWSIM_ATTR_ADDR_TRANSMITTER: MAC address of the radio device that 43 | * the frame was broadcasted from 44 | * @HWSIM_ATTR_FRAME: Data array 45 | * @HWSIM_ATTR_FLAGS: mac80211 transmission flags, used to process 46 | properly the frame at user space 47 | * @HWSIM_ATTR_RX_RATE: estimated rx rate index for this frame at user 48 | space 49 | * @HWSIM_ATTR_SIGNAL: estimated RX signal for this frame at user 50 | space 51 | * @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array 52 | * @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame 53 | * @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_CREATE_RADIO 54 | * command giving the number of channels supported by the new radio 55 | * @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO 56 | * only to destroy a radio 57 | * @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatoro driver hint 58 | * (nla string, length 2) 59 | * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute) 60 | * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute) 61 | * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag) 62 | * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO 63 | * command to force use of channel contexts even when only a 64 | * single channel is supported 65 | * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO 66 | * command to force radio removal when process that created the radio dies 67 | * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666 68 | * @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio. 69 | * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received. 70 | * @__HWSIM_ATTR_MAX: enum limit 71 | */ 72 | 73 | 74 | enum { 75 | HWSIM_ATTR_UNSPEC, 76 | HWSIM_ATTR_ADDR_RECEIVER, 77 | HWSIM_ATTR_ADDR_TRANSMITTER, 78 | HWSIM_ATTR_FRAME, 79 | HWSIM_ATTR_FLAGS, 80 | HWSIM_ATTR_RX_RATE, 81 | HWSIM_ATTR_SIGNAL, 82 | HWSIM_ATTR_TX_INFO, 83 | HWSIM_ATTR_COOKIE, 84 | HWSIM_ATTR_CHANNELS, 85 | HWSIM_ATTR_RADIO_ID, 86 | HWSIM_ATTR_REG_HINT_ALPHA2, 87 | HWSIM_ATTR_REG_CUSTOM_REG, 88 | HWSIM_ATTR_REG_STRICT_REG, 89 | HWSIM_ATTR_SUPPORT_P2P_DEVICE, 90 | HWSIM_ATTR_USE_CHANCTX, 91 | HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE, 92 | HWSIM_ATTR_RADIO_NAME, 93 | HWSIM_ATTR_NO_VIF, 94 | HWSIM_ATTR_FREQ, 95 | HWSIM_ATTR_PAD, 96 | __HWSIM_ATTR_MAX, 97 | }; 98 | #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) 99 | 100 | #define VERSION_NR 1 101 | 102 | #define SNR_DEFAULT 30 103 | #define GAIN_DEFAULT 5 104 | #define GAUSS_RANDOM_DEFAULT 1 105 | #define HEIGHT_DEFAULT 1 106 | #define AP_DEFAULT 2 107 | #define MEDIUM_ID_DEFAULT 0 108 | 109 | #define AP_DEFAULT_PORT 4001 110 | #define PAGE_SIZE 4096 111 | 112 | #include 113 | #include 114 | #include 115 | #include 116 | 117 | #include "list.h" 118 | #include "ieee80211.h" 119 | 120 | typedef uint8_t u8; 121 | typedef uint32_t u32; 122 | typedef uint64_t u64; 123 | 124 | #define TIME_FMT "%lld.%06lld" 125 | #define TIME_ARGS(a) ((unsigned long long)(a)->tv_sec), ((unsigned long long)(a)->tv_nsec/1000) 126 | 127 | #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" 128 | #define MAC_ARGS(a) a[0],a[1],a[2],a[3],a[4],a[5] 129 | 130 | #ifndef min 131 | #define min(x,y) ((x) < (y) ? (x) : (y)) 132 | #endif 133 | 134 | #define NOISE_LEVEL (-91) 135 | #define CCA_THRESHOLD (-90) 136 | #define ENABLE_MEDIUM_DETECTION true 137 | 138 | enum En_OperationMode 139 | { 140 | LOCAL, 141 | REMOTE 142 | }; 143 | 144 | struct wqueue { 145 | struct list_head frames; 146 | int cw_min; 147 | int cw_max; 148 | }; 149 | 150 | struct station { 151 | int index; 152 | u8 addr[ETH_ALEN]; /* virtual interface mac address */ 153 | u8 hwaddr[ETH_ALEN]; /* hardware address of hwsim radio */ 154 | double x, y, z; /* position of the station [m] */ 155 | double dir_x, dir_y; /* direction of the station [meter per MOVE_INTERVAL] */ 156 | int tx_power; /* transmission power [dBm] */ 157 | int gain; /* Antenna Gain [dBm] */ 158 | //int height; /* Antenna Height [m] */ 159 | int gRandom; /* Gaussian Random */ 160 | int isap; /* verify whether the node is ap */ 161 | double freq; /* frequency [Mhz] */ 162 | struct wqueue queues[IEEE80211_NUM_ACS]; 163 | struct list_head list; 164 | int medium_id; 165 | }; 166 | 167 | struct wmediumd { 168 | int op_mode; 169 | int timerfd; 170 | int net_sock; 171 | struct nl_sock *sock; 172 | bool enable_medium_detection; 173 | int num_stas; 174 | struct list_head pending_txinfo_frames; 175 | struct list_head stations; 176 | struct station **sta_array; 177 | int *snr_matrix; 178 | double *error_prob_matrix; 179 | double **station_err_matrix; 180 | struct intf_info *intf; 181 | struct timespec intf_updated; 182 | #define MOVE_INTERVAL (3) /* station movement interval [sec] */ 183 | struct timespec next_move; 184 | void *path_loss_param; 185 | float *per_matrix; 186 | int per_matrix_row_num; 187 | int per_matrix_signal_min; 188 | int fading_coefficient; 189 | int noise_threshold; 190 | 191 | struct nl_cb *cb; 192 | int family_id; 193 | 194 | int (*get_link_snr)(struct wmediumd *, struct station *, 195 | struct station *); 196 | double (*get_error_prob)(struct wmediumd *, double, unsigned int, u32, 197 | int, struct station *, struct station *); 198 | int (*calc_path_loss)(void *, struct station *, 199 | struct station *); 200 | void (*move_stations)(struct wmediumd *); 201 | int (*get_fading_signal)(struct wmediumd *); 202 | 203 | u8 log_lvl; 204 | }; 205 | 206 | struct hwsim_tx_rate { 207 | signed char idx; 208 | unsigned char count; 209 | }; 210 | 211 | struct frame { 212 | struct list_head list; /* frame queue list */ 213 | struct timespec expires; /* frame delivery (absolute) */ 214 | bool acked; 215 | u64 cookie; 216 | u32 freq; 217 | int flags; 218 | int signal; 219 | int duration; 220 | int tx_rates_count; 221 | struct station *sender; 222 | struct hwsim_tx_rate tx_rates[IEEE80211_TX_MAX_RATES]; 223 | size_t data_len; 224 | u8 data[0]; /* frame contents */ 225 | }; 226 | 227 | struct log_distance_model_param { 228 | double path_loss_exponent; 229 | double Xg; 230 | }; 231 | 232 | struct itu_model_param { 233 | int nFLOORS; 234 | int lF; 235 | int pL; 236 | }; 237 | 238 | struct log_normal_shadowing_model_param { 239 | int sL; 240 | double path_loss_exponent; 241 | }; 242 | 243 | struct free_space_model_param { 244 | int sL; 245 | }; 246 | 247 | struct two_ray_ground_model_param { 248 | int sL; 249 | }; 250 | 251 | struct intf_info { 252 | int signal; 253 | int duration; 254 | double prob_col; 255 | }; 256 | 257 | void station_init_queues(struct station *station); 258 | double get_error_prob_from_snr(double snr, unsigned int rate_idx, u32 freq, 259 | int frame_len); 260 | bool timespec_before(struct timespec *t1, struct timespec *t2); 261 | int set_default_per(struct wmediumd *ctx); 262 | int read_per_file(struct wmediumd *ctx, const char *file_name); 263 | int w_logf(struct wmediumd *ctx, u8 level, const char *format, ...); 264 | int w_flogf(struct wmediumd *ctx, u8 level, FILE *stream, const char *format, ...); 265 | int index_to_rate(size_t index, u32 freq); 266 | void detect_mediums(struct wmediumd *ctx, struct station *src, struct station *dest); 267 | 268 | #endif /* WMEDIUMD_H_ */ 269 | -------------------------------------------------------------------------------- /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->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->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 | station_init_queues(station); 128 | list_add_tail(&station->list, &ctx->stations); 129 | //realloc(ctx->sta_array, 1); 130 | ctx->sta_array[station->index] = station; 131 | ctx->num_stas = (int) newnum; 132 | ret = station->index; 133 | 134 | out: 135 | pthread_rwlock_unlock(&snr_lock); 136 | return ret; 137 | } 138 | 139 | int del_station(struct wmediumd *ctx, struct station *station) { 140 | if (ctx->num_stas == 0) { 141 | return -ENXIO; 142 | } 143 | size_t oldnum = (size_t) ctx->num_stas; 144 | size_t newnum = oldnum - 1; 145 | 146 | // Save old matrix and init new matrix 147 | union { 148 | int *old_snr_matrix; 149 | double *old_errprob_matrix; 150 | double **old_station_err_matrix; 151 | } matrizes; 152 | if (ctx->station_err_matrix != NULL) { 153 | swap_matrix(ctx->station_err_matrix, oldnum, newnum, double*, matrizes.old_station_err_matrix); 154 | } else if (ctx->error_prob_matrix != NULL) { 155 | swap_matrix(ctx->error_prob_matrix, oldnum, newnum, double, matrizes.old_errprob_matrix); 156 | } else { 157 | swap_matrix(ctx->snr_matrix, oldnum, newnum, int, matrizes.old_snr_matrix); 158 | } 159 | 160 | size_t index = (size_t) station->index; 161 | 162 | // Decreasing index of stations following deleted station 163 | struct station *sta_loop = station; 164 | list_for_each_entry_from(sta_loop, &ctx->stations, list) { 165 | sta_loop->index = sta_loop->index - 1; 166 | } 167 | 168 | if (ctx->station_err_matrix != NULL) { 169 | for (size_t x = 0; x < oldnum; x++) { 170 | // free old specific matrices 171 | if (matrizes.old_station_err_matrix[x * oldnum + index] != NULL) { 172 | free(matrizes.old_station_err_matrix[x * oldnum + index]); 173 | } 174 | } 175 | 176 | for (size_t y = 0; y < oldnum; y++) { 177 | if(y == index){ 178 | continue; 179 | } 180 | // free old specific matrices 181 | if (matrizes.old_station_err_matrix[index * oldnum + y] != NULL) { 182 | free(matrizes.old_station_err_matrix[index * oldnum + y]); 183 | } 184 | } 185 | } 186 | 187 | // Copy all values not related to deleted station 188 | int xnew = 0; 189 | for (size_t x = 0; x < oldnum; x++) { 190 | if (x == index) { 191 | continue; 192 | } 193 | int ynew = 0; 194 | for (size_t y = 0; y < oldnum; y++) { 195 | if (y == index) { 196 | continue; 197 | } 198 | if (ctx->station_err_matrix != NULL) { 199 | ctx->station_err_matrix[xnew * newnum + ynew] = matrizes.old_station_err_matrix[x * oldnum + y]; 200 | } else if (ctx->error_prob_matrix != NULL) { 201 | ctx->error_prob_matrix[xnew * newnum + ynew] = matrizes.old_errprob_matrix[x * oldnum + y]; 202 | } else { 203 | ctx->snr_matrix[xnew * newnum + ynew] = matrizes.old_snr_matrix[x * oldnum + y]; 204 | } 205 | ynew++; 206 | } 207 | xnew++; 208 | } 209 | 210 | if (ctx->station_err_matrix != NULL) { 211 | free(matrizes.old_station_err_matrix); 212 | } else if (ctx->error_prob_matrix != NULL) { 213 | free(matrizes.old_errprob_matrix); 214 | } else { 215 | free(matrizes.old_snr_matrix); 216 | } 217 | 218 | list_del(&station->list); 219 | ctx->num_stas = (int) newnum; 220 | 221 | free(station); 222 | return 0; 223 | } 224 | 225 | int del_station_by_id(struct wmediumd *ctx, const i32 id) { 226 | pthread_rwlock_wrlock(&snr_lock); 227 | int ret; 228 | struct station *station; 229 | list_for_each_entry(station, &ctx->stations, list) { 230 | if (station->index == id) { 231 | ret = del_station(ctx, station); 232 | goto out; 233 | } 234 | } 235 | 236 | out: 237 | ret = -ENODEV; 238 | pthread_rwlock_unlock(&snr_lock); 239 | return ret; 240 | } 241 | 242 | int del_station_by_mac(struct wmediumd *ctx, const u8 *addr) { 243 | pthread_rwlock_wrlock(&snr_lock); 244 | int ret; 245 | struct station *station; 246 | list_for_each_entry(station, &ctx->stations, list) { 247 | if (memcmp(addr, station->addr, ETH_ALEN) == 0) { 248 | ret = del_station(ctx, station); 249 | goto out; 250 | } 251 | } 252 | ret = -ENODEV; 253 | 254 | out: 255 | pthread_rwlock_unlock(&snr_lock); 256 | return ret; 257 | } 258 | -------------------------------------------------------------------------------- /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/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 struct rate rateset_GI_20[] = { 57 | /* 58 | * For 802.11n: Based on http://mcsindex.com/ 59 | * 60 | */ 61 | { .mbps = 65, .mqam = 2, .fec = FEC_RATE_1_2 }, 62 | { .mbps = 130, .mqam = 4, .fec = FEC_RATE_1_2 }, 63 | { .mbps = 195, .mqam = 4, .fec = FEC_RATE_3_4 }, 64 | { .mbps = 260, .mqam = 16, .fec = FEC_RATE_1_2 }, 65 | { .mbps = 390, .mqam = 16, .fec = FEC_RATE_3_4 }, 66 | { .mbps = 520, .mqam = 64, .fec = FEC_RATE_2_3 }, 67 | { .mbps = 585, .mqam = 64, .fec = FEC_RATE_3_4 }, 68 | { .mbps = 650, .mqam = 64, .fec = FEC_RATE_5_6 }, 69 | { .mbps = 130, .mqam = 2, .fec = FEC_RATE_1_2 }, 70 | { .mbps = 260, .mqam = 4, .fec = FEC_RATE_1_2 }, 71 | { .mbps = 390, .mqam = 4, .fec = FEC_RATE_3_4 }, 72 | { .mbps = 520, .mqam = 16, .fec = FEC_RATE_1_2 }, 73 | { .mbps = 780, .mqam = 16, .fec = FEC_RATE_3_4 }, 74 | { .mbps = 1040, .mqam = 64, .fec = FEC_RATE_2_3 }, 75 | { .mbps = 1170, .mqam = 64, .fec = FEC_RATE_3_4 }, 76 | { .mbps = 1300, .mqam = 64, .fec = FEC_RATE_4_5 }, 77 | }; 78 | static size_t rate_len_GI_20 = ARRAY_SIZE(rateset_GI_20); 79 | 80 | static struct rate rateset_SGI_20[] = { 81 | /* 82 | * For 802.11n: Based on http://mcsindex.com/ 83 | * 84 | */ 85 | { .mbps = 72, .mqam = 2, .fec = FEC_RATE_1_2 }, 86 | { .mbps = 144, .mqam = 4, .fec = FEC_RATE_1_2 }, 87 | { .mbps = 217, .mqam = 4, .fec = FEC_RATE_3_4 }, 88 | { .mbps = 289, .mqam = 16, .fec = FEC_RATE_1_2 }, 89 | { .mbps = 433, .mqam = 16, .fec = FEC_RATE_3_4 }, 90 | { .mbps = 578, .mqam = 64, .fec = FEC_RATE_2_3 }, 91 | { .mbps = 650, .mqam = 64, .fec = FEC_RATE_3_4 }, 92 | { .mbps = 722, .mqam = 64, .fec = FEC_RATE_5_6 }, 93 | { .mbps = 144, .mqam = 2, .fec = FEC_RATE_1_2 }, 94 | { .mbps = 289, .mqam = 4, .fec = FEC_RATE_1_2 }, 95 | { .mbps = 433, .mqam = 4, .fec = FEC_RATE_3_4 }, 96 | { .mbps = 578, .mqam = 16, .fec = FEC_RATE_1_2 }, 97 | { .mbps = 867, .mqam = 16, .fec = FEC_RATE_3_4 }, 98 | { .mbps = 1156, .mqam = 64, .fec = FEC_RATE_2_3 }, 99 | { .mbps = 1303, .mqam = 64, .fec = FEC_RATE_3_4 }, 100 | { .mbps = 1444, .mqam = 64, .fec = FEC_RATE_5_6 }, 101 | }; 102 | static size_t rate_len_SGI_20 = ARRAY_SIZE(rateset_SGI_20); 103 | 104 | static struct rate rateset_GI_40[] = { 105 | /* 106 | * For 802.11n: Based on http://mcsindex.com/ 107 | * 108 | */ 109 | { .mbps = 135, .mqam = 2, .fec = FEC_RATE_1_2 }, 110 | { .mbps = 270, .mqam = 4, .fec = FEC_RATE_1_2 }, 111 | { .mbps = 405, .mqam = 4, .fec = FEC_RATE_3_4 }, 112 | { .mbps = 540, .mqam = 16, .fec = FEC_RATE_1_2 }, 113 | { .mbps = 810, .mqam = 16, .fec = FEC_RATE_3_4 }, 114 | { .mbps = 1080, .mqam = 64, .fec = FEC_RATE_2_3 }, 115 | { .mbps = 1215, .mqam = 64, .fec = FEC_RATE_3_4 }, 116 | { .mbps = 1350, .mqam = 64, .fec = FEC_RATE_5_6 }, 117 | { .mbps = 270, .mqam = 2, .fec = FEC_RATE_1_2 }, 118 | { .mbps = 540, .mqam = 4, .fec = FEC_RATE_1_2 }, 119 | { .mbps = 810, .mqam = 4, .fec = FEC_RATE_3_4 }, 120 | { .mbps = 1080, .mqam = 16, .fec = FEC_RATE_1_2 }, 121 | { .mbps = 1620, .mqam = 16, .fec = FEC_RATE_3_4 }, 122 | { .mbps = 2160, .mqam = 64, .fec = FEC_RATE_2_3 }, 123 | { .mbps = 2430, .mqam = 64, .fec = FEC_RATE_3_4 }, 124 | { .mbps = 2700, .mqam = 64, .fec = FEC_RATE_5_6 }, 125 | }; 126 | static size_t rate_len_GI_40 = ARRAY_SIZE(rateset_GI_40); 127 | 128 | static struct rate rateset_SGI_40[] = { 129 | /* 130 | * For 802.11n: Based on http://mcsindex.com/ 131 | * 132 | */ 133 | { .mbps = 150, .mqam = 2, .fec = FEC_RATE_1_2 }, 134 | { .mbps = 300, .mqam = 4, .fec = FEC_RATE_1_2 }, 135 | { .mbps = 450, .mqam = 4, .fec = FEC_RATE_3_4 }, 136 | { .mbps = 600, .mqam = 16, .fec = FEC_RATE_1_2 }, 137 | { .mbps = 900, .mqam = 16, .fec = FEC_RATE_3_4 }, 138 | { .mbps = 1200, .mqam = 64, .fec = FEC_RATE_2_3 }, 139 | { .mbps = 1350, .mqam = 64, .fec = FEC_RATE_3_4 }, 140 | { .mbps = 1500, .mqam = 64, .fec = FEC_RATE_5_6 }, 141 | { .mbps = 300, .mqam = 2, .fec = FEC_RATE_1_2 }, 142 | { .mbps = 600, .mqam = 4, .fec = FEC_RATE_1_2 }, 143 | { .mbps = 900, .mqam = 4, .fec = FEC_RATE_3_4 }, 144 | { .mbps = 1200, .mqam = 16, .fec = FEC_RATE_1_2 }, 145 | { .mbps = 1800, .mqam = 16, .fec = FEC_RATE_3_4 }, 146 | { .mbps = 2400, .mqam = 64, .fec = FEC_RATE_2_3 }, 147 | { .mbps = 2700, .mqam = 64, .fec = FEC_RATE_3_4 }, 148 | { .mbps = 3000, .mqam = 64, .fec = FEC_RATE_5_6 }, 149 | }; 150 | static size_t rate_len_SGI_40 = ARRAY_SIZE(rateset_SGI_40); 151 | 152 | static double n_choose_k(double n, double k) 153 | { 154 | int i; 155 | double c = 1; 156 | 157 | if (n < k || !k) 158 | return 0; 159 | 160 | if (k > n - k) 161 | k = n - k; 162 | 163 | for (i = 1; i <= k; i++) 164 | c *= (n - (k - i)) / i; 165 | 166 | return c; 167 | } 168 | 169 | static double dot(double *v1, double *v2, int len) 170 | { 171 | int i; 172 | double val = 0; 173 | 174 | for (i = 0; i < len; i++) 175 | val += v1[i] * v2[i]; 176 | 177 | return val; 178 | } 179 | 180 | /* 181 | * Compute bit error rate for BPSK at a given SNR. 182 | * See http://en.wikipedia.org/wiki/Phase-shift_keying 183 | */ 184 | static double bpsk_ber(double snr_db) 185 | { 186 | double snr = pow(10, (snr_db / 10.)); 187 | 188 | return .5 * erfc(sqrt(snr)); 189 | } 190 | 191 | /* 192 | * Compute bit error rate for M-QAM at a given SNR. 193 | * See http://www.dsplog.com/2012/01/01/symbol-error-rate-16qam-64qam-256qam/ 194 | */ 195 | static double mqam_ber(int m, double snr_db) 196 | { 197 | double k = sqrt(1. / ((2./3) * (m - 1))); 198 | double snr = pow(10, (snr_db / 10.)); 199 | double e = erfc(k * sqrt(snr)); 200 | double sqrtm = sqrt(m); 201 | 202 | double b = 2 * (1 - 1./sqrtm) * e; 203 | double c = (1 - 2./sqrtm + 1./m) * pow(e, 2); 204 | double ser = b - c; 205 | 206 | return ser / log2(m); 207 | } 208 | 209 | /* 210 | * Compute packet (frame) error rate given a length 211 | */ 212 | static double per(double ber, enum fec_rate rate, int frame_len) 213 | { 214 | /* free distances for each fec_rate */ 215 | int d_free[] = { 10, 6, 5 }; 216 | 217 | /* initial rate code coefficients */ 218 | double a_d[5][10] = { 219 | /* FEC_RATE_1_2 */ 220 | { 11, 0, 38, 0, 193, 0, 1331, 0, 7275, 0 }, 221 | /* FEC_RATE_2_3 */ 222 | { 1, 16, 48, 158, 642, 2435, 9174, 34701, 131533, 499312 }, 223 | /* FEC_RATE_3_4 */ 224 | { 8, 31, 160, 892, 4512, 23297, 120976, 624304, 3229885, 16721329 }, 225 | /* FEC_RATE_4_5 */ 226 | { 3, 24, 172, 1158, 7408, 48706, 319563, 2094852, 13737566, 90083445 }, 227 | /* FEC_RATE_5_6 */ 228 | { 14, 69, 654, 4996, 39677, 314973, 2503576, 19875546, 157824160, 1253169928 } 229 | }; 230 | 231 | double p_d[ARRAY_SIZE(a_d[0])] = {}; 232 | double rho = ber; 233 | double prob_uncorrected; 234 | int k; 235 | size_t i; 236 | 237 | for (i = 0; i < ARRAY_SIZE(p_d); i++) { 238 | double sum_prob = 0; 239 | int d = d_free[rate] + i; 240 | 241 | if (d & 1) { 242 | for (k = (d + 1)/2; k <= d; k++) 243 | sum_prob += n_choose_k(d, k) * pow(rho, k) * 244 | pow(1 - rho, d - k); 245 | } else { 246 | for (k = d/2 + 1; k <= d; k++) 247 | sum_prob += n_choose_k(d, k) * pow(rho, k) * 248 | pow(1 - rho, d - k); 249 | 250 | sum_prob += .5 * n_choose_k(d, d/2) * pow(rho, d/2) * 251 | pow(1 - rho, d/2); 252 | } 253 | 254 | p_d[i] = sum_prob; 255 | } 256 | 257 | prob_uncorrected = dot(p_d, a_d[rate], ARRAY_SIZE(a_d[rate])); 258 | if (prob_uncorrected > 1) 259 | prob_uncorrected = 1; 260 | 261 | return 1.0 - pow(1 - prob_uncorrected, 8 * frame_len); 262 | } 263 | 264 | double get_error_prob_from_snr(double snr, unsigned int rate_idx, u32 freq, 265 | int frame_len) 266 | { 267 | int m; 268 | enum fec_rate fec; 269 | double ber; 270 | 271 | if (snr <= 0.0) 272 | return 1.0; 273 | 274 | if (freq > 5000) 275 | rate_idx += 4; 276 | 277 | if (rate_idx >= rate_len) 278 | return 1.0; 279 | 280 | m = rateset[rate_idx].mqam; 281 | fec = rateset[rate_idx].fec; 282 | 283 | if (m == 2) 284 | ber = bpsk_ber(snr); 285 | else 286 | ber = mqam_ber(m, snr); 287 | 288 | return per(ber, fec, frame_len); 289 | } 290 | 291 | static double get_error_prob_from_per_matrix(struct wmediumd *ctx, double snr, 292 | unsigned int rate_idx, u32 freq, 293 | int frame_len, struct station *src, 294 | struct station *dst) 295 | { 296 | int signal_idx; 297 | 298 | signal_idx = snr + NOISE_LEVEL - ctx->per_matrix_signal_min; 299 | 300 | if (signal_idx < 0) 301 | return 1.0; 302 | 303 | if (signal_idx >= ctx->per_matrix_row_num) 304 | return 0.0; 305 | 306 | if (freq > 5000) 307 | rate_idx += 4; 308 | 309 | if (rate_idx >= rate_len) 310 | return 1.0; 311 | 312 | return ctx->per_matrix[signal_idx * rate_len + rate_idx]; 313 | } 314 | 315 | int read_per_file(struct wmediumd *ctx, const char *file_name) 316 | { 317 | FILE *fp; 318 | char line[256]; 319 | int signal; 320 | size_t i; 321 | float *temp; 322 | const char *files[] = {"ax"}; 323 | int size = strlen(file_name) + strlen(files[0]) + 1; 324 | char *filename = malloc(size); 325 | 326 | strcpy (filename, file_name); 327 | strcat (filename, files[0]); 328 | 329 | fp = fopen(filename, "r"); 330 | if (fp == NULL) { 331 | w_flogf(ctx, LOG_ERR, stderr, 332 | "fopen failed %s\n", strerror(errno)); 333 | return EXIT_FAILURE; 334 | } 335 | 336 | ctx->per_matrix_signal_min = 1000; 337 | while (fscanf(fp, "%s", line) != EOF){ 338 | if (line[0] == '#') { 339 | if (fgets(line, sizeof(line), fp) == NULL) { 340 | w_flogf(ctx, LOG_ERR, stderr, 341 | "Failed to read comment line\n"); 342 | return EXIT_FAILURE; 343 | } 344 | continue; 345 | } 346 | 347 | signal = atoi(line); 348 | if (ctx->per_matrix_signal_min > signal) 349 | ctx->per_matrix_signal_min = signal; 350 | 351 | if (signal - ctx->per_matrix_signal_min < 0) { 352 | w_flogf(ctx, LOG_ERR, stderr, 353 | "%s: invalid signal=%d\n", __func__, signal); 354 | return EXIT_FAILURE; 355 | } 356 | 357 | temp = realloc(ctx->per_matrix, sizeof(float) * rate_len * 358 | ++ctx->per_matrix_row_num); 359 | if (temp == NULL) { 360 | w_flogf(ctx, LOG_ERR, stderr, 361 | "Out of memory(PER file)\n"); 362 | return EXIT_FAILURE; 363 | } 364 | ctx->per_matrix = temp; 365 | 366 | for (i = 0; i < rate_len; i++) { 367 | if (fscanf(fp, "%f", &ctx->per_matrix[ 368 | (signal - ctx->per_matrix_signal_min) * 369 | rate_len + i]) == EOF) { 370 | w_flogf(ctx, LOG_ERR, stderr, 371 | "Not enough rate found\n"); 372 | return EXIT_FAILURE; 373 | } 374 | } 375 | } 376 | 377 | ctx->get_error_prob = get_error_prob_from_per_matrix; 378 | 379 | return EXIT_SUCCESS; 380 | } 381 | 382 | int index_to_rate(size_t index, u32 freq) 383 | { 384 | if (freq > 5000) 385 | index += 4; 386 | if (index >= rate_len) 387 | index = rate_len - 1; 388 | 389 | return rateset[index].mbps; 390 | } 391 | -------------------------------------------------------------------------------- /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 "ieee80211.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.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[ETH_ALEN]; 36 | 37 | sscanf(str, "%x:%x:%x:%x:%x:%x", 38 | &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]); 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 | } 47 | 48 | static int get_link_snr_default(struct wmediumd *ctx, struct station *sender, 49 | struct station *receiver) 50 | { 51 | return SNR_DEFAULT; 52 | } 53 | 54 | static int get_link_snr_from_snr_matrix(struct wmediumd *ctx, 55 | struct station *sender, 56 | struct station *receiver) 57 | { 58 | return ctx->snr_matrix[sender->index * ctx->num_stas + receiver->index]; 59 | } 60 | 61 | static double _get_error_prob_from_snr(struct wmediumd *ctx, double snr, 62 | unsigned int rate_idx, u32 freq, 63 | int frame_len, 64 | struct station *src, struct station *dst) 65 | { 66 | return get_error_prob_from_snr(snr, rate_idx, freq, frame_len); 67 | } 68 | 69 | static double get_error_prob_from_matrix(struct wmediumd *ctx, double snr, 70 | unsigned int rate_idx, u32 freq, 71 | int frame_len, struct station *src, 72 | struct station *dst) 73 | { 74 | if (dst == NULL) // dst is multicast. returned value will not be used. 75 | return 0.0; 76 | 77 | return ctx->error_prob_matrix[ctx->num_stas * src->index + dst->index]; 78 | } 79 | 80 | int use_fixed_random_value(struct wmediumd *ctx) 81 | { 82 | return ctx->error_prob_matrix != NULL || ctx->station_err_matrix != NULL; 83 | } 84 | 85 | #define FREQ_1CH (2.412e9) // [Hz] 86 | #define SPEED_LIGHT (2.99792458e8) // [meter/sec] 87 | /* 88 | * Calculate path loss based on a free-space path loss 89 | * 90 | * This function returns path loss [dBm]. 91 | */ 92 | static int calc_path_loss_free_space(void *model_param, 93 | struct station *dst, struct station *src) 94 | { 95 | struct free_space_model_param *param; 96 | double PL, d, denominator, numerator, lambda; 97 | double f = src->freq * pow(10,6); 98 | 99 | if (f < 0.1) 100 | f = FREQ_1CH; 101 | 102 | param = model_param; 103 | 104 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 105 | (src->y - dst->y) * (src->y - dst->y) + 106 | (src->z - dst->z) * (src->z - dst->z)); 107 | 108 | /* 109 | * Calculate PL0 with Free-space path loss in decibels 110 | * 111 | * 20 * log10 * (4 * M_PI * d * f / c) 112 | * d: distance [meter] 113 | * f: frequency [Hz] 114 | * c: speed of light in a vacuum [meter/second] 115 | * 116 | * https://en.wikipedia.org/wiki/Free-space_path_loss 117 | */ 118 | lambda = SPEED_LIGHT / f; 119 | denominator = pow(lambda, 2); 120 | numerator = pow((4.0 * M_PI * d), 2) * param->sL; 121 | PL = 10.0 * log10(numerator / denominator); 122 | return PL; 123 | } 124 | /* 125 | * Calculate path loss based on a log distance model 126 | * 127 | * This function returns path loss [dBm]. 128 | */ 129 | static int calc_path_loss_log_distance(void *model_param, 130 | struct station *dst, struct station *src) 131 | { 132 | struct log_distance_model_param *param; 133 | double PL, PL0, d; 134 | double f = src->freq * pow(10,6); 135 | 136 | if (f < 0.1) 137 | f = FREQ_1CH; 138 | 139 | param = model_param; 140 | 141 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 142 | (src->y - dst->y) * (src->y - dst->y) + 143 | (src->z - dst->z) * (src->z - dst->z)); 144 | 145 | /* 146 | * Calculate PL0 with Free-space path loss in decibels 147 | * 148 | * 20 * log10 * (4 * M_PI * d * f / c) 149 | * d: distance [meter] 150 | * f: frequency [Hz] 151 | * c: speed of light in a vacuum [meter/second] 152 | * 153 | * https://en.wikipedia.org/wiki/Free-space_path_loss 154 | */ 155 | PL0 = 20.0 * log10(4.0 * M_PI * 1.0 * f / SPEED_LIGHT); 156 | 157 | /* 158 | * Calculate signal strength with Log-distance path loss model 159 | * https://en.wikipedia.org/wiki/Log-distance_path_loss_model 160 | */ 161 | PL = PL0 + 10.0 * param->path_loss_exponent * log10(d) + param->Xg; 162 | return PL; 163 | } 164 | /* 165 | * Calculate path loss based on a itu model 166 | * 167 | * This function returns path loss [dBm]. 168 | */ 169 | static int calc_path_loss_itu(void *model_param, 170 | struct station *dst, struct station *src) 171 | { 172 | struct itu_model_param *param; 173 | double PL, d; 174 | double f = src->freq; 175 | int N=28, pL; 176 | 177 | if (f < 0.1) 178 | f = FREQ_1CH; 179 | 180 | param = model_param; 181 | pL = param->pL; 182 | 183 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 184 | (src->y - dst->y) * (src->y - dst->y) + 185 | (src->z - dst->z) * (src->z - dst->z)); 186 | 187 | if (d>16) 188 | N=38; 189 | if (pL!=0) 190 | N=pL; 191 | /* 192 | * Calculate signal strength with ITU path loss model 193 | * Power Loss Coefficient Based on the Paper 194 | * Site-Specific Validation of ITU Indoor Path Loss Model at 2.4 GHz 195 | * from Theofilos Chrysikos, Giannis Georgopoulos and Stavros Kotsopoulos 196 | * LF: floor penetration loss factor 197 | * nFLOORS: number of floors 198 | */ 199 | 200 | PL = 20.0 * log10(f) + N * log10(d) + param->lF * param->nFLOORS - 28; 201 | return PL; 202 | } 203 | /* 204 | * Calculate path loss based on a log-normal shadowing model 205 | * 206 | * This function returns path loss [dBm]. 207 | */ 208 | static int calc_path_loss_log_normal_shadowing(void *model_param, 209 | struct station *dst, struct station *src) 210 | { 211 | struct log_normal_shadowing_model_param *param; 212 | double PL, PL0, d; 213 | double f = src->freq * pow(10,6); 214 | double gRandom = src->gRandom; 215 | 216 | if (f < 0.1) 217 | f = FREQ_1CH; 218 | 219 | param = model_param; 220 | 221 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 222 | (src->y - dst->y) * (src->y - dst->y) + 223 | (src->z - dst->z) * (src->z - dst->z)); 224 | 225 | /* 226 | * Calculate PL0 with Free-space path loss in decibels 227 | * 228 | * 20 * log10 * (4 * M_PI * d * f / c) 229 | * d: distance [meter] 230 | * f: frequency [Hz] 231 | * c: speed of light in a vacuum [meter/second] 232 | * 233 | * https://en.wikipedia.org/wiki/Free-space_path_loss 234 | */ 235 | PL0 = 20.0 * log10(4.0 * M_PI * 1.0 * f / SPEED_LIGHT); 236 | 237 | /* 238 | * Calculate signal strength with Log-distance path loss model + gRandom (Gaussian random variable) 239 | * https://en.wikipedia.org/wiki/Log-distance_path_loss_model 240 | */ 241 | PL = PL0 + 10.0 * param->path_loss_exponent * log10(d) - gRandom; 242 | return PL; 243 | } 244 | /* 245 | * Calculate path loss based on a two ray ground model 246 | * 247 | * This function returns path loss [dBm]. 248 | */ 249 | static int calc_path_loss_two_ray_ground(void *model_param, 250 | struct station *dst, struct station *src) 251 | { 252 | //struct two_ray_ground_model_param *param; 253 | double PL, d; 254 | double f = 20 * 1000000; //frequency in Hz 255 | double lambda = SPEED_LIGHT / f; 256 | int ht = 1; 257 | int hr = 1; 258 | double dCross = (4 * M_PI * ht * hr) / (lambda / 1000); 259 | 260 | //param = model_param; 261 | d = sqrt((src->x - dst->x) * (src->x - dst->x) + 262 | (src->y - dst->y) * (src->y - dst->y) + 263 | (src->z - dst->z) * (src->z - dst->z)); 264 | 265 | if (d < dCross){ 266 | PL = calc_path_loss_free_space(model_param, dst, src); 267 | return PL; 268 | } 269 | else{ 270 | double numerator = src->tx_power * src->gain * dst->gain * pow(ht, 2) * pow(hr, 2); 271 | double denominator = pow(d, 4); 272 | PL = (numerator / denominator); 273 | return PL; 274 | } 275 | } 276 | 277 | /* Existing link is from from -> to; copy to other dir */ 278 | static void mirror_link(struct wmediumd *ctx, int from, int to) 279 | { 280 | ctx->snr_matrix[ctx->num_stas * to + from] = 281 | ctx->snr_matrix[ctx->num_stas * from + to]; 282 | 283 | if (ctx->error_prob_matrix) { 284 | ctx->error_prob_matrix[ctx->num_stas * to + from] = 285 | ctx->error_prob_matrix[ctx->num_stas * from + to]; 286 | } 287 | } 288 | 289 | static void recalc_path_loss(struct wmediumd *ctx) 290 | { 291 | int start, end, path_loss, gains, txpower, signal; 292 | 293 | for (start = 0; start < ctx->num_stas; start++) { 294 | for (end = 0; end < ctx->num_stas; end++) { 295 | if (start == end) 296 | continue; 297 | txpower = ctx->sta_array[start]->tx_power; 298 | if (ctx->sta_array[end]->isap == 1) 299 | txpower = ctx->sta_array[end]->tx_power; 300 | 301 | path_loss = ctx->calc_path_loss(ctx->path_loss_param, 302 | ctx->sta_array[end], ctx->sta_array[start]); 303 | gains = txpower + ctx->sta_array[start]->gain + ctx->sta_array[end]->gain; 304 | signal = gains - path_loss - ctx->noise_threshold; 305 | ctx->snr_matrix[ctx->num_stas * start + end] = signal; 306 | ctx->snr_matrix[ctx->num_stas * end + start] = signal; 307 | } 308 | } 309 | } 310 | 311 | static void move_stations_to_direction(struct wmediumd *ctx) 312 | { 313 | struct station *station; 314 | struct timespec now; 315 | 316 | clock_gettime(CLOCK_MONOTONIC, &now); 317 | if (!timespec_before(&ctx->next_move, &now)) 318 | return; 319 | 320 | list_for_each_entry(station, &ctx->stations, list) { 321 | station->x += station->dir_x; 322 | station->y += station->dir_y; 323 | } 324 | recalc_path_loss(ctx); 325 | 326 | clock_gettime(CLOCK_MONOTONIC, &ctx->next_move); 327 | ctx->next_move.tv_sec += MOVE_INTERVAL; 328 | } 329 | 330 | static void move_stations_donothing(struct wmediumd *ctx) 331 | { 332 | } 333 | 334 | static int parse_path_loss(struct wmediumd *ctx, config_t *cf) 335 | { 336 | struct station *station; 337 | const config_setting_t *positions, *position; 338 | const config_setting_t *directions, *direction; 339 | const config_setting_t *tx_powers, *model; 340 | const config_setting_t *isnodeaps; 341 | const char *path_loss_model_name; 342 | 343 | positions = config_lookup(cf, "model.positions"); 344 | if (!positions) { 345 | w_flogf(ctx, LOG_ERR, stderr, 346 | "No positions found in model\n"); 347 | return -EINVAL; 348 | } 349 | if (config_setting_length(positions) != ctx->num_stas) { 350 | w_flogf(ctx, LOG_ERR, stderr, 351 | "Specify %d positions\n", ctx->num_stas); 352 | return -EINVAL; 353 | } 354 | 355 | directions = config_lookup(cf, "model.directions"); 356 | if (directions) { 357 | if (config_setting_length(directions) != ctx->num_stas) { 358 | w_flogf(ctx, LOG_ERR, stderr, 359 | "Specify %d directions\n", ctx->num_stas); 360 | return -EINVAL; 361 | } 362 | ctx->move_stations = move_stations_to_direction; 363 | } 364 | 365 | tx_powers = config_lookup(cf, "model.tx_powers"); 366 | if (!tx_powers) { 367 | w_flogf(ctx, LOG_ERR, stderr, 368 | "No tx_powers found in model\n"); 369 | return -EINVAL; 370 | } 371 | if (config_setting_length(tx_powers) != ctx->num_stas) { 372 | w_flogf(ctx, LOG_ERR, stderr, 373 | "Specify %d tx_powers\n", ctx->num_stas); 374 | return -EINVAL; 375 | } 376 | 377 | isnodeaps = config_lookup(cf, "model.isnodeaps"); 378 | 379 | model = config_lookup(cf, "model"); 380 | if (config_setting_lookup_string(model, "model_name", 381 | &path_loss_model_name) != CONFIG_TRUE) { 382 | w_flogf(ctx, LOG_ERR, stderr, "Specify model_name\n"); 383 | return -EINVAL; 384 | } 385 | if (strncmp(path_loss_model_name, "log_distance", 386 | sizeof("log_distance")) == 0) { 387 | struct log_distance_model_param *param; 388 | ctx->calc_path_loss = calc_path_loss_log_distance; 389 | param = malloc(sizeof(*param)); 390 | if (!param) { 391 | w_flogf(ctx, LOG_ERR, stderr, 392 | "Out of memory(path_loss_param)\n"); 393 | return -EINVAL; 394 | } 395 | 396 | if (config_setting_lookup_float(model, "path_loss_exp", 397 | ¶m->path_loss_exponent) != CONFIG_TRUE) { 398 | w_flogf(ctx, LOG_ERR, stderr, 399 | "path_loss_exponent not found\n"); 400 | return -EINVAL; 401 | } 402 | 403 | if (config_setting_lookup_float(model, "xg", 404 | ¶m->Xg) != CONFIG_TRUE) { 405 | w_flogf(ctx, LOG_ERR, stderr, "xg not found\n"); 406 | return -EINVAL; 407 | } 408 | ctx->path_loss_param = param; 409 | } 410 | else if (strncmp(path_loss_model_name, "free_space", 411 | sizeof("free_space")) == 0) { 412 | struct free_space_model_param *param; 413 | ctx->calc_path_loss = calc_path_loss_free_space; 414 | param = malloc(sizeof(*param)); 415 | if (!param) { 416 | w_flogf(ctx, LOG_ERR, stderr, 417 | "Out of memory(path_loss_param)\n"); 418 | return -EINVAL; 419 | } 420 | 421 | if (config_setting_lookup_int(model, "sL", 422 | ¶m->sL) != CONFIG_TRUE) { 423 | w_flogf(ctx, LOG_ERR, stderr, 424 | "system loss not found\n"); 425 | return -EINVAL; 426 | } 427 | ctx->path_loss_param = param; 428 | } 429 | else if (strncmp(path_loss_model_name, "log_normal_shadowing", 430 | sizeof("log_normal_shadowing")) == 0) { 431 | struct log_normal_shadowing_model_param *param; 432 | ctx->calc_path_loss = calc_path_loss_log_normal_shadowing; 433 | param = malloc(sizeof(*param)); 434 | if (!param) { 435 | w_flogf(ctx, LOG_ERR, stderr, 436 | "Out of memory(path_loss_param)\n"); 437 | return -EINVAL; 438 | } 439 | 440 | if (config_setting_lookup_int(model, "sL", 441 | ¶m->sL) != CONFIG_TRUE) { 442 | w_flogf(ctx, LOG_ERR, stderr, 443 | "system loss not found\n"); 444 | return -EINVAL; 445 | } 446 | 447 | if (config_setting_lookup_float(model, "path_loss_exp", 448 | ¶m->path_loss_exponent) != CONFIG_TRUE) { 449 | w_flogf(ctx, LOG_ERR, stderr, 450 | "path_loss_exponent not found\n"); 451 | return -EINVAL; 452 | } 453 | ctx->path_loss_param = param; 454 | } 455 | else if (strncmp(path_loss_model_name, "two_ray_ground", 456 | sizeof("two_ray_ground")) == 0) { 457 | struct two_ray_ground_model_param *param; 458 | ctx->calc_path_loss = calc_path_loss_two_ray_ground; 459 | param = malloc(sizeof(*param)); 460 | if (!param) { 461 | w_flogf(ctx, LOG_ERR, stderr, 462 | "Out of memory(path_loss_param)\n"); 463 | return -EINVAL; 464 | } 465 | 466 | if (config_setting_lookup_int(model, "sL", 467 | ¶m->sL) != CONFIG_TRUE) { 468 | w_flogf(ctx, LOG_ERR, stderr, 469 | "system loss not found\n"); 470 | return -EINVAL; 471 | } 472 | ctx->path_loss_param = param; 473 | } 474 | else if (strncmp(path_loss_model_name, "itu", 475 | sizeof("itu")) == 0) { 476 | struct itu_model_param *param; 477 | ctx->calc_path_loss = calc_path_loss_itu; 478 | param = malloc(sizeof(*param)); 479 | if (!param) { 480 | w_flogf(ctx, LOG_ERR, stderr, 481 | "Out of memory(path_loss_param)\n"); 482 | return -EINVAL; 483 | } 484 | 485 | if (config_setting_lookup_int(model, "nFLOORS", 486 | ¶m->nFLOORS) != CONFIG_TRUE) { 487 | w_flogf(ctx, LOG_ERR, stderr, 488 | "nFLOORS not found\n"); 489 | return -EINVAL; 490 | } 491 | 492 | if (config_setting_lookup_int(model, "lF", 493 | ¶m->lF) != CONFIG_TRUE) { 494 | w_flogf(ctx, LOG_ERR, stderr, "LF not found\n"); 495 | return -EINVAL; 496 | } 497 | 498 | if (config_setting_lookup_int(model, "pL", 499 | ¶m->pL) != CONFIG_TRUE) { 500 | w_flogf(ctx, LOG_ERR, stderr, "PL not found\n"); 501 | return -EINVAL; 502 | } 503 | ctx->path_loss_param = param; 504 | } 505 | else { 506 | w_flogf(ctx, LOG_ERR, stderr, "No path loss model found\n"); 507 | return -EINVAL; 508 | } 509 | 510 | list_for_each_entry(station, &ctx->stations, list) { 511 | position = config_setting_get_elem(positions, station->index); 512 | if (config_setting_length(position) != 3) { 513 | w_flogf(ctx, LOG_ERR, stderr, 514 | "Invalid position: expected (double,double,double)\n"); 515 | return -EINVAL; 516 | } 517 | station->x = config_setting_get_float_elem(position, 0); 518 | station->y = config_setting_get_float_elem(position, 1); 519 | station->z = config_setting_get_float_elem(position, 2); 520 | 521 | if (directions) { 522 | direction = config_setting_get_elem(directions, 523 | station->index); 524 | if (config_setting_length(direction) != 2) { 525 | w_flogf(ctx, LOG_ERR, stderr, 526 | "Invalid direction: expected (double,double)\n"); 527 | return -EINVAL; 528 | } 529 | station->dir_x = config_setting_get_float_elem( 530 | direction, 0); 531 | station->dir_y = config_setting_get_float_elem( 532 | direction, 1); 533 | } 534 | 535 | station->tx_power = config_setting_get_float_elem( 536 | tx_powers, station->index); 537 | if (isnodeaps) { 538 | station->isap = config_setting_get_int_elem( 539 | isnodeaps, station->index); 540 | } 541 | } 542 | 543 | recalc_path_loss(ctx); 544 | 545 | return 0; 546 | } 547 | 548 | static double pseudo_normal_distribution(void) 549 | { 550 | int i; 551 | double normal = -6.0; 552 | 553 | for (i = 0; i < 12; i++) 554 | normal += drand48(); 555 | 556 | return normal; 557 | } 558 | 559 | static int _get_fading_signal(struct wmediumd *ctx) 560 | { 561 | return ctx->fading_coefficient * pseudo_normal_distribution(); 562 | } 563 | 564 | static int get_no_fading_signal(struct wmediumd *ctx) 565 | { 566 | return 0; 567 | } 568 | 569 | /* 570 | * Loads a config file into memory 571 | */ 572 | int load_config(struct wmediumd *ctx, const char *file, const char *per_file, bool full_dynamic) 573 | { 574 | config_t cfg, *cf; 575 | const config_setting_t *ids, *links, *model_type; 576 | const config_setting_t *error_probs = NULL, *error_prob; 577 | const config_setting_t *enable_interference; 578 | const config_setting_t *fading_coefficient, *noise_threshold, *default_prob; 579 | const config_setting_t *mediums, *medium_data,*interface_data, *medium_detection; 580 | int count_ids, count_mediums, count_interfaces, station_id, i, j; 581 | int start, end, snr; 582 | struct station *station; 583 | const char *model_type_str; 584 | float default_prob_value = 0.0; 585 | bool *link_map = NULL; 586 | 587 | if (full_dynamic) { 588 | ctx->sta_array = malloc(0); 589 | ctx->num_stas = 0; 590 | ctx->intf = NULL; 591 | ctx->get_fading_signal = get_no_fading_signal; 592 | ctx->fading_coefficient = 0; 593 | ctx->move_stations = move_stations_donothing; 594 | ctx->snr_matrix = malloc(0); 595 | ctx->per_matrix = NULL; 596 | ctx->per_matrix_row_num = 0; 597 | ctx->error_prob_matrix = NULL; 598 | ctx->get_link_snr = get_link_snr_default; 599 | ctx->station_err_matrix = malloc(0); 600 | return 0; 601 | } 602 | ctx->station_err_matrix = NULL; 603 | 604 | /*initialize the config file*/ 605 | cf = &cfg; 606 | config_init(cf); 607 | 608 | /*read the file*/ 609 | if (!config_read_file(cf, file)) { 610 | w_logf(ctx, LOG_ERR, "Error loading file %s at line:%d, reason: %s\n", 611 | file, 612 | config_error_line(cf), 613 | config_error_text(cf)); 614 | config_destroy(cf); 615 | return -EIO; 616 | } 617 | 618 | ids = config_lookup(cf, "ifaces.ids"); 619 | if (!ids) { 620 | w_logf(ctx, LOG_ERR, "ids not found in config file\n"); 621 | return -EIO; 622 | } 623 | count_ids = config_setting_length(ids); 624 | 625 | w_logf(ctx, LOG_NOTICE, "#_if = %d\n", count_ids); 626 | 627 | /* Fill the mac_addr */ 628 | ctx->sta_array = malloc(sizeof(struct station *) * count_ids); 629 | if (!ctx->sta_array) { 630 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory(sta_array)!\n"); 631 | return -ENOMEM; 632 | } 633 | for (i = 0; i < count_ids; i++) { 634 | u8 addr[ETH_ALEN]; 635 | const char *str = config_setting_get_string_elem(ids, i); 636 | string_to_mac_address(str, addr); 637 | 638 | station = malloc(sizeof(*station)); 639 | if (!station) { 640 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory!\n"); 641 | return -ENOMEM; 642 | } 643 | station->index = i; 644 | memcpy(station->addr, addr, ETH_ALEN); 645 | memcpy(station->hwaddr, addr, ETH_ALEN); 646 | station->tx_power = SNR_DEFAULT; 647 | station->gain = GAIN_DEFAULT; 648 | //station->height = HEIGHT_DEFAULT; 649 | station->gRandom = GAUSS_RANDOM_DEFAULT; 650 | station->isap = AP_DEFAULT; 651 | station->medium_id = MEDIUM_ID_DEFAULT; 652 | station_init_queues(station); 653 | list_add_tail(&station->list, &ctx->stations); 654 | ctx->sta_array[i] = station; 655 | 656 | w_logf(ctx, LOG_NOTICE, "Added station %d: " MAC_FMT "\n", i, MAC_ARGS(addr)); 657 | } 658 | ctx->num_stas = count_ids; 659 | 660 | enable_interference = config_lookup(cf, "ifaces.enable_interference"); 661 | if (enable_interference && 662 | config_setting_get_bool(enable_interference)) { 663 | ctx->intf = calloc(ctx->num_stas * ctx->num_stas, 664 | sizeof(struct intf_info)); 665 | if (!ctx->intf) { 666 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory(intf)\n"); 667 | return -ENOMEM; 668 | } 669 | for (i = 0; i < ctx->num_stas; i++) 670 | for (j = 0; j < ctx->num_stas; j++) 671 | ctx->intf[i * ctx->num_stas + j].signal = -200; 672 | } else { 673 | ctx->intf = NULL; 674 | } 675 | 676 | noise_threshold = 677 | config_lookup(cf, "model.noise_threshold"); 678 | if (noise_threshold && 679 | config_setting_get_int(noise_threshold) < 0) { 680 | ctx->get_fading_signal = _get_fading_signal; 681 | ctx->noise_threshold = 682 | config_setting_get_int(noise_threshold); 683 | } else { 684 | ctx->noise_threshold = NOISE_LEVEL; 685 | } 686 | 687 | 688 | fading_coefficient = 689 | config_lookup(cf, "model.fading_coefficient"); 690 | if (fading_coefficient && 691 | config_setting_get_int(fading_coefficient) > 0) { 692 | ctx->get_fading_signal = _get_fading_signal; 693 | ctx->fading_coefficient = 694 | config_setting_get_int(fading_coefficient); 695 | } else { 696 | ctx->get_fading_signal = get_no_fading_signal; 697 | ctx->fading_coefficient = 0; 698 | } 699 | 700 | ctx->move_stations = move_stations_donothing; 701 | 702 | /* create link quality matrix */ 703 | ctx->snr_matrix = calloc(sizeof(int), count_ids * count_ids); 704 | if (!ctx->snr_matrix) { 705 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory!\n"); 706 | return -ENOMEM; 707 | } 708 | /* set default snrs */ 709 | for (i = 0; i < count_ids * count_ids; i++) 710 | ctx->snr_matrix[i] = SNR_DEFAULT; 711 | 712 | links = config_lookup(cf, "ifaces.links"); 713 | if (!links) { 714 | model_type = config_lookup(cf, "model.type"); 715 | if (model_type) { 716 | model_type_str = config_setting_get_string(model_type); 717 | if (memcmp("snr", model_type_str, strlen("snr")) == 0) { 718 | links = config_lookup(cf, "model.links"); 719 | } else if (memcmp("prob", model_type_str, 720 | strlen("prob")) == 0) { 721 | error_probs = config_lookup(cf, "model.links"); 722 | } else if (memcmp("path_loss", model_type_str, 723 | strlen("path_loss")) == 0) { 724 | /* calculate signal from positions */ 725 | if (parse_path_loss(ctx, cf)) 726 | goto fail; 727 | } 728 | } 729 | } 730 | mediums = config_lookup(cf, "ifaces.medium_array"); 731 | if (mediums) { 732 | count_mediums = config_setting_length(mediums); 733 | for (i = 0; i < count_mediums; i++) { 734 | medium_data = config_setting_get_elem(mediums, i); 735 | count_interfaces = config_setting_length(medium_data); 736 | for (j = 0; j < count_interfaces; j++) { 737 | interface_data = config_setting_get_elem(medium_data, j); 738 | station_id = config_setting_get_int(interface_data); 739 | ctx->sta_array[station_id]->medium_id = i+1; 740 | } 741 | } 742 | } 743 | medium_detection = config_lookup(cf, "ifaces.enable_medium_detection"); 744 | if (medium_detection) { 745 | ctx->enable_medium_detection =config_setting_get_bool(enable_interference); 746 | }else{ 747 | ctx->enable_medium_detection = ENABLE_MEDIUM_DETECTION; 748 | } 749 | 750 | if (per_file && error_probs) { 751 | w_flogf(ctx, LOG_ERR, stderr, 752 | "per_file and error_probs could not be used at the same time\n"); 753 | goto fail; 754 | } 755 | 756 | ctx->get_link_snr = get_link_snr_from_snr_matrix; 757 | ctx->get_error_prob = _get_error_prob_from_snr; 758 | 759 | ctx->per_matrix = NULL; 760 | ctx->per_matrix_row_num = 0; 761 | if (per_file && read_per_file(ctx, per_file)) 762 | goto fail; 763 | 764 | ctx->error_prob_matrix = NULL; 765 | if (error_probs) { 766 | ctx->error_prob_matrix = calloc(sizeof(double), 767 | count_ids * count_ids); 768 | if (!ctx->error_prob_matrix) { 769 | w_flogf(ctx, LOG_ERR, stderr, 770 | "Out of memory(error_prob_matrix)\n"); 771 | goto fail; 772 | } 773 | 774 | ctx->get_link_snr = get_link_snr_default; 775 | ctx->get_error_prob = get_error_prob_from_matrix; 776 | 777 | default_prob = config_lookup(cf, "model.default_prob"); 778 | if (default_prob) { 779 | default_prob_value = config_setting_get_float( 780 | default_prob); 781 | if (default_prob_value < 0.0 || 782 | default_prob_value > 1.0) { 783 | w_flogf(ctx, LOG_ERR, stderr, 784 | "model.default_prob should be in [0.0, 1.0]\n"); 785 | goto fail; 786 | } 787 | } 788 | } 789 | 790 | link_map = calloc(sizeof(bool), count_ids * count_ids); 791 | if (!link_map) { 792 | w_flogf(ctx, LOG_ERR, stderr, "Out of memory\n"); 793 | goto fail; 794 | } 795 | 796 | /* read snr values */ 797 | for (i = 0; links && i < config_setting_length(links); i++) { 798 | config_setting_t *link; 799 | 800 | link = config_setting_get_elem(links, i); 801 | if (config_setting_length(link) != 3) { 802 | w_flogf(ctx, LOG_ERR, stderr, "Invalid link: expected (int,int,int)\n"); 803 | goto fail; 804 | } 805 | start = config_setting_get_int_elem(link, 0); 806 | end = config_setting_get_int_elem(link, 1); 807 | snr = config_setting_get_int_elem(link, 2); 808 | 809 | if (start < 0 || start >= ctx->num_stas || 810 | end < 0 || end >= ctx->num_stas) { 811 | w_flogf(ctx, LOG_ERR, stderr, "Invalid link [%d,%d,%d]: index out of range\n", 812 | start, end, snr); 813 | goto fail; 814 | } 815 | ctx->snr_matrix[ctx->num_stas * start + end] = snr; 816 | link_map[ctx->num_stas * start + end] = true; 817 | } 818 | 819 | /* initialize with default_prob */ 820 | for (start = 0; error_probs && start < ctx->num_stas; start++) 821 | for (end = start + 1; end < ctx->num_stas; end++) { 822 | ctx->error_prob_matrix[ctx->num_stas * 823 | start + end] = 824 | ctx->error_prob_matrix[ctx->num_stas * 825 | end + start] = default_prob_value; 826 | } 827 | 828 | /* read error probabilities */ 829 | for (i = 0; error_probs && 830 | i < config_setting_length(error_probs); i++) { 831 | float error_prob_value; 832 | 833 | error_prob = config_setting_get_elem(error_probs, i); 834 | if (config_setting_length(error_prob) != 3) { 835 | w_flogf(ctx, LOG_ERR, stderr, "Invalid error probability: expected (int,int,float)\n"); 836 | goto fail; 837 | } 838 | 839 | start = config_setting_get_int_elem(error_prob, 0); 840 | end = config_setting_get_int_elem(error_prob, 1); 841 | error_prob_value = config_setting_get_float_elem(error_prob, 2); 842 | 843 | if (start < 0 || start >= ctx->num_stas || 844 | end < 0 || end >= ctx->num_stas || 845 | error_prob_value < 0.0 || error_prob_value > 1.0) { 846 | w_flogf(ctx, LOG_ERR, stderr, "Invalid error probability [%d,%d,%f]\n", 847 | start, end, error_prob_value); 848 | goto fail; 849 | } 850 | 851 | ctx->error_prob_matrix[ctx->num_stas * start + end] = 852 | error_prob_value; 853 | link_map[ctx->num_stas * start + end] = true; 854 | } 855 | 856 | /* 857 | * If any links are specified in only one direction, mirror them, 858 | * making them symmetric. If specified in both directions they 859 | * can be asymmetric. 860 | */ 861 | for (i = 0; i < ctx->num_stas; i++) { 862 | for (j = 0; j < ctx->num_stas; j++) { 863 | if (i == j) 864 | continue; 865 | 866 | if (link_map[ctx->num_stas * i + j] && 867 | !link_map[ctx->num_stas * j + i]) { 868 | mirror_link(ctx, i, j); 869 | } 870 | } 871 | } 872 | 873 | free(link_map); 874 | config_destroy(cf); 875 | return 0; 876 | 877 | fail: 878 | free(ctx->snr_matrix); 879 | free(ctx->error_prob_matrix); 880 | config_destroy(cf); 881 | return -EINVAL; 882 | } 883 | -------------------------------------------------------------------------------- /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->addr, ETH_ALEN) == 0) { 165 | sender = station; 166 | } 167 | if (memcmp(&request->to_addr, station->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->addr), MAC_ARGS(receiver->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->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->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->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->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->addr, ETH_ALEN) == 0) { 336 | sender = station; 337 | } 338 | if (memcmp(&request->to_addr, station->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->addr), MAC_ARGS(receiver->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->addr, ETH_ALEN) == 0) { 384 | sender = station; 385 | } 386 | if (memcmp(&request->to_addr, station->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->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 | actx->wctx = wctx; 682 | actx->server_socket = fd; 683 | actx->thread = malloc(sizeof(pthread_t)); 684 | if (!actx->thread) { 685 | w_logf(wctx, LOG_ERR, "Error during allocation of memory in on_listen_event wmediumd/wserver.c\n"); 686 | free(actx); 687 | return; 688 | } 689 | actx->client_socket = accept_connection(actx->server_socket); 690 | if (actx->client_socket < 0) { 691 | w_logf(actx->wctx, LOG_ERR, LOG_PREFIX "Accept failed: %s\n", strerror(errno)); 692 | } else { 693 | pthread_create(actx->thread, NULL, handle_accepted_connection, actx); 694 | } 695 | } 696 | 697 | /** 698 | * Run the server using the given wmediumd context 699 | * @param ctx The wmediumd context 700 | * @return NULL, required for pthread 701 | */ 702 | void *run_wserver(void *ctx) { 703 | struct event *accept_event; 704 | 705 | old_sig_handler = signal(SIGINT, handle_sigint); 706 | 707 | listen_soc = create_listen_socket(ctx); 708 | if (listen_soc < 0) { 709 | return NULL; 710 | } 711 | w_logf(ctx, LOG_DEBUG, LOG_PREFIX "Listening for incoming connection\n"); 712 | 713 | evutil_make_socket_nonblocking(listen_soc); 714 | server_event_base = event_base_new(); 715 | accept_event = event_new(server_event_base, listen_soc, EV_READ | EV_PERSIST, on_listen_event, ctx); 716 | event_add(accept_event, NULL); 717 | 718 | w_logf(ctx, LOG_DEBUG, LOG_PREFIX "Waiting for client to connect...\n"); 719 | event_base_dispatch(server_event_base); 720 | 721 | event_free(accept_event); 722 | event_base_free(server_event_base); 723 | stop_wserver(); 724 | return NULL; 725 | } 726 | 727 | int start_wserver(struct wmediumd *ctx) { 728 | return pthread_create(&server_thread, NULL, run_wserver, ctx); 729 | } 730 | 731 | void stop_wserver() { 732 | signal(SIGINT, old_sig_handler); 733 | pthread_cancel(server_thread); 734 | pthread_detach(server_thread); 735 | printf("\n" LOG_PREFIX "shutting down wserver\n"); 736 | close(listen_soc); 737 | unlink(WSERVER_SOCKET_PATH); 738 | } 739 | --------------------------------------------------------------------------------