dcwifi: Add Dual Channel Wi-Fi component packageslilik-openwrt-22.03
@ -0,0 +1,14 @@ | |||||
# Description | |||||
This directory contains package files for including Dual Channel Wi-Fi (dcwifi) components in an OpenWrt build. | |||||
# dcwifi Packages | |||||
The dcwifi packages can be found in the menuconfig in the following locations: | |||||
* dcstad: `Network -> Routing and Redirection` | |||||
* dcwapd: `Network -> Routing and Redirection` | |||||
* libdcwproto: `Libraries -> Networking` | |||||
* libdcwsocket: `Libraries -> Networking` | |||||
* macremapper: `Kernel modules -> Network Support` (listed as `kmod-macremapper`) | |||||
* mrmctl: `Utilities` |
@ -0,0 +1,49 @@ | |||||
# | |||||
# Copyright (C) 2019 EWSI | |||||
# | |||||
# This is free software, licensed under the GNU General Public License v2. | |||||
# See /LICENSE for more information. | |||||
# | |||||
include $(TOPDIR)/rules.mk | |||||
PKG_NAME:=dcstad | |||||
PKG_VERSION:=1.0.0 | |||||
PKG_RELEASE:=1 | |||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz | |||||
PKG_SOURCE_URL:=https://codeload.github.com/ewsi/$(PKG_NAME)/tar.gz/v$(PKG_VERSION)? | |||||
PKG_HASH:=3b146ea22bc5480d8264c5ea269831d25993673aa90a9e82dc2dc601a111da55 | |||||
PKG_MAINTAINER:=Carey Sonsino <careys@edgewaterwireless.com> | |||||
PKG_LICENSE:=Apache-2.0 | |||||
PKG_LICENSE_FILES:=COPYING | |||||
PKG_FIXUP:=autoreconf | |||||
PKG_INSTALL:=1 | |||||
PKG_BUILD_PARALLEL:=1 | |||||
include $(INCLUDE_DIR)/package.mk | |||||
define Package/dcstad | |||||
SECTION:=net | |||||
CATEGORY:=Network | |||||
SUBMENU:=Routing and Redirection | |||||
TITLE:=Dual-Channel WiFi client daemon | |||||
URL:=https://www.edgewaterwireless.com | |||||
DEPENDS:=+libdcwsocket +libdcwproto | |||||
endef | |||||
define Package/dcstad/description | |||||
Implementation of the Dual-Channel WiFi client daemon | |||||
endef | |||||
TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto | |||||
TARGET_LDFLAGS += -Wl,--gc-sections | |||||
define Package/dcstad/install | |||||
$(INSTALL_DIR) $(1)/bin | |||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/dcstad $(1)/bin/ | |||||
endef | |||||
$(eval $(call BuildPackage,dcstad)) |
@ -0,0 +1,11 @@ | |||||
--- a/src/main.c | |||||
+++ b/src/main.c | |||||
@@ -190,7 +190,7 @@ main( int argc, char *argv[] ) { | |||||
rv = 1; /* failure unless proven otherwise */ | |||||
/* first initialize and parse the command line */ | |||||
- bzero(&cfg, sizeof(cfg)); | |||||
+ memset(&cfg, 0, sizeof(cfg)); | |||||
parse_cmdline(&cfg, argc, argv); | |||||
dcwloginfof("%s\n", "DCW Station Daemon Starting Up..."); |
@ -0,0 +1,76 @@ | |||||
# | |||||
# Copyright (C) 2019 EWSI | |||||
# | |||||
# This is free software, licensed under the GNU General Public License v2. | |||||
# See /LICENSE for more information. | |||||
# | |||||
include $(TOPDIR)/rules.mk | |||||
PKG_NAME:=dcwapd | |||||
PKG_VERSION:=1.0.0 | |||||
PKG_RELEASE:=1 | |||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz | |||||
PKG_SOURCE_URL:=https://codeload.github.com/ewsi/$(PKG_NAME)/tar.gz/v$(PKG_VERSION)? | |||||
PKG_HASH:=750a08abccd88d9aeda942307f76ce5711181c06f9f3e8fded5cb5ce42bac323 | |||||
PKG_MAINTAINER:=Carey Sonsino <careys@edgewaterwireless.com> | |||||
PKG_LICENSE:=Apache-2.0 | |||||
PKG_LICENSE_FILES:=COPYING | |||||
PKG_FIXUP:=autoreconf | |||||
PKG_INSTALL:=1 | |||||
PKG_BUILD_PARALLEL:=1 | |||||
include $(INCLUDE_DIR)/uclibc++.mk | |||||
include $(INCLUDE_DIR)/package.mk | |||||
define Package/dcwapd | |||||
SECTION:=net | |||||
CATEGORY:=Network | |||||
SUBMENU:=Routing and Redirection | |||||
TITLE:=Dual-Channel WiFi AP daemon | |||||
URL:=https://www.edgewaterwireless.com | |||||
DEPENDS:=$(CXX_DEPENDS) +kmod-macremapper +libdcwsocket +libdcwproto +mrmctl +libuci | |||||
endef | |||||
define Package/dcwapd/description | |||||
Implementation of the Dual-Channel WiFi AP daemon | |||||
endef | |||||
CONFIGURE_ARGS += \ | |||||
--enable-platform=linuxjsonstatic \ | |||||
--enable-shared | |||||
TARGET_CXXFLAGS += -std=c++11 -DRAPIDJSON_HAS_CXX11_RVALUE_REFS=0 -ffunction-sections -fdata-sections -flto | |||||
TARGET_LDFLAGS += -ldcwproto -ldcwsocket -lmrmfilterparser -luci -Wl,--gc-sections,--as-needed | |||||
define Build/InstallDev | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/* $(1)/usr/lib/ | |||||
endef | |||||
define Package/dcwapd/install | |||||
$(INSTALL_DIR) $(1)/bin | |||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/bin/ | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
# Note: $(INSTALL_BIN) does not keep symlinks, so use $(CP) | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/ | |||||
# Utility files | |||||
$(INSTALL_DIR) $(1)/etc/$(PKG_NAME) | |||||
$(INSTALL_DATA) ./files/*.inc $(1)/etc/$(PKG_NAME)/ | |||||
$(INSTALL_BIN) ./files/*.sh $(1)/etc/$(PKG_NAME)/ | |||||
# UCI config file copy - this is here for convenience and reference only | |||||
$(INSTALL_DATA) ./files/dcwapd.uci $(1)/etc/$(PKG_NAME)/ | |||||
# UCI config file | |||||
$(INSTALL_DIR) $(1)/etc/config | |||||
$(INSTALL_DATA) ./files/dcwapd.uci $(1)/etc/config/dcwapd | |||||
# Init script | |||||
$(INSTALL_DIR) $(1)/etc/init.d | |||||
$(INSTALL_BIN) ./files/dcwapd.init.d $(1)/etc/init.d/dcwapd | |||||
endef | |||||
$(eval $(call BuildPackage,dcwapd)) |
@ -0,0 +1,256 @@ | |||||
#!/bin/sh | |||||
# | |||||
# Dual Channel Wi-Fi Startup Script | |||||
# | |||||
# This script creates the proper network bridge configuration | |||||
# necessary for Dual Channel Wi-Fi, and starts the dcwapd daemon | |||||
# | |||||
verbose=1 | |||||
uciconfig=dcwapd | |||||
result= | |||||
# NOTE: all functions write the result to the $result variable | |||||
get_channelsets() | |||||
{ | |||||
# default to empty | |||||
result= | |||||
channelsets=$(uci show $uciconfig | grep "=channel-set$") | |||||
for channelset in $channelsets; do | |||||
channelset=$(echo "$channelset" | sed -rn "s/$uciconfig\.(.*)=.*/\1/p") | |||||
result="$result $channelset" | |||||
done | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Channel Sets: $result" 2>&1 | logger | |||||
fi | |||||
} | |||||
# $1 : the channel set name | |||||
get_channelset_enabled() | |||||
{ | |||||
# default to disabled | |||||
result=0 | |||||
if [ -n "$1" ]; then | |||||
result=$(uci get $uciconfig."$1".enabled) | |||||
fi | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Channel Set \"$1\" Enabled: $result" 2>&1 | logger | |||||
fi | |||||
} | |||||
# $1 : the channel set name | |||||
get_primary_bridge() | |||||
{ | |||||
result= | |||||
if [ -n "$1" ]; then | |||||
result=$(uci get $uciconfig."$1".bridge) | |||||
fi | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Channel Set \"$1\" Primary Bridge: $result" 2>&1 | logger | |||||
fi | |||||
} | |||||
# $1 : the channel set name | |||||
get_datachannels() | |||||
{ | |||||
# default to empty | |||||
result= | |||||
if [ -n "$1" ]; then | |||||
result=$(uci get $uciconfig."$1".data_channels) | |||||
fi | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Channel Set \"$1\" Data Channels: $result" 2>&1 | logger | |||||
fi | |||||
} | |||||
# $1 : the wlan interface name | |||||
get_wifi_iface_num() | |||||
{ | |||||
result= | |||||
if [ -n "$1" ];then | |||||
#result=$(echo "$1" | sed -n "s/wlan//p") | |||||
result=$(echo "$1" | sed -rn "s/wlan([0-9]*).*/\1/p") | |||||
fi | |||||
} | |||||
# $1 : the bridge name | |||||
get_bridge_network_name() | |||||
{ | |||||
result= | |||||
if [ -n "$1" ];then | |||||
result=$(echo "$1" | sed -n "s/br-//p") | |||||
fi | |||||
} | |||||
# $1 : the wlan interface name | |||||
set_iface_init_state() | |||||
{ | |||||
result= | |||||
if [ -n "$1" ]; then | |||||
iface=$1 | |||||
# need to extract the "X" from wlanX | |||||
get_wifi_iface_num "$iface" | |||||
iface_num=$result | |||||
if [ -n "$iface_num" ]; then | |||||
# get the iface network | |||||
init_net=$(uci get wireless.@wifi-iface[$iface_num].network) | |||||
if [ -n "$init_net" ]; then | |||||
# if the iface network is a bridge, but doesn't start with "br-" | |||||
# I think we need to prepend it? | |||||
net_type=$(uci get network."$init_net".type) | |||||
if [ -n "$net_type" ] && [ "$net_type" = "bridge" ]; then | |||||
prefix_ok=$(echo "$init_net" | grep "^br-") | |||||
if [ -z "$prefix_ok" ]; then | |||||
init_net="br-$init_net" | |||||
fi | |||||
fi | |||||
fi | |||||
# make sure that the init_net section exists | |||||
init_net_section=$(uci get dcwapd.init_net) | |||||
if [ "$init_net_section" != "init_net" ]; then | |||||
# the section did not exist | |||||
uci set dcwapd.init_net=init_net | |||||
fi | |||||
# save the initial network | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Saving '$iface' initial network '$init_net'" 2>&1 | logger | |||||
fi | |||||
uci set $uciconfig.init_net."$iface"="$init_net" | |||||
uci commit | |||||
# save the initial network in the result variable | |||||
result=$init_net | |||||
fi | |||||
fi | |||||
} | |||||
# $1 : the wlan interface name | |||||
get_iface_init_state() | |||||
{ | |||||
result= | |||||
if [ -n "$1" ];then | |||||
init_net=$(uci get $uciconfig.init_net."$iface") | |||||
# if the response starts with "uci: ", it was an error not the real result | |||||
err=$(echo "$init_net" | grep "^uci: ") | |||||
if [ -z "$err" ]; then | |||||
# no error, set the result | |||||
result=$init_net | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Got '$iface' initial network '$init_net'" 2>&1 | logger | |||||
fi | |||||
fi | |||||
fi | |||||
} | |||||
# $1 : the name of the data channel name to bring up | |||||
datachannel_up() | |||||
{ | |||||
if [ -n "$1" ]; then | |||||
bridge=$(uci get $uciconfig."$1".bridge) | |||||
interfaces=$(uci get $uciconfig."$1".interfaces) | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Creating Data Channel Bridge: $bridge" 2>&1 | logger | |||||
fi | |||||
get_bridge_network_name "$bridge" | |||||
netname=$result | |||||
if [ -n "$netname" ]; then | |||||
uci set network."$netname"=interface | |||||
uci set network."$netname".type=bridge | |||||
uci set network."$netname".proto=static | |||||
uci set network."$netname".bridge_empty='1' | |||||
fi | |||||
# create the bridge | |||||
uci commit | |||||
/etc/init.d/network reload | |||||
for iface in $interfaces; do | |||||
# if iface is in a bridge, the bridge name should be stored in result | |||||
set_iface_init_state "$iface" | |||||
init_bridge=$result | |||||
# update uci with the new bridge info | |||||
get_wifi_iface_num "$iface" | |||||
iface_num=$result | |||||
if [ -n "$iface_num" ]; then | |||||
uci set wireless.@wifi-iface[$iface_num].network="$netname" | |||||
fi | |||||
# manually put the interface into the data bridge | |||||
# if iface is in a bridge, remove it before adding it to the data bridge | |||||
if [ -n "$init_bridge" ]; then | |||||
brctl delif "$init_bridge" "$iface" 2>&1 | logger | |||||
fi | |||||
brctl addif "$bridge" "$iface" 2>&1 | logger | |||||
done | |||||
# commit uci changes and reload the network | |||||
uci commit | |||||
/etc/init.d/network reload | |||||
#/etc/init.d/network restart | |||||
# while [ 1 ]; do | |||||
# ifconfig "$bridge" > /dev/null 2>&1 | |||||
# if [ $? == 0 ]; then | |||||
# break; | |||||
# fi | |||||
# sleep 1 | |||||
# done | |||||
fi | |||||
} | |||||
# $1 : the name of the data channel to bring down | |||||
datachannel_down() | |||||
{ | |||||
if [ -n "$1" ]; then | |||||
bridge=$(uci get $uciconfig."$1".bridge) | |||||
interfaces=$(uci get $uciconfig."$1".interfaces) | |||||
for iface in $interfaces; do | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Deconfiguring Data Channel Interface: $iface" 2>&1 | logger | |||||
fi | |||||
# manually remove the interface from the data bridge | |||||
brctl delif "$bridge" "$iface" 2>&1 | logger | |||||
get_iface_init_state "$iface" | |||||
init_bridge=$result | |||||
if [ -n "$init_bridge" ]; then | |||||
# manually move the interface back to the original bridge | |||||
brctl addif "$init_bridge" "$iface" 2>&1 | logger | |||||
# update uci with the new bridge and interface configuration | |||||
get_wifi_iface_num "$iface" | |||||
iface_num=$result | |||||
get_bridge_network_name "$init_bridge" | |||||
netname=$result | |||||
if [ -n "$iface_num" ] && [ -n "$netname" ]; then | |||||
uci set wireless.@wifi-iface[$iface_num].network="$netname" | |||||
fi | |||||
fi | |||||
done | |||||
if [ $verbose -eq 1 ]; then | |||||
echo "Deconfiguring Data Channel Bridge: $bridge" 2>&1 | logger | |||||
fi | |||||
# delete the bridge from uci | |||||
get_bridge_network_name "$bridge" | |||||
netname=$result | |||||
if [ -n "$netname" ]; then | |||||
uci delete network."$netname" | |||||
fi | |||||
# commit uci changes and reload the network | |||||
uci commit | |||||
/etc/init.d/network reload | |||||
#`/etc/init.d/network restart` | |||||
fi | |||||
} |
@ -0,0 +1,31 @@ | |||||
#!/bin/sh /etc/rc.common | |||||
START=99 | |||||
# Setting the stop value makes the restart script unreliable when invoked by LuCI | |||||
#STOP=0 | |||||
scriptdir=/etc/dcwapd | |||||
#validate_section_dcwapd() { | |||||
# uci_validate_section dcwapd general "${1}" \ | |||||
# 'enabled:bool:1' | |||||
#} | |||||
start() { | |||||
# validate_section_dcwapd dcwapd | |||||
# only run the start script if the enabled uci option is set properly | |||||
enabled=$(uci get dcwapd.general.enabled) | |||||
if [ "${enabled}" = "1" ]; then | |||||
${scriptdir}/start_dcwapd.sh | |||||
else | |||||
echo "dcwapd is disabled in UCI" | |||||
return 1 | |||||
fi | |||||
} | |||||
stop() { | |||||
${scriptdir}/stop_dcwapd.sh | |||||
# Add a sleep after stopping because an immediate restat will fail otherwise | |||||
sleep 1 | |||||
} |
@ -0,0 +1,116 @@ | |||||
###################################################### | |||||
# Copyright 2018 EWSI | |||||
# | |||||
# Licensed to the public under the Apache License 2.0. | |||||
###################################################### | |||||
# Dual Channel Wi-Fi AP Daemon configuration | |||||
################### | |||||
# General Options # | |||||
################### | |||||
# The "enabled" option controls the run state of the Dual Channel Wi-Fi AP Daemon | |||||
# 0 - disabled, 1 - enabled | |||||
# The "tmpdir" option MUST be specified | |||||
# option tmpdir '<path_of_temp_dir>' | |||||
config general 'general' | |||||
option enabled 0 | |||||
option tmpdir '/tmp/dcwapd' | |||||
################ | |||||
# Channel Sets # | |||||
################ | |||||
# Sections of type "channel-set" define a Dual Channel Wi-Fi primary channel, | |||||
# along with it's associated data channels | |||||
# | |||||
# The "data_channels" option is a space-delimited list of "datachannel"-typed instance names | |||||
config channel-set 'channelset0' | |||||
option enabled 0 | |||||
# option enabled 1 | |||||
option ssid 'OpenWrt' | |||||
option bridge 'br-lan' | |||||
option data_channels 'datachannel0' | |||||
#config channel-set 'channelset1' | |||||
# option enabled 0 | |||||
# option ssid 'OpenWrt2' | |||||
# option bridge 'br-lan' | |||||
# option data_channels 'datachannel1' | |||||
################# | |||||
# Data Channels # | |||||
################# | |||||
# Sections of type "datachannel" define a Dual Channel Wi-Fi data channel, | |||||
# along with it's associated bridge and wireless interfaces | |||||
# | |||||
# The "interfaces" option is a space-delimited list of wireless interface names | |||||
config datachannel 'datachannel0' | |||||
option ssid 'DCW0' | |||||
option bridge 'br-dc0' | |||||
option interfaces 'wlan2 wlan5' | |||||
#config datachannel 'datachannel1' | |||||
# option ssid 'DCW1' | |||||
# option bridge 'br-dc1' | |||||
# option interfaces 'wlan4' | |||||
#################### | |||||
# Init Net Options # | |||||
#################### | |||||
# The "init_net" section MUST be specified | |||||
# This section will be used to save and restore the state of the data interfaces | |||||
config init_net 'init_net' | |||||
############### | |||||
# Filter Sets # | |||||
############### | |||||
# Sections of type "filter-set" define a Dual Channel Wi-Fi group of filters, | |||||
# along with it's associated MAC address and filter rules | |||||
# | |||||
# The "TFP_Default" filter set MUST be defined, although it is not required | |||||
# to have any associated filter rules | |||||
# The "TFP_Default" filter mac option can have the value of '*', meaning match | |||||
# all MAC addresses | |||||
# | |||||
# The "filters" option is a space-delimited list of "filter"-typed instance names | |||||
config filter-set 'TFP_Default' | |||||
option mac '*' | |||||
option filters 'filter0 filter1' | |||||
#config filter-set 'filterset0' | |||||
# option mac '00:00:BE:EF:F0:0D' | |||||
# option filters 'filter2' | |||||
################ | |||||
# Filter Rules # | |||||
################ | |||||
# Sections of type "filter" define a Dual Channel Wi-Fi filter, | |||||
# along with it's associated filter parameters | |||||
# | |||||
# Any or all of the filter options may be set to '*' to match | |||||
# all values | |||||
config filter 'filter0' | |||||
option packet_size '*' | |||||
option source_ip '*' | |||||
option source_port '80' | |||||
option protocol 'tcp' | |||||
option dest_port '*' | |||||
config filter 'filter1' | |||||
option packet_size '*' | |||||
option source_ip '*' | |||||
option source_port '443' | |||||
option protocol 'tcp' | |||||
option dest_port '*' | |||||
#config filter 'filter2' | |||||
# option packet_size '*' | |||||
# option source_ip '*' | |||||
# option source_port '22' | |||||
# option protocol 'tcp' | |||||
# option dest_port '*' |
@ -0,0 +1,39 @@ | |||||
#!/bin/sh | |||||
# | |||||
# Dual Channel Wi-Fi Startup Script | |||||
# | |||||
# This script creates the proper network bridge configuration | |||||
# necessary for Dual Channel Wi-Fi, and starts the dcwapd daemon | |||||
# | |||||
# Note - shellcheck cannot deal with the dynamic sourcing | |||||
# shellcheck disable=SC1090 | |||||
# which also messes with variables defined in the sourced file | |||||
# shellcheck disable=SC2154 | |||||
scriptdir=$(dirname -- "$(readlink -f -- "$0")") | |||||
. "$scriptdir"/dcwapd.inc | |||||
get_channelsets | |||||
# get the list of channel sets | |||||
channelsets=$result | |||||
for channelset in $channelsets; do | |||||
if [ -n "$channelset" ]; then | |||||
get_channelset_enabled "$channelset" | |||||
enabled=$result | |||||
if [ "$enabled" = "1" ]; then | |||||
# the channel set is enabled | |||||
# get the list of data channels used by the channel set | |||||
get_datachannels "$channelset" | |||||
datachannels=$result | |||||
for datachannel in $datachannels; do | |||||
datachannel_up "$datachannel" | |||||
done | |||||
fi | |||||
fi | |||||
done | |||||
# start dcwapd, sending stdout and stderr to the system log | |||||
dcwapd 2>&1 | logger & |
@ -0,0 +1,45 @@ | |||||
#!/bin/sh | |||||
# | |||||
# Dual Channel Wi-Fi Startup Script | |||||
# | |||||
# This script creates the proper network bridge configuration | |||||
# necessary for Dual Channel Wi-Fi, and starts the dcwapd daemon | |||||
# | |||||
# Note - shellcheck cannot deal with the dynamic sourcing | |||||
# shellcheck disable=SC1090 | |||||
# which also messes with variables defined in the sourced file | |||||
# shellcheck disable=SC2154 | |||||
scriptdir=$(dirname -- "$(readlink -f -- "$0")") | |||||
. "$scriptdir"/dcwapd.inc | |||||
pid=$(pidof dcwapd) | |||||
if [ -n "$pid" ]; then | |||||
if [ "$verbose" -eq "1" ]; then | |||||
echo "Stopping dcwapd..." 2>&1 | logger | |||||
fi | |||||
kill "$pid" | |||||
fi | |||||
get_channelsets | |||||
# get the list of channel sets | |||||
channelsets=$result | |||||
for channelset in $channelsets; do | |||||
if [ -n "$channelset" ]; then | |||||
# we don't care if it is enabled, tear it down | |||||
# get_channelset_enabled $channelset | |||||
# enabled=$result | |||||
# if [ $enabled = "1" ]; then | |||||
# # the channel set is enabled | |||||
# get the list of data channels used by the channel set | |||||
get_datachannels "$channelset" | |||||
datachannels=$result | |||||
for datachannel in $datachannels; do | |||||
datachannel_down "$datachannel" | |||||
done | |||||
# fi | |||||
fi | |||||
done |
@ -0,0 +1,475 @@ | |||||
--- a/dev/null | |||||
+++ b/dcwlinux/uci_configuration_provider.h | |||||
@@ -0,0 +1,104 @@ | |||||
+#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED | |||||
+#define UCI_CONFIGURATION_PROVIDER_H_INCLUDED | |||||
+ | |||||
+#include "./ap_configuration.h" | |||||
+ | |||||
+namespace dcwlinux { | |||||
+ | |||||
+class UciConfigurationProvider : public APConfigurationProvider { | |||||
+ | |||||
+ static const char *SECTION_TYPE_GENERAL; | |||||
+ static const char *SECTION_TYPE_CHANNEL_SET; | |||||
+ static const char *SECTION_TYPE_DATA_CHANNEL; | |||||
+ static const char *SECTION_TYPE_FILTER_SET; | |||||
+ static const char *SECTION_TYPE_FILTER; | |||||
+ static const char *DEFAULT_FILTER_SET_NAME; | |||||
+ | |||||
+ static const char *OPTION_TMPDIR; | |||||
+ static const char *OPTION_ENABLED; | |||||
+ static const char *OPTION_SSID; | |||||
+ static const char *OPTION_BRIDGE; | |||||
+ static const char *OPTION_DATA_CHANNELS; | |||||
+ static const char *OPTION_INTERFACES; | |||||
+ static const char *OPTION_MAC_ADDRESS; | |||||
+ static const char *OPTION_FILTERS; | |||||
+ static const char *OPTION_PACKET_SIZE; | |||||
+ static const char *OPTION_SOURCE_IP; | |||||
+ static const char *OPTION_SOURCE_PORT; | |||||
+ static const char *OPTION_PROTOCOL; | |||||
+ static const char *OPTION_DEST_PORT; | |||||
+ | |||||
+ static const char *FILTER_FILE_EXTENSION; | |||||
+ | |||||
+ UciConfigurationProvider(const UciConfigurationProvider&); //no copy | |||||
+ | |||||
+ typedef std::map<std::string, std::string> DataChannelBridgeMap; | |||||
+ struct PrimaryChannel { | |||||
+ std::string bridgeName; | |||||
+ DataChannelBridgeMap dataChannels; | |||||
+ }; | |||||
+ typedef std::map<std::string, PrimaryChannel> PrimaryChannelMap; | |||||
+ typedef std::map<dcw::MacAddress, std::string> StationFilterMap; | |||||
+ | |||||
+ struct uci_context *_uciContext; | |||||
+ struct uci_package *_uciPackage; | |||||
+ const char *_uciConfig; | |||||
+ | |||||
+ std::string _filterDirectory; | |||||
+ PrimaryChannelMap _primaryChannels; | |||||
+ StationFilterMap _stationFilters; | |||||
+ | |||||
+public: | |||||
+ UciConfigurationProvider(const char * const uciConfig); // the "config" part of UCI commands | |||||
+ virtual ~UciConfigurationProvider(); | |||||
+ | |||||
+ virtual void InstanciateCFileTrafficFilterProfiles(CFTFPList& output) const; | |||||
+ virtual void GetPrimarySsids(SsidSet& output) const; | |||||
+ virtual void GetDataSsids(SsidSet& output, const char * const primarySsid) const; | |||||
+ virtual const char *GetSsidIfname(const char * const ssid) const; | |||||
+ virtual void GetStationTrafficFilterProfiles(StationTFPMap& output) const; | |||||
+}; | |||||
+ | |||||
+}; //namespace dcwlinux { | |||||
+ | |||||
+#endif //#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED | |||||
+#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED | |||||
+#define UCI_CONFIGURATION_PROVIDER_H_INCLUDED | |||||
+ | |||||
+#include "./ap_configuration.h" | |||||
+ | |||||
+namespace dcwlinux { | |||||
+ | |||||
+class UciConfigurationProvider : public APConfigurationProvider { | |||||
+ UciConfigurationProvider(const UciConfigurationProvider&); //no copy | |||||
+ | |||||
+ typedef std::map<std::string, std::string> DataChannelBridgeMap; | |||||
+ struct PrimaryChannel { | |||||
+ std::string bridgeName; | |||||
+ DataChannelBridgeMap dataChannels; | |||||
+ }; | |||||
+ typedef std::map<std::string, PrimaryChannel> PrimaryChannelMap; | |||||
+ typedef std::map<dcw::MacAddress, std::string> StationFilterMap; | |||||
+ | |||||
+ struct uci_context *_uciContext; | |||||
+ struct uci_package *_uciPackage; | |||||
+ const char *_uciConfig; | |||||
+ | |||||
+ PrimaryChannelMap _primaryChannels; | |||||
+ StationFilterMap _stationFilters; | |||||
+ CFTFPList _defaultFilters; | |||||
+ | |||||
+public: | |||||
+ UciConfigurationProvider(const char * const uciConfig); // the "config" part of UCI commands | |||||
+ virtual ~UciConfigurationProvider(); | |||||
+ | |||||
+ virtual void InstanciateCFileTrafficFilterProfiles(CFTFPList& output) const; | |||||
+ virtual void GetPrimarySsids(SsidSet& output) const; | |||||
+ virtual void GetDataSsids(SsidSet& output, const char * const primarySsid) const; | |||||
+ virtual const char *GetSsidIfname(const char * const ssid) const; | |||||
+ virtual void GetStationTrafficFilterProfiles(StationTFPMap& output) const; | |||||
+}; | |||||
+ | |||||
+}; //namespace dcwlinux { | |||||
+ | |||||
+#endif //#ifndef UCI_CONFIGURATION_PROVIDER_H_INCLUDED | |||||
--- a/dev/null | |||||
+++ b/dcwlinux/uci_configuration_provider.cxx | |||||
@@ -0,0 +1,365 @@ | |||||
+ | |||||
+#include <uci.h> | |||||
+#include <string.h> | |||||
+ | |||||
+#include <stdlib.h> | |||||
+#include <stdexcept> | |||||
+#include <sys/stat.h> | |||||
+#include <cerrno> | |||||
+#include <iostream> | |||||
+#include <fstream> | |||||
+ | |||||
+#include "./uci_configuration_provider.h" | |||||
+ | |||||
+#include "dcwposix/filterdirscanner.h" | |||||
+#include "dcw/macaddress.h" | |||||
+#include "dcw/dcwlog.h" | |||||
+ | |||||
+using namespace dcwlinux; | |||||
+ | |||||
+ const char *UciConfigurationProvider::SECTION_TYPE_GENERAL = "general"; | |||||
+ const char *UciConfigurationProvider::SECTION_TYPE_CHANNEL_SET = "channel-set"; | |||||
+ const char *UciConfigurationProvider::SECTION_TYPE_DATA_CHANNEL = "datachannel"; | |||||
+ const char *UciConfigurationProvider::SECTION_TYPE_FILTER_SET = "filter-set"; | |||||
+ const char *UciConfigurationProvider::SECTION_TYPE_FILTER = "filter"; | |||||
+ const char *UciConfigurationProvider::DEFAULT_FILTER_SET_NAME = "TFP_Default"; | |||||
+ | |||||
+ const char *UciConfigurationProvider::OPTION_TMPDIR = "tmpdir"; | |||||
+ const char *UciConfigurationProvider::OPTION_ENABLED = "enabled"; | |||||
+ const char *UciConfigurationProvider::OPTION_SSID = "ssid"; | |||||
+ const char *UciConfigurationProvider::OPTION_BRIDGE = "bridge"; | |||||
+ const char *UciConfigurationProvider::OPTION_DATA_CHANNELS = "data_channels"; | |||||
+ const char *UciConfigurationProvider::OPTION_INTERFACES = "interfaces"; | |||||
+ const char *UciConfigurationProvider::OPTION_MAC_ADDRESS = "mac"; | |||||
+ const char *UciConfigurationProvider::OPTION_FILTERS = "filters"; | |||||
+ const char *UciConfigurationProvider::OPTION_PACKET_SIZE = "packet_size"; | |||||
+ const char *UciConfigurationProvider::OPTION_SOURCE_IP = "source_ip"; | |||||
+ const char *UciConfigurationProvider::OPTION_SOURCE_PORT = "source_port"; | |||||
+ const char *UciConfigurationProvider::OPTION_PROTOCOL = "protocol"; | |||||
+ const char *UciConfigurationProvider::OPTION_DEST_PORT = "dest_port"; | |||||
+ | |||||
+ const char *UciConfigurationProvider::FILTER_FILE_EXTENSION = ".tfp"; | |||||
+ | |||||
+ UciConfigurationProvider::UciConfigurationProvider(const char * const uciConfig) : _uciConfig(uciConfig) { | |||||
+ | |||||
+ //printf("*** Start UciConfigurationProvider(%s)\n", _uciConfig); | |||||
+ //printf("*** About to uci_alloc_context()\n"); | |||||
+ | |||||
+ _uciContext = uci_alloc_context(); | |||||
+ | |||||
+ //printf("*** uci_alloc_context() complete\n"); | |||||
+ //printf("*** About to uci_load()\n"); | |||||
+ | |||||
+ if (_uciContext == NULL) | |||||
+ { | |||||
+ std::string err = "Error creating UCI context "; | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ | |||||
+ uci_load(_uciContext, _uciConfig, &_uciPackage); | |||||
+ | |||||
+ //printf("*** uci_load complete()\n"); | |||||
+ | |||||
+ if (_uciPackage == NULL) | |||||
+ { | |||||
+ std::string err = "Error loading UCI package " + std::string(_uciConfig); | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ | |||||
+ uci_section *generalSection = uci_lookup_section(_uciContext, _uciPackage, UciConfigurationProvider::SECTION_TYPE_GENERAL); | |||||
+ if (generalSection == NULL) | |||||
+ { | |||||
+ std::string err = "Error: A general section (" + std::string(UciConfigurationProvider::SECTION_TYPE_GENERAL) + ") must be specified!"; | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ | |||||
+ uci_option *opt_tmpdir = uci_lookup_option(_uciContext, generalSection, UciConfigurationProvider::OPTION_TMPDIR); | |||||
+ if (opt_tmpdir == NULL) | |||||
+ { | |||||
+ std::string err = "Error: A temporary directory (" + std::string(UciConfigurationProvider::OPTION_TMPDIR) + ") must be specified!"; | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ char *tmpdir = opt_tmpdir->v.string; | |||||
+ //printf(" *** Set tmpdir: %s\n", tmpdir); | |||||
+ | |||||
+ // make sure that tmpdir exists | |||||
+ int status = mkdir(tmpdir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); | |||||
+ if ((status != 0) && // failure | |||||
+ (errno != EEXIST)) // the failure was not that the directory already existed | |||||
+ { | |||||
+ std::string err = "Error: Unable to create the temporary directory (tmpdir), error # " + errno; | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ _filterDirectory = std::string(tmpdir); | |||||
+ | |||||
+ if (uci_lookup_section(_uciContext, _uciPackage, UciConfigurationProvider::DEFAULT_FILTER_SET_NAME) == NULL) | |||||
+ { | |||||
+ std::string err = "Error: A default traffic filter profile named " + std::string(UciConfigurationProvider::DEFAULT_FILTER_SET_NAME) + " MUST exist!"; | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ | |||||
+ // iterate over all of the sections in the package | |||||
+ uci_element *elem; | |||||
+ uci_foreach_element(&_uciPackage->sections, elem) | |||||
+ { | |||||
+ //printf("--==-- element.type: %d\n", elem->type); | |||||
+ //printf("--==-- element.name: %s\n", elem->name); | |||||
+ | |||||
+ if (elem->type == UCI_TYPE_SECTION) | |||||
+ { | |||||
+ // look up the section and get it's type | |||||
+ | |||||
+ uci_section *section = NULL; | |||||
+ //printf("*** Looking up section: %s\n", elem->name); | |||||
+ | |||||
+ section = uci_lookup_section(_uciContext, _uciPackage, elem->name); | |||||
+ | |||||
+ if ((section != NULL) && (section->type != NULL)) | |||||
+ { | |||||
+ //printf(" *** Section type: %s\n", section->type); | |||||
+ if (strcmp(elem->name, UciConfigurationProvider::SECTION_TYPE_GENERAL) == 0) | |||||
+ { | |||||
+ // we already processed the general section for the tmpdir | |||||
+ } | |||||
+ else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_CHANNEL_SET) == 0) | |||||
+ { | |||||
+ // the section is a channel set, populate it with the specified values | |||||
+ | |||||
+ uci_option *enabled = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_ENABLED); | |||||
+ if ((enabled == NULL) || (strcmp(enabled->v.string, "1") != 0)) | |||||
+ { | |||||
+ // found a disabled channel set, ignore it | |||||
+ continue; | |||||
+ } | |||||
+ | |||||
+ uci_option *ssid = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_SSID); | |||||
+ uci_option *bridge = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_BRIDGE); | |||||
+ uci_option *dataChannels = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_DATA_CHANNELS); | |||||
+ | |||||
+ if ((ssid != NULL) && (bridge != NULL) && (dataChannels != NULL)) | |||||
+ { | |||||
+ PrimaryChannel &pc = _primaryChannels[ssid->v.string]; | |||||
+ pc.bridgeName = bridge->v.string; | |||||
+ | |||||
+ char dataChannels_list[255]; | |||||
+ // The dataChannels option is not a list | |||||
+ //if (dataChannels->type == UCI_TYPE_LIST) | |||||
+ if (dataChannels->v.string != NULL) | |||||
+ { | |||||
+ strcpy(dataChannels_list, dataChannels->v.string); | |||||
+ std::string str_dataChannels = dataChannels->v.string; | |||||
+ size_t start_pos = 0; | |||||
+ size_t pos = 0; | |||||
+ while(start_pos != std::string::npos) | |||||
+ { | |||||
+ pos = str_dataChannels.find(" ", start_pos); | |||||
+ //printf("****** start_pos: %u, pos: %u\n", start_pos, pos); | |||||
+ std::string str_dataChannel = str_dataChannels.substr(start_pos, | |||||
+ pos == std::string::npos ? pos : pos-start_pos); | |||||
+ //printf("*** dataChannel: %s\n", str_dataChannel.c_str()); | |||||
+ | |||||
+ // update the start position for next loop | |||||
+ start_pos = (pos == std::string::npos ? pos : pos+1); | |||||
+ | |||||
+ uci_section *dcSection = uci_lookup_section(_uciContext, _uciPackage, str_dataChannel.c_str()); | |||||
+ if (dcSection != NULL) | |||||
+ { | |||||
+ uci_option *dcSsid = uci_lookup_option(_uciContext, dcSection, UciConfigurationProvider::OPTION_SSID); | |||||
+ uci_option *dcBridge = uci_lookup_option(_uciContext, dcSection, UciConfigurationProvider::OPTION_BRIDGE); | |||||
+ | |||||
+ // TODO: configure dcBridge and dcInterfaces | |||||
+ //uci_option *dcInterfaces = uci_lookup_option(_uciContext, dcSection, UciConfigurationProvider::OPTION_INTERFACES); | |||||
+ | |||||
+ if ((dcSsid != NULL) && (dcBridge != NULL)) | |||||
+ { | |||||
+ pc.dataChannels[dcSsid->v.string]; | |||||
+ pc.dataChannels[dcSsid->v.string] = dcBridge->v.string; | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ //printf("Section: %s, SSID: %s, Bridge: %s, Data Channels: %s\n", section->e.name, ssid->v.string, bridge->v.string, dataChannels_list); | |||||
+ } | |||||
+ } | |||||
+ else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_DATA_CHANNEL) == 0) | |||||
+ { | |||||
+ // data channels are processed by the channel set | |||||
+ } | |||||
+ else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_FILTER_SET) == 0) | |||||
+ { | |||||
+ // the section is a filter set, populate it with the specified values | |||||
+ //printf("*** filter set: %s\n", elem->name); | |||||
+ | |||||
+ // create a tfp file for the sectionName | |||||
+ std::ofstream tfpFile; | |||||
+ std::string tfpFilePath = | |||||
+ tmpdir + std::string("/") + | |||||
+ std::string(elem->name) + | |||||
+ std::string(UciConfigurationProvider::FILTER_FILE_EXTENSION); | |||||
+ tfpFile.open(tfpFilePath.c_str(), std::ios::out | std::ios::trunc); | |||||
+ if (!tfpFile.is_open()) | |||||
+ { | |||||
+ std::string err = "Error: Unable to open the filter file: " + tfpFilePath; | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ | |||||
+ const char *filterDelimiter = "\n"; | |||||
+ char sFilterContents[2048]; | |||||
+ sFilterContents[0] = '\0'; | |||||
+ | |||||
+ uci_option *filters = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_FILTERS); | |||||
+ // The filters option is not a list | |||||
+ //if ((filters != NULL) && (filters->type == UCI_TYPE_LIST)) | |||||
+ if (filters != NULL) | |||||
+ { | |||||
+ //printf("*** %s.filters is a list.\n", elem->name); | |||||
+ //struct uci_element *e; | |||||
+ //uci_foreach_element(&filters->v.list, e) | |||||
+ | |||||
+ std::string str_filters = filters->v.string; | |||||
+ //printf("*** STR_FILTERS: %s\n", str_filters.c_str()); | |||||
+ size_t start_pos = 0; | |||||
+ size_t pos = 0; | |||||
+ while(start_pos != std::string::npos) | |||||
+ { | |||||
+ pos = str_filters.find(" ", start_pos); | |||||
+ //printf("****** start_pos: %u, pos: %u\n", start_pos, pos); | |||||
+ std::string str_filter = str_filters.substr(start_pos, | |||||
+ pos == std::string::npos ? pos : pos-start_pos); | |||||
+ //printf("*** Looking for filter section named: %s ...\n", str_filter.c_str()); | |||||
+ | |||||
+ // update the start position for next loop | |||||
+ start_pos = (pos == std::string::npos ? pos : pos+1); | |||||
+ | |||||
+ uci_section *fSection = uci_lookup_section(_uciContext, _uciPackage, str_filter.c_str()); | |||||
+ if (fSection != NULL) | |||||
+ { | |||||
+ uci_option *fPacketSize = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_PACKET_SIZE); | |||||
+ uci_option *fSourceIp = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_SOURCE_IP); | |||||
+ uci_option *fSourcePort = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_SOURCE_PORT); | |||||
+ uci_option *fProtocol = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_PROTOCOL); | |||||
+ uci_option *fDestPort = uci_lookup_option(_uciContext, fSection, UciConfigurationProvider::OPTION_DEST_PORT); | |||||
+ | |||||
+ if ((fPacketSize != NULL) && | |||||
+ (fSourceIp != NULL) && | |||||
+ (fSourcePort != NULL) && | |||||
+ (fProtocol != NULL) && | |||||
+ (fDestPort != NULL)) | |||||
+ { | |||||
+ //printf("*** filter: %s %s:%s:%s:%s:%s\n", e->name, | |||||
+ // fPacketSize->v.string, fSourceIp->v.string, fSourcePort->v.string, | |||||
+ // fProtocol->v.string, fDestPort->v.string); | |||||
+ | |||||
+ strcpy(sFilterContents, fPacketSize->v.string); | |||||
+ strcat(sFilterContents, ":"); | |||||
+ strcat(sFilterContents, fSourceIp->v.string); | |||||
+ strcat(sFilterContents, ":"); | |||||
+ strcat(sFilterContents, fSourcePort->v.string); | |||||
+ strcat(sFilterContents, ":"); | |||||
+ strcat(sFilterContents, fProtocol->v.string); | |||||
+ strcat(sFilterContents, ":"); | |||||
+ strcat(sFilterContents, fDestPort->v.string); | |||||
+ strcat(sFilterContents, filterDelimiter); | |||||
+ | |||||
+ //printf("*** Writing filter contents to file: %s\n", sFilterContents); | |||||
+ tfpFile << sFilterContents; | |||||
+ } | |||||
+ else | |||||
+ { | |||||
+ std::string err = "Error parsing filter: " + str_filter; | |||||
+ throw std::runtime_error(err); | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ tfpFile.close(); | |||||
+ | |||||
+ // if there is a MAC address for the filter set, we need to add it to the station filters list | |||||
+ uci_option *mac = uci_lookup_option(_uciContext, section, UciConfigurationProvider::OPTION_MAC_ADDRESS); | |||||
+ if (mac != NULL) | |||||
+ { | |||||
+ // ignore wildcard MAC address | |||||
+ if (strcmp(mac->v.string,"*") != 0) | |||||
+ { | |||||
+ //printf(" *** MAC Address: %s\n", mac->v.string); | |||||
+ _stationFilters[::dcw::MacAddress(mac->v.string)] = elem->name; | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ else if (strcmp(section->type, UciConfigurationProvider::SECTION_TYPE_FILTER) == 0) | |||||
+ { | |||||
+ // filters are processed by the filter set | |||||
+ } | |||||
+ else | |||||
+ { | |||||
+ //std::string err = "Error: Unknown UCI section type: " + std::string(section->type); | |||||
+ //throw std::runtime_error(err); | |||||
+ | |||||
+ // Don't throw an exception. It is fine for UCI to contain things that we do not know about | |||||
+ // that it may use for other purposes, like UI or internal state | |||||
+ dcwlogdbgf("Ignoring UCI section type: %s\n", section->type); | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ UciConfigurationProvider::~UciConfigurationProvider() { | |||||
+ uci_free_context(_uciContext); | |||||
+ } | |||||
+ | |||||
+ void UciConfigurationProvider::InstanciateCFileTrafficFilterProfiles(CFTFPList& output) const { | |||||
+ ::dcwposix::FilterdirScanner::FileFilterProfileList ffpl; | |||||
+ ::dcwposix::FilterdirScanner dirScanner(_filterDirectory.c_str()); | |||||
+ dirScanner.Scan(ffpl); | |||||
+ | |||||
+ for (::dcwposix::FilterdirScanner::FileFilterProfileList::const_iterator i = ffpl.begin(); i != ffpl.end(); i++) { | |||||
+ output.push_back(new ::dcw::FileTrafficFilterProfile(*i)); | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ | |||||
+ void UciConfigurationProvider::GetPrimarySsids(SsidSet& output) const { | |||||
+ for (PrimaryChannelMap::const_iterator i = _primaryChannels.begin(); i != _primaryChannels.end(); i++) { | |||||
+ output.insert(i->first); | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ void UciConfigurationProvider::GetDataSsids(SsidSet& output, const char * const primarySsid) const { | |||||
+ const PrimaryChannelMap::const_iterator pssid = _primaryChannels.find(primarySsid); | |||||
+ if (pssid == _primaryChannels.end()) return; | |||||
+ | |||||
+ for (DataChannelBridgeMap::const_iterator i = pssid->second.dataChannels.begin(); i != pssid->second.dataChannels.end(); i++) { | |||||
+ output.insert(i->first); | |||||
+ } | |||||
+ } | |||||
+ | |||||
+ const char *UciConfigurationProvider::GetSsidIfname(const char * const ssid) const { | |||||
+ PrimaryChannelMap::const_iterator pssid = _primaryChannels.find(ssid); | |||||
+ if (pssid != _primaryChannels.end()) { | |||||
+ if (pssid->second.bridgeName.empty()) { | |||||
+ return NULL; | |||||
+ } | |||||
+ return pssid->second.bridgeName.c_str(); | |||||
+ } | |||||
+ | |||||
+ for (pssid = _primaryChannels.begin(); pssid != _primaryChannels.end(); pssid++) { | |||||
+ const DataChannelBridgeMap& dataChannels = pssid->second.dataChannels; | |||||
+ const DataChannelBridgeMap::const_iterator dc = dataChannels.find(ssid); | |||||
+ if (dc == dataChannels.end()) continue; | |||||
+ if (dc->second.empty()) { | |||||
+ return NULL; | |||||
+ } | |||||
+ return dc->second.c_str(); | |||||
+ } | |||||
+ | |||||
+ return NULL; | |||||
+ } | |||||
+ | |||||
+ void UciConfigurationProvider::GetStationTrafficFilterProfiles(StationTFPMap& output) const { | |||||
+ for (StationFilterMap::const_iterator i = _stationFilters.begin(); i != _stationFilters.end(); i++) { | |||||
+ output[i->first] = i->second; | |||||
+ } | |||||
+ | |||||
+ } |
@ -0,0 +1,20 @@ | |||||
--- a/dcwapd.linuxjsonstatic/main.cxx | |||||
+++ b/dcwapd.linuxjsonstatic/main.cxx | |||||
@@ -10,6 +10,7 @@ | |||||
#include "dcwlinux/ap_configuration.h" | |||||
#include "dcwlinux/vap_manager.h" | |||||
#include "dcwlinux/json_configuration_provider.h" | |||||
+#include "dcwlinux/uci_configuration_provider.h" | |||||
#include "dcw/dcwlog.h" | |||||
@@ -19,7 +20,8 @@ int | |||||
main( void ) { | |||||
try { | |||||
- dcwlinux::JsonConfigurationProvider configProvider("./dcwapdconf.json"); | |||||
+ //dcwlinux::JsonConfigurationProvider configProvider("./dcwapdconf.json"); | |||||
+ dcwlinux::UciConfigurationProvider configProvider("dcwapd"); | |||||
dcwposix::ProcessSignalManager sigman; | |||||
dcwposix::SelectEventReactor eventReactor; |
@ -0,0 +1,10 @@ | |||||
--- a/dcwlinux/Makefile.am | |||||
+++ b/dcwlinux/Makefile.am | |||||
@@ -6,6 +6,7 @@ libdcwlinux_la_SOURCES = | |||||
ap_configuration.cxx \ | |||||
brctlnetwork.cxx \ | |||||
json_configuration_provider.cxx \ | |||||
+ uci_configuration_provider.cxx \ | |||||
macremapper_driver.cxx \ | |||||
vap_manager.cxx \ | |||||
virtual_ap.cxx |
@ -0,0 +1,40 @@ | |||||
--- a/dcw/controller.cxx | |||||
+++ b/dcw/controller.cxx | |||||
@@ -195,7 +195,7 @@ void Controller::OnStationUnjoin(const MacAddress& primaryMacAddr, const Message | |||||
//remove any channel bondings matching the provided data channel mac addresses | |||||
for (unsigned i = 0; i < m.data_macaddr_count; i++) { | |||||
const ::dcw::MacAddress dcaddr(m.data_macaddrs[i]); | |||||
- const ::dcw::TrafficPolicy::DataChannelMap::iterator dcmEntry = state.policy.dataChannels.find(dcaddr); | |||||
+ ::dcw::TrafficPolicy::DataChannelMap::iterator dcmEntry = state.policy.dataChannels.find(dcaddr); | |||||
if (dcmEntry == state.policy.dataChannels.end()) continue; | |||||
if (dcmEntry->second == NULL) { | |||||
dcwlogwarnf("Data channel MAC address %s on client %s is not currently bonded\n", dcaddr.ToString().c_str(), primaryMacAddr.ToString().c_str()); | |||||
@@ -238,7 +238,7 @@ void Controller::OnStationAck(const MacAddress& primaryMacAddr, const Message& m | |||||
dcwlogdbgf("Got a station ACK from %s\n", primaryMacAddr.ToString().c_str()); | |||||
// first make sure this client has actually sent a join first... | |||||
- const ClientStateMap::iterator client = _clients.find(primaryMacAddr); | |||||
+ ClientStateMap::iterator client = _clients.find(primaryMacAddr); | |||||
if (client == _clients.end()) { | |||||
dcwlogerrf("Got a client ACK without a station join from %s\n", primaryMacAddr.ToString().c_str()); | |||||
Message reply(DCWMSG_AP_REJECT_STA); | |||||
--- a/dcwposix/processsignalmanager.cxx | |||||
+++ b/dcwposix/processsignalmanager.cxx | |||||
@@ -40,7 +40,7 @@ ProcessSignalManager::~ProcessSignalManager() { | |||||
} | |||||
void ProcessSignalManager::RegisterEventHandler(const int signum, ::dcwposix::ProcessSignalManager::EventHandler& eventHandler) { | |||||
- const SignalMap::iterator i = _sigmap.find(signum); | |||||
+ SignalMap::iterator i = _sigmap.find(signum); | |||||
if (i == _sigmap.end()) { | |||||
//be sure to preseve the old signal when inserting a new "unseen" signal | |||||
_sigmap[signum].insert(&eventHandler); | |||||
@@ -53,7 +53,7 @@ void ProcessSignalManager::RegisterEventHandler(const int signum, ::dcwposix::Pr | |||||
} | |||||
void ProcessSignalManager::UnRegisterEventHandler(const int signum, ::dcwposix::ProcessSignalManager::EventHandler& eventHandler) { | |||||
- const SignalMap::iterator i = _sigmap.find(signum); | |||||
+ SignalMap::iterator i = _sigmap.find(signum); | |||||
if (i == _sigmap.end()) { | |||||
dcwlogwarnf("Attempting to unregister handler %p non-registered process signal #%d\n", &eventHandler, signum); |
@ -0,0 +1,11 @@ | |||||
--- a/dcwlinux/macremapper_driver.cxx | |||||
+++ b/dcwlinux/macremapper_driver.cxx | |||||
@@ -174,7 +174,7 @@ void MacRemapperDriver::ApplyClientTrafficPolicy(const dcw::MacAddress& primaryA | |||||
} | |||||
//populate our remap ioctl() | |||||
- bzero(&re, sizeof(re)); | |||||
+ memset(&re, 0, sizeof(re)); | |||||
strncpy(re.filter_name, policy.trafficFilterProfile->GetName(), sizeof(re.filter_name)); | |||||
memcpy(re.match_macaddr, primaryAddr.Value, sizeof(re.match_macaddr)); | |||||
@ -0,0 +1,56 @@ | |||||
# | |||||
# Copyright (C) 2019 EWSI | |||||
# | |||||
# This is free software, licensed under the GNU General Public License v2. | |||||
# See /LICENSE for more information. | |||||
# | |||||
include $(TOPDIR)/rules.mk | |||||
PKG_NAME:=libdcwproto | |||||
PKG_VERSION:=1.0.0 | |||||
PKG_RELEASE:=1 | |||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz | |||||
PKG_SOURCE_URL:=https://codeload.github.com/ewsi/$(PKG_NAME)/tar.gz/v$(PKG_VERSION)? | |||||
PKG_HASH:=5bda395c648aa12eb90515c29024029738fde1a8f73a2cbc553be1c6962c2629 | |||||
PKG_MAINTAINER:=Carey Sonsino <careys@edgewaterwireless.com> | |||||
PKG_LICENSE:=Apache-2.0 | |||||
PKG_LICENSE_FILES:=COPYING | |||||
PKG_INSTALL:=1 | |||||
PKG_BUILD_PARALLEL:=1 | |||||
include $(INCLUDE_DIR)/package.mk | |||||
define Package/libdcwproto | |||||
SECTION:=libs | |||||
CATEGORY:=Libraries | |||||
SUBMENU:=Networking | |||||
TITLE:=Dual-Channel WiFi messaging library | |||||
URL:=https://www.edgewaterwireless.com | |||||
DEPENDS:=+kmod-macremapper | |||||
endef | |||||
define Package/libdcwproto/description | |||||
Platform-independent C library for marshaling and serializing DCW messages | |||||
endef | |||||
TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto | |||||
TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed | |||||
define Build/InstallDev | |||||
$(INSTALL_DIR) $(1)/usr/include | |||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/ | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/$(PKG_NAME)*.so* $(1)/usr/lib/ | |||||
endef | |||||
define Package/libdcwproto/install | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
# Note: $(INSTALL_BIN) does not keep symlinks, so use $(CP) | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/$(PKG_NAME)*.so* $(1)/usr/lib/ | |||||
endef | |||||
$(eval $(call BuildPackage,libdcwproto)) |
@ -0,0 +1,33 @@ | |||||
--- a/src/dcwproto.c | |||||
+++ b/src/dcwproto.c | |||||
@@ -20,12 +20,8 @@ | |||||
-#ifdef WIN32 | |||||
-#define bzero(ptr, size) memset(ptr, 0, size) | |||||
-#else | |||||
#include <config.h> | |||||
#include <strings.h> | |||||
-#endif | |||||
#include <dcwproto.h> | |||||
#include <string.h> | |||||
@@ -95,7 +91,7 @@ dcwmsg_marshal_sta_ack(struct dcwmsg_sta_ack * const output, const unsigned char | |||||
/* copy in the data ssid string bytes */ | |||||
if (buf_len < copy_size) return 0; | |||||
- bzero(output->bonded_data_channels[i].ssid, sizeof(output->bonded_data_channels[i].ssid)); | |||||
+ memset(output->bonded_data_channels[i].ssid, 0, sizeof(output->bonded_data_channels[i].ssid)); | |||||
memcpy(output->bonded_data_channels[i].ssid, buf, copy_size); | |||||
buf_len -= copy_size; | |||||
buf += copy_size; | |||||
@@ -134,7 +130,7 @@ dcwmsg_marshal_ap_accept_sta(struct dcwmsg_ap_accept_sta * const output, const u | |||||
/* copy in the data ssid string bytes */ | |||||
if (buf_len < copy_size) return 0; | |||||
- bzero(output->data_ssids[i], sizeof(output->data_ssids[i])); | |||||
+ memset(output->data_ssids[i], 0, sizeof(output->data_ssids[i])); | |||||
memcpy(output->data_ssids[i], buf, copy_size); | |||||
buf_len -= copy_size; | |||||
buf += copy_size; |
@ -0,0 +1,56 @@ | |||||
# | |||||
# Copyright (C) 2019 EWSI | |||||
# | |||||
# This is free software, licensed under the GNU General Public License v2. | |||||
# See /LICENSE for more information. | |||||
# | |||||
include $(TOPDIR)/rules.mk | |||||
PKG_NAME:=libdcwsocket | |||||
PKG_VERSION:=1.0.0 | |||||
PKG_RELEASE:=1 | |||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz | |||||
PKG_SOURCE_URL:=https://codeload.github.com/ewsi/$(PKG_NAME)/tar.gz/v$(PKG_VERSION)? | |||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) | |||||
PKG_HASH:=c7f6c69a5246fe1f184c21585f0805ceaca09c3c087ae439ded7ed4d25c7a3fa | |||||
PKG_MAINTAINER:=Carey Sonsino <careys@edgewaterwireless.com> | |||||
PKG_LICENSE:=Apache-2.0 | |||||
PKG_LICENSE_FILES:=COPYING | |||||
PKG_INSTALL:=1 | |||||
PKG_BUILD_PARALLEL:=1 | |||||
include $(INCLUDE_DIR)/package.mk | |||||
define Package/libdcwsocket | |||||
SECTION:=libs | |||||
CATEGORY:=Libraries | |||||
SUBMENU:=Networking | |||||
TITLE:=Dual-Channel socket library | |||||
URL:=https://www.edgewaterwireless.com | |||||
endef | |||||
define Package/libdcwsocket/description | |||||
User-land C library for sending and receiving DCW "EtherType"d messages | |||||
endef | |||||
TARGET_CFLAGS += -std=c89 -ffunction-sections -fdata-sections -flto | |||||
TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed | |||||
define Build/InstallDev | |||||
$(INSTALL_DIR) $(1)/usr/include | |||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/ | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/$(PKG_NAME)*.so* $(1)/usr/lib/ | |||||
endef | |||||
define Package/libdcwsocket/install | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
# Note: $(INSTALL_BIN) does not keep symlinks, so use $(CP) | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/$(PKG_NAME)*.so* $(1)/usr/lib/ | |||||
endef | |||||
$(eval $(call BuildPackage,libdcwsocket)) |
@ -0,0 +1,45 @@ | |||||
--- a/src/dcwsocket.c.linux | |||||
+++ b/src/dcwsocket.c.linux | |||||
@@ -100,10 +100,10 @@ dcwsock_open(const char * const ifname) { | |||||
} | |||||
/* sanitize our data structs... defensive */ | |||||
- bzero(rv, sizeof(*rv)); | |||||
- bzero(&ifr, sizeof(ifr)); | |||||
- bzero(&sall, sizeof(sall)); | |||||
- bzero(&sfp, sizeof(sfp)); | |||||
+ memset(rv, 0, sizeof(*rv)); | |||||
+ memset(&ifr, 0, sizeof(ifr)); | |||||
+ memset(&sall, 0, sizeof(sall)); | |||||
+ memset(&sfp, 0, sizeof(sfp)); | |||||
/* open a raw socket... "ETH_P_ALL" says take EVERYTHING | |||||
(this means that it is IMPERATIVE to apply a filter) | |||||
diff --git a/src/dcwsocket.c.osx b/src/dcwsocket.c.osx | |||||
index abead10..75cda2f 100644 | |||||
--- a/src/dcwsocket.c.osx | |||||
+++ b/src/dcwsocket.c.osx | |||||
@@ -90,10 +90,10 @@ dcwsock_open(const char * const ifname) { | |||||
} | |||||
/* sanitize our data structs... defensive */ | |||||
- bzero(rv, sizeof(*rv)); | |||||
- bzero(&dmx_desc, sizeof(dmx_desc)); | |||||
- bzero(&proto_desc, sizeof(proto_desc)); | |||||
- bzero(&snd, sizeof(snd)); | |||||
+ memset(rv, 0, sizeof(*rv)); | |||||
+ memset(&dmx_desc, 0, sizeof(dmx_desc)); | |||||
+ memset(&proto_desc, 0, sizeof(proto_desc)); | |||||
+ memset(&snd, 0, sizeof(snd)); | |||||
/* open a "NDRV" socket... */ | |||||
rv->fd = socket(PF_NDRV, SOCK_RAW, 0); | |||||
@@ -201,7 +201,7 @@ dcwsock_send( dcw_socket_t s, const void * const buf, const unsigned buf_size, c | |||||
fill out a link-level sockaddr cause we can only | |||||
use sendto() with PF_NDRV... | |||||
*/ | |||||
- bzero(&sdl, sizeof(sdl)); | |||||
+ memset(&sdl, 0, sizeof(sdl)); | |||||
sdl.sdl_len = sizeof(sdl); | |||||
sdl.sdl_index = 0; | |||||
sdl.sdl_type = IFT_ETHER; |
@ -0,0 +1,10 @@ | |||||
--- a/src/dcwsocket.c.linux | |||||
+++ b/src/dcwsocket.c.linux | |||||
@@ -31,6 +31,7 @@ | |||||
#include <sys/types.h> | |||||
#include <sys/socket.h> | |||||
#include <net/if.h> | |||||
+#include <linux/if.h> | |||||
#include <linux/if_packet.h> | |||||
#include <linux/if_ether.h> | |||||
#include <linux/filter.h> |
@ -0,0 +1,42 @@ | |||||
# | |||||
# Copyright (C) 2019 EWSI | |||||
# | |||||
# This is free software, licensed under the GNU General Public License v2. | |||||
# See /LICENSE for more information. | |||||
# | |||||
include $(TOPDIR)/rules.mk | |||||
include $(INCLUDE_DIR)/kernel.mk | |||||
PKG_NAME:=macremapper | |||||
PKG_VERSION:=1.0.0 | |||||
PKG_RELEASE:=1 | |||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz | |||||
PKG_SOURCE_URL:=https://codeload.github.com/ewsi/$(PKG_NAME)/tar.gz/v$(PKG_VERSION)? | |||||
PKG_HASH:=f054201dd805ce005b89606a507b58a5717d383a4339c69dfdc02f0202935437 | |||||
PKG_MAINTAINER:=Carey Sonsino <careys@edgewaterwireless.com> | |||||
PKG_LICENSE:=GPL-2.0-only | |||||
PKG_LICENSE_FILES:=kernelmod/COPYING | |||||
include $(INCLUDE_DIR)/package.mk | |||||
define KernelPackage/macremapper | |||||
SUBMENU:=Network Support | |||||
URL:=https://www.edgewaterwireless.com | |||||
VERSION:=$(LINUX_VERSION)-$(BOARD)-$(PKG_RELEASE) | |||||
TITLE:=Dual Channel Wi-Fi macremapper Module | |||||
DEPENDS:= +kmod-cfg80211 +kmod-br-netfilter | |||||
FILES:=$(PKG_BUILD_DIR)/kernelmod/$(PKG_NAME).$(LINUX_KMOD_SUFFIX) | |||||
AUTOLOAD:=$(call AutoProbe,macremapper) | |||||
endef | |||||
define KernelPackage/macremapper/description | |||||
Linux kernel module for implementation the DCW filtering mechanism | |||||
endef | |||||
MAKE_FLAGS += KERNEL_SRC=$(LINUX_DIR) | |||||
MAKE_PATH:=kernelmod | |||||
$(eval $(call KernelPackage,macremapper)) |
@ -0,0 +1,27 @@ | |||||
--- a/kernelmod/main.c | |||||
+++ b/kernelmod/main.c | |||||
@@ -91,8 +91,11 @@ modinit( void ) { | |||||
rv = mrm_rcdb_init(); | |||||
if (rv != 0) return rv; | |||||
- | |||||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0) | |||||
nf_register_hook(&_hops); | |||||
+#else | |||||
+ nf_register_net_hook(&init_net, &_hops); | |||||
+#endif | |||||
mrm_init_ctlfile(); /* XXX not checking for failure! */ | |||||
printk(KERN_INFO "MRM The MAC Address Re-Mapper is now in the kernel\n"); | |||||
@@ -103,7 +106,11 @@ modinit( void ) { | |||||
static void __exit | |||||
modexit( void ) { | |||||
mrm_destroy_ctlfile(); | |||||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0) | |||||
nf_unregister_hook(&_hops); | |||||
+#else | |||||
+ nf_unregister_net_hook(&init_net, &_hops); | |||||
+#endif | |||||
mrm_rcdb_destroy(); /* imperative that this happens last */ | |||||
printk(KERN_INFO "MRM The MAC Address Re-Mapper gone bye-bye\n"); | |||||
} |
@ -0,0 +1,63 @@ | |||||
# | |||||
# Copyright (C) 2019 EWSI | |||||
# | |||||
# This is free software, licensed under the GNU General Public License v2. | |||||
# See /LICENSE for more information. | |||||
# | |||||
include $(TOPDIR)/rules.mk | |||||
PKG_NAME:=mrmctl | |||||
PKG_VERSION:=1.0.0 | |||||
PKG_RELEASE:=1 | |||||
PKG_SOURCE:=macremapper-$(PKG_VERSION).tar.gz | |||||
PKG_SOURCE_URL:=https://codeload.github.com/ewsi/macremapper/tar.gz/v$(PKG_VERSION)? | |||||
PKG_HASH:=f054201dd805ce005b89606a507b58a5717d383a4339c69dfdc02f0202935437 | |||||
PKG_BUILD_DIR:=$(BUILD_DIR)/macremapper-$(PKG_VERSION) | |||||
PKG_MAINTAINER:=Carey Sonsino <careys@edgewaterwireless.com> | |||||
PKG_LICENSE:=Apache-2.0 | |||||
PKG_LICENSE_FILES:=userland/COPYING | |||||
PKG_INSTALL:=1 | |||||
PKG_BUILD_PARALLEL:=1 | |||||
include $(INCLUDE_DIR)/package.mk | |||||
define Package/mrmctl | |||||
SECTION:=utils | |||||
CATEGORY:=Utilities | |||||
TITLE:=mrmctl utility (macremapper kernel module) | |||||
URL:=https://www.edgewaterwireless.com | |||||
DEPENDS:= +kmod-macremapper | |||||
endef | |||||
define Package/mrmctl/description | |||||
Command-line utility to manually manipulate the macremapper kernel module | |||||
endef | |||||
MAKE_PATH:=userland | |||||
CONFIGURE_PATH:=userland | |||||
CONFIGURE_ARGS += \ | |||||
--enable-shared | |||||
TARGET_CFLAGS += -std=c89 -ffunction-sections -fdata-sections -flto | |||||
TARGET_LDFLAGS += -Wl,--gc-sections,--as-needed | |||||
define Build/InstallDev | |||||
$(INSTALL_DIR) $(1)/usr/include | |||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/include/*.h $(1)/usr/include/ | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/ | |||||
endef | |||||
define Package/mrmctl/install | |||||
$(INSTALL_DIR) $(1)/bin | |||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/bin/ | |||||
$(INSTALL_DIR) $(1)/usr/lib | |||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/*.so* $(1)/usr/lib/ | |||||
endef | |||||
$(eval $(call BuildPackage,mrmctl)) |
@ -0,0 +1,24 @@ | |||||
--- a/userland/mrmctl/mrmctl.c | |||||
+++ b/userland/mrmctl/mrmctl.c | |||||
@@ -139,7 +139,7 @@ remap(int argc, char **argv) { | |||||
if (argc < 5) return 1; /* defensive */ | |||||
/* initialize variables and put things into human-readable variable names */ | |||||
- bzero(&re, sizeof(re)); | |||||
+ memset(&re, 0, sizeof(re)); | |||||
filter_name = argv[2]; | |||||
match_macaddr = argv[3]; | |||||
diff --git a/userland/mrmfilterparser/mrm_filter_conf_parser.c b/userland/mrmfilterparser/mrm_filter_conf_parser.c | |||||
index 926fa76..f5c54c1 100644 | |||||
--- a/userland/mrmfilterparser/mrm_filter_conf_parser.c | |||||
+++ b/userland/mrmfilterparser/mrm_filter_conf_parser.c | |||||
@@ -319,7 +319,7 @@ filter_file_loadf(struct mrm_filter_config * const output, FILE * const f) { | |||||
return -1; | |||||
output->rules_active = 0; | |||||
- bzero(output->rules, sizeof(output->rules)); /* defensive */ | |||||
+ memset(output->rules, 0, sizeof(output->rules)); /* defensive */ | |||||
for (linenum = 1; fgets(buf, sizeof(buf), f) != NULL; linenum++) { | |||||