Initial commit
Some checks failed
Build Kernel / Build all affected Kernels (push) Has been cancelled
Build all core packages / Build all core packages for selected target (push) Has been cancelled
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Has been cancelled
Build Toolchains / Build Toolchains for each target (push) Has been cancelled
Build host tools / Build host tools for linux and macos based systems (push) Has been cancelled
Coverity scan build / Coverity x86/64 build (push) Has been cancelled
Some checks failed
Build Kernel / Build all affected Kernels (push) Has been cancelled
Build all core packages / Build all core packages for selected target (push) Has been cancelled
Build and Push prebuilt tools container / Build and Push all prebuilt containers (push) Has been cancelled
Build Toolchains / Build Toolchains for each target (push) Has been cancelled
Build host tools / Build host tools for linux and macos based systems (push) Has been cancelled
Coverity scan build / Coverity x86/64 build (push) Has been cancelled
This commit is contained in:
64
package/network/config/firewall/Makefile
Normal file
64
package/network/config/firewall/Makefile
Normal file
@@ -0,0 +1,64 @@
|
||||
#
|
||||
# Copyright (C) 2013-2016 OpenWrt.org
|
||||
# Copyright (C) 2016 LEDE project
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=firewall
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firewall3.git
|
||||
PKG_SOURCE_DATE:=2024-10-18
|
||||
PKG_SOURCE_VERSION:=1aef9791a21e3d15d4357060f09a7bb9ed3d6e4e
|
||||
PKG_MIRROR_HASH:=61a4f03a34edf5bf25c13b7ae04e4be40ecbaebff77b9f2d1e730dcaa2c77143
|
||||
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
|
||||
PKG_LICENSE:=ISC
|
||||
|
||||
PKG_CONFIG_DEPENDS := CONFIG_IPV6
|
||||
|
||||
PKG_BUILD_FLAGS:=gc-sections lto
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
define Package/firewall
|
||||
SECTION:=net
|
||||
CATEGORY:=Base system
|
||||
TITLE:=OpenWrt C Firewall
|
||||
DEPENDS:=+libubox +libubus +libuci +libip4tc +IPV6:libip6tc +libiptext +IPV6:libiptext6 +libxtables +kmod-ipt-core +kmod-ipt-conntrack +IPV6:kmod-nf-conntrack6 +kmod-ipt-nat
|
||||
PROVIDES:=uci-firewall
|
||||
CONFLICTS:=firewall4
|
||||
endef
|
||||
|
||||
define Package/firewall/description
|
||||
This package provides a config-compatible C implementation of the UCI firewall.
|
||||
endef
|
||||
|
||||
define Package/firewall/conffiles
|
||||
/etc/config/firewall
|
||||
/etc/firewall.user
|
||||
endef
|
||||
|
||||
CMAKE_OPTIONS += $(if $(CONFIG_IPV6),,-DDISABLE_IPV6=1)
|
||||
|
||||
define Package/firewall/install
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/firewall3 $(1)/sbin/fw3
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/firewall.init $(1)/etc/init.d/firewall
|
||||
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
|
||||
$(INSTALL_CONF) ./files/firewall.hotplug $(1)/etc/hotplug.d/iface/20-firewall
|
||||
$(INSTALL_DIR) $(1)/etc/config/
|
||||
$(INSTALL_CONF) ./files/firewall.config $(1)/etc/config/firewall
|
||||
$(INSTALL_DIR) $(1)/etc/
|
||||
$(INSTALL_CONF) ./files/firewall.user $(1)/etc/firewall.user
|
||||
$(INSTALL_DIR) $(1)/usr/share/fw3
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/helpers.conf $(1)/usr/share/fw3
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,firewall))
|
||||
206
package/network/config/firewall/files/firewall.config
Normal file
206
package/network/config/firewall/files/firewall.config
Normal file
@@ -0,0 +1,206 @@
|
||||
config defaults
|
||||
option syn_flood 1
|
||||
option input REJECT
|
||||
option output ACCEPT
|
||||
option forward REJECT
|
||||
# Uncomment this line to disable ipv6 rules
|
||||
# option disable_ipv6 1
|
||||
|
||||
config zone
|
||||
option name lan
|
||||
list network 'lan'
|
||||
option input ACCEPT
|
||||
option output ACCEPT
|
||||
option forward ACCEPT
|
||||
|
||||
config zone
|
||||
option name wan
|
||||
list network 'wan'
|
||||
list network 'wan6'
|
||||
option input REJECT
|
||||
option output ACCEPT
|
||||
option forward REJECT
|
||||
option masq 1
|
||||
option mtu_fix 1
|
||||
|
||||
config forwarding
|
||||
option src lan
|
||||
option dest wan
|
||||
|
||||
# We need to accept udp packets on port 68,
|
||||
# see https://dev.openwrt.org/ticket/4108
|
||||
config rule
|
||||
option name Allow-DHCP-Renew
|
||||
option src wan
|
||||
option proto udp
|
||||
option dest_port 68
|
||||
option target ACCEPT
|
||||
option family ipv4
|
||||
|
||||
# Allow IPv4 ping
|
||||
config rule
|
||||
option name Allow-Ping
|
||||
option src wan
|
||||
option proto icmp
|
||||
option icmp_type echo-request
|
||||
option family ipv4
|
||||
option target ACCEPT
|
||||
|
||||
config rule
|
||||
option name Allow-IGMP
|
||||
option src wan
|
||||
option proto igmp
|
||||
option family ipv4
|
||||
option target ACCEPT
|
||||
|
||||
# Allow DHCPv6 replies
|
||||
# see https://github.com/openwrt/openwrt/issues/5066
|
||||
config rule
|
||||
option name Allow-DHCPv6
|
||||
option src wan
|
||||
option proto udp
|
||||
option dest_port 546
|
||||
option family ipv6
|
||||
option target ACCEPT
|
||||
|
||||
config rule
|
||||
option name Allow-MLD
|
||||
option src wan
|
||||
option proto icmp
|
||||
option src_ip fe80::/10
|
||||
list icmp_type '130/0'
|
||||
list icmp_type '131/0'
|
||||
list icmp_type '132/0'
|
||||
list icmp_type '143/0'
|
||||
option family ipv6
|
||||
option target ACCEPT
|
||||
|
||||
# Allow essential incoming IPv6 ICMP traffic
|
||||
config rule
|
||||
option name Allow-ICMPv6-Input
|
||||
option src wan
|
||||
option proto icmp
|
||||
list icmp_type echo-request
|
||||
list icmp_type echo-reply
|
||||
list icmp_type destination-unreachable
|
||||
list icmp_type packet-too-big
|
||||
list icmp_type time-exceeded
|
||||
list icmp_type bad-header
|
||||
list icmp_type unknown-header-type
|
||||
list icmp_type router-solicitation
|
||||
list icmp_type neighbour-solicitation
|
||||
list icmp_type router-advertisement
|
||||
list icmp_type neighbour-advertisement
|
||||
option limit 1000/sec
|
||||
option family ipv6
|
||||
option target ACCEPT
|
||||
|
||||
# Allow essential forwarded IPv6 ICMP traffic
|
||||
config rule
|
||||
option name Allow-ICMPv6-Forward
|
||||
option src wan
|
||||
option dest *
|
||||
option proto icmp
|
||||
list icmp_type echo-request
|
||||
list icmp_type echo-reply
|
||||
list icmp_type destination-unreachable
|
||||
list icmp_type packet-too-big
|
||||
list icmp_type time-exceeded
|
||||
list icmp_type bad-header
|
||||
list icmp_type unknown-header-type
|
||||
option limit 1000/sec
|
||||
option family ipv6
|
||||
option target ACCEPT
|
||||
|
||||
config rule
|
||||
option name Allow-IPSec-ESP
|
||||
option src wan
|
||||
option dest lan
|
||||
option proto esp
|
||||
option target ACCEPT
|
||||
|
||||
config rule
|
||||
option name Allow-ISAKMP
|
||||
option src wan
|
||||
option dest lan
|
||||
option dest_port 500
|
||||
option proto udp
|
||||
option target ACCEPT
|
||||
|
||||
# allow interoperability with traceroute classic
|
||||
# note that traceroute uses a fixed port range, and depends on getting
|
||||
# back ICMP Unreachables. if we're operating in DROP mode, it won't
|
||||
# work so we explicitly REJECT packets on these ports.
|
||||
config rule
|
||||
option name Support-UDP-Traceroute
|
||||
option src wan
|
||||
option dest_port 33434:33689
|
||||
option proto udp
|
||||
option family ipv4
|
||||
option target REJECT
|
||||
option enabled 0
|
||||
|
||||
# include a file with users custom iptables rules
|
||||
config include
|
||||
option path /etc/firewall.user
|
||||
|
||||
|
||||
### EXAMPLE CONFIG SECTIONS
|
||||
# do not allow a specific ip to access wan
|
||||
#config rule
|
||||
# option src lan
|
||||
# option src_ip 192.168.45.2
|
||||
# option dest wan
|
||||
# option proto tcp
|
||||
# option target REJECT
|
||||
|
||||
# block a specific mac on wan
|
||||
#config rule
|
||||
# option dest wan
|
||||
# option src_mac 00:11:22:33:44:66
|
||||
# option target REJECT
|
||||
|
||||
# block incoming ICMP traffic on a zone
|
||||
#config rule
|
||||
# option src lan
|
||||
# option proto ICMP
|
||||
# option target DROP
|
||||
|
||||
# port redirect port coming in on wan to lan
|
||||
#config redirect
|
||||
# option src wan
|
||||
# option src_dport 80
|
||||
# option dest lan
|
||||
# option dest_ip 192.168.16.235
|
||||
# option dest_port 80
|
||||
# option proto tcp
|
||||
|
||||
# port redirect of remapped ssh port (22001) on wan
|
||||
#config redirect
|
||||
# option src wan
|
||||
# option src_dport 22001
|
||||
# option dest lan
|
||||
# option dest_port 22
|
||||
# option proto tcp
|
||||
|
||||
### FULL CONFIG SECTIONS
|
||||
#config rule
|
||||
# option src lan
|
||||
# option src_ip 192.168.45.2
|
||||
# option src_mac 00:11:22:33:44:55
|
||||
# option src_port 80
|
||||
# option dest wan
|
||||
# option dest_ip 194.25.2.129
|
||||
# option dest_port 120
|
||||
# option proto tcp
|
||||
# option target REJECT
|
||||
|
||||
#config redirect
|
||||
# option src lan
|
||||
# option src_ip 192.168.45.2
|
||||
# option src_mac 00:11:22:33:44:55
|
||||
# option src_port 1024
|
||||
# option src_dport 80
|
||||
# option dest_ip 194.25.2.129
|
||||
# option dest_port 120
|
||||
# option proto tcp
|
||||
11
package/network/config/firewall/files/firewall.hotplug
Normal file
11
package/network/config/firewall/files/firewall.hotplug
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$ACTION" = ifup -o "$ACTION" = ifupdate ] || exit 0
|
||||
[ "$ACTION" = ifupdate -a -z "$IFUPDATE_ADDRESSES" -a -z "$IFUPDATE_DATA" ] && exit 0
|
||||
|
||||
/etc/init.d/firewall enabled || exit 0
|
||||
|
||||
fw3 -q network "$INTERFACE" >/dev/null || exit 0
|
||||
|
||||
logger -t firewall "Reloading firewall due to $ACTION of $INTERFACE ($DEVICE)"
|
||||
fw3 -q reload
|
||||
61
package/network/config/firewall/files/firewall.init
Executable file
61
package/network/config/firewall/files/firewall.init
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=19
|
||||
USE_PROCD=1
|
||||
QUIET=""
|
||||
|
||||
validate_firewall_redirect()
|
||||
{
|
||||
uci_validate_section firewall redirect "${1}" \
|
||||
'proto:or(uinteger, string)' \
|
||||
'src:string' \
|
||||
'src_ip:cidr' \
|
||||
'src_dport:or(port, portrange)' \
|
||||
'dest:string' \
|
||||
'dest_ip:cidr' \
|
||||
'dest_port:or(port, portrange)' \
|
||||
'target:or("SNAT", "DNAT")'
|
||||
}
|
||||
|
||||
validate_firewall_rule()
|
||||
{
|
||||
uci_validate_section firewall rule "${1}" \
|
||||
'proto:or(uinteger, string)' \
|
||||
'src:string' \
|
||||
'dest:string' \
|
||||
'src_port:or(port, portrange)' \
|
||||
'dest_port:or(port, portrange)' \
|
||||
'target:string'
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger firewall
|
||||
|
||||
procd_open_validate
|
||||
validate_firewall_redirect
|
||||
validate_firewall_rule
|
||||
procd_close_validate
|
||||
}
|
||||
|
||||
restart() {
|
||||
fw3 restart
|
||||
}
|
||||
|
||||
start_service() {
|
||||
fw3 ${QUIET} start
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
fw3 flush
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
fw3 reload
|
||||
}
|
||||
|
||||
boot() {
|
||||
# Be silent on boot, firewall might be started by hotplug already,
|
||||
# so don't complain in syslog.
|
||||
QUIET=-q
|
||||
start
|
||||
}
|
||||
7
package/network/config/firewall/files/firewall.user
Normal file
7
package/network/config/firewall/files/firewall.user
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file is interpreted as shell script.
|
||||
# Put your custom iptables rules here, they will
|
||||
# be executed with each firewall (re-)start.
|
||||
|
||||
# Internal uci firewall chains are flushed and recreated on reload, so
|
||||
# put custom rules into the root chains e.g. INPUT or FORWARD or into the
|
||||
# special user chains, e.g. input_wan_rule or postrouting_lan_rule.
|
||||
50
package/network/config/firewall4/Makefile
Normal file
50
package/network/config/firewall4/Makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
#
|
||||
# Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io>
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=firewall4
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/firewall4.git
|
||||
PKG_SOURCE_DATE:=2024-12-18
|
||||
PKG_SOURCE_VERSION:=18fc0ead19faf06b8ce7ec5be84957278e942dfa
|
||||
PKG_MIRROR_HASH:=123d1b5d00cdbbfa77813b3eb694d00949171037a0fa26e6d36a75a37066ba48
|
||||
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
|
||||
PKG_LICENSE:=ISC
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/firewall4
|
||||
SECTION:=net
|
||||
CATEGORY:=Base system
|
||||
TITLE:=OpenWrt 4th gen firewall
|
||||
DEPENDS:= \
|
||||
+kmod-nft-core +kmod-nft-fib +kmod-nft-offload \
|
||||
+kmod-nft-nat \
|
||||
+nftables-json \
|
||||
+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci
|
||||
EXTRA_DEPENDS:=ucode (>=2022.03.22)
|
||||
PROVIDES:=uci-firewall
|
||||
endef
|
||||
|
||||
define Package/firewall4/description
|
||||
This package provides an nftables-based implementation of the UCI firewall
|
||||
sharing the same configuration format.
|
||||
endef
|
||||
|
||||
define Package/firewall4/conffiles
|
||||
/etc/config/firewall
|
||||
/etc/nftables.d/
|
||||
endef
|
||||
|
||||
define Package/firewall4/install
|
||||
$(CP) -a $(PKG_BUILD_DIR)/root/* $(1)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,firewall4))
|
||||
44
package/network/config/gre/Makefile
Normal file
44
package/network/config/gre/Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright (C) 2014 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gre
|
||||
PKG_RELEASE:=13
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/gre/Default
|
||||
endef
|
||||
|
||||
define Package/gre
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
|
||||
TITLE:=Generic Routing Encapsulation config support
|
||||
DEPENDS:=+kmod-gre +IPV6:kmod-gre6 +resolveip
|
||||
PROVIDES:=grev4 grev6
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/gre/description
|
||||
Generic Routing Encapsulation config support (IPv4 and IPv6) in /etc/config/network.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Package/gre/install
|
||||
$(INSTALL_DIR) $(1)/lib/netifd/proto
|
||||
$(INSTALL_BIN) ./files/gre.sh $(1)/lib/netifd/proto/gre.sh
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,gre))
|
||||
296
package/network/config/gre/files/gre.sh
Executable file
296
package/network/config/gre/files/gre.sh
Executable file
@@ -0,0 +1,296 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
. /lib/functions.sh
|
||||
. /lib/functions/network.sh
|
||||
. ../netifd-proto.sh
|
||||
init_proto "$@"
|
||||
}
|
||||
|
||||
gre_generic_setup() {
|
||||
local cfg="$1"
|
||||
local mode="$2"
|
||||
local local="$3"
|
||||
local remote="$4"
|
||||
local link="$5"
|
||||
local mtu ipv6 ttl tos zone ikey okey icsum ocsum iseqno oseqno multicast
|
||||
json_get_vars mtu ipv6 ttl tos zone ikey okey icsum ocsum iseqno oseqno multicast
|
||||
|
||||
[ -z "$multicast" ] && multicast=1
|
||||
|
||||
proto_init_update "$link" 1
|
||||
|
||||
proto_add_tunnel
|
||||
json_add_string mode "$mode"
|
||||
json_add_int mtu "${mtu:-1280}"
|
||||
json_add_boolean ipv6 "${ipv6:-1}"
|
||||
[ -n "$df" ] && json_add_boolean df "$df"
|
||||
[ -n "$ttl" ] && json_add_int ttl "$ttl"
|
||||
[ -n "$tos" ] && json_add_string tos "$tos"
|
||||
json_add_boolean multicast "$multicast"
|
||||
json_add_string local "$local"
|
||||
json_add_string remote "$remote"
|
||||
[ -n "$tunlink" ] && json_add_string link "$tunlink"
|
||||
|
||||
json_add_object 'data'
|
||||
[ -n "$ikey" ] && json_add_int ikey "$ikey"
|
||||
[ -n "$okey" ] && json_add_int okey "$okey"
|
||||
[ -n "$icsum" ] && json_add_boolean icsum "$icsum"
|
||||
[ -n "$ocsum" ] && json_add_boolean ocsum "$ocsum"
|
||||
[ -n "$iseqno" ] && json_add_boolean iseqno "$iseqno"
|
||||
[ -n "$oseqno" ] && json_add_boolean oseqno "$oseqno"
|
||||
[ -n "$encaplimit" ] && json_add_string encaplimit "$encaplimit"
|
||||
json_close_object
|
||||
|
||||
proto_close_tunnel
|
||||
|
||||
proto_add_data
|
||||
[ -n "$zone" ] && json_add_string zone "$zone"
|
||||
proto_close_data
|
||||
|
||||
proto_send_update "$cfg"
|
||||
}
|
||||
|
||||
gre_setup() {
|
||||
local cfg="$1"
|
||||
local mode="$2"
|
||||
local remoteip
|
||||
|
||||
local ipaddr peeraddr
|
||||
json_get_vars df ipaddr peeraddr tunlink nohostroute
|
||||
|
||||
[ -z "$peeraddr" ] && {
|
||||
proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
|
||||
proto_block_restart "$cfg"
|
||||
exit
|
||||
}
|
||||
|
||||
remoteip=$(resolveip -t 10 -4 "$peeraddr")
|
||||
|
||||
if [ -z "$remoteip" ]; then
|
||||
proto_notify_error "$cfg" "PEER_RESOLVE_FAIL"
|
||||
exit
|
||||
fi
|
||||
|
||||
for ip in $remoteip; do
|
||||
peeraddr=$ip
|
||||
break
|
||||
done
|
||||
|
||||
if [ "${nohostroute}" != "1" ]; then
|
||||
( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
|
||||
fi
|
||||
|
||||
[ -z "$ipaddr" ] && {
|
||||
local wanif="$tunlink"
|
||||
if [ -z $wanif ] && ! network_find_wan wanif; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! network_get_ipaddr ipaddr "$wanif"; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
[ -z "$df" ] && df="1"
|
||||
|
||||
case "$mode" in
|
||||
gretapip)
|
||||
gre_generic_setup $cfg $mode $ipaddr $peeraddr "gre4t-$cfg"
|
||||
;;
|
||||
*)
|
||||
gre_generic_setup $cfg $mode $ipaddr $peeraddr "gre4-$cfg"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
proto_gre_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
gre_setup $cfg "greip"
|
||||
}
|
||||
|
||||
proto_gretap_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
local network
|
||||
json_get_vars network
|
||||
|
||||
gre_setup $cfg "gretapip"
|
||||
|
||||
json_init
|
||||
json_add_string name "gre4t-$cfg"
|
||||
json_add_boolean link-ext 0
|
||||
json_close_object
|
||||
|
||||
for i in $network; do
|
||||
ubus call network.interface."$i" add_device "$(json_dump)"
|
||||
done
|
||||
}
|
||||
|
||||
grev6_setup() {
|
||||
local cfg="$1"
|
||||
local mode="$2"
|
||||
local remoteip6
|
||||
|
||||
local ip6addr peer6addr weakif
|
||||
json_get_vars ip6addr peer6addr tunlink weakif encaplimit nohostroute
|
||||
|
||||
[ -z "$peer6addr" ] && {
|
||||
proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
|
||||
proto_block_restart "$cfg"
|
||||
exit
|
||||
}
|
||||
|
||||
remoteip6=$(resolveip -t 10 -6 "$peer6addr")
|
||||
|
||||
if [ -z "$remoteip6" ]; then
|
||||
proto_notify_error "$cfg" "PEER_RESOLVE_FAIL"
|
||||
exit
|
||||
fi
|
||||
|
||||
for ip6 in $remoteip6; do
|
||||
peer6addr=$ip6
|
||||
break
|
||||
done
|
||||
|
||||
if [ "${nohostroute}" != "1" ]; then
|
||||
( proto_add_host_dependency "$cfg" "$peer6addr" "$tunlink" )
|
||||
fi
|
||||
|
||||
[ -z "$ip6addr" ] && {
|
||||
local wanif="$tunlink"
|
||||
if [ -z $wanif ] && ! network_find_wan6 wanif; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! network_get_ipaddr6 ip6addr "$wanif"; then
|
||||
[ -z "$weakif" ] && weakif="lan"
|
||||
if ! network_get_ipaddr6 ip6addr "$weakif"; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
case "$mode" in
|
||||
gretapip6)
|
||||
gre_generic_setup $cfg $mode $ip6addr $peer6addr "gre6t-$cfg"
|
||||
;;
|
||||
*)
|
||||
gre_generic_setup $cfg $mode $ip6addr $peer6addr "gre6-$cfg"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
proto_grev6_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
grev6_setup $cfg "greip6"
|
||||
}
|
||||
|
||||
proto_grev6tap_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
local network
|
||||
json_get_vars network
|
||||
|
||||
grev6_setup $cfg "gretapip6"
|
||||
|
||||
json_init
|
||||
json_add_string name "gre6t-$cfg"
|
||||
json_add_boolean link-ext 0
|
||||
json_close_object
|
||||
|
||||
for i in $network; do
|
||||
ubus call network.interface."$i" add_device "$(json_dump)"
|
||||
done
|
||||
}
|
||||
|
||||
gretap_generic_teardown() {
|
||||
local network
|
||||
json_get_vars network
|
||||
|
||||
json_init
|
||||
json_add_string name "$1"
|
||||
json_add_boolean link-ext 0
|
||||
json_close_object
|
||||
|
||||
for i in $network; do
|
||||
ubus call network.interface."$i" remove_device "$(json_dump)"
|
||||
done
|
||||
}
|
||||
|
||||
proto_gre_teardown() {
|
||||
local cfg="$1"
|
||||
}
|
||||
|
||||
proto_gretap_teardown() {
|
||||
local cfg="$1"
|
||||
|
||||
gretap_generic_teardown "gre4t-$cfg"
|
||||
}
|
||||
|
||||
proto_grev6_teardown() {
|
||||
local cfg="$1"
|
||||
}
|
||||
|
||||
proto_grev6tap_teardown() {
|
||||
local cfg="$1"
|
||||
|
||||
gretap_generic_teardown "gre6t-$cfg"
|
||||
}
|
||||
|
||||
gre_generic_init_config() {
|
||||
no_device=1
|
||||
available=1
|
||||
|
||||
proto_config_add_int "mtu"
|
||||
proto_config_add_boolean "ipv6"
|
||||
proto_config_add_int "ttl"
|
||||
proto_config_add_string "tos"
|
||||
proto_config_add_string "tunlink"
|
||||
proto_config_add_string "zone"
|
||||
proto_config_add_int "ikey"
|
||||
proto_config_add_int "okey"
|
||||
proto_config_add_boolean "icsum"
|
||||
proto_config_add_boolean "ocsum"
|
||||
proto_config_add_boolean "iseqno"
|
||||
proto_config_add_boolean "oseqno"
|
||||
proto_config_add_boolean "multicast"
|
||||
}
|
||||
|
||||
proto_gre_init_config() {
|
||||
gre_generic_init_config
|
||||
proto_config_add_string "ipaddr"
|
||||
proto_config_add_string "peeraddr"
|
||||
proto_config_add_boolean "df"
|
||||
proto_config_add_boolean "nohostroute"
|
||||
}
|
||||
|
||||
proto_gretap_init_config() {
|
||||
proto_gre_init_config
|
||||
proto_config_add_string "network"
|
||||
}
|
||||
|
||||
proto_grev6_init_config() {
|
||||
gre_generic_init_config
|
||||
proto_config_add_string "ip6addr"
|
||||
proto_config_add_string "peer6addr"
|
||||
proto_config_add_string "weakif"
|
||||
proto_config_add_string "encaplimit"
|
||||
proto_config_add_boolean "nohostroute"
|
||||
}
|
||||
|
||||
proto_grev6tap_init_config() {
|
||||
proto_grev6_init_config
|
||||
proto_config_add_string "network"
|
||||
}
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
[ -d /sys/module/ip_gre ] && { add_protocol gre; add_protocol gretap; }
|
||||
[ -d /sys/module/ip6_gre ] && { add_protocol grev6; add_protocol grev6tap; }
|
||||
}
|
||||
40
package/network/config/ipip/Makefile
Normal file
40
package/network/config/ipip/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# Copyright (C) 2014 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=ipip
|
||||
PKG_RELEASE:=4
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/ipip
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
MAINTAINER:=Hans Dedecker <dedeckeh@gmail.com>
|
||||
TITLE:=IP in IP Tunnel config support
|
||||
DEPENDS:= +kmod-ipip +resolveip
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/ipip/description
|
||||
IP in IP Tunnel config support in /etc/config/network.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Package/ipip/install
|
||||
$(INSTALL_DIR) $(1)/lib/netifd/proto
|
||||
$(INSTALL_BIN) ./files/ipip.sh $(1)/lib/netifd/proto/ipip.sh
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,ipip))
|
||||
94
package/network/config/ipip/files/ipip.sh
Executable file
94
package/network/config/ipip/files/ipip.sh
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
. /lib/functions.sh
|
||||
. /lib/functions/network.sh
|
||||
. ../netifd-proto.sh
|
||||
init_proto "$@"
|
||||
}
|
||||
|
||||
proto_ipip_setup() {
|
||||
local cfg="$1"
|
||||
local remoteip
|
||||
|
||||
local df ipaddr peeraddr tunlink ttl tos zone mtu
|
||||
json_get_vars df ipaddr peeraddr tunlink ttl tos zone mtu nohostroute
|
||||
|
||||
[ -z "$peeraddr" ] && {
|
||||
proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
|
||||
proto_block_restart "$cfg"
|
||||
return
|
||||
}
|
||||
|
||||
remoteip=$(resolveip -t 10 -4 "$peeraddr")
|
||||
|
||||
if [ -z "$remoteip" ]; then
|
||||
proto_notify_error "$cfg" "PEER_RESOLVE_FAIL"
|
||||
return
|
||||
fi
|
||||
|
||||
for ip in $remoteip; do
|
||||
peeraddr=$ip
|
||||
break
|
||||
done
|
||||
|
||||
if [ "${nohostroute}" != "1" ]; then
|
||||
( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
|
||||
fi
|
||||
|
||||
[ -z "$ipaddr" ] && {
|
||||
local wanif="$tunlink"
|
||||
if [ -z $wanif ] && ! network_find_wan wanif; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! network_get_ipaddr ipaddr "$wanif"; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
proto_init_update "ipip-$cfg" 1
|
||||
|
||||
proto_add_tunnel
|
||||
json_add_string mode "ipip"
|
||||
json_add_int mtu "${mtu:-1280}"
|
||||
json_add_int ttl "${ttl:-64}"
|
||||
[ -n "$tos" ] && json_add_string tos "$tos"
|
||||
json_add_string local "$ipaddr"
|
||||
json_add_string remote "$peeraddr"
|
||||
[ -n "$tunlink" ] && json_add_string link "$tunlink"
|
||||
json_add_boolean df "${df:-1}"
|
||||
|
||||
proto_close_tunnel
|
||||
|
||||
proto_add_data
|
||||
[ -n "$zone" ] && json_add_string zone "$zone"
|
||||
proto_close_data
|
||||
|
||||
proto_send_update "$cfg"
|
||||
}
|
||||
|
||||
proto_ipip_teardown() {
|
||||
local cfg="$1"
|
||||
}
|
||||
|
||||
proto_ipip_init_config() {
|
||||
no_device=1
|
||||
available=1
|
||||
|
||||
proto_config_add_int "mtu"
|
||||
proto_config_add_int "ttl"
|
||||
proto_config_add_string "tos"
|
||||
proto_config_add_string "tunlink"
|
||||
proto_config_add_string "zone"
|
||||
proto_config_add_string "ipaddr"
|
||||
proto_config_add_string "peeraddr"
|
||||
proto_config_add_boolean "df"
|
||||
proto_config_add_boolean "nohostroute"
|
||||
}
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
add_protocol ipip
|
||||
}
|
||||
83
package/network/config/ltq-adsl-app/Makefile
Normal file
83
package/network/config/ltq-adsl-app/Makefile
Normal file
@@ -0,0 +1,83 @@
|
||||
#
|
||||
# Copyright (C) 2011-2012 OpenWrt.org
|
||||
#
|
||||
# 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:=dsl_cpe_control_danube
|
||||
PKG_VERSION:=3.24.4.4
|
||||
PKG_RELEASE:=13
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/dsl_cpe_control-$(PKG_VERSION)
|
||||
PKG_SOURCE_URL:=@OPENWRT
|
||||
PKG_HASH:=af0bdf45cc7a62e2b38d39aad4924dd83c24fae170ae5bbd8190c2a3d9106257
|
||||
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
|
||||
PKG_LICENSE:=BSD-3-Clause
|
||||
|
||||
PKG_FIXUP:=autoreconf
|
||||
|
||||
PKG_CONFIG_DEPENDS:=\
|
||||
CONFIG_LTQ_DSL_ENABLE_SOAP \
|
||||
CONFIG_LTQ_DSL_ENABLE_DSL_EVENT_POLLING
|
||||
|
||||
PKG_BUILD_DEPENDS:=ltq-adsl
|
||||
|
||||
PKG_FLAGS:=nonshared
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/ltq-adsl-app
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Lantiq DSL userland tool
|
||||
URL:=http://www.lantiq.com/
|
||||
DEPENDS:=@(TARGET_lantiq_xway||TARGET_lantiq_xway_legacy||TARGET_lantiq_ase) +libpthread +ltq-dsl-base +libubox +libubus
|
||||
PROVIDES:=ltq-dsl-app
|
||||
MENU:=1
|
||||
endef
|
||||
|
||||
define Package/ltq-adsl-app/description
|
||||
Infineon DSL CPE API for Amazon SE, Danube and Vinax.
|
||||
endef
|
||||
|
||||
LTQ_DSL_MAX_DEVICE=1
|
||||
LTQ_DSL_LINES_PER_DEVICE=1
|
||||
LTQ_DSL_CHANNELS_PER_LINE=1
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--with-max-device="$(LTQ_DSL_MAX_DEVICE)" \
|
||||
--with-lines-per-device="$(LTQ_DSL_LINES_PER_DEVICE)" \
|
||||
--with-channels-per-line="$(LTQ_DSL_CHANNELS_PER_LINE)" \
|
||||
--enable-danube \
|
||||
--enable-driver-include="-I$(STAGING_DIR)/usr/include/adsl/" \
|
||||
--enable-add-appl-cflags="-DMAX_CLI_PIPES=2" \
|
||||
--enable-model=full \
|
||||
--disable-dsl-pm-retx-counters \
|
||||
--disable-dsl-pm-retx-thresholds \
|
||||
--disable-soap-support \
|
||||
--disable-dti \
|
||||
--disable-adsl-mib-support \
|
||||
--disable-adsl-trace \
|
||||
--enable-adsl-led
|
||||
|
||||
TARGET_CFLAGS += -I$(LINUX_DIR)/include
|
||||
|
||||
define Build/Prepare
|
||||
$(call Build/Prepare/Default)
|
||||
$(CP) ../ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c $(PKG_BUILD_DIR)/src/
|
||||
endef
|
||||
|
||||
define Package/ltq-adsl-app/install
|
||||
$(INSTALL_DIR) $(1)/etc/init.d $(1)/sbin $(1)/etc/hotplug.d/dsl
|
||||
$(INSTALL_BIN) ./files/dsl_control $(1)/etc/init.d/
|
||||
$(INSTALL_BIN) ./files/10_atm.sh $(1)/etc/hotplug.d/dsl
|
||||
$(INSTALL_BIN) ./files/10_ptm.sh $(1)/etc/hotplug.d/dsl
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/dsl_cpe_control $(1)/sbin
|
||||
$(INSTALL_BIN) ./files/dsl_cpe_pipe.sh $(1)/sbin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,ltq-adsl-app))
|
||||
29
package/network/config/ltq-adsl-app/files/10_atm.sh
Executable file
29
package/network/config/ltq-adsl-app/files/10_atm.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$DSL_NOTIFICATION_TYPE" = "DSL_STATUS" ] && \
|
||||
[ "$DSL_TC_LAYER_STATUS" = "ATM" ] && \
|
||||
! grep -q "ltq_atm_ar9\|ltq_atm_ase\|ltq_atm_danube" /proc/modules || exit 0
|
||||
|
||||
logger -p daemon.notice -t "dsl-notify" "Switching to TC-Layer ATM"
|
||||
|
||||
if grep -q "ltq_ptm_ar9\|ltq_ptm_ase\|ltq_ptm_danube" /proc/modules ; then
|
||||
logger -p daemon.notice -t "dsl-notify" "Loading ATM driver while EFM/PTM driver is loaded is not possible. Reboot is needed."
|
||||
exit
|
||||
fi
|
||||
|
||||
case "$(strings /proc/device-tree/compatible)" in
|
||||
*lantiq,ar9*)
|
||||
soc="ar9"
|
||||
;;
|
||||
*lantiq,ase*)
|
||||
soc="ase"
|
||||
;;
|
||||
*lantiq,danube*)
|
||||
soc="danube"
|
||||
;;
|
||||
*)
|
||||
logger -p daemon.notice -t "dsl-notify" "Unsupported SoC"
|
||||
exit
|
||||
esac
|
||||
|
||||
modprobe ltq_atm_${soc}
|
||||
29
package/network/config/ltq-adsl-app/files/10_ptm.sh
Executable file
29
package/network/config/ltq-adsl-app/files/10_ptm.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$DSL_NOTIFICATION_TYPE" = "DSL_STATUS" ] && \
|
||||
[ "$DSL_TC_LAYER_STATUS" = "EFM" ] && \
|
||||
! grep -q "ltq_ptm_ar9\|ltq_ptm_ase\|ltq_ptm_danube" /proc/modules || exit 0
|
||||
|
||||
logger -p daemon.notice -t "dsl-notify" "Switching to TC-Layer EFM/PTM"
|
||||
|
||||
if grep -q "ltq_atm_ar9\|ltq_atm_ase\|ltq_atm_danube" /proc/modules ; then
|
||||
logger -p daemon.notice -t "dsl-notify" "Loading EFM/PTM driver while ATM driver is loaded is not possible. Reboot is needed."
|
||||
exit
|
||||
fi
|
||||
|
||||
case "$(strings /proc/device-tree/compatible)" in
|
||||
*lantiq,ar9*)
|
||||
soc="ar9"
|
||||
;;
|
||||
*lantiq,ase*)
|
||||
soc="ase"
|
||||
;;
|
||||
*lantiq,danube*)
|
||||
soc="danube"
|
||||
;;
|
||||
*)
|
||||
logger -p daemon.notice -t "dsl-notify" "Unsupported SoC"
|
||||
exit
|
||||
esac
|
||||
|
||||
modprobe ltq_ptm_${soc}
|
||||
65
package/network/config/ltq-adsl-app/files/dsl_control
Normal file
65
package/network/config/ltq-adsl-app/files/dsl_control
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2012 OpenWrt.org
|
||||
|
||||
START=97
|
||||
USE_PROCD=1
|
||||
|
||||
dslstat() {
|
||||
ubus call dsl metrics
|
||||
}
|
||||
|
||||
extra_command "dslstat" "Get DSL status information"
|
||||
|
||||
annex_b=10_00_10_00_00_04_00_00
|
||||
annex_bdmt=10_00_00_00_00_00_00_00
|
||||
annex_b2=00_00_10_00_00_00_00_00
|
||||
annex_b2p=00_00_00_00_00_04_00_00
|
||||
annex_a=05_01_04_00_4C_01_04_00
|
||||
annex_at1=01_00_00_00_00_00_00_00
|
||||
annex_alite=00_01_00_00_00_00_00_00
|
||||
annex_admt=04_00_00_00_00_00_00_00
|
||||
annex_a2=00_00_04_00_00_00_00_00
|
||||
annex_a2p=00_00_00_00_00_01_00_00
|
||||
annex_l=00_00_00_00_0C_00_00_00
|
||||
annex_m=00_00_00_00_40_00_04_00
|
||||
annex_m2=00_00_00_00_40_00_00_00
|
||||
annex_m2p=00_00_00_00_00_00_04_00
|
||||
annex_j=10_00_10_40_00_04_01_00
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger network
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local annex
|
||||
local firmware
|
||||
local xtu
|
||||
config_load network
|
||||
config_get annex dsl annex
|
||||
config_get firmware dsl firmware
|
||||
|
||||
eval "xtu=\"\${annex_$annex}\""
|
||||
|
||||
[ -z "${firmware}" ] &&
|
||||
firmware=/lib/firmware/adsl.bin
|
||||
[ -f "${firmware}" ] || {
|
||||
echo failed to find $firmware
|
||||
return 1
|
||||
}
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /sbin/dsl_cpe_control \
|
||||
-i${xtu} \
|
||||
-n /sbin/dsl_notify.sh \
|
||||
-f ${firmware}
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
DSL_NOTIFICATION_TYPE="DSL_INTERFACE_STATUS" \
|
||||
DSL_INTERFACE_STATUS="DOWN" \
|
||||
/sbin/dsl_notify.sh
|
||||
|
||||
service_stop /sbin/dsl_cpe_control
|
||||
}
|
||||
|
||||
18
package/network/config/ltq-adsl-app/files/dsl_cpe_pipe.sh
Executable file
18
package/network/config/ltq-adsl-app/files/dsl_cpe_pipe.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
pipe_no=0
|
||||
|
||||
# use specified pipe no
|
||||
case "$1" in
|
||||
0|1|2)
|
||||
pipe_no=$1; shift; ;;
|
||||
esac
|
||||
|
||||
|
||||
#echo "Call dsl_pipe with $*"
|
||||
lock /var/lock/dsl_pipe
|
||||
echo $* > /tmp/pipe/dsl_cpe${pipe_no}_cmd
|
||||
result=$(cat /tmp/pipe/dsl_cpe${pipe_no}_ack)
|
||||
lock -u /var/lock/dsl_pipe
|
||||
|
||||
echo "$result"
|
||||
@@ -0,0 +1,65 @@
|
||||
--- a/src/dsl_cpe_cli_access.c
|
||||
+++ b/src/dsl_cpe_cli_access.c
|
||||
@@ -1142,7 +1142,7 @@ DSL_CLI_LOCAL DSL_int_t DSL_CPE_CLI_Auto
|
||||
|
||||
if ((ret < 0) && (autobootCtrl.accessCtl.nReturn < DSL_SUCCESS))
|
||||
{
|
||||
- DSL_CPE_FPrintf (out, sFailureReturn, autobootCtrl.accessCtl.nReturn);
|
||||
+ DSL_CPE_FPrintf (out, sFailureReturn, autobootCtrl.accessCtl.nReturn, DSL_CPE_Fd2DevStr(fd));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1213,7 +1213,7 @@ DSL_CLI_LOCAL DSL_int_t DSL_CPE_CLI_Auto
|
||||
|
||||
if ((ret < 0) && (pData.accessCtl.nReturn < DSL_SUCCESS))
|
||||
{
|
||||
- DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn);
|
||||
+ DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn, DSL_CPE_Fd2DevStr(fd));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1290,7 +1290,7 @@ DSL_CLI_LOCAL DSL_int_t DSL_CPE_CLI_Line
|
||||
|
||||
if ((ret < 0) && (pData.accessCtl.nReturn < DSL_SUCCESS))
|
||||
{
|
||||
- DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn);
|
||||
+ DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn, DSL_CPE_Fd2DevStr(fd));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1355,7 +1355,7 @@ DSL_CLI_LOCAL DSL_int_t DSL_CPE_CLI_Reso
|
||||
pCtx, &resourceUsageStatisticsData);
|
||||
if (ret < 0)
|
||||
{
|
||||
- DSL_CPE_FPrintf (out, sFailureReturn, ret);
|
||||
+ DSL_CPE_FPrintf (out, sFailureReturn, ret, DSL_CPE_Fd2DevStr(fd));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3084,7 +3084,7 @@ DSL_CLI_LOCAL DSL_int_t DSL_CPE_CLI_G997
|
||||
|
||||
if ((ret < 0) && (pData->accessCtl.nReturn < DSL_SUCCESS))
|
||||
{
|
||||
- DSL_CPE_FPrintf (out, sFailureReturn, pData->accessCtl.nReturn);
|
||||
+ DSL_CPE_FPrintf (out, sFailureReturn, pData->accessCtl.nReturn, DSL_CPE_Fd2DevStr(fd));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4654,7 +4654,7 @@ DSL_CLI_LOCAL DSL_int_t DSL_CPE_CLI_G997
|
||||
|
||||
if ((ret < 0) && (pData.accessCtl.nReturn < DSL_SUCCESS))
|
||||
{
|
||||
- DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn);
|
||||
+ DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn, DSL_CPE_Fd2DevStr(fd));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5714,7 +5714,7 @@ DSL_CLI_LOCAL DSL_int_t DSL_CPE_CLI_G997
|
||||
|
||||
if ((ret < 0) && (pData.accessCtl.nReturn < DSL_SUCCESS))
|
||||
{
|
||||
- DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn);
|
||||
+ DSL_CPE_FPrintf (out, sFailureReturn, pData.accessCtl.nReturn, DSL_CPE_Fd2DevStr(fd));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -0,0 +1,23 @@
|
||||
--- a/configure.in
|
||||
+++ b/configure.in
|
||||
@@ -29,6 +29,8 @@ AC_C_VOLATILE
|
||||
#AC_FUNC_STRTOD
|
||||
#AC_CHECK_FUNCS([ftime gethostbyname gettimeofday localtime_r memset select socket strchr strerror strstr strtoull])
|
||||
|
||||
+AC_SEARCH_LIBS([clock_gettime],[rt])
|
||||
+
|
||||
#
|
||||
# save the configure arguments
|
||||
#
|
||||
--- a/src/dsl_cpe_linux.h
|
||||
+++ b/src/dsl_cpe_linux.h
|
||||
@@ -45,7 +45,8 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h> /* socket */
|
||||
#include <sys/sem.h> /* semget */
|
||||
-#include <semaphore.h> /* sem_t */
|
||||
+#include <semaphore.h> /* sem_t */
|
||||
+#include <limits.h>
|
||||
|
||||
#ifdef DSL_DEBUG_TOOL_INTERFACE
|
||||
#include <sys/socket.h>
|
||||
@@ -0,0 +1,42 @@
|
||||
From 9d4f86ba2cf10304303011f4f5628fa68dc77624 Mon Sep 17 00:00:00 2001
|
||||
From: Mathias Kresin <dev@kresin.me>
|
||||
Date: Mon, 16 Oct 2017 21:08:26 +0200
|
||||
Subject: ltq-adsl-app: add more script notifications
|
||||
|
||||
Backport HANDSHAKE and TRAINING notification from ltq-vdsl-vr9-app. It
|
||||
unifies the dsl led blinking pattern accross all subtargets and allows
|
||||
to get the current line status from the dsl led.
|
||||
|
||||
Signed-off-by: Mathias Kresin <dev@kresin.me>
|
||||
---
|
||||
.../100-add-more-script-notifications.patch | 27 ++++++++++++++++++++++
|
||||
1 file changed, 27 insertions(+)
|
||||
create mode 100644 package/network/config/ltq-adsl-app/patches/100-add-more-script-notifications.patch
|
||||
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -3273,7 +3273,23 @@ DSL_CPE_STATIC DSL_int_t DSL_CPE_Event_S
|
||||
#ifdef INCLUDE_SCRIPT_NOTIFICATION
|
||||
if (g_sRcScript != DSL_NULL)
|
||||
{
|
||||
- if ( (nLineState == DSL_LINESTATE_SHOWTIME_TC_SYNC) &&
|
||||
+ if ( (nLineState == DSL_LINESTATE_HANDSHAKE) &&
|
||||
+ (g_nPrevLineState[nDevice] != DSL_LINESTATE_HANDSHAKE) )
|
||||
+ {
|
||||
+ if (DSL_CPE_SetEnv("DSL_INTERFACE_STATUS", "HANDSHAKE") == DSL_SUCCESS)
|
||||
+ {
|
||||
+ bExec = DSL_TRUE;
|
||||
+ }
|
||||
+ }
|
||||
+ else if ( (nLineState == DSL_LINESTATE_FULL_INIT) &&
|
||||
+ (g_nPrevLineState[nDevice] != DSL_LINESTATE_FULL_INIT) )
|
||||
+ {
|
||||
+ if (DSL_CPE_SetEnv("DSL_INTERFACE_STATUS", "TRAINING") == DSL_SUCCESS)
|
||||
+ {
|
||||
+ bExec = DSL_TRUE;
|
||||
+ }
|
||||
+ }
|
||||
+ else if ( (nLineState == DSL_LINESTATE_SHOWTIME_TC_SYNC) &&
|
||||
(g_nPrevLineState[nDevice] != DSL_LINESTATE_SHOWTIME_TC_SYNC) )
|
||||
{
|
||||
if (DSL_CPE_SetEnv("DSL_INTERFACE_STATUS", "UP") == DSL_SUCCESS)
|
||||
50
package/network/config/ltq-adsl-app/patches/300-ubus.patch
Normal file
50
package/network/config/ltq-adsl-app/patches/300-ubus.patch
Normal file
@@ -0,0 +1,50 @@
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -139,6 +139,9 @@ extern DSL_Error_t DSL_CPE_Pipe_StaticRe
|
||||
#endif /* INCLUDE_DSL_RESOURCE_STATISTICS*/
|
||||
#endif
|
||||
|
||||
+extern void ubus_init();
|
||||
+extern void ubus_deinit();
|
||||
+
|
||||
DSL_char_t *g_sFirmwareName1 = DSL_NULL;
|
||||
DSL_char_t *g_sFirmwareName2 = DSL_NULL;
|
||||
#ifdef INCLUDE_SCRIPT_NOTIFICATION
|
||||
@@ -5343,6 +5346,8 @@ DSL_int_t dsl_cpe_daemon (
|
||||
signal (SIGINT, DSL_CPE_TerminationHandler);
|
||||
#endif /* RTEMS*/
|
||||
|
||||
+ ubus_init();
|
||||
+
|
||||
/* Open DSL_CPE_MAX_DEVICE_NUMBER devices*/
|
||||
for (nDevice = 0; nDevice < DSL_CPE_MAX_DEVICE_NUMBER; nDevice++)
|
||||
{
|
||||
@@ -5738,6 +5743,7 @@ DSL_int_t dsl_cpe_daemon (
|
||||
#endif /* INCLUDE_DSL_CPE_CLI_SUPPORT */
|
||||
|
||||
DSL_CPE_CONTROL_EXIT:
|
||||
+ ubus_deinit();
|
||||
|
||||
#ifdef INCLUDE_DSL_BONDING
|
||||
DSL_CPE_BND_Stop((DSL_CPE_BND_Context_t*)pCtrlCtx->pBnd);
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -11,7 +11,7 @@ else
|
||||
dsl_cpe_control_common_ldflags =
|
||||
endif
|
||||
|
||||
-dsl_cpe_control_LDADD = -lpthread
|
||||
+dsl_cpe_control_LDADD = -lpthread -lubox -lubus
|
||||
|
||||
if INCLUDE_DSL_CPE_SOAP_SUPPORT
|
||||
dsl_cpe_control_LDADD += -lm
|
||||
@@ -70,7 +70,8 @@ dsl_cpe_control_SOURCES = \
|
||||
dsl_cpe_control.c \
|
||||
dsl_cpe_init_cfg.c \
|
||||
dsl_cpe_linux.c \
|
||||
- dsl_cpe_debug.c
|
||||
+ dsl_cpe_debug.c \
|
||||
+ dsl_cpe_ubus.c
|
||||
|
||||
dsl_cpe_control_SOURCES += \
|
||||
$(dsl_cpe_control_dti_sources)
|
||||
92
package/network/config/ltq-vdsl-vr11-app/Makefile
Normal file
92
package/network/config/ltq-vdsl-vr11-app/Makefile
Normal file
@@ -0,0 +1,92 @@
|
||||
# Copyright (C) 2010 OpenWrt.org
|
||||
# Copyright (C) 2015-2016 Lantiq Beteiligungs GmbH & Co KG.
|
||||
#
|
||||
# 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:=ltq-vdsl-vr11-app
|
||||
PKG_VERSION:=4.23.1
|
||||
PKG_RELEASE:=5
|
||||
PKG_BASE_NAME:=dsl_cpe_control
|
||||
|
||||
UGW_VERSION=8.5.2.10
|
||||
UGW_BASENAME=$(PKG_BASE_NAME)-ugw_$(UGW_VERSION)
|
||||
|
||||
PKG_SOURCE:=$(UGW_BASENAME).tar.bz2
|
||||
PKG_SOURCE_URL:=https://gitlab.com/prpl-foundation/intel/$(PKG_BASE_NAME)/-/archive/ugw_$(UGW_VERSION)/
|
||||
PKG_HASH:=d21ec74ca30f7f3893a8aa26d2b74ec319652f6b112832efab6f1274c7e5d1fc
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(UGW_BASENAME)
|
||||
PKG_LICENSE:=BSD-2-Clause
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
PKG_BUILD_DEPENDS:=ltq-vdsl-vr11
|
||||
|
||||
PKG_FLAGS:=nonshared
|
||||
PKG_FIXUP:=autoreconf
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/ltq-vdsl-vr11-app
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Lantiq VDSL userland tool
|
||||
URL:=http://www.lantiq.com/
|
||||
DEPENDS:=@TARGET_ipq40xx +libpthread +librt +libubox +libubus +ltq-dsl-base +kmod-ltq-vdsl-vr11
|
||||
PROVIDES:=ltq-dsl-app
|
||||
endef
|
||||
|
||||
define Package/ltq-vdsl-vr11-app/description
|
||||
Userland tool needed to control Lantiq VDSL CPE
|
||||
endef
|
||||
|
||||
# ltq-vdsl-vr11-app uses a header provided by the MEI driver which has some
|
||||
# conditionals.
|
||||
#
|
||||
# Define them here with the default values they would get in the MEI driver,
|
||||
# have the same view on both sides.
|
||||
#
|
||||
# If you change them, you need to change them for the ltq-vdsl-vr11-app as well
|
||||
VDSL_APP_CFLAGS = \
|
||||
-DMAX_CLI_PIPES=1 \
|
||||
-DMEI_SUPPORT_DEBUG_STREAMS=1 \
|
||||
-DMEI_SUPPORT_OPTIMIZED_FW_DL=1
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--enable-debug-logger-support=no
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--enable-vrx \
|
||||
--enable-vrx-device=vr11 \
|
||||
--enable-driver-include="-I$(STAGING_DIR)/usr/include/drv_vdsl_cpe_api" \
|
||||
--enable-device-driver-include="-I$(STAGING_DIR)/usr/include/vdsl/" \
|
||||
--enable-ifxos \
|
||||
--enable-ifxos-include="-I$(STAGING_DIR)/usr/include/ifxos" \
|
||||
--enable-ifxos-library="-I$(STAGING_DIR)/usr/lib" \
|
||||
--enable-add-appl-cflags="$(VDSL_APP_CFLAGS)" \
|
||||
--enable-debug \
|
||||
--disable-dti
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--enable-model=full \
|
||||
--enable-dsl-ceoc=no
|
||||
#CONFIGURE_ARGS += --enable-model=lite
|
||||
#CONFIGURE_ARGS += --enable-model=footprint
|
||||
#CONFIGURE_ARGS += --enable-model=typical
|
||||
#CONFIGURE_ARGS += --enable-model=debug
|
||||
|
||||
define Build/Prepare
|
||||
$(call Build/Prepare/Default)
|
||||
$(CP) ../ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c $(PKG_BUILD_DIR)/src/
|
||||
endef
|
||||
|
||||
define Package/ltq-vdsl-vr11-app/install
|
||||
$(INSTALL_DIR) $(1)/etc/init.d $(1)/sbin $(1)/etc/hotplug.d/dsl
|
||||
$(INSTALL_BIN) ./files/dsl_control $(1)/etc/init.d/
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/dsl_cpe_control $(1)/sbin/vdsl_cpe_control
|
||||
$(INSTALL_BIN) ./files/dsl_cpe_pipe.sh $(1)/sbin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,ltq-vdsl-vr11-app))
|
||||
265
package/network/config/ltq-vdsl-vr11-app/files/dsl_control
Normal file
265
package/network/config/ltq-vdsl-vr11-app/files/dsl_control
Normal file
@@ -0,0 +1,265 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2012 OpenWrt.org
|
||||
|
||||
START=97
|
||||
USE_PROCD=1
|
||||
|
||||
dslstat() {
|
||||
ubus call dsl metrics
|
||||
}
|
||||
|
||||
extra_command "dslstat" "Get DSL status information"
|
||||
|
||||
#
|
||||
# ITU-T G.997.1 (06/2012) - Section 7.3.1.1.1 (xTU transmission system enabling (XTSE))
|
||||
# ITU-T G.997.1 Amendment 2 (04/2013) - Section 2.1 - (Vectoring mode enable (VECTORMODE_ENABLE))
|
||||
#
|
||||
# G.992.1 Annex A
|
||||
# G.992.2 Annex A
|
||||
# G.992.3 Annex A / L-US1 / L_US-2 / M
|
||||
# G.992.5 Annex A / M
|
||||
# G.993.2 Annex A/B/C
|
||||
# G.993.5 Annex A/B/C
|
||||
xtse_xdsl_a="05_01_04_00_4C_01_04_07"
|
||||
|
||||
# G.992.1 Annex B
|
||||
# G.992.3 Annex B
|
||||
# G.992.5 Annex B
|
||||
# G.993.2 Annex A/B/C
|
||||
# G.993.5 Annex A/B/C
|
||||
xtse_xdsl_b="10_00_10_00_00_04_00_07"
|
||||
|
||||
# G.992.1 Annex B
|
||||
# G.992.3 Annex B
|
||||
# G.992.3 Annex J
|
||||
# G.992.5 Annex B
|
||||
# G.992.5 Annex J
|
||||
# G.993.2 Annex A/B/C
|
||||
# G.993.5 Annex A/B/C
|
||||
xtse_xdsl_j="10_00_10_40_00_04_01_07"
|
||||
|
||||
# G.992.1 Annex B
|
||||
xtse_xdsl_bdmt="10_00_00_00_00_00_00_00"
|
||||
|
||||
# G.992.3 Annex B
|
||||
xtse_xdsl_b2="00_00_10_00_00_00_00_00"
|
||||
|
||||
# G.992.5 Annex B
|
||||
xtse_xdsl_b2p="00_00_00_00_00_04_00_00"
|
||||
|
||||
# ANSI T1.413
|
||||
xtse_xdsl_at1="01_00_00_00_00_00_00_00"
|
||||
|
||||
# G.992.2 Annex A
|
||||
xtse_xdsl_alite="00_01_00_00_00_00_00_00"
|
||||
|
||||
# G.992.1 Annex A
|
||||
xtse_xdsl_admt="04_00_00_00_00_00_00_00"
|
||||
|
||||
# G.992.3 Annex A
|
||||
xtse_xdsl_a2="00_00_04_00_00_00_00_00"
|
||||
|
||||
# G.992.5 Annex A
|
||||
xtse_xdsl_a2p="00_00_00_00_00_01_00_00"
|
||||
|
||||
# G.992.3 Annex L
|
||||
xtse_xdsl_l="00_00_00_00_0C_00_00_00"
|
||||
|
||||
# G.992.3 Annex M
|
||||
# G.992.5 Annex M
|
||||
xtse_xdsl_m="00_00_00_00_40_00_04_00"
|
||||
|
||||
# G.992.3 Annex M
|
||||
xtse_xdsl_m2="00_00_00_00_40_00_00_00"
|
||||
|
||||
# G.992.5 Annex M
|
||||
xtse_xdsl_m2p="00_00_00_00_00_00_04_00"
|
||||
|
||||
#
|
||||
# ITU-T G.994.1 (06/2012) - Table 2 (Mandatory carrier sets)
|
||||
#
|
||||
|
||||
# A43
|
||||
tone_adsl_a="0x142" # A43C + J43 + A43
|
||||
tone_vdsl_a="0x142" # A43C + J43 + A43
|
||||
|
||||
# A43 + V43
|
||||
tone_adsl_av="0x142" # A43C + J43 + A43
|
||||
tone_vdsl_av="0x146" # A43C + J43 + A43 + V43
|
||||
|
||||
# B43
|
||||
tone_adsl_b="0x81" # B43 + B43c
|
||||
tone_vdsl_b="0x1" # B43
|
||||
|
||||
# B43 + V43
|
||||
tone_adsl_bv="0x81" # B43 + B43c
|
||||
tone_vdsl_bv="0x5" # B43 + V43
|
||||
|
||||
# create DSL autoboot script. Used for SNR margin tweak and to set MAC address for vectoring error reports
|
||||
autoboot_script() {
|
||||
echo "[WaitForConfiguration]={
|
||||
locs nLine=0 0 $1
|
||||
dsmmcs nLine=0 $2
|
||||
}
|
||||
|
||||
[WaitForLinkActivate]={
|
||||
}
|
||||
|
||||
[WaitForRestart]={
|
||||
}
|
||||
|
||||
[Common]={
|
||||
}" > /tmp/dsl.scr
|
||||
}
|
||||
|
||||
lowlevel_cfg() {
|
||||
echo "# VRX Low Level Configuration File
|
||||
#
|
||||
# Parameters must be separated by tabs or spaces.
|
||||
# Empty lines and comments will be ignored.
|
||||
#
|
||||
|
||||
# nFilter
|
||||
#
|
||||
# NA = -1
|
||||
# OFF = 0
|
||||
# ISDN = 1
|
||||
# POTS = 2
|
||||
# POTS_2 = 3
|
||||
# POTS_3 = 4
|
||||
#
|
||||
# (dec)
|
||||
-1
|
||||
|
||||
# nHsToneGroupMode nHsToneGroup_A nHsToneGroup_V nHsToneGroup_AV
|
||||
#
|
||||
# NA = -1 NA = -1 see see
|
||||
# AUTO = 0 VDSL2_B43 = 0x0001 nHsToneGroup_A nHsToneGroup_A
|
||||
# MANUAL = 1 VDSL2_A43 = 0x0002
|
||||
# VDSL2_V43 = 0x0004
|
||||
# VDSL1_V43P = 0x0008
|
||||
# VDSL1_V43I = 0x0010
|
||||
# ADSL1_C43 = 0x0020
|
||||
# ADSL2_J43 = 0x0040
|
||||
# ADSL2_B43C = 0x0080
|
||||
# ADSL2_A43C = 0x0100
|
||||
#
|
||||
# (dec) (hex) (hex) (hex)
|
||||
1 $1 $2 0x0
|
||||
|
||||
# nBaseAddr nIrqNum
|
||||
#
|
||||
# (hex) (dec)
|
||||
0x1e116000 63
|
||||
|
||||
# nUtopiaPhyAdr nUtopiaBusWidth nPosPhyParity
|
||||
# default(16b) = 0 NA = -1
|
||||
# 8-bit = 1 ODD = 0
|
||||
# 16-bit = 2
|
||||
#
|
||||
#
|
||||
# (hex) (dec) (dec)
|
||||
0xFF 0 0
|
||||
|
||||
# bNtrEnable
|
||||
#
|
||||
# (dec)
|
||||
0" > /tmp/lowlevel.cfg
|
||||
}
|
||||
|
||||
get_macaddr() {
|
||||
local name
|
||||
config_get name $1 name
|
||||
[ "$name" = "dsl0" ] && config_get $2 $1 macaddr
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger network
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local annex
|
||||
local firmware
|
||||
local tone
|
||||
local tone_adsl
|
||||
local tone_vdsl
|
||||
local xtse
|
||||
local xfer_mode
|
||||
local line_mode
|
||||
local tc_layer
|
||||
local mode
|
||||
local lowlevel
|
||||
local snr
|
||||
local macaddr
|
||||
|
||||
config_load network
|
||||
config_get tone dsl tone
|
||||
config_get annex dsl annex
|
||||
config_get firmware dsl firmware
|
||||
config_get xfer_mode dsl xfer_mode
|
||||
config_get line_mode dsl line_mode
|
||||
config_get snr dsl ds_snr_offset
|
||||
config_foreach get_macaddr device macaddr
|
||||
|
||||
eval "xtse=\"\${xtse_xdsl_$annex}\""
|
||||
|
||||
case "${xfer_mode}" in
|
||||
atm)
|
||||
tc_layer="-T1:0x1:0x1_1:0x1:0x1"
|
||||
;;
|
||||
ptm)
|
||||
tc_layer="-T2:0x1:0x1_2:0x1:0x1"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${line_mode}" in
|
||||
adsl)
|
||||
mode="-M1"
|
||||
|
||||
# mask out VDSL bits when ADSL is requested
|
||||
xtse="${xtse%_*}_00"
|
||||
;;
|
||||
vdsl)
|
||||
mode="-M2"
|
||||
|
||||
# mask out ADSL bits when VDSL is requested
|
||||
xtse="00_00_00_00_00_00_00_${xtse##*_}"
|
||||
;;
|
||||
esac
|
||||
|
||||
[ -z "${firmware}" ] && firmware=/lib/firmware/vdsl.bin
|
||||
[ -f "${firmware}" ] || {
|
||||
echo failed to find $firmware
|
||||
return 1
|
||||
}
|
||||
|
||||
eval "tone_adsl=\"\${tone_adsl_$tone}\""
|
||||
eval "tone_vdsl=\"\${tone_vdsl_$tone}\""
|
||||
[ -n "${tone_adsl}" ] && [ -n "${tone_vdsl}" ] && {
|
||||
lowlevel_cfg "${tone_adsl}" "${tone_vdsl}"
|
||||
lowlevel="-l /tmp/lowlevel.cfg"
|
||||
}
|
||||
|
||||
[ -z "${snr}" ] && snr=0
|
||||
[ -z "${macaddr}" ] && macaddr="00:00:00:00:00:00"
|
||||
autoboot_script "$snr" "$macaddr"
|
||||
autoboot="-a /tmp/dsl.scr -A /tmp/dsl.scr"
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /sbin/vdsl_cpe_control \
|
||||
-i$xtse \
|
||||
-n /sbin/dsl_notify.sh \
|
||||
-f ${firmware} \
|
||||
$lowlevel \
|
||||
${mode} \
|
||||
${tc_layer} \
|
||||
$autoboot
|
||||
procd_set_param term_timeout 10
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
DSL_NOTIFICATION_TYPE="DSL_INTERFACE_STATUS" \
|
||||
DSL_INTERFACE_STATUS="DOWN" \
|
||||
/sbin/dsl_notify.sh
|
||||
}
|
||||
18
package/network/config/ltq-vdsl-vr11-app/files/dsl_cpe_pipe.sh
Executable file
18
package/network/config/ltq-vdsl-vr11-app/files/dsl_cpe_pipe.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
pipe_no=0
|
||||
|
||||
# use specified pipe no
|
||||
case "$1" in
|
||||
0|1|2)
|
||||
pipe_no=$1; shift; ;;
|
||||
esac
|
||||
|
||||
|
||||
#echo "Call dsl_pipe with $*"
|
||||
lock /var/lock/dsl_pipe
|
||||
echo $* > /tmp/pipe/dsl_cpe${pipe_no}_cmd
|
||||
result=$(cat /tmp/pipe/dsl_cpe${pipe_no}_ack)
|
||||
lock -u /var/lock/dsl_pipe
|
||||
|
||||
echo "$result"
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/src/dsl_cpe_init_cfg.c
|
||||
+++ b/src/dsl_cpe_init_cfg.c
|
||||
@@ -38,7 +38,7 @@ DSL_InitData_t gInitCfgData =
|
||||
DSL_DEV_HS_TONE_GROUP_CLEANED, \
|
||||
DSL_DEV_HS_TONE_GROUP_CLEANED, \
|
||||
DSL_DEV_HS_TONE_GROUP_CLEANED, \
|
||||
- 0x1E116000, 0x37, -1),
|
||||
+ 0x1E116000, 0x3f, -1),
|
||||
DSL_CPE_SIC_SET(DSL_TC_ATM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII, \
|
||||
DSL_TC_EFM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII),
|
||||
DSL_CPE_MAC_CFG_SET(DSL_EFM_SPEED_100, DSL_EFM_DUPLEX_FULL, DSL_EFM_FLOWCTRL_ON, DSL_EFM_AUTONEG_OFF, \
|
||||
@@ -0,0 +1,87 @@
|
||||
--- a/src/dsl_cpe_control.h
|
||||
+++ b/src/dsl_cpe_control.h
|
||||
@@ -13,6 +13,8 @@
|
||||
#ifndef _DSL_CPE_CONTROL_H
|
||||
#define _DSL_CPE_CONTROL_H
|
||||
|
||||
+#include <string.h>
|
||||
+
|
||||
/** \defgroup DSL_CPE_CONTROL Lantiq DSL CPE API Control Application
|
||||
Lists the entire modules to the DSL CPE_API Control Application.
|
||||
@{ */
|
||||
--- a/src/dsl_cpe_safec_wrapper.h
|
||||
+++ b/src/dsl_cpe_safec_wrapper.h
|
||||
@@ -23,7 +23,7 @@
|
||||
#define cpe_control_vsnprintf_s vsnprintf_s
|
||||
|
||||
/* snprintf_s symbol is not exported in SafeC lib */
|
||||
-static int cpe_control_snprintf_s(char *dest,
|
||||
+static inline int cpe_control_snprintf_s(char *dest,
|
||||
size_t dmax,
|
||||
const char *fmt,
|
||||
...)
|
||||
@@ -40,7 +40,7 @@ static int cpe_control_snprintf_s(char *
|
||||
|
||||
#else
|
||||
|
||||
-#warning "Safe C library is not available!"
|
||||
+//#warning "Safe C library is not available!"
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <stdarg.h> /* va_list */
|
||||
@@ -55,7 +55,7 @@ static __inline__ size_t safec_wrapper_m
|
||||
#define cpe_control_memset_s(dest, destsz, src, srcsz) memset(dest, src, safec_wrapper_min(destsz,srcsz))
|
||||
#define cpe_control_strncpy_s(dest, destsz, src, srcsz) strncpy(dest, src, safec_wrapper_min(destsz,srcsz))
|
||||
|
||||
-static size_t cpe_control_strnlen_s(const char *str,
|
||||
+static inline size_t cpe_control_strnlen_s(const char *str,
|
||||
size_t smax)
|
||||
{
|
||||
/* preconditions */
|
||||
@@ -74,7 +74,7 @@ static size_t cpe_control_strnlen_s(cons
|
||||
return size;
|
||||
}
|
||||
|
||||
-static char *cpe_control_strtok_s(char *dest,
|
||||
+static inline char *cpe_control_strtok_s(char *dest,
|
||||
size_t *dmax,
|
||||
const char *delim,
|
||||
char **ptr)
|
||||
@@ -123,7 +123,7 @@ static char *cpe_control_strtok_s(char *
|
||||
return pTmp;
|
||||
}
|
||||
|
||||
-static int cpe_control_pipe_strcat_s(char *dest,
|
||||
+static inline int cpe_control_pipe_strcat_s(char *dest,
|
||||
size_t destsz,
|
||||
char *src)
|
||||
{
|
||||
@@ -157,7 +157,7 @@ static int cpe_control_pipe_strcat_s(cha
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cpe_control_snprintf_s(char *dest,
|
||||
+static inline int cpe_control_snprintf_s(char *dest,
|
||||
size_t dmax,
|
||||
const char *fmt,
|
||||
...)
|
||||
@@ -181,7 +181,7 @@ static int cpe_control_snprintf_s(char *
|
||||
return retVal;
|
||||
}
|
||||
|
||||
-static int cpe_control_vsnprintf_s(char *dest,
|
||||
+static inline int cpe_control_vsnprintf_s(char *dest,
|
||||
size_t dmax,
|
||||
const char *fmt,
|
||||
va_list vlist)
|
||||
--- a/tools/pipe/dsl_cpe_safec_wrapper.h
|
||||
+++ b/tools/pipe/dsl_cpe_safec_wrapper.h
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#else
|
||||
|
||||
-#warning "Safe C library is not available!"
|
||||
+//#warning "Safe C library is not available!"
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
static __inline__ size_t safec_wrapper_min(size_t a, size_t b)
|
||||
@@ -0,0 +1,149 @@
|
||||
This enables automatic connection after the control daemon is started,
|
||||
and also changes the way the connection is stopped on termination.
|
||||
|
||||
Using the autoboot restart command (in combination with configuring the
|
||||
state machine to wait) is necessary because the stop command would stop
|
||||
the autoboot thread, and the driver offers no working way to start it
|
||||
again later, short of unloading and reloading the module.
|
||||
|
||||
The disconnection code is also moved to a separate function, so it can
|
||||
be called in other exit code paths than the one for SIGTERM.
|
||||
|
||||
--- a/src/dsl_cpe_init_cfg.c
|
||||
+++ b/src/dsl_cpe_init_cfg.c
|
||||
@@ -27,7 +27,7 @@ DSL_InitData_t gInitCfgData =
|
||||
DSL_CPE_FW2_SET(DSL_NULL, 0x0),
|
||||
DSL_CPE_XTU_SET(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7),
|
||||
DSL_CPE_LINE_INV_NE_SET(DSL_NULL),
|
||||
- DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_STOP),
|
||||
+ DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_START),
|
||||
DSL_CPE_AUTOBOOT_CFG_SET(DSL_FALSE, DSL_FALSE, DSL_FALSE),
|
||||
DSL_CPE_TEST_MODE_CTRL_SET(DSL_TESTMODE_DISABLE),
|
||||
DSL_CPE_LINE_ACTIVATE_CTRL_SET(DSL_G997_INHIBIT_LDSF, DSL_G997_INHIBIT_ACSF, DSL_G997_NORMAL_STARTUP),
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -7252,6 +7252,58 @@ static DSL_boolean_t DSL_CPE_DebugAndTes
|
||||
#endif /* defined(DSL_DEBUG_TOOL_INTERFACE) || defined(INCLUDE_DSL_CPE_DTI_SUPPORT) */
|
||||
#endif /* defined(INCLUDE_DSL_JSON_PARSING) && (INCLUDE_DSL_JSON_PARSING == 1) */
|
||||
|
||||
+DSL_CPE_STATIC DSL_void_t DSL_CPE_ShutdownConnection(void)
|
||||
+{
|
||||
+ DSL_Error_t nRet = DSL_SUCCESS;
|
||||
+ DSL_int_t nDevice = 0;
|
||||
+ DSL_AutobootConfig_t sAutobootCfg;
|
||||
+ DSL_AutobootControl_t sAutobootCtl;
|
||||
+
|
||||
+ for (nDevice = 0; nDevice < DSL_CPE_DSL_ENTITIES; ++nDevice)
|
||||
+ {
|
||||
+ g_bWaitBeforeConfigWrite[nDevice] = DSL_TRUE;
|
||||
+ g_bWaitBeforeLinkActivation[nDevice] = DSL_TRUE;
|
||||
+ g_bWaitBeforeRestart[nDevice] = DSL_TRUE;
|
||||
+
|
||||
+ g_bAutoContinueWaitBeforeConfigWrite[nDevice] = DSL_FALSE;
|
||||
+ g_bAutoContinueWaitBeforeLinkActivation[nDevice] = DSL_FALSE;
|
||||
+ g_bAutoContinueWaitBeforeRestart[nDevice] = DSL_FALSE;
|
||||
+
|
||||
+ memset(&sAutobootCfg, 0x0, sizeof(DSL_AutobootConfig_t));
|
||||
+ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeConfigWrite = DSL_TRUE;
|
||||
+ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeLinkActivation = DSL_TRUE;
|
||||
+ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeRestart = DSL_TRUE;
|
||||
+
|
||||
+ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
|
||||
+ DSL_CPE_GetGlobalContext()->fd[nDevice],
|
||||
+ DSL_FIO_AUTOBOOT_CONFIG_SET, (DSL_int_t)&sAutobootCfg);
|
||||
+
|
||||
+ if (nRet < DSL_SUCCESS)
|
||||
+ {
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
|
||||
+ "Autoboot configuration for device (%d) failed!, nRet = %d!"
|
||||
+ DSL_CPE_CRLF, nDevice, sAutobootCfg.accessCtl.nReturn));
|
||||
+ }
|
||||
+
|
||||
+ memset(&sAutobootCtl, 0, sizeof(DSL_AutobootControl_t));
|
||||
+ sAutobootCtl.data.nCommand = DSL_AUTOBOOT_CTRL_RESTART;
|
||||
+
|
||||
+ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
|
||||
+ DSL_CPE_GetGlobalContext()->fd[nDevice],
|
||||
+ DSL_FIO_AUTOBOOT_CONTROL_SET, (DSL_int_t)&sAutobootCtl);
|
||||
+
|
||||
+ if (nRet < DSL_SUCCESS)
|
||||
+ {
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
|
||||
+ "Autoboot restart for device (%d) failed!, nRet = %d!"
|
||||
+ DSL_CPE_CRLF, nDevice, sAutobootCtl.accessCtl.nReturn));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_MSG, (DSL_CPE_PREFIX
|
||||
+ "Connection shutdown finished." DSL_CPE_CRLF));
|
||||
+}
|
||||
+
|
||||
#ifndef RTEMS
|
||||
/**
|
||||
Signal handler.
|
||||
@@ -7327,6 +7379,8 @@ DSL_CPE_STATIC DSL_void_t DSL_CPE_CLI_Q
|
||||
|
||||
DSL_CPE_STATIC DSL_void_t DSL_CPE_Interruption(void)
|
||||
{
|
||||
+ DSL_CPE_ShutdownConnection();
|
||||
+
|
||||
DSL_CPE_DaemonExit();
|
||||
|
||||
#ifdef INCLUDE_DSL_CPE_CLI_SUPPORT
|
||||
@@ -7336,37 +7390,16 @@ DSL_CPE_STATIC DSL_void_t DSL_CPE_Inter
|
||||
|
||||
DSL_CPE_STATIC DSL_void_t DSL_CPE_Termination(void)
|
||||
{
|
||||
- DSL_Error_t nRet = DSL_SUCCESS;
|
||||
- DSL_int_t nDevice = 0;
|
||||
- DSL_AutobootControl_t sAutobootCtl;
|
||||
DSL_CPE_Control_Context_t *pCtrlCtx = DSL_NULL;
|
||||
|
||||
+ DSL_CPE_ShutdownConnection();
|
||||
+
|
||||
pCtrlCtx = DSL_CPE_GetGlobalContext();
|
||||
if (pCtrlCtx != DSL_NULL)
|
||||
{
|
||||
pCtrlCtx->bEvtRun = DSL_FALSE;
|
||||
}
|
||||
|
||||
- for (nDevice = 0; nDevice < DSL_CPE_DSL_ENTITIES; ++nDevice)
|
||||
- {
|
||||
- memset(&sAutobootCtl, 0, sizeof(DSL_AutobootControl_t));
|
||||
- sAutobootCtl.data.nCommand = DSL_AUTOBOOT_CTRL_STOP;
|
||||
-
|
||||
- nRet = (DSL_Error_t)DSL_CPE_Ioctl(
|
||||
- DSL_CPE_GetGlobalContext()->fd[nDevice],
|
||||
- DSL_FIO_AUTOBOOT_CONTROL_SET, (DSL_int_t)&sAutobootCtl);
|
||||
-
|
||||
- if (nRet < DSL_SUCCESS)
|
||||
- {
|
||||
- DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
|
||||
- "Autoboot stop for device (%d) failed!, nRet = %d!"
|
||||
- DSL_CPE_CRLF, nDevice, sAutobootCtl.accessCtl.nReturn));
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- DSL_CCA_DEBUG(DSL_CCA_DBG_MSG, (DSL_CPE_PREFIX
|
||||
- "Autoboot stop executed" DSL_CPE_CRLF));
|
||||
-
|
||||
DSL_CPE_DaemonExit();
|
||||
|
||||
#ifdef INCLUDE_DSL_CPE_CLI_SUPPORT
|
||||
@@ -8551,6 +8584,9 @@ void DSL_CPE_main(void)
|
||||
DSL_CPE_STATIC DSL_Error_t DSL_CPE_Control_Exit (DSL_void_t * pContext)
|
||||
{
|
||||
dummy_console_t *pConsole = pContext;
|
||||
+
|
||||
+ DSL_CPE_ShutdownConnection();
|
||||
+
|
||||
pConsole->bRun = DSL_FALSE;
|
||||
return DSL_SUCCESS;
|
||||
}
|
||||
@@ -8798,4 +8834,4 @@ DSL_CPE_STATIC DSL_Error_t DSL_CPE_Firmw
|
||||
pDecimal));
|
||||
|
||||
return nErrCode;
|
||||
-}
|
||||
\ No newline at end of file
|
||||
+}
|
||||
@@ -0,0 +1,73 @@
|
||||
Try to perform an orderly shutdown via L3 request before the connection
|
||||
is stopped on exit.
|
||||
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -7252,15 +7252,58 @@ static DSL_boolean_t DSL_CPE_DebugAndTes
|
||||
#endif /* defined(DSL_DEBUG_TOOL_INTERFACE) || defined(INCLUDE_DSL_CPE_DTI_SUPPORT) */
|
||||
#endif /* defined(INCLUDE_DSL_JSON_PARSING) && (INCLUDE_DSL_JSON_PARSING == 1) */
|
||||
|
||||
+DSL_CPE_STATIC DSL_void_t DSL_CPE_EnableConnection(void)
|
||||
+{
|
||||
+ DSL_Error_t nRet = DSL_SUCCESS;
|
||||
+ DSL_int_t nDevice = 0;
|
||||
+ DSL_G997_PowerManagementStateForcedTrigger_t sPowerManagementStateForcedTrigger;
|
||||
+
|
||||
+ for (nDevice = 0; nDevice < DSL_CPE_DSL_ENTITIES; ++nDevice)
|
||||
+ {
|
||||
+ memset(&sPowerManagementStateForcedTrigger, 0x0,
|
||||
+ sizeof(DSL_G997_PowerManagementStateForcedTrigger_t));
|
||||
+ sPowerManagementStateForcedTrigger.data.nPowerManagementState = DSL_G997_PMSF_L3_TO_L0;
|
||||
+
|
||||
+ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
|
||||
+ DSL_CPE_GetGlobalContext()->fd[nDevice],
|
||||
+ DSL_FIO_G997_POWER_MANAGEMENT_STATE_FORCED_TRIGGER,
|
||||
+ (DSL_int_t)&sPowerManagementStateForcedTrigger);
|
||||
+
|
||||
+ if (nRet < DSL_SUCCESS)
|
||||
+ {
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
|
||||
+ "Transition to L0 state (%d) failed!, nRet = %d!"
|
||||
+ DSL_CPE_CRLF, nDevice, sPowerManagementStateForcedTrigger.accessCtl.nReturn));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
DSL_CPE_STATIC DSL_void_t DSL_CPE_ShutdownConnection(void)
|
||||
{
|
||||
DSL_Error_t nRet = DSL_SUCCESS;
|
||||
DSL_int_t nDevice = 0;
|
||||
+ DSL_G997_PowerManagementStateForcedTrigger_t sPowerManagementStateForcedTrigger;
|
||||
DSL_AutobootConfig_t sAutobootCfg;
|
||||
DSL_AutobootControl_t sAutobootCtl;
|
||||
|
||||
for (nDevice = 0; nDevice < DSL_CPE_DSL_ENTITIES; ++nDevice)
|
||||
{
|
||||
+ memset(&sPowerManagementStateForcedTrigger, 0x0,
|
||||
+ sizeof(DSL_G997_PowerManagementStateForcedTrigger_t));
|
||||
+ sPowerManagementStateForcedTrigger.data.nPowerManagementState = DSL_G997_PMSF_LX_TO_L3;
|
||||
+
|
||||
+ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
|
||||
+ DSL_CPE_GetGlobalContext()->fd[nDevice],
|
||||
+ DSL_FIO_G997_POWER_MANAGEMENT_STATE_FORCED_TRIGGER,
|
||||
+ (DSL_int_t)&sPowerManagementStateForcedTrigger);
|
||||
+
|
||||
+ if (nRet < DSL_SUCCESS)
|
||||
+ {
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
|
||||
+ "Transition to L3 state (%d) failed!, nRet = %d!"
|
||||
+ DSL_CPE_CRLF, nDevice, sPowerManagementStateForcedTrigger.accessCtl.nReturn));
|
||||
+ }
|
||||
+
|
||||
g_bWaitBeforeConfigWrite[nDevice] = DSL_TRUE;
|
||||
g_bWaitBeforeLinkActivation[nDevice] = DSL_TRUE;
|
||||
g_bWaitBeforeRestart[nDevice] = DSL_TRUE;
|
||||
@@ -8318,6 +8361,8 @@ DSL_int_t dsl_cpe_daemon (
|
||||
#endif /* defined(INCLUDE_DSL_JSON_PARSING) && (INCLUDE_DSL_JSON_PARSING == 1) */
|
||||
}
|
||||
|
||||
+ DSL_CPE_EnableConnection();
|
||||
+
|
||||
#ifdef INCLUDE_DSL_CPE_CLI_SUPPORT
|
||||
#ifndef DSL_CPE_REMOVE_PIPE_SUPPORT
|
||||
if (DSL_CPE_Pipe_Init (pCtrlCtx) == DSL_ERROR)
|
||||
@@ -0,0 +1,50 @@
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -221,6 +221,9 @@ extern DSL_Error_t DSL_CPE_Pipe_StaticRe
|
||||
#endif /* INCLUDE_DSL_RESOURCE_STATISTICS*/
|
||||
#endif
|
||||
|
||||
+extern void ubus_init();
|
||||
+extern void ubus_deinit();
|
||||
+
|
||||
DSL_char_t *g_sFirmwareName1 = DSL_NULL;
|
||||
DSL_FirmwareFeatures_t g_nFwFeatures1 = {DSL_FW_XDSLMODE_CLEANED, DSL_FW_XDSLFEATURE_CLEANED,
|
||||
DSL_FW_XDSLFEATURE_CLEANED};
|
||||
@@ -7882,6 +7885,8 @@ DSL_int_t dsl_cpe_daemon (
|
||||
#endif /* defined(INCLUDE_DSL_JSON_PARSING) && (INCLUDE_DSL_JSON_PARSING == 1) */
|
||||
#endif /* RTEMS*/
|
||||
|
||||
+ ubus_init();
|
||||
+
|
||||
/* Open DSL_CPE_MAX_DSL_ENTITIES devices*/
|
||||
for (nDevice = 0; nDevice < DSL_CPE_DSL_ENTITIES; nDevice++)
|
||||
{
|
||||
@@ -8420,6 +8425,7 @@ DSL_int_t dsl_cpe_daemon (
|
||||
#endif /* INCLUDE_DSL_CPE_CLI_SUPPORT */
|
||||
|
||||
DSL_CPE_CONTROL_EXIT:
|
||||
+ ubus_deinit();
|
||||
|
||||
if (INCLUDE_DSL_BONDING)
|
||||
{
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -17,7 +17,7 @@ else
|
||||
dsl_cpe_control_common_ldflags =
|
||||
endif
|
||||
|
||||
-dsl_cpe_control_LDADD = -lpthread -lrt
|
||||
+dsl_cpe_control_LDADD = -lpthread -lrt -lubox -lubus
|
||||
|
||||
if INCLUDE_DSL_CPE_DTI_SUPPORT
|
||||
dsl_cpe_control_LDADD += -ldti_agent
|
||||
@@ -118,7 +118,8 @@ dsl_cpe_control_SOURCES = \
|
||||
dsl_cpe_control.c \
|
||||
dsl_cpe_init_cfg.c \
|
||||
dsl_cpe_linux.c \
|
||||
- dsl_cpe_debug.c
|
||||
+ dsl_cpe_debug.c \
|
||||
+ dsl_cpe_ubus.c
|
||||
|
||||
dsl_cpe_control_SOURCES += \
|
||||
$(dsl_cpe_control_dti_sources)
|
||||
83
package/network/config/ltq-vdsl-vr9-app/Makefile
Normal file
83
package/network/config/ltq-vdsl-vr9-app/Makefile
Normal file
@@ -0,0 +1,83 @@
|
||||
# Copyright (C) 2010 OpenWrt.org
|
||||
# Copyright (C) 2015-2016 Lantiq Beteiligungs GmbH & Co KG.
|
||||
#
|
||||
# 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:=ltq-vdsl-vr9-app
|
||||
PKG_VERSION:=4.17.18.6
|
||||
PKG_RELEASE:=7
|
||||
PKG_BASE_NAME:=dsl_cpe_control
|
||||
PKG_SOURCE:=$(PKG_BASE_NAME)_vrx-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=@OPENWRT
|
||||
PKG_HASH:=da8bb929526a61aea0e153ef524331fcd472a1ebbc6d88ca017735a4f82ece02
|
||||
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_BASE_NAME)-$(PKG_VERSION)
|
||||
PKG_LICENSE:=BSD-2-Clause
|
||||
|
||||
PKG_BUILD_DEPENDS:=ltq-vdsl-vr9
|
||||
|
||||
PKG_FLAGS:=nonshared
|
||||
PKG_FIXUP:=autoreconf
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/ltq-vdsl-vr9-app
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Lantiq VDSL userland tool
|
||||
URL:=http://www.lantiq.com/
|
||||
DEPENDS:=@(TARGET_lantiq_xrx200||TARGET_lantiq_xrx200_legacy) +libpthread +librt +ltq-dsl-base +libubox +libubus
|
||||
PROVIDES:=ltq-dsl-app
|
||||
endef
|
||||
|
||||
define Package/ltq-vdsl-vr9-app/description
|
||||
Userland tool needed to control Lantiq VDSL CPE
|
||||
endef
|
||||
|
||||
# ltq-vdsl-vr9-app uses a header provided by the MEI driver which has some
|
||||
# conditionals.
|
||||
#
|
||||
# Define them here with the default values they would get in the MEI driver,
|
||||
# have the same view on both sides.
|
||||
#
|
||||
# If you change them, you need to change them for the ltq-vdsl-vr9-app as well
|
||||
VDSL_APP_CFLAGS = \
|
||||
-DMAX_CLI_PIPES=1 \
|
||||
-DMEI_SUPPORT_DEBUG_STREAMS=1 \
|
||||
-DMEI_SUPPORT_OPTIMIZED_FW_DL=1
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--enable-vrx \
|
||||
--enable-vrx-device=vr9 \
|
||||
--enable-driver-include="-I$(STAGING_DIR)/usr/include/drv_vdsl_cpe_api" \
|
||||
--enable-device-driver-include="-I$(STAGING_DIR)/usr/include/vdsl/" \
|
||||
--enable-ifxos \
|
||||
--enable-ifxos-include="-I$(STAGING_DIR)/usr/include/ifxos" \
|
||||
--enable-ifxos-library="-I$(STAGING_DIR)/usr/lib" \
|
||||
--enable-add-appl-cflags="$(VDSL_APP_CFLAGS)" \
|
||||
--enable-debug \
|
||||
--disable-dti \
|
||||
--with-channels-per-line="1"
|
||||
|
||||
CONFIGURE_ARGS += \
|
||||
--enable-model=full \
|
||||
--enable-dsl-ceoc=no
|
||||
#CONFIGURE_ARGS += --enable-model=lite
|
||||
#CONFIGURE_ARGS += --enable-model=footprint
|
||||
#CONFIGURE_ARGS += --enable-model=typical
|
||||
#CONFIGURE_ARGS += --enable-model=debug
|
||||
|
||||
define Package/ltq-vdsl-vr9-app/install
|
||||
$(INSTALL_DIR) $(1)/etc/init.d $(1)/sbin $(1)/etc/hotplug.d/dsl
|
||||
$(INSTALL_BIN) ./files/dsl_control $(1)/etc/init.d/
|
||||
$(INSTALL_BIN) ./files/10_atm.sh $(1)/etc/hotplug.d/dsl
|
||||
$(INSTALL_BIN) ./files/10_ptm.sh $(1)/etc/hotplug.d/dsl
|
||||
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/dsl_cpe_control $(1)/sbin/vdsl_cpe_control
|
||||
$(INSTALL_BIN) ./files/dsl_cpe_pipe.sh $(1)/sbin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,ltq-vdsl-vr9-app))
|
||||
14
package/network/config/ltq-vdsl-vr9-app/files/10_atm.sh
Executable file
14
package/network/config/ltq-vdsl-vr9-app/files/10_atm.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$DSL_NOTIFICATION_TYPE" = "DSL_STATUS" ] && \
|
||||
[ "$DSL_TC_LAYER_STATUS" = "ATM" ] && \
|
||||
! grep -q "ltq_atm_vr9" /proc/modules || exit 0
|
||||
|
||||
logger -p daemon.notice -t "dsl-notify" "Switching to TC-Layer ATM"
|
||||
|
||||
if grep -q "ltq_ptm_vr9" /proc/modules ; then
|
||||
logger -p daemon.notice -t "dsl-notify" "Loading ATM driver while EFM/PTM driver is loaded is not possible. Reboot is needed."
|
||||
exit
|
||||
fi
|
||||
|
||||
modprobe ltq_atm_vr9
|
||||
14
package/network/config/ltq-vdsl-vr9-app/files/10_ptm.sh
Executable file
14
package/network/config/ltq-vdsl-vr9-app/files/10_ptm.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$DSL_NOTIFICATION_TYPE" = "DSL_STATUS" ] && \
|
||||
[ "$DSL_TC_LAYER_STATUS" = "EFM" ] && \
|
||||
! grep -q "ltq_ptm_vr9" /proc/modules || exit 0
|
||||
|
||||
logger -p daemon.notice -t "dsl-notify" "Switching to TC-Layer EFM/PTM"
|
||||
|
||||
if grep -q "ltq_atm_vr9" /proc/modules ; then
|
||||
logger -p daemon.notice -t "dsl-notify" "Loading EFM/PTM driver while ATM driver is loaded is not possible. Reboot is needed."
|
||||
exit
|
||||
fi
|
||||
|
||||
modprobe ltq_ptm_vr9
|
||||
322
package/network/config/ltq-vdsl-vr9-app/files/dsl_control
Normal file
322
package/network/config/ltq-vdsl-vr9-app/files/dsl_control
Normal file
@@ -0,0 +1,322 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2012 OpenWrt.org
|
||||
|
||||
START=97
|
||||
USE_PROCD=1
|
||||
|
||||
dslstat() {
|
||||
ubus call dsl metrics
|
||||
}
|
||||
|
||||
extra_command "dslstat" "Get DSL status information"
|
||||
|
||||
#
|
||||
# ITU-T G.997.1 (06/2012) - Section 7.3.1.1.1 (xTU transmission system enabling (XTSE))
|
||||
# ITU-T G.997.1 Amendment 2 (04/2013) - Section 2.1 - (Vectoring mode enable (VECTORMODE_ENABLE))
|
||||
#
|
||||
# G.992.1 Annex A
|
||||
# G.992.2 Annex A
|
||||
# G.992.3 Annex A / L-US1 / L_US-2 / M
|
||||
# G.992.5 Annex A / M
|
||||
# G.993.2 Annex A/B/C
|
||||
# G.993.5 Annex A/B/C
|
||||
xtse_xdsl_a="05_01_04_00_4C_01_04_07"
|
||||
|
||||
# G.992.1 Annex B
|
||||
# G.992.3 Annex B
|
||||
# G.992.5 Annex B
|
||||
# G.993.2 Annex A/B/C
|
||||
# G.993.5 Annex A/B/C
|
||||
xtse_xdsl_b="10_00_10_00_00_04_00_07"
|
||||
|
||||
# G.992.1 Annex B
|
||||
# G.992.3 Annex B
|
||||
# G.992.3 Annex J
|
||||
# G.992.5 Annex B
|
||||
# G.992.5 Annex J
|
||||
# G.993.2 Annex A/B/C
|
||||
# G.993.5 Annex A/B/C
|
||||
xtse_xdsl_j="10_00_10_40_00_04_01_07"
|
||||
|
||||
# G.992.1 Annex B
|
||||
xtse_xdsl_bdmt="10_00_00_00_00_00_00_00"
|
||||
|
||||
# G.992.3 Annex B
|
||||
xtse_xdsl_b2="00_00_10_00_00_00_00_00"
|
||||
|
||||
# G.992.5 Annex B
|
||||
xtse_xdsl_b2p="00_00_00_00_00_04_00_00"
|
||||
|
||||
# ANSI T1.413
|
||||
xtse_xdsl_at1="01_00_00_00_00_00_00_00"
|
||||
|
||||
# G.992.2 Annex A
|
||||
xtse_xdsl_alite="00_01_00_00_00_00_00_00"
|
||||
|
||||
# G.992.1 Annex A
|
||||
xtse_xdsl_admt="04_00_00_00_00_00_00_00"
|
||||
|
||||
# G.992.3 Annex A
|
||||
xtse_xdsl_a2="00_00_04_00_00_00_00_00"
|
||||
|
||||
# G.992.5 Annex A
|
||||
xtse_xdsl_a2p="00_00_00_00_00_01_00_00"
|
||||
|
||||
# G.992.3 Annex L
|
||||
xtse_xdsl_l="00_00_00_00_0C_00_00_00"
|
||||
|
||||
# G.992.3 Annex M
|
||||
# G.992.5 Annex M
|
||||
xtse_xdsl_m="00_00_00_00_40_00_04_00"
|
||||
|
||||
# G.992.3 Annex M
|
||||
xtse_xdsl_m2="00_00_00_00_40_00_00_00"
|
||||
|
||||
# G.992.5 Annex M
|
||||
xtse_xdsl_m2p="00_00_00_00_00_00_04_00"
|
||||
|
||||
#
|
||||
# ITU-T G.994.1 (06/2012) - Table 2 (Mandatory carrier sets)
|
||||
#
|
||||
|
||||
# A43
|
||||
tone_adsl_a="0x142" # A43C + J43 + A43
|
||||
tone_vdsl_a="0x142" # A43C + J43 + A43
|
||||
|
||||
# A43 + V43
|
||||
tone_adsl_av="0x142" # A43C + J43 + A43
|
||||
tone_vdsl_av="0x146" # A43C + J43 + A43 + V43
|
||||
|
||||
# B43
|
||||
tone_adsl_b="0x81" # B43 + B43c
|
||||
tone_vdsl_b="0x1" # B43
|
||||
|
||||
# B43 + V43
|
||||
tone_adsl_bv="0x81" # B43 + B43c
|
||||
tone_vdsl_bv="0x5" # B43 + V43
|
||||
|
||||
# create DSL autoboot script. Used for SNR margin tweak and to set MAC address for vectoring error reports
|
||||
autoboot_script() {
|
||||
echo "[WaitForConfiguration]={
|
||||
locs 0 $1
|
||||
dsmmcs $2
|
||||
}
|
||||
|
||||
[WaitForLinkActivate]={
|
||||
}
|
||||
|
||||
[WaitForRestart]={
|
||||
}
|
||||
|
||||
[Common]={
|
||||
}" > /tmp/dsl.scr
|
||||
}
|
||||
|
||||
lowlevel_cfg() {
|
||||
echo "# VRX Low Level Configuration File
|
||||
#
|
||||
# Parameters must be separated by tabs or spaces.
|
||||
# Empty lines and comments will be ignored.
|
||||
#
|
||||
|
||||
# nFilter
|
||||
#
|
||||
# NA = -1
|
||||
# OFF = 0
|
||||
# ISDN = 1
|
||||
# POTS = 2
|
||||
# POTS_2 = 3
|
||||
# POTS_3 = 4
|
||||
#
|
||||
# (dec)
|
||||
-1
|
||||
|
||||
# nHsToneGroupMode nHsToneGroup_A nHsToneGroup_V nHsToneGroup_AV
|
||||
#
|
||||
# NA = -1 NA = -1 see see
|
||||
# AUTO = 0 VDSL2_B43 = 0x0001 nHsToneGroup_A nHsToneGroup_A
|
||||
# MANUAL = 1 VDSL2_A43 = 0x0002
|
||||
# VDSL2_V43 = 0x0004
|
||||
# VDSL1_V43P = 0x0008
|
||||
# VDSL1_V43I = 0x0010
|
||||
# ADSL1_C43 = 0x0020
|
||||
# ADSL2_J43 = 0x0040
|
||||
# ADSL2_B43C = 0x0080
|
||||
# ADSL2_A43C = 0x0100
|
||||
#
|
||||
# (dec) (hex) (hex) (hex)
|
||||
1 $1 $2 0x0
|
||||
|
||||
# nBaseAddr nIrqNum
|
||||
#
|
||||
# (hex) (dec)
|
||||
0x1e116000 63
|
||||
|
||||
# nUtopiaPhyAdr nUtopiaBusWidth nPosPhyParity
|
||||
# default(16b) = 0 NA = -1
|
||||
# 8-bit = 1 ODD = 0
|
||||
# 16-bit = 2
|
||||
#
|
||||
#
|
||||
# (hex) (dec) (dec)
|
||||
0xFF 0 0
|
||||
|
||||
# bNtrEnable
|
||||
#
|
||||
# (dec)
|
||||
0" > /tmp/lowlevel.cfg
|
||||
}
|
||||
|
||||
get_macaddr() {
|
||||
local name
|
||||
config_get name $1 name
|
||||
[ "$name" = "dsl0" ] && config_get $2 $1 macaddr
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger network
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local annex
|
||||
local firmware
|
||||
local tone
|
||||
local tone_adsl
|
||||
local tone_vdsl
|
||||
local xtse
|
||||
local xfer_mode
|
||||
local line_mode
|
||||
local tc_layer
|
||||
local mode
|
||||
local lowlevel
|
||||
local snr
|
||||
local macaddr
|
||||
|
||||
config_load network
|
||||
config_get tone dsl tone
|
||||
config_get annex dsl annex
|
||||
config_get firmware dsl firmware
|
||||
config_get xfer_mode dsl xfer_mode
|
||||
config_get line_mode dsl line_mode
|
||||
config_get snr dsl ds_snr_offset
|
||||
config_foreach get_macaddr device macaddr
|
||||
|
||||
eval "xtse=\"\${xtse_xdsl_$annex}\""
|
||||
|
||||
case "${xfer_mode}" in
|
||||
atm)
|
||||
tc_layer="-T1:0x1:0x1_1:0x1:0x1"
|
||||
;;
|
||||
ptm)
|
||||
tc_layer="-T2:0x1:0x1_2:0x1:0x1"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${line_mode}" in
|
||||
adsl)
|
||||
mode="-M1"
|
||||
|
||||
# mask out VDSL bits when ADSL is requested
|
||||
xtse="${xtse%_*}_00"
|
||||
;;
|
||||
vdsl)
|
||||
mode="-M2"
|
||||
|
||||
# mask out ADSL bits when VDSL is requested
|
||||
xtse="00_00_00_00_00_00_00_${xtse##*_}"
|
||||
;;
|
||||
esac
|
||||
|
||||
local annexgpio="/sys/class/gpio/annex"
|
||||
if [ -d "${annexgpio}a" ] && [ -d "${annexgpio}b" ]; then
|
||||
case "${annex}" in
|
||||
a*|l*|m*)
|
||||
echo 1 > "${annexgpio}a/value"
|
||||
echo 0 > "${annexgpio}b/value"
|
||||
;;
|
||||
b*|j*)
|
||||
echo 0 > "${annexgpio}a/value"
|
||||
echo 1 > "${annexgpio}b/value"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ -z "${firmware}" ]; then
|
||||
# search for the firmware provided by dsl-vrx200-firmware-xdsl-*
|
||||
if grep -qE "system type.*: (VR9|xRX200)" /proc/cpuinfo; then
|
||||
case "${annex}" in
|
||||
a*|l*|m*)
|
||||
if [ -f "/lib/firmware/lantiq-vrx200-a.bin" ]; then
|
||||
firmware="/lib/firmware/lantiq-vrx200-a.bin"
|
||||
elif [ -f "/tmp/lantiq-vrx200-a.bin" ]; then
|
||||
firmware="/tmp/lantiq-vrx200-a.bin"
|
||||
elif [ -f "/lib/firmware/lantiq-vrx200-b.bin" ] && [ -f "/lib/firmware/lantiq-vrx200-b-to-a.bspatch" ]; then
|
||||
bspatch /lib/firmware/lantiq-vrx200-b.bin \
|
||||
/tmp/lantiq-vrx200-a.bin \
|
||||
/lib/firmware/lantiq-vrx200-b-to-a.bspatch
|
||||
firmware="/tmp/lantiq-vrx200-a.bin"
|
||||
else
|
||||
echo "firmware for annex a not found"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
b*|j*)
|
||||
if [ -f "/lib/firmware/vr9_dsl_fw_annex_b.bin" ]; then
|
||||
firmware="/lib/firmware/vr9_dsl_fw_annex_b.bin"
|
||||
elif [ -f "/lib/firmware/lantiq-vrx200-b.bin" ]; then
|
||||
firmware="/lib/firmware/lantiq-vrx200-b.bin"
|
||||
elif [ -f "/tmp/lantiq-vrx200-b.bin" ]; then
|
||||
firmware="/tmp/lantiq-vrx200-b.bin"
|
||||
elif [ -f "/lib/firmware/lantiq-vrx200-a.bin" ] && [ -f "/lib/firmware/lantiq-vrx200-a-to-b.bspatch" ]; then
|
||||
bspatch /lib/firmware/lantiq-vrx200-a.bin \
|
||||
/tmp/lantiq-vrx200-b.bin \
|
||||
/lib/firmware/lantiq-vrx200-a-to-b.bspatch
|
||||
firmware="/tmp/lantiq-vrx200-b.bin"
|
||||
else
|
||||
echo "firmware for annex b not found"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "annex type not supported use a or b"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
[ -z "${firmware}" ] && firmware=/lib/firmware/vdsl.bin
|
||||
[ -f "${firmware}" ] || {
|
||||
echo failed to find $firmware
|
||||
return 1
|
||||
}
|
||||
|
||||
eval "tone_adsl=\"\${tone_adsl_$tone}\""
|
||||
eval "tone_vdsl=\"\${tone_vdsl_$tone}\""
|
||||
[ -n "${tone_adsl}" ] && [ -n "${tone_vdsl}" ] && {
|
||||
lowlevel_cfg "${tone_adsl}" "${tone_vdsl}"
|
||||
lowlevel="-l /tmp/lowlevel.cfg"
|
||||
}
|
||||
|
||||
[ -z "${snr}" ] && snr=0
|
||||
[ -z "${macaddr}" ] && macaddr="00:00:00:00:00:00"
|
||||
autoboot_script "$snr" "$macaddr"
|
||||
autoboot="-a /tmp/dsl.scr -A /tmp/dsl.scr"
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /sbin/vdsl_cpe_control \
|
||||
-i$xtse \
|
||||
-n /sbin/dsl_notify.sh \
|
||||
-f ${firmware} \
|
||||
$lowlevel \
|
||||
${mode} \
|
||||
${tc_layer} \
|
||||
$autoboot
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
DSL_NOTIFICATION_TYPE="DSL_INTERFACE_STATUS" \
|
||||
DSL_INTERFACE_STATUS="DOWN" \
|
||||
/sbin/dsl_notify.sh
|
||||
}
|
||||
18
package/network/config/ltq-vdsl-vr9-app/files/dsl_cpe_pipe.sh
Executable file
18
package/network/config/ltq-vdsl-vr9-app/files/dsl_cpe_pipe.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
pipe_no=0
|
||||
|
||||
# use specified pipe no
|
||||
case "$1" in
|
||||
0|1|2)
|
||||
pipe_no=$1; shift; ;;
|
||||
esac
|
||||
|
||||
|
||||
#echo "Call dsl_pipe with $*"
|
||||
lock /var/lock/dsl_pipe
|
||||
echo $* > /tmp/pipe/dsl_cpe${pipe_no}_cmd
|
||||
result=$(cat /tmp/pipe/dsl_cpe${pipe_no}_ack)
|
||||
lock -u /var/lock/dsl_pipe
|
||||
|
||||
echo "$result"
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/src/dsl_cpe_init_cfg.c
|
||||
+++ b/src/dsl_cpe_init_cfg.c
|
||||
@@ -38,7 +38,7 @@ DSL_InitData_t gInitCfgData =
|
||||
DSL_DEV_HS_TONE_GROUP_CLEANED, \
|
||||
DSL_DEV_HS_TONE_GROUP_CLEANED, \
|
||||
DSL_DEV_HS_TONE_GROUP_CLEANED, \
|
||||
- 0x1E116000, 0x37, -1),
|
||||
+ 0x1E116000, 0x3f, -1),
|
||||
DSL_CPE_SIC_SET(DSL_TC_ATM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII, \
|
||||
DSL_TC_EFM, DSL_EMF_TC_CLEANED, DSL_EMF_TC_CLEANED, DSL_SYSTEMIF_MII),
|
||||
DSL_CPE_MAC_CFG_SET(DSL_EFM_SPEED_100, DSL_EFM_DUPLEX_FULL, DSL_EFM_FLOWCTRL_ON, DSL_EFM_AUTONEG_OFF, \
|
||||
@@ -0,0 +1,10 @@
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -11,6 +11,7 @@
|
||||
/*
|
||||
Includes
|
||||
*/
|
||||
+#include <limits.h>
|
||||
#include "dsl_cpe_control.h"
|
||||
#include "dsl_cpe_cli.h"
|
||||
#include "dsl_cpe_cli_console.h"
|
||||
@@ -0,0 +1,98 @@
|
||||
This enables automatic connection after the control daemon is started,
|
||||
and also stops the connection on termination.
|
||||
|
||||
Using the autoboot restart command (in combination with configuring the
|
||||
state machine to wait) is necessary because the stop command doesn't
|
||||
actually stop the connection, and would also leave the driver in a state
|
||||
where an explicit start command is necessary to connect again.
|
||||
|
||||
--- a/src/dsl_cpe_init_cfg.c
|
||||
+++ b/src/dsl_cpe_init_cfg.c
|
||||
@@ -27,7 +27,7 @@ DSL_InitData_t gInitCfgData =
|
||||
DSL_CPE_FW2_SET(DSL_NULL, 0x0),
|
||||
DSL_CPE_XTU_SET(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7),
|
||||
DSL_CPE_LINE_INV_NE_SET(DSL_NULL),
|
||||
- DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_STOP),
|
||||
+ DSL_CPE_AUTOBOOT_CTRL_SET(DSL_AUTOBOOT_CTRL_START),
|
||||
DSL_CPE_AUTOBOOT_CFG_SET(DSL_FALSE, DSL_FALSE, DSL_FALSE),
|
||||
DSL_CPE_TEST_MODE_CTRL_SET(DSL_TESTMODE_DISABLE),
|
||||
DSL_CPE_LINE_ACTIVATE_CTRL_SET(DSL_G997_INHIBIT_LDSF, DSL_G997_INHIBIT_ACSF, DSL_G997_NORMAL_STARTUP),
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -6491,6 +6491,57 @@ DSL_int32_t DSL_CPE_DeviceInit (
|
||||
return ret;
|
||||
}
|
||||
|
||||
+DSL_CPE_STATIC DSL_void_t DSL_CPE_ShutdownConnection(void)
|
||||
+{
|
||||
+ DSL_Error_t nRet = DSL_SUCCESS;
|
||||
+ DSL_int_t nDevice = 0;
|
||||
+ DSL_AutobootConfig_t sAutobootCfg;
|
||||
+ DSL_AutobootControl_t sAutobootCtl;
|
||||
+
|
||||
+ for (nDevice = 0; nDevice < DSL_CPE_MAX_DSL_ENTITIES; ++nDevice)
|
||||
+ {
|
||||
+ g_bWaitBeforeConfigWrite[nDevice] = DSL_TRUE;
|
||||
+ g_bWaitBeforeLinkActivation[nDevice] = DSL_TRUE;
|
||||
+ g_bWaitBeforeRestart[nDevice] = DSL_TRUE;
|
||||
+
|
||||
+ g_bAutoContinueWaitBeforeConfigWrite[nDevice] = DSL_FALSE;
|
||||
+ g_bAutoContinueWaitBeforeLinkActivation[nDevice] = DSL_FALSE;
|
||||
+ g_bAutoContinueWaitBeforeRestart[nDevice] = DSL_FALSE;
|
||||
+
|
||||
+ memset(&sAutobootCfg, 0x0, sizeof(DSL_AutobootConfig_t));
|
||||
+ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeConfigWrite = DSL_TRUE;
|
||||
+ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeLinkActivation = DSL_TRUE;
|
||||
+ sAutobootCfg.data.nStateMachineOptions.bWaitBeforeRestart = DSL_TRUE;
|
||||
+
|
||||
+ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
|
||||
+ DSL_CPE_GetGlobalContext()->fd[nDevice],
|
||||
+ DSL_FIO_AUTOBOOT_CONFIG_SET, (DSL_int_t)&sAutobootCfg);
|
||||
+
|
||||
+ if (nRet < DSL_SUCCESS)
|
||||
+ {
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
|
||||
+ "Autoboot configuration for device (%d) failed!, nRet = %d!"
|
||||
+ DSL_CPE_CRLF, nDevice, sAutobootCfg.accessCtl.nReturn));
|
||||
+ }
|
||||
+
|
||||
+ memset(&sAutobootCtl, 0, sizeof(DSL_AutobootControl_t));
|
||||
+ sAutobootCtl.data.nCommand = DSL_AUTOBOOT_CTRL_RESTART;
|
||||
+
|
||||
+ nRet = (DSL_Error_t)DSL_CPE_Ioctl(
|
||||
+ DSL_CPE_GetGlobalContext()->fd[nDevice],
|
||||
+ DSL_FIO_AUTOBOOT_CONTROL_SET, (DSL_int_t)&sAutobootCtl);
|
||||
+
|
||||
+ if (nRet < DSL_SUCCESS)
|
||||
+ {
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_ERR, (DSL_CPE_PREFIX
|
||||
+ "Autoboot restart for device (%d) failed!, nRet = %d!"
|
||||
+ DSL_CPE_CRLF, nDevice, sAutobootCtl.accessCtl.nReturn));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ DSL_CCA_DEBUG(DSL_CCA_DBG_MSG, (DSL_CPE_PREFIX
|
||||
+ "Connection shutdown finished." DSL_CPE_CRLF));
|
||||
+}
|
||||
|
||||
/**
|
||||
Termination handler. Will clean up in case of ctrl-c.
|
||||
@@ -6521,6 +6572,8 @@ DSL_CPE_STATIC DSL_void_t DSL_CPE_Termi
|
||||
|
||||
DSL_CPE_Control_Context_t *pCtrlCtx;
|
||||
|
||||
+ DSL_CPE_ShutdownConnection();
|
||||
+
|
||||
pCtrlCtx = DSL_CPE_GetGlobalContext();
|
||||
if (pCtrlCtx != DSL_NULL)
|
||||
{
|
||||
@@ -7416,6 +7469,9 @@ void DSL_CPE_main(void)
|
||||
DSL_CPE_STATIC DSL_Error_t DSL_CPE_Control_Exit (DSL_void_t * pContext)
|
||||
{
|
||||
dummy_console_t *pConsole = pContext;
|
||||
+
|
||||
+ DSL_CPE_ShutdownConnection();
|
||||
+
|
||||
pConsole->bRun = DSL_FALSE;
|
||||
return DSL_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -6555,7 +6555,7 @@ DSL_CPE_STATIC void DSL_CPE_Termination
|
||||
/* ignore the signal, we'll handle by ourself */
|
||||
signal (sig, SIG_IGN);
|
||||
|
||||
- if (sig == SIGINT)
|
||||
+ if (sig == SIGINT || sig == SIGTERM)
|
||||
{
|
||||
DSL_CCA_DEBUG(DSL_CCA_DBG_MSG, (DSL_CPE_PREFIX "terminated" DSL_CPE_CRLF));
|
||||
DSL_CPE_Termination ();
|
||||
@@ -6809,6 +6809,7 @@ DSL_int_t dsl_cpe_daemon (
|
||||
|
||||
#ifndef RTEMS
|
||||
signal (SIGINT, DSL_CPE_TerminationHandler);
|
||||
+ signal (SIGTERM, DSL_CPE_TerminationHandler);
|
||||
#endif /* RTEMS*/
|
||||
|
||||
/* Open DSL_CPE_MAX_DSL_ENTITIES devices*/
|
||||
@@ -0,0 +1,50 @@
|
||||
--- a/src/dsl_cpe_control.c
|
||||
+++ b/src/dsl_cpe_control.c
|
||||
@@ -177,6 +177,9 @@ extern DSL_Error_t DSL_CPE_Pipe_StaticRe
|
||||
#endif /* INCLUDE_DSL_RESOURCE_STATISTICS*/
|
||||
#endif
|
||||
|
||||
+extern void ubus_init();
|
||||
+extern void ubus_deinit();
|
||||
+
|
||||
DSL_char_t *g_sFirmwareName1 = DSL_NULL;
|
||||
DSL_FirmwareFeatures_t g_nFwFeatures1 = {DSL_FW_XDSLMODE_CLEANED, DSL_FW_XDSLFEATURE_CLEANED,
|
||||
DSL_FW_XDSLFEATURE_CLEANED};
|
||||
@@ -6812,6 +6815,8 @@ DSL_int_t dsl_cpe_daemon (
|
||||
signal (SIGTERM, DSL_CPE_TerminationHandler);
|
||||
#endif /* RTEMS*/
|
||||
|
||||
+ ubus_init();
|
||||
+
|
||||
/* Open DSL_CPE_MAX_DSL_ENTITIES devices*/
|
||||
for (nDevice = 0; nDevice < DSL_CPE_MAX_DSL_ENTITIES; nDevice++)
|
||||
{
|
||||
@@ -7266,6 +7271,7 @@ DSL_int_t dsl_cpe_daemon (
|
||||
#endif /* INCLUDE_DSL_CPE_CLI_SUPPORT */
|
||||
|
||||
DSL_CPE_CONTROL_EXIT:
|
||||
+ ubus_deinit();
|
||||
|
||||
#ifdef INCLUDE_DSL_BONDING
|
||||
DSL_CPE_BND_Stop((DSL_CPE_BND_Context_t*)pCtrlCtx->pBnd);
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -11,7 +11,7 @@ else
|
||||
dsl_cpe_control_common_ldflags =
|
||||
endif
|
||||
|
||||
-dsl_cpe_control_LDADD = -lpthread -lrt
|
||||
+dsl_cpe_control_LDADD = -lpthread -lrt -lubox -lubus
|
||||
|
||||
if INCLUDE_DSL_CPE_DTI_SUPPORT
|
||||
dsl_cpe_control_LDADD += -ldti_agent
|
||||
@@ -66,7 +66,8 @@ dsl_cpe_control_SOURCES = \
|
||||
dsl_cpe_control.c \
|
||||
dsl_cpe_init_cfg.c \
|
||||
dsl_cpe_linux.c \
|
||||
- dsl_cpe_debug.c
|
||||
+ dsl_cpe_debug.c \
|
||||
+ dsl_cpe_ubus.c
|
||||
|
||||
dsl_cpe_control_SOURCES += \
|
||||
$(dsl_cpe_control_dti_sources)
|
||||
1170
package/network/config/ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c
Normal file
1170
package/network/config/ltq-vdsl-vr9-app/src/src/dsl_cpe_ubus.c
Normal file
File diff suppressed because it is too large
Load Diff
52
package/network/config/netifd/Makefile
Normal file
52
package/network/config/netifd/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=netifd
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
|
||||
PKG_SOURCE_DATE:=2024-12-17
|
||||
PKG_SOURCE_VERSION:=ea01ed41f3212ecbe000422f3c122a01b93fe874
|
||||
PKG_MIRROR_HASH:=dbaad26c1f9b15d0caff6ccdf80d85b34d96bda72cbd2b1dc188a04136d96c28
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
PKG_LICENSE_FILES:=
|
||||
|
||||
PKG_BUILD_FLAGS:=lto
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
|
||||
define Package/netifd
|
||||
SECTION:=base
|
||||
CATEGORY:=Base system
|
||||
DEPENDS:=+libuci +libnl-tiny +libubus +ubus +ubusd +jshn +libubox +libudebug +ucode +ucode-mod-fs
|
||||
TITLE:=OpenWrt Network Interface Configuration Daemon
|
||||
endef
|
||||
|
||||
define Package/netifd/conffiles
|
||||
/etc/udhcpc.user
|
||||
/etc/udhcpc.user.d/
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS += \
|
||||
-I$(STAGING_DIR)/usr/include/libnl-tiny \
|
||||
-I$(STAGING_DIR)/usr/include
|
||||
|
||||
CMAKE_OPTIONS += \
|
||||
-DLIBNL_LIBS=-lnl-tiny \
|
||||
-DDEBUG=1
|
||||
|
||||
define Package/netifd/install
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/netifd $(1)/sbin/
|
||||
$(CP) ./files/* $(1)/
|
||||
$(INSTALL_DIR) $(1)/etc/udhcpc.user.d/
|
||||
$(CP) \
|
||||
$(PKG_BUILD_DIR)/scripts/utils.sh \
|
||||
$(PKG_BUILD_DIR)/scripts/netifd-proto.sh \
|
||||
$(1)/lib/netifd/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,netifd))
|
||||
@@ -0,0 +1,6 @@
|
||||
[ ifup = "$ACTION" ] && {
|
||||
uci_toggle_state network "$INTERFACE" up 1
|
||||
[ -n "$DEVICE" ] && {
|
||||
uci_toggle_state network "$INTERFACE" ifname "$DEVICE"
|
||||
}
|
||||
}
|
||||
144
package/network/config/netifd/files/etc/init.d/network
Executable file
144
package/network/config/netifd/files/etc/init.d/network
Executable file
@@ -0,0 +1,144 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=20
|
||||
STOP=90
|
||||
|
||||
USE_PROCD=1
|
||||
|
||||
init_switch() {
|
||||
setup_switch() { return 0; }
|
||||
|
||||
include /lib/network
|
||||
setup_switch
|
||||
}
|
||||
|
||||
start_service() {
|
||||
init_switch
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /sbin/netifd
|
||||
procd_set_param respawn
|
||||
procd_set_param watch network.interface
|
||||
[ -e /proc/sys/kernel/core_pattern ] && {
|
||||
procd_set_param limits core="unlimited"
|
||||
}
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
local rv=0
|
||||
|
||||
init_switch
|
||||
ubus call network reload || rv=1
|
||||
[ -x /sbin/wifi ] && /sbin/wifi reload_legacy
|
||||
return $rv
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
[ -x /sbin/wifi ] && /sbin/wifi down
|
||||
ifdown -a
|
||||
sleep 1
|
||||
}
|
||||
|
||||
validate_atm_bridge_section()
|
||||
{
|
||||
uci_validate_section network "atm-bridge" "${1}" \
|
||||
'unit:uinteger:0' \
|
||||
'vci:range(32, 65535):35' \
|
||||
'vpi:range(0, 255):8' \
|
||||
'atmdev:uinteger:0' \
|
||||
'encaps:or("llc", "vc"):llc' \
|
||||
'payload:or("bridged", "routed"):bridged'
|
||||
}
|
||||
|
||||
validate_route_section()
|
||||
{
|
||||
uci_validate_section network route "${1}" \
|
||||
'interface:string' \
|
||||
'target:cidr4' \
|
||||
'netmask:netmask4' \
|
||||
'gateway:ip4addr' \
|
||||
'metric:uinteger' \
|
||||
'mtu:uinteger' \
|
||||
'table:or(range(0,65535),string)'
|
||||
}
|
||||
|
||||
validate_route6_section()
|
||||
{
|
||||
uci_validate_section network route6 "${1}" \
|
||||
'interface:string' \
|
||||
'target:cidr6' \
|
||||
'gateway:ip6addr' \
|
||||
'metric:uinteger' \
|
||||
'mtu:uinteger' \
|
||||
'table:or(range(0,65535),string)'
|
||||
}
|
||||
|
||||
validate_rule_section()
|
||||
{
|
||||
uci_validate_section network rule "${1}" \
|
||||
'in:string' \
|
||||
'out:string' \
|
||||
'src:cidr4' \
|
||||
'dest:cidr4' \
|
||||
'tos:range(0,31)' \
|
||||
'mark:string' \
|
||||
'invert:bool' \
|
||||
'lookup:or(range(0,65535),string)' \
|
||||
'goto:range(0,65535)' \
|
||||
'action:or("prohibit", "unreachable", "blackhole", "throw")'
|
||||
}
|
||||
|
||||
validate_rule6_section()
|
||||
{
|
||||
uci_validate_section network rule6 "${1}" \
|
||||
'in:string' \
|
||||
'out:string' \
|
||||
'src:cidr6' \
|
||||
'dest:cidr6' \
|
||||
'tos:range(0,31)' \
|
||||
'mark:string' \
|
||||
'invert:bool' \
|
||||
'lookup:or(range(0,65535),string)' \
|
||||
'goto:range(0,65535)' \
|
||||
'action:or("prohibit", "unreachable", "blackhole", "throw")'
|
||||
}
|
||||
|
||||
validate_switch_section()
|
||||
{
|
||||
uci_validate_section network switch "${1}" \
|
||||
'name:string' \
|
||||
'enable:bool' \
|
||||
'enable_vlan:bool' \
|
||||
'reset:bool' \
|
||||
'ar8xxx_mib_poll_interval:uinteger' \
|
||||
'ar8xxx_mib_type:range(0,1)'
|
||||
}
|
||||
|
||||
validate_switch_vlan()
|
||||
{
|
||||
uci_validate_section network switch_vlan "${1}" \
|
||||
'device:string' \
|
||||
'vlan:uinteger' \
|
||||
'ports:list(ports)'
|
||||
}
|
||||
|
||||
service_triggers()
|
||||
{
|
||||
procd_add_reload_trigger network wireless
|
||||
|
||||
procd_open_validate
|
||||
validate_atm_bridge_section
|
||||
validate_route_section
|
||||
[ -e /proc/sys/net/ipv6 ] && validate_route6_section
|
||||
validate_rule_section
|
||||
[ -e /proc/sys/net/ipv6 ] && validate_rule6_section
|
||||
validate_switch_section
|
||||
validate_switch_vlan
|
||||
procd_close_validate
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
ifdown -a
|
||||
sleep 1
|
||||
}
|
||||
25
package/network/config/netifd/files/etc/init.d/packet_steering
Executable file
25
package/network/config/netifd/files/etc/init.d/packet_steering
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=25
|
||||
USE_PROCD=1
|
||||
|
||||
start_service() {
|
||||
reload_service
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "network"
|
||||
procd_add_reload_trigger "firewall"
|
||||
procd_add_raw_trigger "interface.*" 1000 /etc/init.d/packet_steering reload
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
packet_steering="$(uci -q get "network.@globals[0].packet_steering")"
|
||||
steering_flows="$(uci -q get "network.@globals[0].steering_flows")"
|
||||
[ "${steering_flows:-0}" -gt 0 ] && opts="-l $steering_flows"
|
||||
if [ -e "/usr/libexec/platform/packet-steering.sh" ]; then
|
||||
/usr/libexec/platform/packet-steering.sh "$packet_steering"
|
||||
else
|
||||
/usr/libexec/network/packet-steering.uc $opts "$packet_steering"
|
||||
fi
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
. /lib/functions.sh
|
||||
|
||||
migrate_release() {
|
||||
local config="$1"
|
||||
local proto
|
||||
local release
|
||||
|
||||
config_get proto "$config" proto
|
||||
config_get release "$config" release
|
||||
|
||||
[ "$proto" = "dhcp" ] && [ -n "$release" ] && {
|
||||
norelease="$((!$release))"
|
||||
uci_set network "$config" norelease "$norelease"
|
||||
uci_remove network "$config" release
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
config_load network
|
||||
config_foreach migrate_release interface
|
||||
uci commit network
|
||||
|
||||
exit 0
|
||||
1
package/network/config/netifd/files/etc/udhcpc.user
Normal file
1
package/network/config/netifd/files/etc/udhcpc.user
Normal file
@@ -0,0 +1 @@
|
||||
# This script is sourced by udhcpc's dhcp.script at every DHCP event.
|
||||
120
package/network/config/netifd/files/lib/netifd/dhcp.script
Executable file
120
package/network/config/netifd/files/lib/netifd/dhcp.script
Executable file
@@ -0,0 +1,120 @@
|
||||
#!/bin/sh
|
||||
[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1
|
||||
|
||||
. /lib/functions.sh
|
||||
. /lib/netifd/netifd-proto.sh
|
||||
|
||||
set_classless_routes() {
|
||||
local max=128
|
||||
while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do
|
||||
proto_add_ipv4_route "${1%%/*}" "${1##*/}" "$2" "$ip"
|
||||
max=$(($max-1))
|
||||
shift 2
|
||||
done
|
||||
}
|
||||
|
||||
setup_interface () {
|
||||
proto_init_update "*" 1
|
||||
proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}"
|
||||
# TODO: apply $broadcast
|
||||
|
||||
local ip_net IP PREFIX NETWORK NETMASK BROADCAST
|
||||
ipcalc "$ip/$mask" && ip_net="$NETWORK"
|
||||
|
||||
local i
|
||||
for i in $router; do
|
||||
local gw_net
|
||||
ipcalc "$i/$mask" && gw_net="$NETWORK"
|
||||
|
||||
[ "$ip_net" != "$gw_net" ] && proto_add_ipv4_route "$i" 32 "" "$ip"
|
||||
proto_add_ipv4_route 0.0.0.0 0 "$i" "$ip"
|
||||
|
||||
local r
|
||||
for r in $CUSTOMROUTES; do
|
||||
proto_add_ipv4_route "${r%%/*}" "${r##*/}" "$i" "$ip"
|
||||
done
|
||||
done
|
||||
|
||||
# CIDR STATIC ROUTES (rfc3442)
|
||||
[ -n "$staticroutes" ] && set_classless_routes $staticroutes
|
||||
[ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes
|
||||
|
||||
for i in $dns; do
|
||||
proto_add_dns_server "$i"
|
||||
done
|
||||
for i in $domain; do
|
||||
proto_add_dns_search "$i"
|
||||
done
|
||||
|
||||
# TODO: Deprecate timesvr in favor of timesrv
|
||||
if [ -n "$timesvr" -a -z "$timesrv" ]; then
|
||||
timesrv="$timesvr"
|
||||
echo "Environment variable 'timesvr' will be deprecated; use 'timesrv' instead."
|
||||
fi
|
||||
|
||||
proto_add_data
|
||||
[ -n "$ZONE" ] && json_add_string zone "$ZONE"
|
||||
[ -n "$ntpsrv" ] && json_add_string ntpserver "$ntpsrv"
|
||||
[ -n "$timesrv" ] && json_add_string timeserver "$timesrv"
|
||||
[ -n "$hostname" ] && json_add_string hostname "$hostname"
|
||||
[ -n "$message" ] && json_add_string message "$message"
|
||||
[ -n "$timezone" ] && json_add_int timezone "$timezone"
|
||||
[ -n "$lease" ] && json_add_int leasetime "$lease"
|
||||
[ -n "$serverid" ] && json_add_string dhcpserver "$serverid"
|
||||
proto_close_data
|
||||
|
||||
proto_send_update "$INTERFACE"
|
||||
|
||||
|
||||
if [ "$IFACE6RD" != 0 -a -n "$ip6rd" ]; then
|
||||
local v4mask="${ip6rd%% *}"
|
||||
ip6rd="${ip6rd#* }"
|
||||
local ip6rdprefixlen="${ip6rd%% *}"
|
||||
ip6rd="${ip6rd#* }"
|
||||
local ip6rdprefix="${ip6rd%% *}"
|
||||
ip6rd="${ip6rd#* }"
|
||||
local ip6rdbr="${ip6rd%% *}"
|
||||
|
||||
[ -n "$ZONE" ] || ZONE=$(fw3 -q network $INTERFACE 2>/dev/null)
|
||||
[ -z "$IFACE6RD" -o "$IFACE6RD" = 1 ] && IFACE6RD=${INTERFACE}_6
|
||||
|
||||
json_init
|
||||
json_add_string name "$IFACE6RD"
|
||||
json_add_string ifname "@$INTERFACE"
|
||||
json_add_string proto "6rd"
|
||||
json_add_string peeraddr "$ip6rdbr"
|
||||
json_add_int ip4prefixlen "$v4mask"
|
||||
json_add_string ip6prefix "$ip6rdprefix"
|
||||
json_add_int ip6prefixlen "$ip6rdprefixlen"
|
||||
json_add_string tunlink "$INTERFACE"
|
||||
[ -n "$IFACE6RD_DELEGATE" ] && json_add_boolean delegate "$IFACE6RD_DELEGATE"
|
||||
[ -n "$ZONE6RD" ] || ZONE6RD=$ZONE
|
||||
[ -n "$ZONE6RD" ] && json_add_string zone "$ZONE6RD"
|
||||
[ -n "$MTU6RD" ] && json_add_string mtu "$MTU6RD"
|
||||
json_close_object
|
||||
|
||||
ubus call network add_dynamic "$(json_dump)"
|
||||
fi
|
||||
}
|
||||
|
||||
deconfig_interface() {
|
||||
proto_init_update "*" 0
|
||||
proto_send_update "$INTERFACE"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
deconfig)
|
||||
deconfig_interface
|
||||
;;
|
||||
renew|bound)
|
||||
setup_interface
|
||||
;;
|
||||
esac
|
||||
|
||||
# user rules
|
||||
[ -f /etc/udhcpc.user ] && . /etc/udhcpc.user "$@"
|
||||
for f in /etc/udhcpc.user.d/*; do
|
||||
[ -f "$f" ] && (. "$f" "$@")
|
||||
done
|
||||
|
||||
exit 0
|
||||
88
package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
Executable file
88
package/network/config/netifd/files/lib/netifd/proto/dhcp.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -x /sbin/udhcpc ] || exit 0
|
||||
|
||||
. /lib/functions.sh
|
||||
. ../netifd-proto.sh
|
||||
init_proto "$@"
|
||||
|
||||
proto_dhcp_init_config() {
|
||||
renew_handler=1
|
||||
|
||||
proto_config_add_string 'ipaddr:ipaddr'
|
||||
proto_config_add_string 'hostname:hostname'
|
||||
proto_config_add_string clientid
|
||||
proto_config_add_string vendorid
|
||||
proto_config_add_boolean 'broadcast:bool'
|
||||
proto_config_add_boolean 'norelease:bool'
|
||||
proto_config_add_string 'reqopts:list(string)'
|
||||
proto_config_add_boolean 'defaultreqopts:bool'
|
||||
proto_config_add_string iface6rd
|
||||
proto_config_add_array 'sendopts:list(string)'
|
||||
proto_config_add_boolean delegate
|
||||
proto_config_add_string zone6rd
|
||||
proto_config_add_string zone
|
||||
proto_config_add_string mtu6rd
|
||||
proto_config_add_string customroutes
|
||||
proto_config_add_boolean classlessroute
|
||||
}
|
||||
|
||||
proto_dhcp_add_sendopts() {
|
||||
[ -n "$1" ] && append "$3" "-x $1"
|
||||
}
|
||||
|
||||
proto_dhcp_setup() {
|
||||
local config="$1"
|
||||
local iface="$2"
|
||||
|
||||
local ipaddr hostname clientid vendorid broadcast norelease reqopts defaultreqopts iface6rd sendopts delegate zone6rd zone mtu6rd customroutes classlessroute
|
||||
json_get_vars ipaddr hostname clientid vendorid broadcast norelease reqopts defaultreqopts iface6rd delegate zone6rd zone mtu6rd customroutes classlessroute
|
||||
|
||||
local opt dhcpopts
|
||||
for opt in $reqopts; do
|
||||
append dhcpopts "-O $opt"
|
||||
done
|
||||
|
||||
json_for_each_item proto_dhcp_add_sendopts sendopts dhcpopts
|
||||
|
||||
[ -z "$hostname" ] && hostname="$(cat /proc/sys/kernel/hostname)"
|
||||
[ "$hostname" = "*" ] && hostname=
|
||||
|
||||
[ "$defaultreqopts" = 0 ] && defaultreqopts="-o" || defaultreqopts=
|
||||
[ "$broadcast" = 1 ] && broadcast="-B" || broadcast=
|
||||
[ "$norelease" = 1 ] && norelease="" || norelease="-R"
|
||||
[ -n "$clientid" ] && clientid="-x 0x3d:${clientid//:/}" || clientid="-C"
|
||||
[ -n "$iface6rd" ] && proto_export "IFACE6RD=$iface6rd"
|
||||
[ "$iface6rd" != 0 -a -f /lib/netifd/proto/6rd.sh ] && append dhcpopts "-O 212"
|
||||
[ -n "$zone6rd" ] && proto_export "ZONE6RD=$zone6rd"
|
||||
[ -n "$zone" ] && proto_export "ZONE=$zone"
|
||||
[ -n "$mtu6rd" ] && proto_export "MTU6RD=$mtu6rd"
|
||||
[ -n "$customroutes" ] && proto_export "CUSTOMROUTES=$customroutes"
|
||||
[ "$delegate" = "0" ] && proto_export "IFACE6RD_DELEGATE=0"
|
||||
# Request classless route option (see RFC 3442) by default
|
||||
[ "$classlessroute" = "0" ] || append dhcpopts "-O 121"
|
||||
|
||||
proto_export "INTERFACE=$config"
|
||||
proto_run_command "$config" udhcpc \
|
||||
-p /var/run/udhcpc-$iface.pid \
|
||||
-s /lib/netifd/dhcp.script \
|
||||
-f -t 0 -i "$iface" \
|
||||
${ipaddr:+-r ${ipaddr/\/*/}} \
|
||||
${hostname:+-x "hostname:$hostname"} \
|
||||
${vendorid:+-V "$vendorid"} \
|
||||
$clientid $defaultreqopts $broadcast $norelease $dhcpopts
|
||||
}
|
||||
|
||||
proto_dhcp_renew() {
|
||||
local interface="$1"
|
||||
# SIGUSR1 forces udhcpc to renew its lease
|
||||
local sigusr1="$(kill -l SIGUSR1)"
|
||||
[ -n "$sigusr1" ] && proto_kill_command "$interface" $sigusr1
|
||||
}
|
||||
|
||||
proto_dhcp_teardown() {
|
||||
local interface="$1"
|
||||
proto_kill_command "$interface"
|
||||
}
|
||||
|
||||
add_protocol dhcp
|
||||
76
package/network/config/netifd/files/lib/network/config.sh
Executable file
76
package/network/config/netifd/files/lib/network/config.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2011 OpenWrt.org
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
find_config() {
|
||||
local device="$1"
|
||||
local ifdev ifl3dev ifobj
|
||||
for ifobj in $(ubus list network.interface.\*); do
|
||||
interface="${ifobj##network.interface.}"
|
||||
(
|
||||
json_load "$(ifstatus $interface)"
|
||||
json_get_var ifdev device
|
||||
json_get_var ifl3dev l3_device
|
||||
if [ "$device" = "$ifdev" ] || [ "$device" = "$ifl3dev" ]; then
|
||||
echo "$interface"
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
) && return
|
||||
done
|
||||
}
|
||||
|
||||
unbridge() {
|
||||
return
|
||||
}
|
||||
|
||||
ubus_call() {
|
||||
json_init
|
||||
local _data="$(ubus -S call "$1" "$2")"
|
||||
[ -z "$_data" ] && return 1
|
||||
json_load "$_data"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
fixup_interface() {
|
||||
local config="$1"
|
||||
local ifname type device l3dev
|
||||
|
||||
config_get type "$config" type
|
||||
config_get ifname "$config" ifname
|
||||
[ "bridge" = "$type" ] && ifname="br-$config"
|
||||
ubus_call "network.interface.$config" status || return 0
|
||||
json_get_var l3dev l3_device
|
||||
[ -n "$l3dev" ] && ifname="$l3dev"
|
||||
json_init
|
||||
config_set "$config" ifname "$ifname"
|
||||
}
|
||||
|
||||
scan_interfaces() {
|
||||
config_load network
|
||||
config_foreach fixup_interface interface
|
||||
}
|
||||
|
||||
prepare_interface_bridge() {
|
||||
local config="$1"
|
||||
|
||||
[ -n "$config" ] || return 0
|
||||
ubus call network.interface."$config" prepare
|
||||
}
|
||||
|
||||
setup_interface() {
|
||||
local iface="$1"
|
||||
local config="$2"
|
||||
|
||||
[ -n "$config" ] || return 0
|
||||
ubus call network.interface."$config" add_device "{ \"name\": \"$iface\" }"
|
||||
}
|
||||
|
||||
do_sysctl() {
|
||||
[ -n "$2" ] && \
|
||||
sysctl -n -e -w "$1=$2" >/dev/null || \
|
||||
sysctl -n -e "$1"
|
||||
}
|
||||
12
package/network/config/netifd/files/sbin/devstatus
Executable file
12
package/network/config/netifd/files/sbin/devstatus
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
DEVICE="$1"
|
||||
|
||||
[ -n "$DEVICE" ] || {
|
||||
echo "Usage: $0 <device>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
json_init
|
||||
json_add_string name "$DEVICE"
|
||||
ubus call network.device status "$(json_dump)"
|
||||
1
package/network/config/netifd/files/sbin/ifdown
Symbolic link
1
package/network/config/netifd/files/sbin/ifdown
Symbolic link
@@ -0,0 +1 @@
|
||||
ifup
|
||||
13
package/network/config/netifd/files/sbin/ifstatus
Executable file
13
package/network/config/netifd/files/sbin/ifstatus
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
INTERFACE="$1"
|
||||
|
||||
[ -n "$INTERFACE" ] || {
|
||||
echo "Usage: $0 <interface>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
ubus -S list "network.interface.$INTERFACE" >/dev/null || {
|
||||
echo "Interface $INTERFACE not found"
|
||||
exit 1
|
||||
}
|
||||
ubus call network.interface status "{ \"interface\" : \"$INTERFACE\" }"
|
||||
44
package/network/config/netifd/files/sbin/ifup
Executable file
44
package/network/config/netifd/files/sbin/ifup
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
|
||||
ifup_all=
|
||||
|
||||
if_call() {
|
||||
local interface="$1"
|
||||
for mode in $modes; do
|
||||
ubus call network.interface $mode "{ \"interface\" : \"$interface\" }"
|
||||
done
|
||||
}
|
||||
|
||||
case "$0" in
|
||||
*ifdown) modes=down;;
|
||||
*ifup)
|
||||
modes="down up"
|
||||
;;
|
||||
*) echo "Invalid command: $0";;
|
||||
esac
|
||||
|
||||
while :; do
|
||||
case "$1" in
|
||||
-a)
|
||||
ifup_all=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ "$modes" = "down up" ] && ubus call network reload
|
||||
if [ -n "$ifup_all" ]; then
|
||||
for interface in $(ubus -S list 'network.interface.*'); do
|
||||
if_call "${interface##network.interface.}"
|
||||
done
|
||||
exit
|
||||
else
|
||||
ubus -S list "network.interface.$1" > /dev/null || {
|
||||
echo "Interface $1 not found"
|
||||
exit
|
||||
}
|
||||
if_call "$1"
|
||||
fi
|
||||
236
package/network/config/netifd/files/usr/libexec/network/packet-steering.uc
Executable file
236
package/network/config/netifd/files/usr/libexec/network/packet-steering.uc
Executable file
@@ -0,0 +1,236 @@
|
||||
#!/usr/bin/env ucode
|
||||
'use strict';
|
||||
import { glob, basename, dirname, readlink, readfile, realpath, writefile, error, open } from "fs";
|
||||
|
||||
let napi_weight = 1.0;
|
||||
let cpu_thread_weight = 0.75;
|
||||
let rx_weight = 0.75;
|
||||
let eth_bias = 2.0;
|
||||
let debug = 0, do_nothing = 0;
|
||||
let disable;
|
||||
let cpus;
|
||||
let all_cpus;
|
||||
let local_flows = 0;
|
||||
|
||||
while (length(ARGV) > 0) {
|
||||
let arg = shift(ARGV);
|
||||
switch (arg) {
|
||||
case "-d":
|
||||
debug++;
|
||||
break;
|
||||
case "-n":
|
||||
do_nothing++;
|
||||
break;
|
||||
case '0':
|
||||
disable = true;
|
||||
break;
|
||||
case '2':
|
||||
all_cpus = true;
|
||||
break;
|
||||
case '-l':
|
||||
local_flows = +shift(ARGV);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function task_name(pid)
|
||||
{
|
||||
let stat = open(`/proc/${pid}/status`, "r");
|
||||
if (!stat)
|
||||
return;
|
||||
let line = stat.read("line");
|
||||
stat.close();
|
||||
return trim(split(line, "\t", 2)[1]);
|
||||
}
|
||||
|
||||
function set_task_cpu(pid, cpu) {
|
||||
if (disable)
|
||||
cpu = join(",", map(cpus, (cpu) => cpu.id));
|
||||
let name = task_name(pid);
|
||||
if (!name)
|
||||
return;
|
||||
if (debug || do_nothing)
|
||||
warn(`taskset -p -c ${cpu} ${name}\n`);
|
||||
if (!do_nothing)
|
||||
system(`taskset -p -c ${cpu} ${pid}`);
|
||||
}
|
||||
|
||||
function cpu_mask(cpu)
|
||||
{
|
||||
let mask;
|
||||
if (cpu < 0)
|
||||
mask = (1 << length(cpus)) - 1;
|
||||
else
|
||||
mask = (1 << int(cpu));
|
||||
return sprintf("%x", mask);
|
||||
}
|
||||
|
||||
function set_netdev_cpu(dev, cpu) {
|
||||
let queues = glob(`/sys/class/net/${dev}/queues/rx-*/rps_cpus`);
|
||||
let val = cpu_mask(cpu);
|
||||
if (disable)
|
||||
val = 0;
|
||||
for (let queue in queues) {
|
||||
if (debug || do_nothing)
|
||||
warn(`echo ${val} > ${queue}\n`);
|
||||
if (!do_nothing)
|
||||
writefile(queue, `${val}`);
|
||||
}
|
||||
queues = glob(`/sys/class/net/${dev}/queues/rx-*/rps_flow_cnt`);
|
||||
for (let queue in queues) {
|
||||
if (debug || do_nothing)
|
||||
warn(`echo ${local_flows} > ${queue}\n`);
|
||||
if (!do_nothing)
|
||||
writefile(queue, `${local_flows}`);
|
||||
}
|
||||
}
|
||||
|
||||
function task_device_match(name, device)
|
||||
{
|
||||
let napi_match = match(name, /napi\/([^-+])-\d+/);
|
||||
if (!napi_match)
|
||||
napi_match = match(name, /mt76-tx (phy\d+)/);
|
||||
if (napi_match &&
|
||||
(index(device.phy, napi_match[1]) >= 0 ||
|
||||
index(device.netdev, napi_match[1]) >= 0))
|
||||
return true;
|
||||
|
||||
if (device.driver == "mtk_soc_eth" && match(name, /napi\/mtk_eth-/))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
cpus = map(glob("/sys/bus/cpu/devices/*"), (path) => {
|
||||
return {
|
||||
id: int(match(path, /.*cpu(\d+)/)[1]),
|
||||
core: int(trim(readfile(`${path}/topology/core_id`))),
|
||||
load: 0.0,
|
||||
};
|
||||
});
|
||||
|
||||
cpus = slice(cpus, 0, 64);
|
||||
if (length(cpus) < 2)
|
||||
exit(0);
|
||||
|
||||
function cpu_add_weight(cpu_id, weight)
|
||||
{
|
||||
let cpu = cpus[cpu_id];
|
||||
cpu.load += weight;
|
||||
for (let sibling in cpus) {
|
||||
if (sibling == cpu || sibling.core != cpu.core)
|
||||
continue;
|
||||
sibling.load += weight * cpu_thread_weight;
|
||||
}
|
||||
}
|
||||
|
||||
function get_next_cpu(weight, prev_cpu)
|
||||
{
|
||||
if (disable)
|
||||
return 0;
|
||||
|
||||
let sort_cpus = sort(slice(cpus), (a, b) => a.load - b.load);
|
||||
let idx = 0;
|
||||
|
||||
if (prev_cpu != null && sort_cpus[idx].id == prev_cpu)
|
||||
idx++;
|
||||
|
||||
let cpu = sort_cpus[idx].id;
|
||||
cpu_add_weight(cpu, weight);
|
||||
return cpu;
|
||||
}
|
||||
|
||||
let phys_devs = {};
|
||||
let netdev_phys = {};
|
||||
let netdevs = map(glob("/sys/class/net/*"), (dev) => basename(dev));
|
||||
|
||||
for (let dev in netdevs) {
|
||||
let pdev_path = realpath(`/sys/class/net/${dev}/device`);
|
||||
if (!pdev_path)
|
||||
continue;
|
||||
|
||||
if (length(glob(`/sys/class/net/${dev}/lower_*`)) > 0)
|
||||
continue;
|
||||
|
||||
let pdev = phys_devs[pdev_path];
|
||||
if (!pdev) {
|
||||
pdev = phys_devs[pdev_path] = {
|
||||
path: pdev_path,
|
||||
driver: basename(readlink(`${pdev_path}/driver`)),
|
||||
netdev: [],
|
||||
phy: [],
|
||||
tasks: [],
|
||||
};
|
||||
}
|
||||
|
||||
let phyidx = trim(readfile(`/sys/class/net/${dev}/phy80211/index`));
|
||||
if (phyidx != null) {
|
||||
let phy = `phy${phyidx}`;
|
||||
if (index(pdev.phy, phy) < 0)
|
||||
push(pdev.phy, phy);
|
||||
}
|
||||
|
||||
push(pdev.netdev, dev);
|
||||
netdev_phys[dev] = pdev;
|
||||
}
|
||||
|
||||
for (let path in glob("/proc/*/exe")) {
|
||||
readlink(path);
|
||||
if (error() != "No such file or directory")
|
||||
continue;
|
||||
|
||||
let pid = basename(dirname(path));
|
||||
let name = task_name(pid);
|
||||
for (let devname in phys_devs) {
|
||||
let dev = phys_devs[devname];
|
||||
if (!task_device_match(name, dev))
|
||||
continue;
|
||||
|
||||
push(dev.tasks, pid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function assign_dev_cpu(dev) {
|
||||
if (length(dev.tasks) > 0) {
|
||||
let cpu = dev.napi_cpu = get_next_cpu(napi_weight);
|
||||
for (let task in dev.tasks)
|
||||
set_task_cpu(task, cpu);
|
||||
}
|
||||
|
||||
if (length(dev.netdev) > 0) {
|
||||
let cpu;
|
||||
if (all_cpus)
|
||||
cpu = -1;
|
||||
else
|
||||
cpu = get_next_cpu(rx_weight, dev.napi_cpu);
|
||||
dev.rx_cpu = cpu;
|
||||
for (let netdev in dev.netdev)
|
||||
set_netdev_cpu(netdev, cpu);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign ethernet devices first
|
||||
for (let devname in phys_devs) {
|
||||
let dev = phys_devs[devname];
|
||||
if (!length(dev.phy))
|
||||
assign_dev_cpu(dev);
|
||||
}
|
||||
|
||||
// Add bias to avoid assigning other tasks to CPUs with ethernet NAPI
|
||||
for (let devname in phys_devs) {
|
||||
let dev = phys_devs[devname];
|
||||
if (!length(dev.tasks) || dev.napi_cpu == null)
|
||||
continue;
|
||||
cpu_add_weight(dev.napi_cpu, eth_bias);
|
||||
}
|
||||
|
||||
// Assign WLAN devices
|
||||
for (let devname in phys_devs) {
|
||||
let dev = phys_devs[devname];
|
||||
if (length(dev.phy) > 0)
|
||||
assign_dev_cpu(dev);
|
||||
}
|
||||
|
||||
if (debug > 1)
|
||||
warn(sprintf("devices: %.J\ncpus: %.J\n", phys_devs, cpus));
|
||||
57
package/network/config/netifd/files/usr/share/udhcpc/default.script
Executable file
57
package/network/config/netifd/files/usr/share/udhcpc/default.script
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
[ -z "$1" ] && echo "Error: should be run by udhcpc" && exit 1
|
||||
|
||||
set_classless_routes() {
|
||||
local max=128
|
||||
local type
|
||||
while [ -n "$1" -a -n "$2" -a $max -gt 0 ]; do
|
||||
[ ${1##*/} -eq 32 ] && type=host || type=net
|
||||
echo "udhcpc: adding route for $type $1 via $2"
|
||||
route add -$type "$1" gw "$2" dev "$interface"
|
||||
max=$(($max-1))
|
||||
shift 2
|
||||
done
|
||||
}
|
||||
|
||||
setup_interface() {
|
||||
echo "udhcpc: ip addr add $ip/${subnet:-255.255.255.0} broadcast ${broadcast:-+} dev $interface"
|
||||
ip addr add $ip/${subnet:-255.255.255.0} broadcast ${broadcast:-+} dev $interface
|
||||
|
||||
[ -n "$router" ] && [ "$router" != "0.0.0.0" ] && [ "$router" != "255.255.255.255" ] && {
|
||||
echo "udhcpc: setting default routers: $router"
|
||||
|
||||
local valid_gw=""
|
||||
for i in $router ; do
|
||||
route add default gw $i dev $interface
|
||||
valid_gw="${valid_gw:+$valid_gw|}$i"
|
||||
done
|
||||
|
||||
eval $(route -n | awk '
|
||||
/^0.0.0.0\W{9}('$valid_gw')\W/ {next}
|
||||
/^0.0.0.0/ {print "route del -net "$1" gw "$2";"}
|
||||
')
|
||||
}
|
||||
|
||||
# CIDR STATIC ROUTES (rfc3442)
|
||||
[ -n "$staticroutes" ] && set_classless_routes $staticroutes
|
||||
[ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes
|
||||
}
|
||||
|
||||
|
||||
applied=
|
||||
case "$1" in
|
||||
deconfig)
|
||||
ip -4 addr flush dev "$interface"
|
||||
;;
|
||||
renew)
|
||||
setup_interface update
|
||||
;;
|
||||
bound)
|
||||
setup_interface ifup
|
||||
;;
|
||||
esac
|
||||
|
||||
# user rules
|
||||
[ -f /etc/udhcpc.user ] && . /etc/udhcpc.user
|
||||
|
||||
exit 0
|
||||
53
package/network/config/qos-scripts/Makefile
Normal file
53
package/network/config/qos-scripts/Makefile
Normal file
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright (C) 2006-2015 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=qos-scripts
|
||||
PKG_VERSION:=1.3.1
|
||||
PKG_RELEASE:=33
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/qos-scripts
|
||||
SECTION:=utils
|
||||
CATEGORY:=Base system
|
||||
DEPENDS:=+tc +kmod-sched-core +kmod-sched-connmark +kmod-ifb +iptables +iptables-mod-ipopt +iptables-mod-conntrack-extra
|
||||
TITLE:=QoS scripts
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/qos-scripts/description
|
||||
A set of scripts that abstract QoS configuration into a simple
|
||||
configuration file supporting stanzas that specify any number of QoS
|
||||
entries.
|
||||
endef
|
||||
|
||||
define Package/qos-scripts/conffiles
|
||||
/etc/config/qos
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/qos-scripts/install
|
||||
$(INSTALL_DIR) $(1)
|
||||
$(CP) ./files/* $(1)/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,qos-scripts))
|
||||
68
package/network/config/qos-scripts/files/etc/config/qos
Normal file
68
package/network/config/qos-scripts/files/etc/config/qos
Normal file
@@ -0,0 +1,68 @@
|
||||
# QoS configuration for OpenWrt
|
||||
|
||||
# INTERFACES:
|
||||
config interface wan
|
||||
option classgroup "Default"
|
||||
option enabled 0
|
||||
option upload 128
|
||||
option download 1024
|
||||
|
||||
# RULES:
|
||||
config classify
|
||||
option target "Priority"
|
||||
option ports "22,53"
|
||||
option comment "ssh, dns"
|
||||
config classify
|
||||
option target "Normal"
|
||||
option proto "tcp"
|
||||
option ports "20,21,25,80,110,443,993,995"
|
||||
option comment "ftp, smtp, http(s), imap"
|
||||
config classify
|
||||
option target "Express"
|
||||
option ports "5190"
|
||||
option comment "AOL, iChat, ICQ"
|
||||
config default
|
||||
option target "Express"
|
||||
option proto "udp"
|
||||
option pktsize "-500"
|
||||
config reclassify
|
||||
option target "Priority"
|
||||
option proto "icmp"
|
||||
config default
|
||||
option target "Bulk"
|
||||
option portrange "1024-65535"
|
||||
|
||||
|
||||
# Don't change the stuff below unless you
|
||||
# really know what it means :)
|
||||
|
||||
config classgroup "Default"
|
||||
option classes "Priority Express Normal Bulk"
|
||||
option default "Normal"
|
||||
|
||||
|
||||
config class "Priority"
|
||||
option packetsize 400
|
||||
option avgrate 10
|
||||
option priority 20
|
||||
config class "Priority_down"
|
||||
option packetsize 1000
|
||||
option avgrate 10
|
||||
|
||||
|
||||
config class "Express"
|
||||
option packetsize 1000
|
||||
option avgrate 50
|
||||
option priority 10
|
||||
|
||||
config class "Normal"
|
||||
option packetsize 1500
|
||||
option packetdelay 100
|
||||
option avgrate 10
|
||||
option priority 5
|
||||
config class "Normal_down"
|
||||
option avgrate 20
|
||||
|
||||
config class "Bulk"
|
||||
option avgrate 1
|
||||
option packetdelay 200
|
||||
2
package/network/config/qos-scripts/files/etc/hotplug.d/iface/10-qos
Executable file
2
package/network/config/qos-scripts/files/etc/hotplug.d/iface/10-qos
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
[ "$ACTION" = ifup ] && /etc/init.d/qos enabled && /usr/lib/qos/generate.sh interface "$INTERFACE" | sh
|
||||
28
package/network/config/qos-scripts/files/etc/init.d/qos
Executable file
28
package/network/config/qos-scripts/files/etc/init.d/qos
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2006 OpenWrt.org
|
||||
|
||||
START=50
|
||||
USE_PROCD=1
|
||||
|
||||
validate_qos_section()
|
||||
{
|
||||
uci_validate_section qos interface "${1}" \
|
||||
'enabled:bool' \
|
||||
'upload:uinteger' \
|
||||
'download:uinteger'
|
||||
}
|
||||
|
||||
service_triggers()
|
||||
{
|
||||
procd_add_reload_trigger "qos"
|
||||
procd_add_validation validate_qos_section
|
||||
qos-start
|
||||
}
|
||||
|
||||
start_service() {
|
||||
qos-start
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
qos-start
|
||||
}
|
||||
4
package/network/config/qos-scripts/files/usr/bin/qos-start
Executable file
4
package/network/config/qos-scripts/files/usr/bin/qos-start
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
qos-stop
|
||||
/usr/lib/qos/generate.sh all | sh
|
||||
68
package/network/config/qos-scripts/files/usr/bin/qos-stat
Executable file
68
package/network/config/qos-scripts/files/usr/bin/qos-stat
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2011 OpenWrt.org
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
include /lib/network
|
||||
|
||||
get_ifname() {
|
||||
local interface="$1"
|
||||
local cfgt
|
||||
|
||||
scan_interfaces
|
||||
config_get cfgt "$interface" TYPE
|
||||
[ "$cfgt" = "interface" ] && config_get "$interface" ifname
|
||||
}
|
||||
|
||||
qos_set_device() {
|
||||
config_get TYPE "$1" TYPE
|
||||
[ "interface" = "$TYPE" ] && {
|
||||
config_get device "$1" ifname
|
||||
[ -z "$device" ] && device="$(get_ifname $1)"
|
||||
config_set "$1" device "$device"
|
||||
}
|
||||
}
|
||||
|
||||
config_load qos
|
||||
config_foreach qos_set_device
|
||||
|
||||
print_comments() {
|
||||
echo ''
|
||||
echo '# Interface: '"$1"
|
||||
echo '# Direction: '"$2"
|
||||
echo '# Stats: '"$3"
|
||||
echo ''
|
||||
}
|
||||
|
||||
get_device() {
|
||||
( config_load network; scan_interfaces; config_get "$1" ifname )
|
||||
}
|
||||
|
||||
interface_stats() {
|
||||
local interface="$1"
|
||||
local device
|
||||
|
||||
device="$(get_device "$interface")"
|
||||
[ -z "$device" ] && config_get device "$interface" device
|
||||
config_get_bool enabled "$interface" enabled 1
|
||||
[ -z "$device" -o 1 -ne "$enabled" ] && {
|
||||
return 1
|
||||
}
|
||||
config_get_bool halfduplex "$interface" halfduplex 0
|
||||
|
||||
if [ 1 -ne "$halfduplex" ]; then
|
||||
unset halfduplex
|
||||
print_comments "$interface" "Egress" "Start"
|
||||
tc -s class show dev "$device"
|
||||
print_comments "$interface" "Egress" "End"
|
||||
id="root"
|
||||
else
|
||||
id=""
|
||||
fi
|
||||
|
||||
print_comments "$interface" "Ingress${halfduplex:+/Egress}" "Start"
|
||||
tc -s class show dev "$(tc filter show dev $device $id | grep mirred | sed -e 's,.*\(ifb.*\)).*,\1,')"
|
||||
print_comments "$interface" "Ingress${halfduplex:+/Egress}" "End"
|
||||
}
|
||||
|
||||
[ -z "$1" ] && config_foreach interface_stats interface || interface_stats "$1"
|
||||
7
package/network/config/qos-scripts/files/usr/bin/qos-stop
Executable file
7
package/network/config/qos-scripts/files/usr/bin/qos-stop
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
for iface in $(tc qdisc show | grep -E '(hfsc|ingress)' | awk '{print $5}'); do
|
||||
tc qdisc del dev "$iface" ingress 2>&- >&-
|
||||
tc qdisc del dev "$iface" root 2>&- >&-
|
||||
done
|
||||
/usr/lib/qos/generate.sh firewall stop | sh
|
||||
542
package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
Executable file
542
package/network/config/qos-scripts/files/usr/lib/qos/generate.sh
Executable file
@@ -0,0 +1,542 @@
|
||||
#!/bin/sh
|
||||
[ -e /lib/functions.sh ] && . /lib/functions.sh || . ./functions.sh
|
||||
[ -x /sbin/modprobe ] && {
|
||||
insmod="modprobe"
|
||||
} || {
|
||||
insmod="insmod"
|
||||
}
|
||||
rmmod="rmmod"
|
||||
|
||||
add_insmod() {
|
||||
eval "export isset=\${insmod_$1}"
|
||||
case "$isset" in
|
||||
1) ;;
|
||||
*) {
|
||||
[ "$2" ] && append INSMOD "$rmmod $1 >&- 2>&-" "$N"
|
||||
append INSMOD "$insmod $* >&- 2>&-" "$N"; export insmod_$1=1
|
||||
};;
|
||||
esac
|
||||
}
|
||||
|
||||
[ -e /etc/config/network ] && {
|
||||
# only try to parse network config on openwrt
|
||||
|
||||
. /lib/functions/network.sh
|
||||
|
||||
find_ifname() {
|
||||
local ifname
|
||||
if network_get_device ifname "$1"; then
|
||||
echo "$ifname"
|
||||
else
|
||||
echo "Device for interface $1 not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
} || {
|
||||
find_ifname() {
|
||||
echo "Interface not found." >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
parse_matching_rule() {
|
||||
local var="$1"
|
||||
local section="$2"
|
||||
local options="$3"
|
||||
local prefix="$4"
|
||||
local suffix="$5"
|
||||
local proto="$6"
|
||||
local mport=""
|
||||
local ports=""
|
||||
|
||||
append "$var" "$prefix" "$N"
|
||||
for option in $options; do
|
||||
case "$option" in
|
||||
proto) config_get value "$section" proto; proto="${proto:-$value}";;
|
||||
esac
|
||||
done
|
||||
config_get type "$section" TYPE
|
||||
case "$type" in
|
||||
classify) unset pkt; append "$var" "-m mark --mark 0/0x0f";;
|
||||
default) pkt=1; append "$var" "-m mark --mark 0/0xf0";;
|
||||
reclassify) pkt=1;;
|
||||
esac
|
||||
append "$var" "${proto:+-p $proto}"
|
||||
for option in $options; do
|
||||
config_get value "$section" "$option"
|
||||
|
||||
case "$pkt:$option" in
|
||||
*:srchost)
|
||||
append "$var" "-s $value"
|
||||
;;
|
||||
*:dsthost)
|
||||
append "$var" "-d $value"
|
||||
;;
|
||||
*:ports|*:srcports|*:dstports)
|
||||
value="$(echo "$value" | sed -e 's,-,:,g')"
|
||||
lproto=${lproto:-tcp}
|
||||
case "$proto" in
|
||||
""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} -m multiport";;
|
||||
*) unset "$var"; return 0;;
|
||||
esac
|
||||
case "$option" in
|
||||
ports)
|
||||
config_set "$section" srcports ""
|
||||
config_set "$section" dstports ""
|
||||
config_set "$section" portrange ""
|
||||
append "$var" "--ports $value"
|
||||
;;
|
||||
srcports)
|
||||
config_set "$section" ports ""
|
||||
config_set "$section" dstports ""
|
||||
config_set "$section" portrange ""
|
||||
append "$var" "--sports $value"
|
||||
;;
|
||||
dstports)
|
||||
config_set "$section" ports ""
|
||||
config_set "$section" srcports ""
|
||||
config_set "$section" portrange ""
|
||||
append "$var" "--dports $value"
|
||||
;;
|
||||
esac
|
||||
ports=1
|
||||
;;
|
||||
*:portrange)
|
||||
config_set "$section" ports ""
|
||||
config_set "$section" srcports ""
|
||||
config_set "$section" dstports ""
|
||||
value="$(echo "$value" | sed -e 's,-,:,g')"
|
||||
case "$proto" in
|
||||
""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} --sport $value --dport $value";;
|
||||
*) unset "$var"; return 0;;
|
||||
esac
|
||||
ports=1
|
||||
;;
|
||||
*:connbytes)
|
||||
value="$(echo "$value" | sed -e 's,-,:,g')"
|
||||
add_insmod xt_connbytes
|
||||
append "$var" "-m connbytes --connbytes $value --connbytes-dir both --connbytes-mode bytes"
|
||||
;;
|
||||
*:comment)
|
||||
add_insmod xt_comment
|
||||
append "$var" "-m comment --comment '$value'"
|
||||
;;
|
||||
*:tos)
|
||||
add_insmod xt_dscp
|
||||
case "$value" in
|
||||
!*) append "$var" "-m tos ! --tos $value";;
|
||||
*) append "$var" "-m tos --tos $value"
|
||||
esac
|
||||
;;
|
||||
*:dscp)
|
||||
add_insmod xt_dscp
|
||||
dscp_option="--dscp"
|
||||
[ -z "${value%%[EBCA]*}" ] && dscp_option="--dscp-class"
|
||||
case "$value" in
|
||||
!*) append "$var" "-m dscp ! $dscp_option $value";;
|
||||
*) append "$var" "-m dscp $dscp_option $value"
|
||||
esac
|
||||
;;
|
||||
*:direction)
|
||||
value="$(echo "$value" | sed -e 's,-,:,g')"
|
||||
if [ "$value" = "out" ]; then
|
||||
append "$var" "-o $device"
|
||||
elif [ "$value" = "in" ]; then
|
||||
append "$var" "-i $device"
|
||||
fi
|
||||
;;
|
||||
*:srciface)
|
||||
append "$var" "-i $value"
|
||||
;;
|
||||
1:pktsize)
|
||||
value="$(echo "$value" | sed -e 's,-,:,g')"
|
||||
add_insmod xt_length
|
||||
append "$var" "-m length --length $value"
|
||||
;;
|
||||
1:limit)
|
||||
add_insmod xt_limit
|
||||
append "$var" "-m limit --limit $value"
|
||||
;;
|
||||
1:tcpflags)
|
||||
case "$proto" in
|
||||
tcp) append "$var" "-m tcp --tcp-flags ALL $value";;
|
||||
*) unset $var; return 0;;
|
||||
esac
|
||||
;;
|
||||
1:mark)
|
||||
config_get class "${value##!}" classnr
|
||||
[ -z "$class" ] && continue;
|
||||
case "$value" in
|
||||
!*) append "$var" "-m mark ! --mark $class/0x0f";;
|
||||
*) append "$var" "-m mark --mark $class/0x0f";;
|
||||
esac
|
||||
;;
|
||||
1:TOS)
|
||||
add_insmod xt_DSCP
|
||||
config_get TOS "$rule" 'TOS'
|
||||
suffix="-j TOS --set-tos "${TOS:-"Normal-Service"}
|
||||
;;
|
||||
1:DSCP)
|
||||
add_insmod xt_DSCP
|
||||
config_get DSCP "$rule" 'DSCP'
|
||||
[ -z "${DSCP%%[EBCA]*}" ] && set_value="--set-dscp-class $DSCP" \
|
||||
|| set_value="--set-dscp $DSCP"
|
||||
suffix="-j DSCP $set_value"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
append "$var" "$suffix"
|
||||
case "$ports:$proto" in
|
||||
1:) parse_matching_rule "$var" "$section" "$options" "$prefix" "$suffix" "udp";;
|
||||
esac
|
||||
}
|
||||
|
||||
config_cb() {
|
||||
option_cb() {
|
||||
return 0
|
||||
}
|
||||
case "$1" in
|
||||
interface)
|
||||
config_set "$2" "classgroup" "Default"
|
||||
config_set "$2" "upload" "128"
|
||||
;;
|
||||
classify|default|reclassify)
|
||||
option_cb() {
|
||||
append "CONFIG_${CONFIG_SECTION}_options" "$1"
|
||||
}
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
qos_parse_config() {
|
||||
config_get TYPE "$1" TYPE
|
||||
case "$TYPE" in
|
||||
interface)
|
||||
config_get_bool enabled "$1" enabled 1
|
||||
[ 1 -eq "$enabled" ] && {
|
||||
config_get classgroup "$1" classgroup
|
||||
config_set "$1" ifbdev "$C"
|
||||
C=$(($C+1))
|
||||
append INTERFACES "$1"
|
||||
config_set "$classgroup" enabled 1
|
||||
config_get device "$1" device
|
||||
[ -z "$device" ] && {
|
||||
device="$(find_ifname $1)"
|
||||
[ -z "$device" ] && exit 1
|
||||
config_set "$1" device "$device"
|
||||
}
|
||||
}
|
||||
;;
|
||||
classgroup) append CG "$1";;
|
||||
classify|default|reclassify)
|
||||
case "$TYPE" in
|
||||
classify) var="ctrules";;
|
||||
*) var="rules";;
|
||||
esac
|
||||
append "$var" "$1"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
enum_classes() {
|
||||
local c="0"
|
||||
config_get classes "$1" classes
|
||||
config_get default "$1" default
|
||||
for class in $classes; do
|
||||
c="$(($c + 1))"
|
||||
config_set "${class}" classnr $c
|
||||
case "$class" in
|
||||
$default) class_default=$c;;
|
||||
esac
|
||||
done
|
||||
class_default="${class_default:-$c}"
|
||||
}
|
||||
|
||||
cls_var() {
|
||||
local varname="$1"
|
||||
local class="$2"
|
||||
local name="$3"
|
||||
local type="$4"
|
||||
local default="$5"
|
||||
local tmp tmp1 tmp2
|
||||
config_get tmp1 "$class" "$name"
|
||||
config_get tmp2 "${class}_${type}" "$name"
|
||||
tmp="${tmp2:-$tmp1}"
|
||||
tmp="${tmp:-$tmp2}"
|
||||
export ${varname}="${tmp:-$default}"
|
||||
}
|
||||
|
||||
tcrules() {
|
||||
_dir=/usr/lib/qos
|
||||
[ -e $_dir/tcrules.awk ] || _dir=.
|
||||
echo "$cstr" | awk \
|
||||
-v device="$dev" \
|
||||
-v linespeed="$rate" \
|
||||
-v direction="$dir" \
|
||||
-f $_dir/tcrules.awk
|
||||
}
|
||||
|
||||
start_interface() {
|
||||
local iface="$1"
|
||||
local num_ifb="$2"
|
||||
config_get device "$iface" device
|
||||
config_get_bool enabled "$iface" enabled 1
|
||||
[ -z "$device" -o 1 -ne "$enabled" ] && {
|
||||
return 1
|
||||
}
|
||||
config_get upload "$iface" upload
|
||||
config_get_bool halfduplex "$iface" halfduplex
|
||||
config_get download "$iface" download
|
||||
config_get classgroup "$iface" classgroup
|
||||
config_get_bool overhead "$iface" overhead 0
|
||||
|
||||
download="${download:-${halfduplex:+$upload}}"
|
||||
enum_classes "$classgroup"
|
||||
for dir in ${halfduplex:-up} ${download:+down}; do
|
||||
case "$dir" in
|
||||
up)
|
||||
[ "$overhead" = 1 ] && upload=$(($upload * 98 / 100 - (15 * 128 / $upload)))
|
||||
dev="$device"
|
||||
rate="$upload"
|
||||
dl_mode=""
|
||||
prefix="cls"
|
||||
;;
|
||||
down)
|
||||
[ "$(ls -d /proc/sys/net/ipv4/conf/ifb* 2>&- | wc -l)" -ne "$num_ifb" ] && add_insmod ifb numifbs="$num_ifb"
|
||||
config_get ifbdev "$iface" ifbdev
|
||||
[ "$overhead" = 1 ] && download=$(($download * 98 / 100 - (80 * 1024 / $download)))
|
||||
dev="ifb$ifbdev"
|
||||
rate="$download"
|
||||
dl_mode=1
|
||||
prefix="d_cls"
|
||||
;;
|
||||
*) continue;;
|
||||
esac
|
||||
cstr=
|
||||
for class in $classes; do
|
||||
cls_var pktsize "$class" packetsize $dir 1500
|
||||
cls_var pktdelay "$class" packetdelay $dir 0
|
||||
cls_var maxrate "$class" limitrate $dir 100
|
||||
cls_var prio "$class" priority $dir 1
|
||||
cls_var avgrate "$class" avgrate $dir 0
|
||||
cls_var qdisc "$class" qdisc $dir ""
|
||||
cls_var filter "$class" filter $dir ""
|
||||
config_get classnr "$class" classnr
|
||||
append cstr "$classnr:$prio:$avgrate:$pktsize:$pktdelay:$maxrate:$qdisc:$filter" "$N"
|
||||
done
|
||||
append ${prefix}q "$(tcrules)" "$N"
|
||||
export dev_${dir}="ip link add ${dev} type ifb >&- 2>&-
|
||||
ip link set $dev up >&- 2>&-
|
||||
tc qdisc del dev $dev root >&- 2>&-
|
||||
tc qdisc add dev $dev root handle 1: hfsc default ${class_default}0
|
||||
tc class add dev $dev parent 1: classid 1:1 hfsc sc rate ${rate}kbit ul rate ${rate}kbit"
|
||||
done
|
||||
[ -n "$download" ] && {
|
||||
add_insmod cls_u32
|
||||
add_insmod em_u32
|
||||
add_insmod act_connmark
|
||||
add_insmod act_mirred
|
||||
add_insmod sch_ingress
|
||||
}
|
||||
if [ -n "$halfduplex" ]; then
|
||||
export dev_up="tc qdisc del dev $device root >&- 2>&-
|
||||
tc qdisc add dev $device root handle 1: hfsc
|
||||
tc filter add dev $device parent 1: prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb$ifbdev"
|
||||
elif [ -n "$download" ]; then
|
||||
append dev_${dir} "tc qdisc del dev $device ingress >&- 2>&-
|
||||
tc qdisc add dev $device ingress
|
||||
tc filter add dev $device parent ffff: prio 1 u32 match u32 0 0 flowid 1:1 action connmark action mirred egress redirect dev ifb$ifbdev" "$N"
|
||||
fi
|
||||
add_insmod cls_fw
|
||||
add_insmod sch_hfsc
|
||||
|
||||
cat <<EOF
|
||||
${INSMOD:+$INSMOD$N}${dev_up:+$dev_up
|
||||
$clsq
|
||||
}${ifbdev:+$dev_down
|
||||
$d_clsq
|
||||
$d_clsl
|
||||
$d_clsf
|
||||
}
|
||||
EOF
|
||||
unset INSMOD clsq clsf clsl d_clsq d_clsl d_clsf dev_up dev_down
|
||||
}
|
||||
|
||||
start_interfaces() {
|
||||
local C="$1"
|
||||
for iface in $INTERFACES; do
|
||||
start_interface "$iface" "$C"
|
||||
done
|
||||
}
|
||||
|
||||
add_rules() {
|
||||
local var="$1"
|
||||
local rules="$2"
|
||||
local prefix="$3"
|
||||
|
||||
for rule in $rules; do
|
||||
unset iptrule
|
||||
config_get target "$rule" target
|
||||
config_get target "$target" classnr
|
||||
config_get options "$rule" options
|
||||
|
||||
## If we want to override the TOS field, let's clear the DSCP field first.
|
||||
[ ! -z "$(echo $options | grep 'TOS')" ] && {
|
||||
s_options=${options%%TOS}
|
||||
add_insmod xt_DSCP
|
||||
parse_matching_rule iptrule "$rule" "$s_options" "$prefix" "-j DSCP --set-dscp 0"
|
||||
append "$var" "$iptrule" "$N"
|
||||
unset iptrule
|
||||
}
|
||||
|
||||
target=$(($target | ($target << 4)))
|
||||
parse_matching_rule iptrule "$rule" "$options" "$prefix" "-j MARK --set-mark $target/0xff"
|
||||
append "$var" "$iptrule" "$N"
|
||||
done
|
||||
}
|
||||
|
||||
start_cg() {
|
||||
local cg="$1"
|
||||
local iptrules
|
||||
local pktrules
|
||||
local sizerules
|
||||
enum_classes "$cg"
|
||||
for command in $iptables; do
|
||||
add_rules iptrules "$ctrules" "$command -w -t mangle -A qos_${cg}_ct"
|
||||
done
|
||||
config_get classes "$cg" classes
|
||||
for class in $classes; do
|
||||
config_get mark "$class" classnr
|
||||
config_get maxsize "$class" maxsize
|
||||
[ -z "$maxsize" -o -z "$mark" ] || {
|
||||
add_insmod xt_length
|
||||
for command in $iptables; do
|
||||
append pktrules "$command -w -t mangle -A qos_${cg} -m mark --mark $mark/0x0f -m length --length $maxsize: -j MARK --set-mark 0/0xff" "$N"
|
||||
done
|
||||
}
|
||||
done
|
||||
for command in $iptables; do
|
||||
add_rules pktrules "$rules" "$command -w -t mangle -A qos_${cg}"
|
||||
done
|
||||
for iface in $INTERFACES; do
|
||||
config_get classgroup "$iface" classgroup
|
||||
config_get device "$iface" device
|
||||
config_get ifbdev "$iface" ifbdev
|
||||
config_get upload "$iface" upload
|
||||
config_get download "$iface" download
|
||||
config_get halfduplex "$iface" halfduplex
|
||||
download="${download:-${halfduplex:+$upload}}"
|
||||
for command in $iptables; do
|
||||
append up "$command -w -t mangle -A OUTPUT -o $device -j qos_${cg}" "$N"
|
||||
append up "$command -w -t mangle -A FORWARD -o $device -j qos_${cg}" "$N"
|
||||
done
|
||||
done
|
||||
cat <<EOF
|
||||
$INSMOD
|
||||
EOF
|
||||
|
||||
for command in $iptables; do
|
||||
cat <<EOF
|
||||
$command -w -t mangle -N qos_${cg}
|
||||
$command -w -t mangle -N qos_${cg}_ct
|
||||
EOF
|
||||
done
|
||||
cat <<EOF
|
||||
${iptrules:+${iptrules}${N}}
|
||||
EOF
|
||||
for command in $iptables; do
|
||||
cat <<EOF
|
||||
$command -w -t mangle -A qos_${cg}_ct -j CONNMARK --save-mark --mask 0xff
|
||||
$command -w -t mangle -A qos_${cg} -j CONNMARK --restore-mark --mask 0x0f
|
||||
$command -w -t mangle -A qos_${cg} -m mark --mark 0/0x0f -j qos_${cg}_ct
|
||||
EOF
|
||||
done
|
||||
cat <<EOF
|
||||
$pktrules
|
||||
EOF
|
||||
for command in $iptables; do
|
||||
cat <<EOF
|
||||
$command -w -t mangle -A qos_${cg} -j CONNMARK --save-mark --mask 0xff
|
||||
EOF
|
||||
done
|
||||
cat <<EOF
|
||||
$up$N${down:+${down}$N}
|
||||
EOF
|
||||
unset INSMOD
|
||||
}
|
||||
|
||||
start_firewall() {
|
||||
add_insmod xt_multiport
|
||||
add_insmod xt_connmark
|
||||
stop_firewall
|
||||
for group in $CG; do
|
||||
start_cg $group
|
||||
done
|
||||
}
|
||||
|
||||
stop_firewall() {
|
||||
# Builds up a list of iptables commands to flush the qos_* chains,
|
||||
# remove rules referring to them, then delete them
|
||||
|
||||
# Print rules in the mangle table, like iptables-save
|
||||
for command in $iptables; do
|
||||
$command -w -t mangle -S |
|
||||
# Find rules for the qos_* chains
|
||||
grep -E '(^-N qos_|-j qos_)' |
|
||||
# Exclude rules in qos_* chains (inter-qos_* refs)
|
||||
grep -v '^-A qos_' |
|
||||
# Replace -N with -X and hold, with -F and print
|
||||
# Replace -A with -D
|
||||
# Print held lines at the end (note leading newline)
|
||||
sed -e '/^-N/{s/^-N/-X/;H;s/^-X/-F/}' \
|
||||
-e 's/^-A/-D/' \
|
||||
-e '${p;g}' |
|
||||
# Make into proper iptables calls
|
||||
# Note: awkward in previous call due to hold space usage
|
||||
sed -n -e "s/^./${command} -w -t mangle &/p"
|
||||
done
|
||||
}
|
||||
|
||||
C="0"
|
||||
INTERFACES=""
|
||||
[ -e ./qos.conf ] && {
|
||||
. ./qos.conf
|
||||
config_cb
|
||||
} || {
|
||||
config_load qos
|
||||
config_foreach qos_parse_config
|
||||
}
|
||||
|
||||
C="0"
|
||||
for iface in $INTERFACES; do
|
||||
export C="$(($C + 1))"
|
||||
done
|
||||
|
||||
[ -x /usr/sbin/ip6tables ] && {
|
||||
iptables="ip6tables iptables"
|
||||
} || {
|
||||
iptables="iptables"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
all)
|
||||
start_interfaces "$C"
|
||||
start_firewall
|
||||
;;
|
||||
interface)
|
||||
start_interface "$2" "$C"
|
||||
;;
|
||||
interfaces)
|
||||
start_interfaces
|
||||
;;
|
||||
firewall)
|
||||
case "$2" in
|
||||
stop)
|
||||
stop_firewall
|
||||
;;
|
||||
start|"")
|
||||
start_firewall
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
105
package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
Normal file
105
package/network/config/qos-scripts/files/usr/lib/qos/tcrules.awk
Normal file
@@ -0,0 +1,105 @@
|
||||
BEGIN {
|
||||
dmax=100
|
||||
if (!(linespeed > 0)) linespeed = 128
|
||||
FS=":"
|
||||
n = 0
|
||||
}
|
||||
|
||||
($1 != "") {
|
||||
n++
|
||||
class[n] = $1
|
||||
prio[n] = $2
|
||||
avgrate[n] = ($3 * linespeed / 100)
|
||||
pktsize[n] = $4
|
||||
delay[n] = $5
|
||||
maxrate[n] = ($6 * linespeed / 100)
|
||||
qdisc[n] = $7
|
||||
filter[n] = $8
|
||||
}
|
||||
|
||||
END {
|
||||
allocated = 0
|
||||
maxdelay = 0
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
# set defaults
|
||||
if (!(pktsize[i] > 0)) pktsize[i] = 1500
|
||||
if (!(prio[i] > 0)) prio[i] = 1
|
||||
|
||||
allocated += avgrate[i]
|
||||
sum_prio += prio[i]
|
||||
if ((avgrate[i] > 0) && !(delay[i] > 0)) {
|
||||
sum_rtprio += prio[i]
|
||||
}
|
||||
}
|
||||
|
||||
# allocation of m1 in rt classes:
|
||||
# sum(d * m1) must not exceed dmax * (linespeed - allocated)
|
||||
dmax = 0
|
||||
for (i = 1; i <= n; i++) {
|
||||
if (avgrate[i] > 0) {
|
||||
rtm2[i] = avgrate[i]
|
||||
if (delay[i] > 0) {
|
||||
d[i] = delay[i]
|
||||
} else {
|
||||
d[i] = 2 * pktsize[i] * 1000 / (linespeed * 1024)
|
||||
if (d[i] > dmax) dmax = d[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ds_avail = dmax * (linespeed - allocated)
|
||||
for (i = 1; i <= n; i++) {
|
||||
lsm1[i] = 0
|
||||
rtm1[i] = 0
|
||||
lsm2[i] = linespeed * prio[i] / sum_prio
|
||||
if ((avgrate[i] > 0) && (d[i] > 0)) {
|
||||
if (!(delay[i] > 0)) {
|
||||
ds = ds_avail * prio[i] / sum_rtprio
|
||||
ds_avail -= ds
|
||||
rtm1[i] = rtm2[i] + ds/d[i]
|
||||
}
|
||||
lsm1[i] = rtm1[i]
|
||||
}
|
||||
else {
|
||||
d[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
# main qdisc
|
||||
for (i = 1; i <= n; i++) {
|
||||
printf "tc class add dev "device" parent 1:1 classid 1:"class[i]"0 hfsc"
|
||||
if (rtm1[i] > 0) {
|
||||
printf " rt m1 " int(rtm1[i]) "kbit d " int(d[i] * 1000) "us m2 " int(rtm2[i])"kbit"
|
||||
}
|
||||
printf " ls m1 " int(lsm1[i]) "kbit d " int(d[i] * 1000) "us m2 " int(lsm2[i]) "kbit"
|
||||
print " ul rate " int(maxrate[i]) "kbit"
|
||||
}
|
||||
|
||||
# leaf qdisc
|
||||
avpkt = 1200
|
||||
for (i = 1; i <= n; i++) {
|
||||
print "tc qdisc add dev "device" parent 1:"class[i]"0 handle "class[i]"00: fq_codel limit 800 quantum 300 noecn"
|
||||
}
|
||||
|
||||
# filter rule
|
||||
for (i = 1; i <= n; i++) {
|
||||
filter_cmd = "tc filter add dev "device" parent 1: prio %d handle %s fw flowid 1:%d0\n";
|
||||
if (direction == "up") {
|
||||
filter_1 = sprintf("0x%x0/0xf0", class[i])
|
||||
filter_2 = sprintf("0x0%x/0x0f", class[i])
|
||||
} else {
|
||||
filter_1 = sprintf("0x0%x/0x0f", class[i])
|
||||
filter_2 = sprintf("0x%x0/0xf0", class[i])
|
||||
}
|
||||
|
||||
printf filter_cmd, class[i] * 2, filter_1, class[i]
|
||||
printf filter_cmd, class[i] * 2 + 1, filter_2, class[i]
|
||||
|
||||
filterc=1
|
||||
if (filter[i] != "") {
|
||||
print " tc filter add dev "device" parent "class[i]"00: handle "filterc"0 "filter[i]
|
||||
filterc=filterc+1
|
||||
}
|
||||
}
|
||||
}
|
||||
76
package/network/config/qosify/Makefile
Normal file
76
package/network/config/qosify/Makefile
Normal file
@@ -0,0 +1,76 @@
|
||||
#
|
||||
# Copyright (C) 2021 OpenWrt.org
|
||||
#
|
||||
# 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:=qosify
|
||||
PKG_SOURCE_URL=$(PROJECT_GIT)/project/qosify.git
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2024-09-20
|
||||
PKG_SOURCE_VERSION:=1501e0935175d713ad229d88a8401dbfddc0a6b4
|
||||
PKG_MIRROR_HASH:=6d6e07285a6c46f040ba88555accc64c291837f9726944b9e41ec4efbaaf6c20
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
PKG_BUILD_DEPENDS:=bpf-headers
|
||||
PKG_FLAGS:=nonshared
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/cmake.mk
|
||||
include $(INCLUDE_DIR)/bpf.mk
|
||||
include $(INCLUDE_DIR)/nls.mk
|
||||
|
||||
define Package/qosify
|
||||
SECTION:=utils
|
||||
CATEGORY:=Base system
|
||||
TITLE:=A simple QoS solution based eBPF + CAKE
|
||||
DEPENDS:=+libbpf +libubox +libubus +libnl-tiny +kmod-sched-cake +kmod-sched-bpf +kmod-ifb +tc $(BPF_DEPENDS)
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS += \
|
||||
-Wno-error=deprecated-declarations \
|
||||
-I$(STAGING_DIR)/usr/include/libnl-tiny \
|
||||
-I$(STAGING_DIR)/usr/include
|
||||
|
||||
CMAKE_OPTIONS += \
|
||||
-DLIBNL_LIBS=-lnl-tiny
|
||||
|
||||
define Build/Compile
|
||||
$(call CompileBPF,$(PKG_BUILD_DIR)/qosify-bpf.c)
|
||||
$(Build/Compile/Default)
|
||||
endef
|
||||
|
||||
define Package/qosify/conffiles
|
||||
/etc/config/qosify
|
||||
/etc/qosify/00-defaults.conf
|
||||
endef
|
||||
|
||||
define Package/qosify/install
|
||||
$(INSTALL_DIR) \
|
||||
$(1)/lib/bpf \
|
||||
$(1)/usr/sbin \
|
||||
$(1)/etc/init.d \
|
||||
$(1)/etc/config \
|
||||
$(1)/etc/qosify \
|
||||
$(1)/etc/hotplug.d/net \
|
||||
$(1)/etc/hotplug.d/iface
|
||||
$(INSTALL_DATA) $(PKG_BUILD_DIR)/qosify-bpf.o $(1)/lib/bpf
|
||||
$(INSTALL_BIN) \
|
||||
$(PKG_INSTALL_DIR)/usr/bin/qosify \
|
||||
./files/qosify-status \
|
||||
$(1)/usr/sbin/
|
||||
$(INSTALL_BIN) ./files/qosify.init $(1)/etc/init.d/qosify
|
||||
$(INSTALL_DATA) ./files/qosify-defaults.conf $(1)/etc/qosify/00-defaults.conf
|
||||
$(INSTALL_DATA) ./files/qosify.conf $(1)/etc/config/qosify
|
||||
$(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/net/10-qosify
|
||||
$(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/iface/10-qosify
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,qosify))
|
||||
17
package/network/config/qosify/files/qosify-defaults.conf
Normal file
17
package/network/config/qosify/files/qosify-defaults.conf
Normal file
@@ -0,0 +1,17 @@
|
||||
# DNS
|
||||
tcp:53 voice
|
||||
tcp:5353 voice
|
||||
udp:53 voice
|
||||
udp:5353 voice
|
||||
|
||||
# NTP
|
||||
udp:123 voice
|
||||
|
||||
# SSH
|
||||
tcp:22 +video
|
||||
|
||||
# HTTP/QUIC
|
||||
tcp:80 +besteffort
|
||||
tcp:443 +besteffort
|
||||
udp:80 +besteffort
|
||||
udp:443 +besteffort
|
||||
70
package/network/config/qosify/files/qosify-status
Normal file
70
package/network/config/qosify/files/qosify-status
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/bin/sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
dev_status() {
|
||||
tc -s qdisc sh dev "$1" root
|
||||
echo
|
||||
}
|
||||
|
||||
common_status() {
|
||||
json_get_vars ifname ingress egress
|
||||
|
||||
[ -n "$ifname" ] || return
|
||||
|
||||
[ "$egress" -gt 0 ] && {
|
||||
echo "egress status:"
|
||||
dev_status "$ifname"
|
||||
}
|
||||
[ "$ingress" -gt 0 ] && {
|
||||
echo "ingress status:"
|
||||
dev_status "$(printf %.16s "ifb-$ifname")"
|
||||
}
|
||||
}
|
||||
|
||||
is_active() {
|
||||
json_get_vars active
|
||||
|
||||
[ "${active:-0}" -gt 0 ]
|
||||
}
|
||||
|
||||
device_status() {
|
||||
local name="$2"
|
||||
|
||||
json_select "$name"
|
||||
|
||||
if is_active; then
|
||||
status="active"
|
||||
else
|
||||
status="not found"
|
||||
fi
|
||||
|
||||
echo "===== device $name: $status ====="
|
||||
|
||||
is_active && common_status
|
||||
|
||||
json_select ..
|
||||
}
|
||||
|
||||
interface_status() {
|
||||
local name="$2"
|
||||
|
||||
json_select "$name"
|
||||
|
||||
if is_active; then
|
||||
status="active"
|
||||
elif ubus -S -t 0 wait_for "network.interface.$name"; then
|
||||
status="down"
|
||||
else
|
||||
status="not found"
|
||||
fi
|
||||
|
||||
echo "===== interface $name: $status ====="
|
||||
|
||||
is_active && common_status
|
||||
|
||||
json_select ..
|
||||
}
|
||||
|
||||
json_load "$(ubus call qosify status)"
|
||||
json_for_each_item device_status devices
|
||||
json_for_each_item interface_status interfaces
|
||||
48
package/network/config/qosify/files/qosify.conf
Normal file
48
package/network/config/qosify/files/qosify.conf
Normal file
@@ -0,0 +1,48 @@
|
||||
config defaults
|
||||
list defaults /etc/qosify/*.conf
|
||||
option dscp_prio video
|
||||
option dscp_icmp +besteffort
|
||||
option dscp_default_udp besteffort
|
||||
option prio_max_avg_pkt_len 500
|
||||
|
||||
config class besteffort
|
||||
option ingress CS0
|
||||
option egress CS0
|
||||
|
||||
config class bulk
|
||||
option ingress LE
|
||||
option egress LE
|
||||
|
||||
config class video
|
||||
option ingress AF41
|
||||
option egress AF41
|
||||
|
||||
config class voice
|
||||
option ingress CS6
|
||||
option egress CS6
|
||||
option bulk_trigger_pps 100
|
||||
option bulk_trigger_timeout 5
|
||||
option dscp_bulk CS0
|
||||
|
||||
config interface wan
|
||||
option name wan
|
||||
option disabled 1
|
||||
option bandwidth_up 100mbit
|
||||
option bandwidth_down 100mbit
|
||||
option overhead_type none
|
||||
# defaults:
|
||||
option ingress 1
|
||||
option egress 1
|
||||
option mode diffserv4
|
||||
option nat 1
|
||||
option host_isolate 1
|
||||
option autorate_ingress 0
|
||||
option ingress_options ""
|
||||
option egress_options ""
|
||||
option options ""
|
||||
|
||||
config device wandev
|
||||
option disabled 1
|
||||
option name wan
|
||||
option bandwidth 100mbit
|
||||
|
||||
2
package/network/config/qosify/files/qosify.hotplug
Normal file
2
package/network/config/qosify/files/qosify.hotplug
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
ubus call qosify check_devices
|
||||
171
package/network/config/qosify/files/qosify.init
Normal file
171
package/network/config/qosify/files/qosify.init
Normal file
@@ -0,0 +1,171 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (c) 2021 OpenWrt.org
|
||||
|
||||
START=19
|
||||
|
||||
USE_PROCD=1
|
||||
PROG=/usr/sbin/qosify
|
||||
|
||||
add_option() {
|
||||
local type="$1"
|
||||
local name="$2"
|
||||
|
||||
config_get val "$cfg" "$name"
|
||||
|
||||
[ -n "$val" ] && json_add_$type "$name" "$val"
|
||||
}
|
||||
|
||||
add_flow_config() {
|
||||
local cfg="$1"
|
||||
|
||||
add_option string dscp_prio
|
||||
add_option string dscp_bulk
|
||||
add_option int bulk_trigger_timeout
|
||||
add_option int bulk_trigger_pps
|
||||
add_option int prio_max_avg_pkt_len
|
||||
}
|
||||
|
||||
add_defaults() {
|
||||
cfg="$1"
|
||||
|
||||
json_add_boolean reset 1
|
||||
|
||||
config_get files "$cfg" defaults
|
||||
json_add_array files
|
||||
for i in $files; do
|
||||
json_add_string "" "$i"
|
||||
done
|
||||
json_close_array
|
||||
|
||||
add_flow_config "$cfg"
|
||||
add_option int timeout
|
||||
add_option string dscp_icmp
|
||||
add_option string dscp_default_udp
|
||||
add_option string dscp_default_tcp
|
||||
}
|
||||
|
||||
add_interface() {
|
||||
local cfg="$1"
|
||||
|
||||
config_get_bool disabled "$cfg" disabled 0
|
||||
[ "$disabled" -gt 0 ] && return
|
||||
|
||||
config_get name "$cfg" name
|
||||
json_add_object "$name"
|
||||
|
||||
config_get bw "$cfg" bandwidth
|
||||
|
||||
config_get bw_up "$cfg" bandwidth_up
|
||||
bw_up="${bw_up:-$bw}"
|
||||
[ -n "$bw_up" ] && json_add_string bandwidth_up "$bw_up"
|
||||
|
||||
config_get bw_down "$cfg" bandwidth_down
|
||||
bw_down="${bw_down:-$bw}"
|
||||
[ -n "$bw_down" ] && json_add_string bandwidth_down "$bw_down"
|
||||
|
||||
add_option string bandwidth
|
||||
add_option boolean ingress
|
||||
add_option boolean egress
|
||||
add_option string mode
|
||||
add_option boolean nat
|
||||
add_option boolean host_isolate
|
||||
add_option boolean autorate_ingress
|
||||
add_option string ingress_options
|
||||
add_option string egress_options
|
||||
|
||||
config_get user_options "$cfg" options
|
||||
|
||||
config_get otype "$cfg" overhead_type
|
||||
options=
|
||||
case "$otype" in
|
||||
none);;
|
||||
manual)
|
||||
config_get overhead "$cfg" overhead
|
||||
[ -n "$overhead" ] && append options "overhead $overhead"
|
||||
|
||||
config_get encap "$cfg" overhead_encap
|
||||
[ -n "$encap" ] && append options "$encap"
|
||||
;;
|
||||
conservative|\
|
||||
pppoa-vcmux|\
|
||||
pppoa-llc|\
|
||||
pppoe-vcmux|\
|
||||
pppoe-llcsnap|\
|
||||
bridged-vcmux|\
|
||||
bridged-llcsnap|\
|
||||
ipoa-vcmux|\
|
||||
ipoa-llcsnap|\
|
||||
pppoe-ptm|\
|
||||
bridged-ptm|\
|
||||
docsis|\
|
||||
ethernet)
|
||||
append options "$otype"
|
||||
;;
|
||||
esac
|
||||
|
||||
config_get mpu "$cfg" overhead_mpu
|
||||
[ -n "$mpu" ] && append options "mpu $mpu"
|
||||
|
||||
config_get ovlan "$cfg" overhead_vlan
|
||||
[ "${ovlan:-0}" -ge 2 ] && append options "ether-vlan"
|
||||
[ "${ovlan:-0}" -ge 1 ] && append options "ether-vlan"
|
||||
|
||||
[ -n "$user_options" ] && append options "$user_options"
|
||||
[ -n "$options" ] && json_add_string options "$options"
|
||||
|
||||
json_close_object
|
||||
}
|
||||
|
||||
add_class() {
|
||||
local cfg="$1"
|
||||
|
||||
config_get value "$cfg" value
|
||||
config_get ingress "$cfg" ingress
|
||||
config_get egress "$cfg" egress
|
||||
|
||||
json_add_object "$cfg"
|
||||
json_add_string ingress "${ingress:-$value}"
|
||||
json_add_string egress "${egress:-$value}"
|
||||
add_flow_config "$cfg"
|
||||
json_close_object
|
||||
}
|
||||
|
||||
|
||||
reload_service() {
|
||||
json_init
|
||||
|
||||
config_load qosify
|
||||
|
||||
config_foreach add_defaults defaults
|
||||
|
||||
json_add_object interfaces
|
||||
config_foreach add_interface interface
|
||||
json_close_object
|
||||
|
||||
json_add_object classes
|
||||
config_foreach add_class class
|
||||
config_foreach add_class alias
|
||||
json_close_object
|
||||
|
||||
json_add_object devices
|
||||
config_foreach add_interface device
|
||||
json_close_object
|
||||
|
||||
ubus call qosify config "$(json_dump)"
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger qosify
|
||||
}
|
||||
|
||||
start_service() {
|
||||
procd_open_instance
|
||||
procd_set_param command "$PROG"
|
||||
procd_set_param respawn
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_started() {
|
||||
ubus -t 10 wait_for qosify
|
||||
[ $? = 0 ] && reload_service
|
||||
}
|
||||
45
package/network/config/soloscli/Makefile
Normal file
45
package/network/config/soloscli/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# Copyright (C) 2006-2014 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=soloscli
|
||||
PKG_VERSION:=1.04
|
||||
PKG_RELEASE:=3
|
||||
|
||||
PKG_SOURCE:=solos-pci-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=@SF/openadsl
|
||||
PKG_HASH:=6379e6970a5c97fd5a223d024138ebb71b15d70e2ad1fe9da09edc5b2d760e1d
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/solos-pci-$(PKG_VERSION)
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/soloscli
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Configuration utility for Solos ADSL2+ modems
|
||||
DEPENDS:=+kmod-solos-pci
|
||||
URL:=http://sourceforge.net/projects/openadsl
|
||||
endef
|
||||
|
||||
define Package/soloscli/description
|
||||
This package contains the soloscli utility
|
||||
for interrogating Traverse Technologies' Solos ADSL2+ modems.
|
||||
endef
|
||||
|
||||
define Package/soloscli/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/soloscli/soloscli $(1)/usr/bin/
|
||||
$(INSTALL_BIN) ./files/solos-log-stats $(1)/usr/bin/
|
||||
$(INSTALL_DIR) $(1)/etc/hotplug.d/atm
|
||||
$(INSTALL_CONF) ./files/etc/hotplug.d/atm/15-solos-init $(1)/etc/hotplug.d/atm/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,soloscli))
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
dialog() {
|
||||
local tag="$(echo "$1" | cut -d= -f1)"
|
||||
local value="$(echo "$1" | cut -d= -f2-)"
|
||||
local response
|
||||
|
||||
response="$(soloscli -s "$port" "$tag" "$value")"
|
||||
[ $? -ne 0 ] && {
|
||||
logger "soloscli($port): $tag '$value' returns $response"
|
||||
}
|
||||
}
|
||||
|
||||
if [ "$ACTION" = "add" ]; then
|
||||
include /lib/network
|
||||
scan_interfaces
|
||||
|
||||
case $DEVICENAME in
|
||||
solos-pci[0-3])
|
||||
port="${DEVICENAME#solos-pci}"
|
||||
device="solos${port}"
|
||||
|
||||
config_list_foreach wan "$device" dialog
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
13
package/network/config/soloscli/files/etc/uci-defaults/solos
Normal file
13
package/network/config/soloscli/files/etc/uci-defaults/solos
Normal file
@@ -0,0 +1,13 @@
|
||||
uci batch <<__EOF__
|
||||
|
||||
delete network.wan.solos0
|
||||
|
||||
add_list network.wan.solos0="ActivateLine=Abort"
|
||||
add_list network.wan.solos0="Retrain=EnableAll"
|
||||
add_list network.wan.solos0="DetectNoise=Enable"
|
||||
add_list network.wan.solos0="BisMCapability=Disable"
|
||||
add_list network.wan.solos0="BisACapability=Disable"
|
||||
add_list network.wan.solos0="ActivateLine=Start"
|
||||
|
||||
commit network
|
||||
__EOF__
|
||||
19
package/network/config/soloscli/files/solos-log-stats
Normal file
19
package/network/config/soloscli/files/solos-log-stats
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd /sys/class/atm/ || exit 1
|
||||
|
||||
for PORT in solos-pci* ; do
|
||||
|
||||
RXRATE=`cat $PORT/parameters/RxBitRate`
|
||||
TXRATE=`cat $PORT/parameters/TxBitRate`
|
||||
RXSNR=`cat $PORT/parameters/LocalSNRMargin | sed "s/ dB//"`
|
||||
TXSNR=`cat $PORT/parameters/RemoteSNRMargin | sed "s/ dB//"`
|
||||
RXERR=`cat $PORT/parameters/RSUnCorrectedErrorsDn`
|
||||
TXERR=`cat $PORT/parameters/RSUnCorrectedErrorsUp`
|
||||
RXFEC=`cat $PORT/parameters/RSCorrectedErrorsDn`
|
||||
TXFEC=`cat $PORT/parameters/RSCorrectedErrorsUp`
|
||||
|
||||
echo "$RXRATE $RXSNR $RXERR $RXFEC / $TXRATE $TXSNR $TXERR $TXFEC" |
|
||||
logger -t $PORT
|
||||
done
|
||||
|
||||
11
package/network/config/soloscli/patches/001-no-driver.patch
Normal file
11
package/network/config/soloscli/patches/001-no-driver.patch
Normal file
@@ -0,0 +1,11 @@
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -11,7 +11,7 @@ else
|
||||
KDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
-all: soloscli driver
|
||||
+all: soloscli
|
||||
|
||||
soloscli: soloscli/soloscli
|
||||
|
||||
12
package/network/config/soloscli/patches/002-cflags.patch
Normal file
12
package/network/config/soloscli/patches/002-cflags.patch
Normal file
@@ -0,0 +1,12 @@
|
||||
--- a/soloscli/Makefile
|
||||
+++ b/soloscli/Makefile
|
||||
@@ -4,9 +4,6 @@
|
||||
# Last Mod: 2009-06-16
|
||||
#
|
||||
|
||||
-CC=gcc
|
||||
-CFLAGS=-Wall
|
||||
-
|
||||
soloscli: soloscli.c soloscli.h
|
||||
|
||||
clean:
|
||||
56
package/network/config/swconfig/Makefile
Normal file
56
package/network/config/swconfig/Makefile
Normal file
@@ -0,0 +1,56 @@
|
||||
#
|
||||
# Copyright (C) 2008-2010 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=swconfig
|
||||
PKG_RELEASE:=12
|
||||
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
PKG_BUILD_FLAGS:=lto
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
define Package/swconfig
|
||||
SECTION:=base
|
||||
CATEGORY:=Base system
|
||||
DEPENDS:=+libuci +libnl-tiny
|
||||
TITLE:=Switch configuration utility
|
||||
endef
|
||||
|
||||
TARGET_CPPFLAGS := \
|
||||
-D_GNU_SOURCE \
|
||||
-I$(STAGING_DIR)/usr/include/libnl-tiny \
|
||||
-I$(PKG_BUILD_DIR) \
|
||||
$(TARGET_CPPFLAGS) \
|
||||
-I$(LINUX_DIR)/user_headers/include
|
||||
|
||||
define Build/Compile
|
||||
CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
$(TARGET_CONFIGURE_OPTS) \
|
||||
LIBS="$(TARGET_LDFLAGS) -lnl-tiny -lm -luci -lubox"
|
||||
endef
|
||||
|
||||
define Build/InstallDev
|
||||
$(INSTALL_DIR) $(1)/usr/include
|
||||
$(CP) $(PKG_BUILD_DIR)/swlib.h $(1)/usr/include/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_BUILD_DIR)/libsw.a $(1)/usr/lib/
|
||||
endef
|
||||
|
||||
define Package/swconfig/install
|
||||
$(INSTALL_DIR) $(1)/sbin $(1)/lib/network
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/swconfig $(1)/sbin/swconfig
|
||||
$(INSTALL_DATA) ./files/switch.sh $(1)/lib/network/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,swconfig))
|
||||
15
package/network/config/swconfig/files/switch.sh
Normal file
15
package/network/config/swconfig/files/switch.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2009 OpenWrt.org
|
||||
|
||||
setup_switch_dev() {
|
||||
local name
|
||||
config_get name "$1" name
|
||||
name="${name:-$1}"
|
||||
[ -d "/sys/class/net/$name" ] && ip link set dev "$name" up
|
||||
swconfig dev "$name" load network
|
||||
}
|
||||
|
||||
setup_switch() {
|
||||
config_load network
|
||||
config_foreach setup_switch_dev switch
|
||||
}
|
||||
16
package/network/config/swconfig/src/Makefile
Normal file
16
package/network/config/swconfig/src/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -O2 -g -I ../src
|
||||
endif
|
||||
LIBS=-lnl -lnl-genl
|
||||
|
||||
all: swconfig
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -fPIC -c -o $@ $^
|
||||
|
||||
libsw.a: swlib.o
|
||||
$(AR) rcu $@ swlib.o
|
||||
$(RANLIB) $@
|
||||
|
||||
swconfig: libsw.a cli.o uci.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -L./ -lsw
|
||||
408
package/network/config/swconfig/src/cli.c
Normal file
408
package/network/config/swconfig/src/cli.c
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* swconfig.c: Switch configuration utility
|
||||
*
|
||||
* Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
|
||||
* Copyright (C) 2010 Martin Mares <mj@ucw.cz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundatio.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <uci.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <linux/switch.h>
|
||||
#include "swlib.h"
|
||||
|
||||
enum {
|
||||
CMD_NONE,
|
||||
CMD_GET,
|
||||
CMD_SET,
|
||||
CMD_LOAD,
|
||||
CMD_HELP,
|
||||
CMD_SHOW,
|
||||
CMD_PORTMAP,
|
||||
};
|
||||
|
||||
static void
|
||||
print_attrs(const struct switch_attr *attr)
|
||||
{
|
||||
int i = 0;
|
||||
while (attr) {
|
||||
const char *type;
|
||||
switch(attr->type) {
|
||||
case SWITCH_TYPE_INT:
|
||||
type = "int";
|
||||
break;
|
||||
case SWITCH_TYPE_STRING:
|
||||
type = "string";
|
||||
break;
|
||||
case SWITCH_TYPE_PORTS:
|
||||
type = "ports";
|
||||
break;
|
||||
case SWITCH_TYPE_NOVAL:
|
||||
type = "none";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
break;
|
||||
}
|
||||
printf("\tAttribute %d (%s): %s (%s)\n", ++i, type, attr->name, attr->description);
|
||||
attr = attr->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
list_attributes(struct switch_dev *dev)
|
||||
{
|
||||
printf("%s: %s(%s), ports: %d (cpu @ %d), vlans: %d\n", dev->dev_name, dev->alias, dev->name, dev->ports, dev->cpu_port, dev->vlans);
|
||||
printf(" --switch\n");
|
||||
print_attrs(dev->ops);
|
||||
printf(" --vlan\n");
|
||||
print_attrs(dev->vlan_ops);
|
||||
printf(" --port\n");
|
||||
print_attrs(dev->port_ops);
|
||||
}
|
||||
|
||||
static const char *
|
||||
speed_str(int speed)
|
||||
{
|
||||
switch (speed) {
|
||||
case 10:
|
||||
return "10baseT";
|
||||
case 100:
|
||||
return "100baseT";
|
||||
case 1000:
|
||||
return "1000baseT";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void
|
||||
free_attr_val(const struct switch_attr *attr, const struct switch_val *val)
|
||||
{
|
||||
switch (attr->type) {
|
||||
case SWITCH_TYPE_STRING:
|
||||
free(val->value.s);
|
||||
break;
|
||||
case SWITCH_TYPE_PORTS:
|
||||
free(val->value.ports);
|
||||
break;
|
||||
case SWITCH_TYPE_LINK:
|
||||
free(val->value.link);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_attr_val(const struct switch_attr *attr, const struct switch_val *val)
|
||||
{
|
||||
struct switch_port_link *link;
|
||||
int i;
|
||||
|
||||
switch (attr->type) {
|
||||
case SWITCH_TYPE_INT:
|
||||
printf("%d", val->value.i);
|
||||
break;
|
||||
case SWITCH_TYPE_STRING:
|
||||
printf("%s", val->value.s);
|
||||
break;
|
||||
case SWITCH_TYPE_PORTS:
|
||||
for(i = 0; i < val->len; i++) {
|
||||
printf("%d%s ",
|
||||
val->value.ports[i].id,
|
||||
(val->value.ports[i].flags &
|
||||
SWLIB_PORT_FLAG_TAGGED) ? "t" : "");
|
||||
}
|
||||
break;
|
||||
case SWITCH_TYPE_LINK:
|
||||
link = val->value.link;
|
||||
if (link->link)
|
||||
printf("port:%d link:up speed:%s %s-duplex %s%s%s%s%s",
|
||||
val->port_vlan,
|
||||
speed_str(link->speed),
|
||||
link->duplex ? "full" : "half",
|
||||
link->tx_flow ? "txflow " : "",
|
||||
link->rx_flow ? "rxflow " : "",
|
||||
link->eee & SWLIB_LINK_FLAG_EEE_100BASET ? "eee100 " : "",
|
||||
link->eee & SWLIB_LINK_FLAG_EEE_1000BASET ? "eee1000 " : "",
|
||||
link->aneg ? "auto" : "");
|
||||
else
|
||||
printf("port:%d link:down", val->port_vlan);
|
||||
break;
|
||||
default:
|
||||
printf("?unknown-type?");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_attrs(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
while (attr) {
|
||||
if (attr->type != SWITCH_TYPE_NOVAL) {
|
||||
printf("\t%s: ", attr->name);
|
||||
if (swlib_get_attr(dev, attr, val) < 0)
|
||||
printf("???");
|
||||
else {
|
||||
print_attr_val(attr, val);
|
||||
free_attr_val(attr, val);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
attr = attr->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_global(struct switch_dev *dev)
|
||||
{
|
||||
struct switch_val val;
|
||||
|
||||
printf("Global attributes:\n");
|
||||
show_attrs(dev, dev->ops, &val);
|
||||
}
|
||||
|
||||
static void
|
||||
show_port(struct switch_dev *dev, int port)
|
||||
{
|
||||
struct switch_val val;
|
||||
|
||||
printf("Port %d:\n", port);
|
||||
val.port_vlan = port;
|
||||
show_attrs(dev, dev->port_ops, &val);
|
||||
}
|
||||
|
||||
static void
|
||||
show_vlan(struct switch_dev *dev, int vlan, bool all)
|
||||
{
|
||||
struct switch_val val;
|
||||
struct switch_attr *attr;
|
||||
|
||||
val.port_vlan = vlan;
|
||||
|
||||
if (all) {
|
||||
attr = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_VLAN, "ports");
|
||||
if (swlib_get_attr(dev, attr, &val) < 0)
|
||||
return;
|
||||
|
||||
if (!val.len)
|
||||
return;
|
||||
}
|
||||
|
||||
printf("VLAN %d:\n", vlan);
|
||||
show_attrs(dev, dev->vlan_ops, &val);
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage(void)
|
||||
{
|
||||
printf("swconfig list\n");
|
||||
printf("swconfig dev <dev> [port <port>|vlan <vlan>] (help|set <key> <value>|get <key>|load <config>|show)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
swconfig_load_uci(struct switch_dev *dev, const char *name)
|
||||
{
|
||||
struct uci_context *ctx;
|
||||
struct uci_package *p = NULL;
|
||||
int ret = -1;
|
||||
|
||||
ctx = uci_alloc_context();
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
uci_load(ctx, name, &p);
|
||||
if (!p) {
|
||||
uci_perror(ctx, "Failed to load config file: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = swlib_apply_from_uci(dev, p);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "Failed to apply configuration for switch '%s'\n", dev->dev_name);
|
||||
|
||||
out:
|
||||
uci_free_context(ctx);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int retval = 0;
|
||||
struct switch_dev *dev;
|
||||
struct switch_attr *a;
|
||||
struct switch_val val;
|
||||
int i;
|
||||
|
||||
int cmd = CMD_NONE;
|
||||
char *cdev = NULL;
|
||||
int cport = -1;
|
||||
int cvlan = -1;
|
||||
char *ckey = NULL;
|
||||
char *cvalue = NULL;
|
||||
char *csegment = NULL;
|
||||
|
||||
if((argc == 2) && !strcmp(argv[1], "list")) {
|
||||
swlib_list();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(argc < 4)
|
||||
print_usage();
|
||||
|
||||
if(strcmp(argv[1], "dev"))
|
||||
print_usage();
|
||||
|
||||
cdev = argv[2];
|
||||
|
||||
for(i = 3; i < argc; i++)
|
||||
{
|
||||
char *arg = argv[i];
|
||||
if (cmd != CMD_NONE) {
|
||||
print_usage();
|
||||
} else if (!strcmp(arg, "port") && i+1 < argc) {
|
||||
cport = atoi(argv[++i]);
|
||||
} else if (!strcmp(arg, "vlan") && i+1 < argc) {
|
||||
cvlan = atoi(argv[++i]);
|
||||
} else if (!strcmp(arg, "help")) {
|
||||
cmd = CMD_HELP;
|
||||
} else if (!strcmp(arg, "set") && i+1 < argc) {
|
||||
cmd = CMD_SET;
|
||||
ckey = argv[++i];
|
||||
if (i+1 < argc)
|
||||
cvalue = argv[++i];
|
||||
} else if (!strcmp(arg, "get") && i+1 < argc) {
|
||||
cmd = CMD_GET;
|
||||
ckey = argv[++i];
|
||||
} else if (!strcmp(arg, "load") && i+1 < argc) {
|
||||
if ((cport >= 0) || (cvlan >= 0))
|
||||
print_usage();
|
||||
cmd = CMD_LOAD;
|
||||
ckey = argv[++i];
|
||||
} else if (!strcmp(arg, "portmap")) {
|
||||
if (i + 1 < argc)
|
||||
csegment = argv[++i];
|
||||
cmd = CMD_PORTMAP;
|
||||
} else if (!strcmp(arg, "show")) {
|
||||
cmd = CMD_SHOW;
|
||||
} else {
|
||||
print_usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == CMD_NONE)
|
||||
print_usage();
|
||||
if (cport > -1 && cvlan > -1)
|
||||
print_usage();
|
||||
|
||||
dev = swlib_connect(cdev);
|
||||
if (!dev) {
|
||||
fprintf(stderr, "Failed to connect to the switch. Use the \"list\" command to see which switches are available.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
swlib_scan(dev);
|
||||
|
||||
if (cmd == CMD_GET || cmd == CMD_SET) {
|
||||
if(cport > -1)
|
||||
a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_PORT, ckey);
|
||||
else if(cvlan > -1)
|
||||
a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_VLAN, ckey);
|
||||
else
|
||||
a = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, ckey);
|
||||
|
||||
if(!a)
|
||||
{
|
||||
fprintf(stderr, "Unknown attribute \"%s\"\n", ckey);
|
||||
retval = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case CMD_SET:
|
||||
if ((a->type != SWITCH_TYPE_NOVAL) &&
|
||||
(cvalue == NULL))
|
||||
print_usage();
|
||||
|
||||
if(cvlan > -1)
|
||||
cport = cvlan;
|
||||
|
||||
retval = swlib_set_attr_string(dev, a, cport, cvalue);
|
||||
if (retval < 0)
|
||||
{
|
||||
nl_perror(-retval, "Failed to set attribute");
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case CMD_GET:
|
||||
if(cvlan > -1)
|
||||
val.port_vlan = cvlan;
|
||||
if(cport > -1)
|
||||
val.port_vlan = cport;
|
||||
retval = swlib_get_attr(dev, a, &val);
|
||||
if (retval < 0)
|
||||
{
|
||||
nl_perror(-retval, "Failed to get attribute");
|
||||
goto out;
|
||||
}
|
||||
print_attr_val(a, &val);
|
||||
free_attr_val(a, &val);
|
||||
putchar('\n');
|
||||
break;
|
||||
case CMD_LOAD:
|
||||
swconfig_load_uci(dev, ckey);
|
||||
break;
|
||||
case CMD_HELP:
|
||||
list_attributes(dev);
|
||||
break;
|
||||
case CMD_PORTMAP:
|
||||
swlib_print_portmap(dev, csegment);
|
||||
break;
|
||||
case CMD_SHOW:
|
||||
if (cport >= 0 || cvlan >= 0) {
|
||||
if (cport >= 0)
|
||||
show_port(dev, cport);
|
||||
else
|
||||
show_vlan(dev, cvlan, false);
|
||||
} else {
|
||||
show_global(dev);
|
||||
for (i=0; i < dev->ports; i++)
|
||||
show_port(dev, i);
|
||||
for (i=0; i < dev->vlans; i++)
|
||||
show_vlan(dev, i, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
swlib_free_all(dev);
|
||||
return retval;
|
||||
}
|
||||
924
package/network/config/swconfig/src/swlib.c
Normal file
924
package/network/config/swconfig/src/swlib.c
Normal file
@@ -0,0 +1,924 @@
|
||||
/*
|
||||
* swlib.c: Switch configuration API (user space part)
|
||||
*
|
||||
* Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/switch.h>
|
||||
#include "swlib.h"
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/genl/family.h>
|
||||
|
||||
//#define DEBUG 1
|
||||
#ifdef DEBUG
|
||||
#define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
static struct nl_sock *handle;
|
||||
static struct nl_cache *cache;
|
||||
static struct genl_family *family;
|
||||
static struct nlattr *tb[SWITCH_ATTR_MAX + 1];
|
||||
static int refcount = 0;
|
||||
|
||||
static struct nla_policy port_policy[SWITCH_ATTR_MAX] = {
|
||||
[SWITCH_PORT_ID] = { .type = NLA_U32 },
|
||||
[SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static struct nla_policy portmap_policy[SWITCH_PORTMAP_MAX] = {
|
||||
[SWITCH_PORTMAP_SEGMENT] = { .type = NLA_STRING },
|
||||
[SWITCH_PORTMAP_VIRT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = {
|
||||
[SWITCH_LINK_FLAG_LINK] = { .type = NLA_FLAG },
|
||||
[SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG },
|
||||
[SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG },
|
||||
[SWITCH_LINK_SPEED] = { .type = NLA_U32 },
|
||||
[SWITCH_LINK_FLAG_EEE_100BASET] = { .type = NLA_FLAG },
|
||||
[SWITCH_LINK_FLAG_EEE_1000BASET] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static inline void *
|
||||
swlib_alloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = malloc(size);
|
||||
if (!ptr)
|
||||
goto done;
|
||||
memset(ptr, 0, size);
|
||||
|
||||
done:
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int
|
||||
wait_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
int *finished = arg;
|
||||
|
||||
*finished = 1;
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
/* helper function for performing netlink requests */
|
||||
static int
|
||||
swlib_call(int cmd, int (*call)(struct nl_msg *, void *),
|
||||
int (*data)(struct nl_msg *, void *), void *arg)
|
||||
{
|
||||
struct nl_msg *msg;
|
||||
struct nl_cb *cb = NULL;
|
||||
int finished;
|
||||
int flags = 0;
|
||||
int err = 0;
|
||||
|
||||
msg = nlmsg_alloc();
|
||||
if (!msg) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!data)
|
||||
flags |= NLM_F_DUMP;
|
||||
|
||||
genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family), 0, flags, cmd, 0);
|
||||
if (data) {
|
||||
err = data(msg, arg);
|
||||
if (err < 0)
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
cb = nl_cb_alloc(NL_CB_CUSTOM);
|
||||
if (!cb) {
|
||||
fprintf(stderr, "nl_cb_alloc failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
err = nl_send_auto_complete(handle, msg);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "nl_send_auto_complete failed: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
finished = 0;
|
||||
|
||||
if (call)
|
||||
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, call, arg);
|
||||
|
||||
if (data)
|
||||
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
|
||||
else
|
||||
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
|
||||
|
||||
err = nl_recvmsgs(handle, cb);
|
||||
if (err < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!finished)
|
||||
err = nl_wait_for_ack(handle);
|
||||
|
||||
out:
|
||||
if (cb)
|
||||
nl_cb_put(cb);
|
||||
nla_put_failure:
|
||||
nlmsg_free(msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
send_attr(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct switch_val *val = arg;
|
||||
struct switch_attr *attr = val->attr;
|
||||
|
||||
NLA_PUT_U32(msg, SWITCH_ATTR_ID, attr->dev->id);
|
||||
NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, attr->id);
|
||||
switch(attr->atype) {
|
||||
case SWLIB_ATTR_GROUP_PORT:
|
||||
NLA_PUT_U32(msg, SWITCH_ATTR_OP_PORT, val->port_vlan);
|
||||
break;
|
||||
case SWLIB_ATTR_GROUP_VLAN:
|
||||
NLA_PUT_U32(msg, SWITCH_ATTR_OP_VLAN, val->port_vlan);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
store_port_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
|
||||
{
|
||||
struct nlattr *p;
|
||||
int ports = val->attr->dev->ports;
|
||||
int err = 0;
|
||||
int remaining;
|
||||
|
||||
if (!val->value.ports)
|
||||
val->value.ports = malloc(sizeof(struct switch_port) * ports);
|
||||
|
||||
nla_for_each_nested(p, nla, remaining) {
|
||||
struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
|
||||
struct switch_port *port;
|
||||
|
||||
if (val->len >= ports)
|
||||
break;
|
||||
|
||||
err = nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, p, port_policy);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (!tb[SWITCH_PORT_ID])
|
||||
continue;
|
||||
|
||||
port = &val->value.ports[val->len];
|
||||
port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
|
||||
port->flags = 0;
|
||||
if (tb[SWITCH_PORT_FLAG_TAGGED])
|
||||
port->flags |= SWLIB_PORT_FLAG_TAGGED;
|
||||
|
||||
val->len++;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
store_link_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
|
||||
{
|
||||
struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1];
|
||||
struct switch_port_link *link;
|
||||
int err = 0;
|
||||
|
||||
if (!val->value.link)
|
||||
val->value.link = malloc(sizeof(struct switch_port_link));
|
||||
|
||||
err = nla_parse_nested(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
link = val->value.link;
|
||||
link->link = !!tb[SWITCH_LINK_FLAG_LINK];
|
||||
link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX];
|
||||
link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG];
|
||||
link->tx_flow = !!tb[SWITCH_LINK_FLAG_TX_FLOW];
|
||||
link->rx_flow = !!tb[SWITCH_LINK_FLAG_RX_FLOW];
|
||||
link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]);
|
||||
link->eee = 0;
|
||||
if (tb[SWITCH_LINK_FLAG_EEE_100BASET])
|
||||
link->eee |= SWLIB_LINK_FLAG_EEE_100BASET;
|
||||
if (tb[SWITCH_LINK_FLAG_EEE_1000BASET])
|
||||
link->eee |= SWLIB_LINK_FLAG_EEE_1000BASET;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
store_val(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||
struct switch_val *val = arg;
|
||||
|
||||
if (!val)
|
||||
goto error;
|
||||
|
||||
if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
|
||||
genlmsg_attrlen(gnlh, 0), NULL) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (tb[SWITCH_ATTR_OP_VALUE_INT])
|
||||
val->value.i = nla_get_u32(tb[SWITCH_ATTR_OP_VALUE_INT]);
|
||||
else if (tb[SWITCH_ATTR_OP_VALUE_STR])
|
||||
val->value.s = strdup(nla_get_string(tb[SWITCH_ATTR_OP_VALUE_STR]));
|
||||
else if (tb[SWITCH_ATTR_OP_VALUE_PORTS])
|
||||
val->err = store_port_val(msg, tb[SWITCH_ATTR_OP_VALUE_PORTS], val);
|
||||
else if (tb[SWITCH_ATTR_OP_VALUE_LINK])
|
||||
val->err = store_link_val(msg, tb[SWITCH_ATTR_OP_VALUE_LINK], val);
|
||||
|
||||
val->err = 0;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
int
|
||||
swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
int cmd;
|
||||
int err;
|
||||
|
||||
switch(attr->atype) {
|
||||
case SWLIB_ATTR_GROUP_GLOBAL:
|
||||
cmd = SWITCH_CMD_GET_GLOBAL;
|
||||
break;
|
||||
case SWLIB_ATTR_GROUP_PORT:
|
||||
cmd = SWITCH_CMD_GET_PORT;
|
||||
break;
|
||||
case SWLIB_ATTR_GROUP_VLAN:
|
||||
cmd = SWITCH_CMD_GET_VLAN;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&val->value, 0, sizeof(val->value));
|
||||
val->len = 0;
|
||||
val->attr = attr;
|
||||
val->err = -EINVAL;
|
||||
err = swlib_call(cmd, store_val, send_attr, val);
|
||||
if (!err)
|
||||
err = val->err;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
send_attr_ports(struct nl_msg *msg, struct switch_val *val)
|
||||
{
|
||||
struct nlattr *n;
|
||||
int i;
|
||||
|
||||
/* TODO implement multipart? */
|
||||
if (val->len == 0)
|
||||
goto done;
|
||||
n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_PORTS);
|
||||
if (!n)
|
||||
goto nla_put_failure;
|
||||
for (i = 0; i < val->len; i++) {
|
||||
struct switch_port *port = &val->value.ports[i];
|
||||
struct nlattr *np;
|
||||
|
||||
np = nla_nest_start(msg, SWITCH_ATTR_PORT);
|
||||
if (!np)
|
||||
goto nla_put_failure;
|
||||
|
||||
NLA_PUT_U32(msg, SWITCH_PORT_ID, port->id);
|
||||
if (port->flags & SWLIB_PORT_FLAG_TAGGED)
|
||||
NLA_PUT_FLAG(msg, SWITCH_PORT_FLAG_TAGGED);
|
||||
|
||||
nla_nest_end(msg, np);
|
||||
}
|
||||
nla_nest_end(msg, n);
|
||||
done:
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
send_attr_link(struct nl_msg *msg, struct switch_val *val)
|
||||
{
|
||||
struct switch_port_link *link = val->value.link;
|
||||
struct nlattr *n;
|
||||
|
||||
n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_LINK);
|
||||
if (!n)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (link->duplex)
|
||||
NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_DUPLEX);
|
||||
if (link->aneg)
|
||||
NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_ANEG);
|
||||
NLA_PUT_U32(msg, SWITCH_LINK_SPEED, link->speed);
|
||||
|
||||
nla_nest_end(msg, n);
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
send_attr_val(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct switch_val *val = arg;
|
||||
struct switch_attr *attr = val->attr;
|
||||
|
||||
if (send_attr(msg, arg))
|
||||
goto nla_put_failure;
|
||||
|
||||
switch(attr->type) {
|
||||
case SWITCH_TYPE_NOVAL:
|
||||
break;
|
||||
case SWITCH_TYPE_INT:
|
||||
NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val->value.i);
|
||||
break;
|
||||
case SWITCH_TYPE_STRING:
|
||||
if (!val->value.s)
|
||||
goto nla_put_failure;
|
||||
NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val->value.s);
|
||||
break;
|
||||
case SWITCH_TYPE_PORTS:
|
||||
if (send_attr_ports(msg, val) < 0)
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
case SWITCH_TYPE_LINK:
|
||||
if (send_attr_link(msg, val))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
default:
|
||||
goto nla_put_failure;
|
||||
}
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
int cmd;
|
||||
|
||||
switch(attr->atype) {
|
||||
case SWLIB_ATTR_GROUP_GLOBAL:
|
||||
cmd = SWITCH_CMD_SET_GLOBAL;
|
||||
break;
|
||||
case SWLIB_ATTR_GROUP_PORT:
|
||||
cmd = SWITCH_CMD_SET_PORT;
|
||||
break;
|
||||
case SWLIB_ATTR_GROUP_VLAN:
|
||||
cmd = SWITCH_CMD_SET_VLAN;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val->attr = attr;
|
||||
return swlib_call(cmd, NULL, send_attr_val, val);
|
||||
}
|
||||
|
||||
enum {
|
||||
CMD_NONE,
|
||||
CMD_DUPLEX,
|
||||
CMD_ANEG,
|
||||
CMD_SPEED,
|
||||
};
|
||||
|
||||
int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *a, int port_vlan, const char *str)
|
||||
{
|
||||
struct switch_port *ports;
|
||||
struct switch_port_link *link;
|
||||
struct switch_val val;
|
||||
char *ptr;
|
||||
int cmd = CMD_NONE;
|
||||
|
||||
memset(&val, 0, sizeof(val));
|
||||
val.port_vlan = port_vlan;
|
||||
switch(a->type) {
|
||||
case SWITCH_TYPE_INT:
|
||||
val.value.i = atoi(str);
|
||||
break;
|
||||
case SWITCH_TYPE_STRING:
|
||||
val.value.s = (char *)str;
|
||||
break;
|
||||
case SWITCH_TYPE_PORTS:
|
||||
ports = alloca(sizeof(struct switch_port) * dev->ports);
|
||||
memset(ports, 0, sizeof(struct switch_port) * dev->ports);
|
||||
val.len = 0;
|
||||
ptr = (char *)str;
|
||||
while(ptr && *ptr)
|
||||
{
|
||||
while(*ptr && isspace(*ptr))
|
||||
ptr++;
|
||||
|
||||
if (!*ptr)
|
||||
break;
|
||||
|
||||
if (!isdigit(*ptr))
|
||||
return -1;
|
||||
|
||||
if (val.len >= dev->ports)
|
||||
return -1;
|
||||
|
||||
ports[val.len].flags = 0;
|
||||
ports[val.len].id = strtoul(ptr, &ptr, 10);
|
||||
while(*ptr && !isspace(*ptr)) {
|
||||
if (*ptr == 't')
|
||||
ports[val.len].flags |= SWLIB_PORT_FLAG_TAGGED;
|
||||
else
|
||||
return -1;
|
||||
|
||||
ptr++;
|
||||
}
|
||||
if (*ptr)
|
||||
ptr++;
|
||||
val.len++;
|
||||
}
|
||||
val.value.ports = ports;
|
||||
break;
|
||||
case SWITCH_TYPE_LINK:
|
||||
link = malloc(sizeof(struct switch_port_link));
|
||||
memset(link, 0, sizeof(struct switch_port_link));
|
||||
ptr = (char *)str;
|
||||
for (ptr = strtok(ptr," "); ptr; ptr = strtok(NULL, " ")) {
|
||||
switch (cmd) {
|
||||
case CMD_NONE:
|
||||
if (!strcmp(ptr, "duplex"))
|
||||
cmd = CMD_DUPLEX;
|
||||
else if (!strcmp(ptr, "autoneg"))
|
||||
cmd = CMD_ANEG;
|
||||
else if (!strcmp(ptr, "speed"))
|
||||
cmd = CMD_SPEED;
|
||||
else
|
||||
fprintf(stderr, "Unsupported option %s\n", ptr);
|
||||
break;
|
||||
case CMD_DUPLEX:
|
||||
if (!strcmp(ptr, "half"))
|
||||
link->duplex = 0;
|
||||
else if (!strcmp(ptr, "full"))
|
||||
link->duplex = 1;
|
||||
else
|
||||
fprintf(stderr, "Unsupported value %s\n", ptr);
|
||||
cmd = CMD_NONE;
|
||||
break;
|
||||
case CMD_ANEG:
|
||||
if (!strcmp(ptr, "on"))
|
||||
link->aneg = 1;
|
||||
else if (!strcmp(ptr, "off"))
|
||||
link->aneg = 0;
|
||||
else
|
||||
fprintf(stderr, "Unsupported value %s\n", ptr);
|
||||
cmd = CMD_NONE;
|
||||
break;
|
||||
case CMD_SPEED:
|
||||
link->speed = atoi(ptr);
|
||||
cmd = CMD_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
val.value.link = link;
|
||||
break;
|
||||
case SWITCH_TYPE_NOVAL:
|
||||
if (str && !strcmp(str, "0"))
|
||||
return 0;
|
||||
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return swlib_set_attr(dev, a, &val);
|
||||
}
|
||||
|
||||
|
||||
struct attrlist_arg {
|
||||
int id;
|
||||
int atype;
|
||||
struct switch_dev *dev;
|
||||
struct switch_attr *prev;
|
||||
struct switch_attr **head;
|
||||
};
|
||||
|
||||
static int
|
||||
add_id(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct attrlist_arg *l = arg;
|
||||
|
||||
NLA_PUT_U32(msg, SWITCH_ATTR_ID, l->id);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
add_attr(struct nl_msg *msg, void *ptr)
|
||||
{
|
||||
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||
struct attrlist_arg *arg = ptr;
|
||||
struct switch_attr *new;
|
||||
|
||||
if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
|
||||
genlmsg_attrlen(gnlh, 0), NULL) < 0)
|
||||
goto done;
|
||||
|
||||
new = swlib_alloc(sizeof(struct switch_attr));
|
||||
if (!new)
|
||||
goto done;
|
||||
|
||||
new->dev = arg->dev;
|
||||
new->atype = arg->atype;
|
||||
if (arg->prev) {
|
||||
arg->prev->next = new;
|
||||
} else {
|
||||
arg->prev = *arg->head;
|
||||
}
|
||||
*arg->head = new;
|
||||
arg->head = &new->next;
|
||||
|
||||
if (tb[SWITCH_ATTR_OP_ID])
|
||||
new->id = nla_get_u32(tb[SWITCH_ATTR_OP_ID]);
|
||||
if (tb[SWITCH_ATTR_OP_TYPE])
|
||||
new->type = nla_get_u32(tb[SWITCH_ATTR_OP_TYPE]);
|
||||
if (tb[SWITCH_ATTR_OP_NAME])
|
||||
new->name = strdup(nla_get_string(tb[SWITCH_ATTR_OP_NAME]));
|
||||
if (tb[SWITCH_ATTR_OP_DESCRIPTION])
|
||||
new->description = strdup(nla_get_string(tb[SWITCH_ATTR_OP_DESCRIPTION]));
|
||||
|
||||
done:
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
int
|
||||
swlib_scan(struct switch_dev *dev)
|
||||
{
|
||||
struct attrlist_arg arg;
|
||||
|
||||
if (dev->ops || dev->port_ops || dev->vlan_ops)
|
||||
return 0;
|
||||
|
||||
arg.atype = SWLIB_ATTR_GROUP_GLOBAL;
|
||||
arg.dev = dev;
|
||||
arg.id = dev->id;
|
||||
arg.prev = NULL;
|
||||
arg.head = &dev->ops;
|
||||
swlib_call(SWITCH_CMD_LIST_GLOBAL, add_attr, add_id, &arg);
|
||||
|
||||
arg.atype = SWLIB_ATTR_GROUP_PORT;
|
||||
arg.prev = NULL;
|
||||
arg.head = &dev->port_ops;
|
||||
swlib_call(SWITCH_CMD_LIST_PORT, add_attr, add_id, &arg);
|
||||
|
||||
arg.atype = SWLIB_ATTR_GROUP_VLAN;
|
||||
arg.prev = NULL;
|
||||
arg.head = &dev->vlan_ops;
|
||||
swlib_call(SWITCH_CMD_LIST_VLAN, add_attr, add_id, &arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct switch_attr *swlib_lookup_attr(struct switch_dev *dev,
|
||||
enum swlib_attr_group atype, const char *name)
|
||||
{
|
||||
struct switch_attr *head;
|
||||
|
||||
if (!name || !dev)
|
||||
return NULL;
|
||||
|
||||
switch(atype) {
|
||||
case SWLIB_ATTR_GROUP_GLOBAL:
|
||||
head = dev->ops;
|
||||
break;
|
||||
case SWLIB_ATTR_GROUP_PORT:
|
||||
head = dev->port_ops;
|
||||
break;
|
||||
case SWLIB_ATTR_GROUP_VLAN:
|
||||
head = dev->vlan_ops;
|
||||
break;
|
||||
}
|
||||
while(head) {
|
||||
if (!strcmp(name, head->name))
|
||||
return head;
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
swlib_priv_free(void)
|
||||
{
|
||||
if (family)
|
||||
nl_object_put((struct nl_object*)family);
|
||||
if (cache)
|
||||
nl_cache_free(cache);
|
||||
if (handle)
|
||||
nl_socket_free(handle);
|
||||
family = NULL;
|
||||
handle = NULL;
|
||||
cache = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
swlib_priv_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
handle = nl_socket_alloc();
|
||||
if (!handle) {
|
||||
DPRINTF("Failed to create handle\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (genl_connect(handle)) {
|
||||
DPRINTF("Failed to connect to generic netlink\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = genl_ctrl_alloc_cache(handle, &cache);
|
||||
if (ret < 0) {
|
||||
DPRINTF("Failed to allocate netlink cache\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
family = genl_ctrl_search_by_name(cache, "switch");
|
||||
if (!family) {
|
||||
DPRINTF("Switch API not present\n");
|
||||
goto err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
swlib_priv_free();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct swlib_scan_arg {
|
||||
const char *name;
|
||||
struct switch_dev *head;
|
||||
struct switch_dev *ptr;
|
||||
};
|
||||
|
||||
static int
|
||||
add_port_map(struct switch_dev *dev, struct nlattr *nla)
|
||||
{
|
||||
struct nlattr *p;
|
||||
int err = 0, idx = 0;
|
||||
int remaining;
|
||||
|
||||
dev->maps = malloc(sizeof(struct switch_portmap) * dev->ports);
|
||||
if (!dev->maps)
|
||||
return -1;
|
||||
memset(dev->maps, 0, sizeof(struct switch_portmap) * dev->ports);
|
||||
|
||||
nla_for_each_nested(p, nla, remaining) {
|
||||
struct nlattr *tb[SWITCH_PORTMAP_MAX+1];
|
||||
|
||||
if (idx >= dev->ports)
|
||||
continue;
|
||||
|
||||
err = nla_parse_nested(tb, SWITCH_PORTMAP_MAX, p, portmap_policy);
|
||||
if (err < 0)
|
||||
continue;
|
||||
|
||||
|
||||
if (tb[SWITCH_PORTMAP_SEGMENT] && tb[SWITCH_PORTMAP_VIRT]) {
|
||||
dev->maps[idx].segment = strdup(nla_get_string(tb[SWITCH_PORTMAP_SEGMENT]));
|
||||
dev->maps[idx].virt = nla_get_u32(tb[SWITCH_PORTMAP_VIRT]);
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
add_switch(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct swlib_scan_arg *sa = arg;
|
||||
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||
struct switch_dev *dev;
|
||||
const char *name;
|
||||
const char *alias;
|
||||
|
||||
if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
|
||||
goto done;
|
||||
|
||||
if (!tb[SWITCH_ATTR_DEV_NAME])
|
||||
goto done;
|
||||
|
||||
name = nla_get_string(tb[SWITCH_ATTR_DEV_NAME]);
|
||||
alias = nla_get_string(tb[SWITCH_ATTR_ALIAS]);
|
||||
|
||||
if (sa->name && (strcmp(name, sa->name) != 0) && (strcmp(alias, sa->name) != 0))
|
||||
goto done;
|
||||
|
||||
dev = swlib_alloc(sizeof(struct switch_dev));
|
||||
if (!dev)
|
||||
goto done;
|
||||
|
||||
strncpy(dev->dev_name, name, IFNAMSIZ - 1);
|
||||
dev->alias = strdup(alias);
|
||||
if (tb[SWITCH_ATTR_ID])
|
||||
dev->id = nla_get_u32(tb[SWITCH_ATTR_ID]);
|
||||
if (tb[SWITCH_ATTR_NAME])
|
||||
dev->name = strdup(nla_get_string(tb[SWITCH_ATTR_NAME]));
|
||||
if (tb[SWITCH_ATTR_PORTS])
|
||||
dev->ports = nla_get_u32(tb[SWITCH_ATTR_PORTS]);
|
||||
if (tb[SWITCH_ATTR_VLANS])
|
||||
dev->vlans = nla_get_u32(tb[SWITCH_ATTR_VLANS]);
|
||||
if (tb[SWITCH_ATTR_CPU_PORT])
|
||||
dev->cpu_port = nla_get_u32(tb[SWITCH_ATTR_CPU_PORT]);
|
||||
if (tb[SWITCH_ATTR_PORTMAP])
|
||||
add_port_map(dev, tb[SWITCH_ATTR_PORTMAP]);
|
||||
|
||||
if (!sa->head) {
|
||||
sa->head = dev;
|
||||
sa->ptr = dev;
|
||||
} else {
|
||||
sa->ptr->next = dev;
|
||||
sa->ptr = dev;
|
||||
}
|
||||
|
||||
refcount++;
|
||||
done:
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
static int
|
||||
list_switch(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||
|
||||
if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
|
||||
goto done;
|
||||
|
||||
if (!tb[SWITCH_ATTR_DEV_NAME] || !tb[SWITCH_ATTR_NAME])
|
||||
goto done;
|
||||
|
||||
printf("Found: %s - %s\n", nla_get_string(tb[SWITCH_ATTR_DEV_NAME]),
|
||||
nla_get_string(tb[SWITCH_ATTR_ALIAS]));
|
||||
|
||||
done:
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
void
|
||||
swlib_list(void)
|
||||
{
|
||||
if (swlib_priv_init() < 0)
|
||||
return;
|
||||
swlib_call(SWITCH_CMD_GET_SWITCH, list_switch, NULL, NULL);
|
||||
swlib_priv_free();
|
||||
}
|
||||
|
||||
void
|
||||
swlib_print_portmap(struct switch_dev *dev, char *segment)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (segment) {
|
||||
if (!strcmp(segment, "cpu")) {
|
||||
printf("%d ", dev->cpu_port);
|
||||
} else if (!strcmp(segment, "disabled")) {
|
||||
for (i = 0; i < dev->ports; i++)
|
||||
if (!dev->maps[i].segment)
|
||||
printf("%d ", i);
|
||||
} else for (i = 0; i < dev->ports; i++) {
|
||||
if (dev->maps[i].segment && !strcmp(dev->maps[i].segment, segment))
|
||||
printf("%d ", i);
|
||||
}
|
||||
} else {
|
||||
printf("%s - %s\n", dev->dev_name, dev->name);
|
||||
for (i = 0; i < dev->ports; i++)
|
||||
if (i == dev->cpu_port)
|
||||
printf("port%d:\tcpu\n", i);
|
||||
else if (dev->maps[i].segment)
|
||||
printf("port%d:\t%s.%d\n", i, dev->maps[i].segment, dev->maps[i].virt);
|
||||
else
|
||||
printf("port%d:\tdisabled\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
struct switch_dev *
|
||||
swlib_connect(const char *name)
|
||||
{
|
||||
struct swlib_scan_arg arg;
|
||||
|
||||
if (!refcount) {
|
||||
if (swlib_priv_init() < 0)
|
||||
return NULL;
|
||||
};
|
||||
|
||||
arg.head = NULL;
|
||||
arg.ptr = NULL;
|
||||
arg.name = name;
|
||||
swlib_call(SWITCH_CMD_GET_SWITCH, add_switch, NULL, &arg);
|
||||
|
||||
if (!refcount)
|
||||
swlib_priv_free();
|
||||
|
||||
return arg.head;
|
||||
}
|
||||
|
||||
static void
|
||||
swlib_free_attributes(struct switch_attr **head)
|
||||
{
|
||||
struct switch_attr *a = *head;
|
||||
struct switch_attr *next;
|
||||
|
||||
while (a) {
|
||||
next = a->next;
|
||||
free(a->name);
|
||||
free(a->description);
|
||||
free(a);
|
||||
a = next;
|
||||
}
|
||||
*head = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
swlib_free_port_map(struct switch_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!dev || !dev->maps)
|
||||
return;
|
||||
|
||||
for (i = 0; i < dev->ports; i++)
|
||||
free(dev->maps[i].segment);
|
||||
free(dev->maps);
|
||||
}
|
||||
|
||||
void
|
||||
swlib_free(struct switch_dev *dev)
|
||||
{
|
||||
swlib_free_attributes(&dev->ops);
|
||||
swlib_free_attributes(&dev->port_ops);
|
||||
swlib_free_attributes(&dev->vlan_ops);
|
||||
swlib_free_port_map(dev);
|
||||
free(dev->name);
|
||||
free(dev->alias);
|
||||
free(dev);
|
||||
|
||||
if (--refcount == 0)
|
||||
swlib_priv_free();
|
||||
}
|
||||
|
||||
void
|
||||
swlib_free_all(struct switch_dev *dev)
|
||||
{
|
||||
struct switch_dev *p;
|
||||
|
||||
while (dev) {
|
||||
p = dev->next;
|
||||
swlib_free(dev);
|
||||
dev = p;
|
||||
}
|
||||
}
|
||||
269
package/network/config/swconfig/src/swlib.h
Normal file
269
package/network/config/swconfig/src/swlib.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* swlib.h: Switch configuration API (user space part)
|
||||
*
|
||||
* Copyright (C) 2008-2009 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
|
||||
Usage of the library functions:
|
||||
|
||||
The main datastructure for a switch is the struct switch_device
|
||||
To get started, you first need to use switch_connect() to probe
|
||||
for switches and allocate an instance of this struct.
|
||||
|
||||
There are two possible usage modes:
|
||||
dev = switch_connect("eth0");
|
||||
- this call will look for a switch registered for the linux device
|
||||
"eth0" and only allocate a switch_device for this particular switch.
|
||||
|
||||
dev = switch_connect(NULL)
|
||||
- this will return one switch_device struct for each available
|
||||
switch. The switch_device structs are chained with by ->next pointer
|
||||
|
||||
Then to query a switch for all available attributes, use:
|
||||
swlib_scan(dev);
|
||||
|
||||
All allocated datastructures for the switch_device struct can be freed with
|
||||
swlib_free(dev);
|
||||
or
|
||||
swlib_free_all(dev);
|
||||
|
||||
The latter traverses a whole chain of switch_device structs and frees them all
|
||||
|
||||
Switch attributes (struct switch_attr) are divided into three groups:
|
||||
dev->ops:
|
||||
- global settings
|
||||
dev->port_ops:
|
||||
- per-port settings
|
||||
dev->vlan_ops:
|
||||
- per-vlan settings
|
||||
|
||||
switch_lookup_attr() is a small helper function to locate attributes
|
||||
by name.
|
||||
|
||||
switch_set_attr() and switch_get_attr() can alter or request the values
|
||||
of attributes.
|
||||
|
||||
Usage of the switch_attr struct:
|
||||
|
||||
->atype: attribute group, one of:
|
||||
- SWLIB_ATTR_GROUP_GLOBAL
|
||||
- SWLIB_ATTR_GROUP_VLAN
|
||||
- SWLIB_ATTR_GROUP_PORT
|
||||
|
||||
->id: identifier for the attribute
|
||||
|
||||
->type: data type, one of:
|
||||
- SWITCH_TYPE_INT
|
||||
- SWITCH_TYPE_STRING
|
||||
- SWITCH_TYPE_PORT
|
||||
|
||||
->name: short name of the attribute
|
||||
->description: longer description
|
||||
->next: pointer to the next attribute of the current group
|
||||
|
||||
|
||||
Usage of the switch_val struct:
|
||||
|
||||
When setting attributes, following members of the struct switch_val need
|
||||
to be set up:
|
||||
|
||||
->len (for attr->type == SWITCH_TYPE_PORT)
|
||||
->port_vlan:
|
||||
- port number (for attr->atype == SWLIB_ATTR_GROUP_PORT), or:
|
||||
- vlan number (for attr->atype == SWLIB_ATTR_GROUP_VLAN)
|
||||
->value.i (for attr->type == SWITCH_TYPE_INT)
|
||||
->value.s (for attr->type == SWITCH_TYPE_STRING)
|
||||
- owned by the caller, not stored in the library internally
|
||||
->value.ports (for attr->type == SWITCH_TYPE_PORT)
|
||||
- must point to an array of at lest val->len * sizeof(struct switch_port)
|
||||
|
||||
When getting string attributes, val->value.s must be freed by the caller
|
||||
When getting port list attributes, an internal static buffer is used,
|
||||
which changes from call to call.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __SWLIB_H
|
||||
#define __SWLIB_H
|
||||
|
||||
enum swlib_attr_group {
|
||||
SWLIB_ATTR_GROUP_GLOBAL,
|
||||
SWLIB_ATTR_GROUP_VLAN,
|
||||
SWLIB_ATTR_GROUP_PORT,
|
||||
};
|
||||
|
||||
enum swlib_port_flags {
|
||||
SWLIB_PORT_FLAG_TAGGED = (1 << 0),
|
||||
};
|
||||
|
||||
enum swlib_link_flags {
|
||||
SWLIB_LINK_FLAG_EEE_100BASET = (1 << 0),
|
||||
SWLIB_LINK_FLAG_EEE_1000BASET = (1 << 1),
|
||||
};
|
||||
|
||||
struct switch_dev;
|
||||
struct switch_attr;
|
||||
struct switch_port;
|
||||
struct switch_port_map;
|
||||
struct switch_port_link;
|
||||
struct switch_val;
|
||||
struct uci_package;
|
||||
|
||||
struct switch_dev {
|
||||
int id;
|
||||
char dev_name[IFNAMSIZ];
|
||||
char *name;
|
||||
char *alias;
|
||||
int ports;
|
||||
int vlans;
|
||||
int cpu_port;
|
||||
struct switch_attr *ops;
|
||||
struct switch_attr *port_ops;
|
||||
struct switch_attr *vlan_ops;
|
||||
struct switch_portmap *maps;
|
||||
struct switch_dev *next;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct switch_val {
|
||||
struct switch_attr *attr;
|
||||
int len;
|
||||
int err;
|
||||
int port_vlan;
|
||||
union {
|
||||
char *s;
|
||||
int i;
|
||||
struct switch_port *ports;
|
||||
struct switch_port_link *link;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct switch_attr {
|
||||
struct switch_dev *dev;
|
||||
int atype;
|
||||
int id;
|
||||
int type;
|
||||
char *name;
|
||||
char *description;
|
||||
struct switch_attr *next;
|
||||
};
|
||||
|
||||
struct switch_port {
|
||||
unsigned int id;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct switch_portmap {
|
||||
unsigned int virt;
|
||||
char *segment;
|
||||
};
|
||||
|
||||
struct switch_port_link {
|
||||
int link:1;
|
||||
int duplex:1;
|
||||
int aneg:1;
|
||||
int tx_flow:1;
|
||||
int rx_flow:1;
|
||||
int speed;
|
||||
/* in ethtool adv_t format */
|
||||
uint32_t eee;
|
||||
};
|
||||
|
||||
/**
|
||||
* swlib_list: list all switches
|
||||
*/
|
||||
void swlib_list(void);
|
||||
|
||||
/**
|
||||
* swlib_print_portmap: get portmap
|
||||
* @dev: switch device struct
|
||||
*/
|
||||
void swlib_print_portmap(struct switch_dev *dev, char *segment);
|
||||
|
||||
/**
|
||||
* swlib_connect: connect to the switch through netlink
|
||||
* @name: name of the ethernet interface,
|
||||
*
|
||||
* if name is NULL, it connect and builds a chain of all switches
|
||||
*/
|
||||
struct switch_dev *swlib_connect(const char *name);
|
||||
|
||||
/**
|
||||
* swlib_free: free all dynamically allocated data for the switch connection
|
||||
* @dev: switch device struct
|
||||
*
|
||||
* all members of a switch device chain (generated by swlib_connect(NULL))
|
||||
* must be freed individually
|
||||
*/
|
||||
void swlib_free(struct switch_dev *dev);
|
||||
|
||||
/**
|
||||
* swlib_free_all: run swlib_free on all devices in the chain
|
||||
* @dev: switch device struct
|
||||
*/
|
||||
void swlib_free_all(struct switch_dev *dev);
|
||||
|
||||
/**
|
||||
* swlib_scan: probe the switch driver for available commands/attributes
|
||||
* @dev: switch device struct
|
||||
*/
|
||||
int swlib_scan(struct switch_dev *dev);
|
||||
|
||||
/**
|
||||
* swlib_lookup_attr: look up a switch attribute
|
||||
* @dev: switch device struct
|
||||
* @type: global, port or vlan
|
||||
* @name: name of the attribute
|
||||
*/
|
||||
struct switch_attr *swlib_lookup_attr(struct switch_dev *dev,
|
||||
enum swlib_attr_group atype, const char *name);
|
||||
|
||||
/**
|
||||
* swlib_set_attr: set the value for an attribute
|
||||
* @dev: switch device struct
|
||||
* @attr: switch attribute struct
|
||||
* @val: attribute value pointer
|
||||
* returns 0 on success
|
||||
*/
|
||||
int swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
|
||||
/**
|
||||
* swlib_set_attr_string: set the value for an attribute with type conversion
|
||||
* @dev: switch device struct
|
||||
* @attr: switch attribute struct
|
||||
* @port_vlan: port or vlan (if applicable)
|
||||
* @str: string value
|
||||
* returns 0 on success
|
||||
*/
|
||||
int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *attr,
|
||||
int port_vlan, const char *str);
|
||||
|
||||
/**
|
||||
* swlib_get_attr: get the value for an attribute
|
||||
* @dev: switch device struct
|
||||
* @attr: switch attribute struct
|
||||
* @val: attribute value pointer
|
||||
* returns 0 on success
|
||||
* for string attributes, the result string must be freed by the caller
|
||||
*/
|
||||
int swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr,
|
||||
struct switch_val *val);
|
||||
|
||||
/**
|
||||
* swlib_apply_from_uci: set up the switch from a uci configuration
|
||||
* @dev: switch device struct
|
||||
* @p: uci package which contains the desired global config
|
||||
*/
|
||||
int swlib_apply_from_uci(struct switch_dev *dev, struct uci_package *p);
|
||||
|
||||
#endif
|
||||
253
package/network/config/swconfig/src/uci.c
Normal file
253
package/network/config/swconfig/src/uci.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* uci.c: UCI binding for the switch configuration utility
|
||||
*
|
||||
* Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundatio.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <uci.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <linux/switch.h>
|
||||
#include "swlib.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
|
||||
struct swlib_setting {
|
||||
struct switch_attr *attr;
|
||||
const char *name;
|
||||
int port_vlan;
|
||||
const char *val;
|
||||
struct swlib_setting *next;
|
||||
};
|
||||
|
||||
struct swlib_setting early_settings[] = {
|
||||
{ .name = "reset", .val = "1" },
|
||||
{ .name = "enable_vlan", .val = "1" },
|
||||
};
|
||||
|
||||
static struct swlib_setting *settings;
|
||||
static struct swlib_setting **head;
|
||||
|
||||
static bool swlib_match_name(struct switch_dev *dev, const char *name)
|
||||
{
|
||||
return (strcmp(name, dev->dev_name) == 0 ||
|
||||
strcmp(name, dev->alias) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
swlib_map_settings(struct switch_dev *dev, int type, int port_vlan, struct uci_section *s)
|
||||
{
|
||||
struct swlib_setting *setting;
|
||||
struct switch_attr *attr;
|
||||
struct uci_element *e;
|
||||
struct uci_option *o;
|
||||
|
||||
uci_foreach_element(&s->options, e) {
|
||||
o = uci_to_option(e);
|
||||
|
||||
if (o->type != UCI_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
if (!strcmp(e->name, "device"))
|
||||
continue;
|
||||
|
||||
/* map early settings */
|
||||
if (type == SWLIB_ATTR_GROUP_GLOBAL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(early_settings); i++) {
|
||||
if (strcmp(e->name, early_settings[i].name) != 0)
|
||||
continue;
|
||||
|
||||
early_settings[i].val = o->v.string;
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
|
||||
attr = swlib_lookup_attr(dev, type, e->name);
|
||||
if (!attr)
|
||||
continue;
|
||||
|
||||
setting = malloc(sizeof(struct swlib_setting));
|
||||
memset(setting, 0, sizeof(struct swlib_setting));
|
||||
setting->attr = attr;
|
||||
setting->port_vlan = port_vlan;
|
||||
setting->val = o->v.string;
|
||||
*head = setting;
|
||||
head = &setting->next;
|
||||
skip:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int swlib_apply_from_uci(struct switch_dev *dev, struct uci_package *p)
|
||||
{
|
||||
struct switch_attr *attr;
|
||||
struct uci_element *e;
|
||||
struct uci_section *s;
|
||||
struct uci_option *o;
|
||||
struct uci_ptr ptr;
|
||||
struct switch_val val;
|
||||
int i;
|
||||
|
||||
settings = NULL;
|
||||
head = &settings;
|
||||
|
||||
uci_foreach_element(&p->sections, e) {
|
||||
struct uci_element *n;
|
||||
|
||||
s = uci_to_section(e);
|
||||
|
||||
if (strcmp(s->type, "switch") != 0)
|
||||
continue;
|
||||
|
||||
uci_foreach_element(&s->options, n) {
|
||||
struct uci_option *o = uci_to_option(n);
|
||||
|
||||
if (strcmp(n->name, "name") != 0)
|
||||
continue;
|
||||
|
||||
if (o->type != UCI_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
if (swlib_match_name(dev, o->v.string))
|
||||
goto found;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!swlib_match_name(dev, e->name))
|
||||
continue;
|
||||
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
return -1;
|
||||
|
||||
found:
|
||||
/* look up available early options, which need to be taken care
|
||||
* of in the correct order */
|
||||
for (i = 0; i < ARRAY_SIZE(early_settings); i++) {
|
||||
early_settings[i].attr = swlib_lookup_attr(dev,
|
||||
SWLIB_ATTR_GROUP_GLOBAL, early_settings[i].name);
|
||||
}
|
||||
swlib_map_settings(dev, SWLIB_ATTR_GROUP_GLOBAL, 0, s);
|
||||
|
||||
/* look for port or vlan sections */
|
||||
uci_foreach_element(&p->sections, e) {
|
||||
struct uci_element *os;
|
||||
s = uci_to_section(e);
|
||||
|
||||
if (!strcmp(s->type, "switch_vlan")) {
|
||||
char *devn = NULL, *vlan = NULL, *vlan_err = NULL;
|
||||
int vlan_n;
|
||||
|
||||
uci_foreach_element(&s->options, os) {
|
||||
o = uci_to_option(os);
|
||||
if (o->type != UCI_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
if (!strcmp(os->name, "device")) {
|
||||
devn = o->v.string;
|
||||
if (!swlib_match_name(dev, devn))
|
||||
devn = NULL;
|
||||
} else if (!strcmp(os->name, "vlan")) {
|
||||
vlan = o->v.string;
|
||||
}
|
||||
}
|
||||
if (!devn || !vlan || !vlan[0])
|
||||
continue;
|
||||
|
||||
vlan_n = strtoul(vlan, &vlan_err, 0);
|
||||
if (vlan_err && vlan_err[0])
|
||||
continue;
|
||||
|
||||
swlib_map_settings(dev, SWLIB_ATTR_GROUP_VLAN, vlan_n, s);
|
||||
}
|
||||
}
|
||||
uci_foreach_element(&p->sections, e) {
|
||||
struct uci_element *os;
|
||||
char *devn = NULL, *port = NULL, *port_err = NULL;
|
||||
int port_n;
|
||||
|
||||
s = uci_to_section(e);
|
||||
|
||||
if (strcmp(s->type, "switch_port"))
|
||||
continue;
|
||||
|
||||
uci_foreach_element(&s->options, os) {
|
||||
o = uci_to_option(os);
|
||||
if (o->type != UCI_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
if (!strcmp(os->name, "device")) {
|
||||
devn = o->v.string;
|
||||
if (!swlib_match_name(dev, devn))
|
||||
devn = NULL;
|
||||
} else if (!strcmp(os->name, "port")) {
|
||||
port = o->v.string;
|
||||
}
|
||||
}
|
||||
if (!devn || !port || !port[0])
|
||||
continue;
|
||||
|
||||
port_n = strtoul(port, &port_err, 0);
|
||||
if (port_err && port_err[0])
|
||||
continue;
|
||||
|
||||
swlib_map_settings(dev, SWLIB_ATTR_GROUP_PORT, port_n, s);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(early_settings); i++) {
|
||||
struct swlib_setting *st = &early_settings[i];
|
||||
if (!st->attr || !st->val)
|
||||
continue;
|
||||
swlib_set_attr_string(dev, st->attr, st->port_vlan, st->val);
|
||||
|
||||
}
|
||||
|
||||
while (settings) {
|
||||
struct swlib_setting *st = settings;
|
||||
|
||||
swlib_set_attr_string(dev, st->attr, st->port_vlan, st->val);
|
||||
st = st->next;
|
||||
free(settings);
|
||||
settings = st;
|
||||
}
|
||||
|
||||
/* Apply the config */
|
||||
attr = swlib_lookup_attr(dev, SWLIB_ATTR_GROUP_GLOBAL, "apply");
|
||||
if (!attr)
|
||||
return 0;
|
||||
|
||||
memset(&val, 0, sizeof(val));
|
||||
swlib_set_attr(dev, attr, &val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
44
package/network/config/vti/Makefile
Normal file
44
package/network/config/vti/Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright (C) 2014 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=vti
|
||||
PKG_RELEASE:=5
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/vti/Default
|
||||
endef
|
||||
|
||||
define Package/vti
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
MAINTAINER:=Andre Valentin <avalentin@marcant.net>
|
||||
TITLE:=Virtual IPsec Tunnel Interface config support
|
||||
DEPENDS:=+kmod-ip-vti +IPV6:kmod-ip6-vti
|
||||
PROVIDES:=vtiv4 vtiv6
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/vti/description
|
||||
Virtual IPsec Tunnel Interface config support (IPv4 and IPv6) in /etc/config/network.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Package/vti/install
|
||||
$(INSTALL_DIR) $(1)/lib/netifd/proto
|
||||
$(INSTALL_BIN) ./files/vti.sh $(1)/lib/netifd/proto/vti.sh
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,vti))
|
||||
154
package/network/config/vti/files/vti.sh
Executable file
154
package/network/config/vti/files/vti.sh
Executable file
@@ -0,0 +1,154 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
. /lib/functions.sh
|
||||
. /lib/functions/network.sh
|
||||
. ../netifd-proto.sh
|
||||
init_proto "$@"
|
||||
}
|
||||
|
||||
vti_generic_setup() {
|
||||
local cfg="$1"
|
||||
local mode="$2"
|
||||
local local="$3"
|
||||
local remote="$4"
|
||||
local link="$5"
|
||||
local mtu zone ikey
|
||||
json_get_vars mtu zone ikey okey
|
||||
|
||||
proto_init_update "$link" 1
|
||||
|
||||
proto_add_tunnel
|
||||
json_add_string mode "$mode"
|
||||
json_add_int mtu "${mtu:-1280}"
|
||||
json_add_string local "$local"
|
||||
json_add_string remote "$remote"
|
||||
[ -n "$tunlink" ] && json_add_string link "$tunlink"
|
||||
|
||||
json_add_object 'data'
|
||||
[ -n "$ikey" ] && json_add_int ikey "$ikey"
|
||||
[ -n "$okey" ] && json_add_int okey "$okey"
|
||||
json_close_object
|
||||
|
||||
proto_close_tunnel
|
||||
|
||||
proto_add_data
|
||||
[ -n "$zone" ] && json_add_string zone "$zone"
|
||||
proto_close_data
|
||||
|
||||
proto_send_update "$cfg"
|
||||
}
|
||||
|
||||
vti_setup() {
|
||||
local cfg="$1"
|
||||
local mode="$2"
|
||||
|
||||
local ipaddr peeraddr
|
||||
json_get_vars df ipaddr peeraddr tunlink
|
||||
|
||||
[ -z "$peeraddr" ] && {
|
||||
proto_notify_error "$cfg" "MISSING_ADDRESS"
|
||||
proto_block_restart "$cfg"
|
||||
exit
|
||||
}
|
||||
|
||||
( proto_add_host_dependency "$cfg" "$peeraddr" "$tunlink" )
|
||||
|
||||
[ -z "$ipaddr" ] && {
|
||||
local wanif="$tunlink"
|
||||
if [ -z $wanif ] && ! network_find_wan wanif; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! network_get_ipaddr ipaddr "$wanif"; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
vti_generic_setup $cfg $mode $ipaddr $peeraddr "vti-$cfg"
|
||||
}
|
||||
|
||||
proto_vti_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
vti_setup $cfg "vtiip"
|
||||
}
|
||||
|
||||
vti6_setup() {
|
||||
local cfg="$1"
|
||||
local mode="$2"
|
||||
|
||||
local ip6addr peer6addr weakif
|
||||
json_get_vars ip6addr peer6addr tunlink weakif
|
||||
|
||||
[ -z "$peer6addr" ] && {
|
||||
proto_notify_error "$cfg" "MISSING_ADDRESS"
|
||||
proto_block_restart "$cfg"
|
||||
exit
|
||||
}
|
||||
|
||||
( proto_add_host_dependency "$cfg" "$peer6addr" "$tunlink" )
|
||||
|
||||
[ -z "$ip6addr" ] && {
|
||||
local wanif="$tunlink"
|
||||
if [ -z $wanif ] && ! network_find_wan6 wanif; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! network_get_ipaddr6 ip6addr "$wanif"; then
|
||||
[ -z "$weakif" ] && weakif="lan"
|
||||
if ! network_get_ipaddr6 ip6addr "$weakif"; then
|
||||
proto_notify_error "$cfg" "NO_WAN_LINK"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
vti_generic_setup $cfg $mode $ip6addr $peer6addr "vti6-$cfg"
|
||||
}
|
||||
|
||||
proto_vti6_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
vti6_setup $cfg "vtiip6"
|
||||
}
|
||||
|
||||
proto_vti_teardown() {
|
||||
local cfg="$1"
|
||||
}
|
||||
|
||||
proto_vti6_teardown() {
|
||||
local cfg="$1"
|
||||
}
|
||||
|
||||
vti_generic_init_config() {
|
||||
no_device=1
|
||||
available=1
|
||||
|
||||
proto_config_add_int "mtu"
|
||||
proto_config_add_string "tunlink"
|
||||
proto_config_add_string "zone"
|
||||
proto_config_add_int "ikey"
|
||||
proto_config_add_int "okey"
|
||||
}
|
||||
|
||||
proto_vti_init_config() {
|
||||
vti_generic_init_config
|
||||
proto_config_add_string "ipaddr"
|
||||
proto_config_add_string "peeraddr"
|
||||
}
|
||||
|
||||
proto_vti6_init_config() {
|
||||
vti_generic_init_config
|
||||
proto_config_add_string "ip6addr"
|
||||
proto_config_add_string "peer6addr"
|
||||
proto_config_add_string "weakif"
|
||||
}
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
[ -d /sys/module/ip_vti ] && add_protocol vti
|
||||
[ -d /sys/module/ip6_vti ] && add_protocol vti6
|
||||
}
|
||||
33
package/network/config/vxlan/Makefile
Normal file
33
package/network/config/vxlan/Makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=vxlan
|
||||
PKG_RELEASE:=7
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/vxlan
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
MAINTAINER:=Matthias Schiffer <mschiffer@universe-factory.net>
|
||||
TITLE:=Virtual eXtensible LAN config support
|
||||
DEPENDS:=+kmod-vxlan
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/vxlan/description
|
||||
Virtual eXtensible LAN config support in /etc/config/network.
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Package/vxlan/install
|
||||
$(INSTALL_DIR) $(1)/lib/netifd/proto
|
||||
$(INSTALL_BIN) ./files/vxlan.sh $(1)/lib/netifd/proto/vxlan.sh
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,vxlan))
|
||||
195
package/network/config/vxlan/files/vxlan.sh
Executable file
195
package/network/config/vxlan/files/vxlan.sh
Executable file
@@ -0,0 +1,195 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
. /lib/functions.sh
|
||||
. /lib/functions/network.sh
|
||||
. ../netifd-proto.sh
|
||||
init_proto "$@"
|
||||
}
|
||||
|
||||
proto_vxlan_setup_peer() {
|
||||
type bridge &> /dev/null || {
|
||||
proto_notify_error "$cfg" "MISSING_BRIDGE_COMMAND"
|
||||
exit
|
||||
}
|
||||
|
||||
local peer_config="$1"
|
||||
|
||||
local vxlan
|
||||
local lladdr
|
||||
local dst
|
||||
local src_vni
|
||||
local vni
|
||||
local port
|
||||
local via
|
||||
|
||||
config_get vxlan "${peer_config}" "vxlan"
|
||||
config_get lladdr "${peer_config}" "lladdr"
|
||||
config_get dst "${peer_config}" "dst"
|
||||
config_get src_vni "${peer_config}" "src_vni"
|
||||
config_get vni "${peer_config}" "vni"
|
||||
config_get port "${peer_config}" "port"
|
||||
config_get via "${peer_config}" "via"
|
||||
|
||||
[ "$cfg" = "$vxlan" ] || {
|
||||
# This peer section belongs to another device
|
||||
return
|
||||
}
|
||||
|
||||
[ -n "${dst}" ] || {
|
||||
proto_notify_error "$cfg" "MISSING_PEER_ADDRESS"
|
||||
exit
|
||||
}
|
||||
|
||||
bridge fdb append \
|
||||
${lladdr:-00:00:00:00:00:00} \
|
||||
dev ${cfg} \
|
||||
dst ${dst} \
|
||||
${src_vni:+src_vni $src_vni} \
|
||||
${vni:+vni $vni} \
|
||||
${port:+port $port} \
|
||||
${via:+via $via}
|
||||
}
|
||||
|
||||
vxlan_generic_setup() {
|
||||
local cfg="$1"
|
||||
local mode="$2"
|
||||
local local="$3"
|
||||
local remote="$4"
|
||||
|
||||
local link="$cfg"
|
||||
|
||||
local port vid ttl tos mtu macaddr zone rxcsum txcsum srcportmin srcportmax ageing maxaddress learning rsc proxy l2miss l3miss gbp
|
||||
json_get_vars port vid ttl tos mtu macaddr zone rxcsum txcsum srcportmin srcportmax ageing maxaddress learning rsc proxy l2miss l3miss gbp
|
||||
|
||||
proto_init_update "$link" 1
|
||||
|
||||
proto_add_tunnel
|
||||
json_add_string mode "$mode"
|
||||
|
||||
[ -n "$tunlink" ] && json_add_string link "$tunlink"
|
||||
[ -n "$local" ] && json_add_string local "$local"
|
||||
[ -n "$remote" ] && json_add_string remote "$remote"
|
||||
|
||||
[ -n "$ttl" ] && json_add_int ttl "$ttl"
|
||||
[ -n "$tos" ] && json_add_string tos "$tos"
|
||||
[ -n "$mtu" ] && json_add_int mtu "$mtu"
|
||||
|
||||
json_add_object 'data'
|
||||
[ -n "$port" ] && json_add_int port "$port"
|
||||
[ -n "$vid" ] && json_add_int id "$vid"
|
||||
[ -n "$srcportmin" ] && json_add_int srcportmin "$srcportmin"
|
||||
[ -n "$srcportmax" ] && json_add_int srcportmax "$srcportmax"
|
||||
[ -n "$ageing" ] && json_add_int ageing "$ageing"
|
||||
[ -n "$maxaddress" ] && json_add_int maxaddress "$maxaddress"
|
||||
[ -n "$macaddr" ] && json_add_string macaddr "$macaddr"
|
||||
[ -n "$rxcsum" ] && json_add_boolean rxcsum "$rxcsum"
|
||||
[ -n "$txcsum" ] && json_add_boolean txcsum "$txcsum"
|
||||
[ -n "$learning" ] && json_add_boolean learning "$learning"
|
||||
[ -n "$rsc" ] && json_add_boolean rsc "$rsc"
|
||||
[ -n "$proxy" ] && json_add_boolean proxy "$proxy"
|
||||
[ -n "$l2miss" ] && json_add_boolean l2miss "$l2miss"
|
||||
[ -n "$l3miss" ] && json_add_boolean l3miss "$l3miss"
|
||||
[ -n "$gbp" ] && json_add_boolean gbp "$gbp"
|
||||
|
||||
json_close_object
|
||||
|
||||
proto_close_tunnel
|
||||
|
||||
proto_add_data
|
||||
[ -n "$zone" ] && json_add_string zone "$zone"
|
||||
proto_close_data
|
||||
|
||||
proto_send_update "$cfg"
|
||||
|
||||
config_load network
|
||||
config_foreach proto_vxlan_setup_peer "vxlan_peer"
|
||||
}
|
||||
|
||||
proto_vxlan_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
local ipaddr peeraddr
|
||||
json_get_vars ipaddr peeraddr tunlink
|
||||
|
||||
( proto_add_host_dependency "$cfg" '' "$tunlink" )
|
||||
|
||||
case "$ipaddr" in
|
||||
"auto"|"")
|
||||
ipaddr="0.0.0.0"
|
||||
;;
|
||||
esac
|
||||
|
||||
vxlan_generic_setup "$cfg" 'vxlan' "$ipaddr" "$peeraddr"
|
||||
}
|
||||
|
||||
proto_vxlan6_setup() {
|
||||
local cfg="$1"
|
||||
|
||||
local ip6addr peer6addr
|
||||
json_get_vars ip6addr peer6addr tunlink
|
||||
|
||||
( proto_add_host_dependency "$cfg" '' "$tunlink" )
|
||||
|
||||
case "$ip6addr" in
|
||||
"auto"|"")
|
||||
# ensure tunnel via ipv6
|
||||
ip6addr="::"
|
||||
;;
|
||||
esac
|
||||
|
||||
vxlan_generic_setup "$cfg" 'vxlan6' "$ip6addr" "$peer6addr"
|
||||
}
|
||||
|
||||
proto_vxlan_teardown() {
|
||||
local cfg="$1"
|
||||
}
|
||||
|
||||
proto_vxlan6_teardown() {
|
||||
local cfg="$1"
|
||||
}
|
||||
|
||||
vxlan_generic_init_config() {
|
||||
no_device=1
|
||||
available=1
|
||||
|
||||
proto_config_add_string "tunlink"
|
||||
proto_config_add_string "zone"
|
||||
|
||||
proto_config_add_int "vid"
|
||||
proto_config_add_int "port"
|
||||
proto_config_add_int "ttl"
|
||||
proto_config_add_int "tos"
|
||||
proto_config_add_int "mtu"
|
||||
proto_config_add_int "srcportmin"
|
||||
proto_config_add_int "srcportmax"
|
||||
proto_config_add_int "ageing"
|
||||
proto_config_add_int "maxaddress"
|
||||
proto_config_add_boolean "rxcsum"
|
||||
proto_config_add_boolean "txcsum"
|
||||
proto_config_add_boolean "learning"
|
||||
proto_config_add_boolean "rsc"
|
||||
proto_config_add_boolean "proxy"
|
||||
proto_config_add_boolean "l2miss"
|
||||
proto_config_add_boolean "l3miss"
|
||||
proto_config_add_boolean "gbp"
|
||||
proto_config_add_string "macaddr"
|
||||
|
||||
}
|
||||
|
||||
proto_vxlan_init_config() {
|
||||
vxlan_generic_init_config
|
||||
proto_config_add_string "ipaddr"
|
||||
proto_config_add_string "peeraddr"
|
||||
}
|
||||
|
||||
proto_vxlan6_init_config() {
|
||||
vxlan_generic_init_config
|
||||
proto_config_add_string "ip6addr"
|
||||
proto_config_add_string "peer6addr"
|
||||
}
|
||||
|
||||
[ -n "$INCLUDE_ONLY" ] || {
|
||||
add_protocol vxlan
|
||||
add_protocol vxlan6
|
||||
}
|
||||
3
package/network/config/wifi-scripts/Config.in
Normal file
3
package/network/config/wifi-scripts/Config.in
Normal file
@@ -0,0 +1,3 @@
|
||||
config WIFI_SCRIPTS_UCODE
|
||||
bool "Use new ucode based scripts"
|
||||
default n
|
||||
53
package/network/config/wifi-scripts/Makefile
Normal file
53
package/network/config/wifi-scripts/Makefile
Normal file
@@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright (C) 2024 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=wifi-scripts
|
||||
PKG_VERSION:=1.0
|
||||
PKG_RELEASE:=1
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
PKG_CONFIG_DEPENDS:=CONFIG_WIFI_SCRIPTS_UCODE
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/wifi-scripts
|
||||
SECTION:=utils
|
||||
CATEGORY:=Base system
|
||||
DEPENDS:=+netifd +ucode +ucode-mod-nl80211 +ucode-mod-rtnl +ucode-mod-ubus +ucode-mod-uci +ucode-mod-digest
|
||||
TITLE:=Wi-Fi configuration scripts
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/wifi-scripts/config
|
||||
source "$(SOURCE)/Config.in"
|
||||
endef
|
||||
|
||||
define Package/wifi-scripts/description
|
||||
A set of scripts that handle setup and configuration of Wi-Fi devices.
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/wifi-scripts/install
|
||||
$(INSTALL_DIR) $(1)
|
||||
$(CP) ./files/* $(1)/
|
||||
ifeq ($(CONFIG_WIFI_SCRIPTS_UCODE),y)
|
||||
$(CP) ./files-ucode/* $(1)/
|
||||
endif
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,wifi-scripts))
|
||||
401
package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh
Executable file
401
package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh
Executable file
@@ -0,0 +1,401 @@
|
||||
#!/usr/bin/ucode
|
||||
|
||||
'use strict';
|
||||
|
||||
import { set_default, log } from 'wifi.common';
|
||||
import { validate, dump_options } from 'wifi.validate';
|
||||
import * as supplicant from 'wifi.supplicant';
|
||||
import * as hostapd from 'wifi.hostapd';
|
||||
import * as netifd from 'wifi.netifd';
|
||||
import * as iface from 'wifi.iface';
|
||||
import * as nl80211 from 'nl80211';
|
||||
import * as fs from 'fs';
|
||||
|
||||
global.radio = ARGV[2];
|
||||
|
||||
const mesh_param_list = [
|
||||
"mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links",
|
||||
"mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries",
|
||||
"mesh_path_refresh_time", "mesh_min_discovery_timeout", "mesh_hwmp_active_path_timeout",
|
||||
"mesh_hwmp_preq_min_interval", "mesh_hwmp_net_diameter_traversal_time", "mesh_hwmp_rootmode",
|
||||
"mesh_hwmp_rann_interval", "mesh_gate_announcements", "mesh_sync_offset_max_neighor",
|
||||
"mesh_rssi_threshold", "mesh_hwmp_active_path_to_root_timeout", "mesh_hwmp_root_interval",
|
||||
"mesh_hwmp_confirmation_interval", "mesh_awake_window", "mesh_plink_timeout",
|
||||
"mesh_auto_open_plinks", "mesh_fwding", "mesh_power_mode"
|
||||
];
|
||||
|
||||
function phy_suffix(radio, sep) {
|
||||
if (radio == null || radio < 0)
|
||||
return "";
|
||||
return sep + radio;
|
||||
}
|
||||
|
||||
function reset_config(phy, radio) {
|
||||
let name = phy + phy_suffix(radio, ".");
|
||||
let prev_config = `/var/run/hostapd-${name}.conf`;
|
||||
|
||||
global.ubus.call('hostapd', 'config_set', { phy, radio, config: '', prev_config });
|
||||
global.ubus.call('wpa_supplicant', 'config_set', { phy, radio, config: []});
|
||||
|
||||
name = phy + phy_suffix(radio, ":");
|
||||
system(`ucode /usr/share/hostap/wdev.uc ${name} set_config '{}'`);
|
||||
}
|
||||
|
||||
function phy_filename(phy, name) {
|
||||
return `/sys/class/ieee80211/${phy}/${name}`;
|
||||
}
|
||||
|
||||
function phy_file(phy, name) {
|
||||
return fs.readfile(phy_filename(phy, name));
|
||||
}
|
||||
|
||||
function phy_index(phy) {
|
||||
return +phy_file(phy, "index");
|
||||
}
|
||||
|
||||
function phy_path_match(phy, path) {
|
||||
let phy_path = fs.realpath(phy_filename(phy, "device"));
|
||||
return substr(phy_path, -length(path)) == path;
|
||||
}
|
||||
|
||||
function __find_phy_by_path(phys, path) {
|
||||
if (!path)
|
||||
return null;
|
||||
|
||||
path = split(path, "+");
|
||||
phys = filter(phys, (phy) => phy_path_match(phy, path[0]));
|
||||
phys = sort(phys, (a, b) => phy_index(a) - phy_index(b));
|
||||
|
||||
return phys[+path[1]];
|
||||
}
|
||||
|
||||
function find_phy_by_macaddr(phys, macaddr) {
|
||||
macaddr = lc(macaddr);
|
||||
return filter(phys, (phy) => phy_file(phy, "macaddr") == macaddr)[0];
|
||||
}
|
||||
|
||||
function rename_phy_by_name(phys, name) {
|
||||
let data = json(fs.readfile("/etc/board.json")).wlan;
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
data = data[name];
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
let prev_name = __find_phy_by_path(phys, data.path);
|
||||
if (!prev_name)
|
||||
return;
|
||||
|
||||
let idx = phy_index(prev_name);
|
||||
nl80211.request(nl80211.const.NL80211_CMD_SET_WIPHY, 0, {
|
||||
wiphy: idx,
|
||||
wiphy_name: name
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function find_phy_by_path(phys, path) {
|
||||
let name = __find_phy_by_path(phys, path);
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
let data = json(fs.readfile("/etc/board.json")).wlan;
|
||||
if (!data || data[name])
|
||||
return name;
|
||||
|
||||
for (let cur_name, cur_data in data) {
|
||||
if (!phy_path_match(name, cur_data.path))
|
||||
continue;
|
||||
|
||||
let idx = phy_index(name);
|
||||
nl80211.request(nl80211.const.NL80211_CMD_SET_WIPHY, 0, {
|
||||
wiphy: idx,
|
||||
wiphy_name: cur_name
|
||||
});
|
||||
|
||||
return cur_name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function find_phy_by_name(phys, name) {
|
||||
if (index(phys, name) >= 0)
|
||||
return name;
|
||||
|
||||
rename_phy_by_name(phys, name);
|
||||
return index(phys, name) < 0 ? null : name;
|
||||
}
|
||||
|
||||
function find_phy(config) {
|
||||
let phys = fs.lsdir("/sys/class/ieee80211");
|
||||
|
||||
return find_phy_by_path(phys, config.path) ??
|
||||
find_phy_by_macaddr(phys, config.macaddr) ??
|
||||
find_phy_by_name(phys, config.phy);
|
||||
}
|
||||
|
||||
function get_channel_frequency(band, channel) {
|
||||
if (channel < 1)
|
||||
return null;
|
||||
|
||||
switch (band) {
|
||||
case '2g':
|
||||
if (channel == 14)
|
||||
return 2484;
|
||||
return 2407 + channel * 5;
|
||||
case '5g':
|
||||
if (channel >= 182 && channel <= 196)
|
||||
return 4000 + channel * 5;
|
||||
return 5000 + channel * 5;
|
||||
case '6g':
|
||||
if (channel == 2)
|
||||
return 5935;
|
||||
return 5950 + channel * 5;
|
||||
case '60g':
|
||||
return 56160 + channel * 2160;
|
||||
}
|
||||
}
|
||||
|
||||
function setup_phy(phy, config, data) {
|
||||
if (config.channel == "auto")
|
||||
config.channel = 0;
|
||||
config.channel = +config.channel;
|
||||
config.frequency = get_channel_frequency(config.band, config.channel);
|
||||
|
||||
if (config.country) {
|
||||
log(`Setting country code to ${config.country}`);
|
||||
system(`iw reg set ${config.country}`);
|
||||
}
|
||||
|
||||
set_default(config, 'rxantenna', 0xffffffff);
|
||||
set_default(config, 'txantenna', 0xffffffff);
|
||||
|
||||
if (config.txantenna == 'all')
|
||||
config.txantenna = 0xffffffff;
|
||||
if (config.rxantenna == 'all')
|
||||
config.rxantenna = 0xffffffff;
|
||||
|
||||
if (config.txantenna != data?.txantenna || config.rxantenna != data?.rxantenna)
|
||||
reset_config(phy, config.radio);
|
||||
|
||||
netifd.set_data({
|
||||
phy,
|
||||
radio: config.radio,
|
||||
txantenna: config.txantenna,
|
||||
rxantenna: config.rxantenna
|
||||
});
|
||||
|
||||
if (config.txpower)
|
||||
config.txpower = 'fixed ' + config.txpower + '00';
|
||||
else
|
||||
config.txpower = 'auto';
|
||||
|
||||
log(`Configuring '${phy}' txantenna: ${config.txantenna}, rxantenna: ${config.rxantenna} distance: ${config.distance}`);
|
||||
system(`iw phy ${phy} set antenna ${config.txantenna} ${config.rxantenna}`);
|
||||
system(`iw phy ${phy} set distance ${config.distance}`);
|
||||
|
||||
if (config.frag)
|
||||
system(`iw phy ${phy} set frag ${frag}`);
|
||||
if (config.rts)
|
||||
system(`iw phy ${phy} set rts ${rts}`);
|
||||
}
|
||||
|
||||
function iw_htmode(config) {
|
||||
let suffix = substr(config.htmode, 3);
|
||||
if (suffix == "40+" || suffix == "40-")
|
||||
return "HT" + suffix;
|
||||
|
||||
switch (config.htmode ?? "NONE") {
|
||||
case "HT20":
|
||||
case "VHT20":
|
||||
case "HE20":
|
||||
case "EHT20":
|
||||
return "HT20";
|
||||
case "VHT80":
|
||||
case "HE80":
|
||||
case "EHT80":
|
||||
case "HE160":
|
||||
case "EHT160":
|
||||
case "EHT320":
|
||||
return "80MHZ";
|
||||
case "NONE":
|
||||
case "NOHT":
|
||||
return "NOHT";
|
||||
}
|
||||
|
||||
if (substr(config.htmode, 2) == "40") {
|
||||
switch (config.band) {
|
||||
case "2g":
|
||||
if (+config.channel < 7)
|
||||
return "HT40+";
|
||||
else
|
||||
return "HT40-";
|
||||
default:
|
||||
return ((+config.channel / 4) % 2) ? "HT40+" : "HT40-";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function config_add(config, name, val) {
|
||||
if (val != null)
|
||||
config[name] = val;
|
||||
}
|
||||
|
||||
function config_add_mesh_params(config, data) {
|
||||
for (let param in mesh_param_list)
|
||||
config_add(config, param, data[param]);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
let data = json(ARGV[3]);
|
||||
|
||||
data.phy = find_phy(data.config);
|
||||
if (!data.phy) {
|
||||
log('Bug: PHY is undefined for device');
|
||||
netifd.set_retry(false);
|
||||
return 1;
|
||||
}
|
||||
data.phy_suffix = phy_suffix(data.config.radio, ":");
|
||||
data.vif_phy_suffix = phy_suffix(data.config.radio, ".");
|
||||
data.ifname_prefix = data.config.ifname_prefix;
|
||||
if (!data.ifname_prefix)
|
||||
data.ifname_prefix = data.phy + data.vif_phy_suffix + "-";
|
||||
let active_ifnames = [];
|
||||
|
||||
log('Starting');
|
||||
|
||||
validate('device', data.config);
|
||||
setup_phy(data.phy, data.config, data.data);
|
||||
|
||||
let supplicant_mesh;
|
||||
let has_ap = false;
|
||||
let idx = {};
|
||||
let supplicant_data = [];
|
||||
let wdev_data = {};
|
||||
|
||||
for (let k, v in data.interfaces) {
|
||||
let mode = v.config.mode;
|
||||
idx[mode] ??= 0;
|
||||
let mode_idx = idx[mode]++;
|
||||
|
||||
if (!v.config.ifname)
|
||||
v.config.ifname = data.ifname_prefix + mode + mode_idx;
|
||||
push(active_ifnames, v.config.ifname);
|
||||
|
||||
if (v.config.encryption == 'owe' && v.config.owe_transition) {
|
||||
mode_idx = idx[mode]++;
|
||||
v.config.owe_transition_ifname = data.ifname_prefix + mode + mode_idx;
|
||||
push(active_ifnames, v.config.ifname);
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case 'ap':
|
||||
has_ap = true;
|
||||
// fallthrough
|
||||
case 'sta':
|
||||
case 'adhoc':
|
||||
case 'mesh':
|
||||
if (mode != "ap")
|
||||
data.config.noscan = true;
|
||||
validate('iface', v.config);
|
||||
iface.prepare(v.config, data.phy + data.phy_suffix, data.config.num_global_macaddr, data.config.macaddr_base);
|
||||
netifd.set_vif(k, v.config.ifname);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case 'adhoc':
|
||||
if (config.frequency && !v.config.wpa)
|
||||
break;
|
||||
// fallthrough
|
||||
case 'mesh':
|
||||
supplicant_mesh ??= !system("wpa_supplicant -vmesh");
|
||||
if (mode == "mesh" && !supplicant_mesh)
|
||||
break;
|
||||
// fallthrough
|
||||
case 'sta':
|
||||
let config = supplicant.generate(supplicant_data, data, v);
|
||||
if (mode == "mesh")
|
||||
config_add_mesh_params(config, v.config);
|
||||
continue;
|
||||
case 'monitor':
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// fallback to wdev setup
|
||||
let config = {
|
||||
mode,
|
||||
ssid: v.config.ssid,
|
||||
};
|
||||
|
||||
if (!v.config.default_macaddr)
|
||||
config.macaddr = v.config.macaddr;
|
||||
|
||||
config_add(config, "htmode", wdev_htmode(data.config));
|
||||
if (mode != "monitor") {
|
||||
config_add(config, "basic-rates", supplicant.ratelist(data.config.basic_rate));
|
||||
config_add(config, "mcast-rate", supplicant.ratestr(v.config.mcast_rate));
|
||||
config_add(config, "beacon-interval", data.config.beacon_int);
|
||||
if (mode == "mesh") {
|
||||
config_add(config, "ssid", v.config.mesh_id);
|
||||
config_add_mesh_params(config, v.config);
|
||||
}
|
||||
}
|
||||
|
||||
wdev_data[v.config.ifname] = config;
|
||||
}
|
||||
|
||||
if (length(supplicant_data) > 0)
|
||||
supplicant.setup(supplicant_data, data);
|
||||
|
||||
if (has_ap)
|
||||
hostapd.setup(data);
|
||||
|
||||
system(`ucode /usr/share/hostap/wdev.uc ${data.phy}${data.phy_suffix} set_config '${printf("%J", wdev_data)}' ${join(' ', active_ifnames)}`);
|
||||
|
||||
if (length(supplicant_data) > 0)
|
||||
supplicant.start(data);
|
||||
|
||||
netifd.set_up();
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
let data = json(ARGV[3]);
|
||||
|
||||
if (!data.data?.phy) {
|
||||
log('Bug: PHY is undefined for device');
|
||||
return 1;
|
||||
}
|
||||
|
||||
log(`Tearing down ${data.data.phy}`);
|
||||
|
||||
reset_config(data.data.phy, data.data.radio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
let ret = 1;
|
||||
|
||||
switch(ARGV[1]) {
|
||||
case 'dump':
|
||||
ret = dump_options();
|
||||
break;
|
||||
|
||||
case 'setup':
|
||||
ret = setup();
|
||||
break;
|
||||
|
||||
case 'teardown':
|
||||
ret = teardown();
|
||||
break;
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
156
package/network/config/wifi-scripts/files-ucode/usr/bin/iwinfo
Executable file
156
package/network/config/wifi-scripts/files-ucode/usr/bin/iwinfo
Executable file
@@ -0,0 +1,156 @@
|
||||
#!/usr/bin/ucode
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as iwinfo from 'iwinfo';
|
||||
|
||||
function print_assoclist(stations) {
|
||||
for (let mac, station in stations) {
|
||||
printf(`${station.mac} ${station.signal} dBm / ${station.noise} dBm (SNR ${station.snr}) ${station.inactive_time} ms ago\n`);
|
||||
for (let k in [ 'rx', 'tx' ]) {
|
||||
let bitrate = station[k];
|
||||
let flags = join(', ', bitrate.flags);
|
||||
|
||||
printf(`\t${uc(k)}: ${bitrate.bitrate} MBit/s`);
|
||||
if (length(bitrate.flags))
|
||||
printf(', %s', flags);
|
||||
printf('%10d Pkts.\n', bitrate.packets);
|
||||
}
|
||||
printf(`\texpected throughput: ${station.expected_throughput}\n\n`);
|
||||
}
|
||||
}
|
||||
|
||||
function print_countrylist(list) {
|
||||
for (let k, v in list.countries)
|
||||
printf(`${k == list.active ? '*' : ' '} ${k} "${v}"\n`);
|
||||
}
|
||||
|
||||
function print_freqlist(channels) {
|
||||
for (let channel in channels) {
|
||||
printf(`${channel.active ? '*' : ' '} ${channel.freq} GHz (Band: ${channel.band} GHz, Channel ${channel.channel})`);
|
||||
if (length(channel.flags))
|
||||
printf(` [${join(', ', channel.flags)}]`);
|
||||
printf('\n');
|
||||
}
|
||||
}
|
||||
|
||||
function print_htmodelist(htmode) {
|
||||
printf('%s\n', join(' ', htmode));
|
||||
}
|
||||
|
||||
function print_info(list) {
|
||||
let padding = ' ';
|
||||
|
||||
for (let bss in list) {
|
||||
printf(`${bss.iface} ESSID: "${bss.ssid}"\n`);
|
||||
printf(`${padding}Access Point: ${bss.mac}\n`);
|
||||
printf(`${padding}Mode: ${bss.mode} Channel: ${bss.channel} (${bss.freq} GHz) HT Mode: ${bss.htmode}\n`);
|
||||
printf(`${padding}Center Channel 1: ${bss.center_freq1} 2: ${bss.center_freq2}\n`);
|
||||
printf(`${padding}Tx-Power: ${bss.txpower} dBm Link Quality: ${bss.quality}/70\n`);
|
||||
printf(`${padding}Signal: ${bss.signal} Noise: ${bss.noise}\n`);
|
||||
printf(`${padding}Bit Rate: ${bss.bitrate ?? 'unknown'} MBit/s\n`);
|
||||
printf(`${padding}Encryption: ${bss.encryption}\n`);
|
||||
printf(`${padding}Type: nl80211 HW Mode(s): 802.11${bss.hwmode}\n`);
|
||||
printf(`${padding}Hardware: ${bss.hw_type} [${bss.hw_id}]\n`);
|
||||
printf(`${padding}TX power offset: ${bss.power_offset}\n`);
|
||||
printf(`${padding}Channel offset: ${bss.channel_offset}\n`);
|
||||
printf(`${padding}Supports VAPs: ${bss.vaps} PHY name: ${bss.phy}\n`);
|
||||
if (bss.owe_transition_ifname)
|
||||
printf(`${padding}OWE partner: ${bss.owe_transition_ifname}\n`);
|
||||
printf('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function print_scan(cells) {
|
||||
let idx = 1;
|
||||
|
||||
for (let cell in cells) {
|
||||
printf('Cell %02d - Address: %s\n', idx++, cell.bssid);
|
||||
printf('\t Mode: %s Frequency: %s GHz Band: %s GHz Channel: %d\n', cell.mode, cell.frequency, cell.band, cell.channel);
|
||||
printf('\t Signal: %d dBm Quality: %2d/70\n', cell.dbm, cell.quality);
|
||||
|
||||
if (!length(cell.crypto.key_mgmt))
|
||||
printf('\t Encryption: NONE\n');
|
||||
else
|
||||
printf('\t Encryption: %s (%s)\n', join(' / ', cell.crypto.key_mgmt), join(' / ', cell.crypto.pair));
|
||||
|
||||
if (cell.ht) {
|
||||
printf('\t HT Operation:\n');
|
||||
printf('\t\tPrimary Channel: %d\n', cell.ht.primary_channel);
|
||||
printf('\t\tSecondary Channel Offset: %s\n', cell.ht.secondary_chan_off);
|
||||
printf('\t\tChannel Width: %s\n', cell.ht.chan_width);
|
||||
}
|
||||
|
||||
if (cell.vht) {
|
||||
printf('\t VHT Operation:\n');
|
||||
printf('\t\tCenter Frequency 1: %d\n', cell.vht.center_chan_1);
|
||||
printf('\t\tCenter Frequency 2: %s\n', cell.vht.center_chan_2);
|
||||
printf('\t\tChannel Width: %s\n', cell.vht.chan_width);
|
||||
}
|
||||
|
||||
printf('\n');
|
||||
}
|
||||
}
|
||||
|
||||
function print_txpowerlist(list) {
|
||||
for (let power in list)
|
||||
printf('%s %2d dbm (%4d mW)\n', power.active ? '*' : ' ', power.dbm, power.mw);
|
||||
}
|
||||
|
||||
let pretty = true;
|
||||
if (ARGV[0] == '-j') {
|
||||
pretty = false;
|
||||
shift(ARGV);
|
||||
}
|
||||
|
||||
if (!length(ARGV)) {
|
||||
let info = iwinfo.info();
|
||||
if (pretty)
|
||||
print_info(info);
|
||||
else
|
||||
printf('%.J\n', info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const commands = {
|
||||
assoclist: [ iwinfo.assoclist, print_assoclist ],
|
||||
countrylist: [ iwinfo.countrylist, print_countrylist ],
|
||||
freqlist: [ iwinfo.freqlist, print_freqlist ],
|
||||
htmodelist: [ iwinfo.htmodelist, print_htmodelist ],
|
||||
info: [ iwinfo.info, print_info ],
|
||||
scan: [ iwinfo.scan, print_scan ],
|
||||
txpowerlist: [ iwinfo.txpowerlist, print_txpowerlist ],
|
||||
};
|
||||
|
||||
if (length(ARGV) == 2 && iwinfo.ifaces[ARGV[0]])
|
||||
for (let cmd, cb in commands)
|
||||
if (substr(cmd, 0, length(ARGV[1])) == ARGV[1]) {
|
||||
let ret = cb[0](ARGV[0]);
|
||||
|
||||
if (pretty)
|
||||
cb[1](ret);
|
||||
else
|
||||
printf('%.J\n', ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(ARGV[0]) {
|
||||
case 'phy':
|
||||
printf('%.J\n', iwinfo.phys);
|
||||
return 0;
|
||||
|
||||
case 'iface':
|
||||
printf('%.J\n', iwinfo.ifaces);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf('Usage:\n' +
|
||||
'\tiwinfo <device> info\n' +
|
||||
'\tiwinfo <device> scan\n' +
|
||||
'\tiwinfo <device> txpowerlist\n' +
|
||||
'\tiwinfo <device> freqlist\n' +
|
||||
'\tiwinfo <device> assoclist\n' +
|
||||
'\tiwinfo <device> countrylist\n' +
|
||||
'\tiwinfo <device> htmodelist\n' +
|
||||
'\tiwinfo <backend> phyname <section>\n');
|
||||
@@ -0,0 +1,249 @@
|
||||
{
|
||||
"00": "World",
|
||||
"AD": "Andorra",
|
||||
"AE": "United Arab Emirates",
|
||||
"AF": "Afghanistan",
|
||||
"AG": "Antigua and Barbuda",
|
||||
"AI": "Anguilla",
|
||||
"AL": "Albania",
|
||||
"AM": "Armenia",
|
||||
"AN": "Netherlands Antilles",
|
||||
"AO": "Angola",
|
||||
"AQ": "Antarctica",
|
||||
"AR": "Argentina",
|
||||
"AS": "American Samoa",
|
||||
"AT": "Austria",
|
||||
"AU": "Australia",
|
||||
"AW": "Aruba",
|
||||
"AX": "Aland Islands",
|
||||
"AZ": "Azerbaijan",
|
||||
"BA": "Bosnia and Herzegovina",
|
||||
"BB": "Barbados",
|
||||
"BD": "Bangladesh",
|
||||
"BE": "Belgium",
|
||||
"BF": "Burkina Faso",
|
||||
"BG": "Bulgaria",
|
||||
"BH": "Bahrain",
|
||||
"BI": "Burundi",
|
||||
"BJ": "Benin",
|
||||
"BL": "Saint Barthelemy",
|
||||
"BM": "Bermuda",
|
||||
"BN": "Brunei Darussalam",
|
||||
"BO": "Bolivia",
|
||||
"BR": "Brazil",
|
||||
"BS": "Bahamas",
|
||||
"BT": "Bhutan",
|
||||
"BV": "Bouvet Island",
|
||||
"BW": "Botswana",
|
||||
"BY": "Belarus",
|
||||
"BZ": "Belize",
|
||||
"CA": "Canada",
|
||||
"CC": "Cocos (Keeling) Islands",
|
||||
"CD": "Congo",
|
||||
"CF": "Central African Republic",
|
||||
"CG": "Congo",
|
||||
"CH": "Switzerland",
|
||||
"CI": "Cote d'Ivoire",
|
||||
"CK": "Cook Islands",
|
||||
"CL": "Chile",
|
||||
"CM": "Cameroon",
|
||||
"CN": "China",
|
||||
"CO": "Colombia",
|
||||
"CR": "Costa Rica",
|
||||
"CU": "Cuba",
|
||||
"CV": "Cape Verde",
|
||||
"CX": "Christmas Island",
|
||||
"CY": "Cyprus",
|
||||
"CZ": "Czech Republic",
|
||||
"DE": "Germany",
|
||||
"DJ": "Djibouti",
|
||||
"DK": "Denmark",
|
||||
"DM": "Dominica",
|
||||
"DO": "Dominican Republic",
|
||||
"DZ": "Algeria",
|
||||
"EC": "Ecuador",
|
||||
"EE": "Estonia",
|
||||
"EG": "Egypt",
|
||||
"EH": "Western Sahara",
|
||||
"ER": "Eritrea",
|
||||
"ES": "Spain",
|
||||
"ET": "Ethiopia",
|
||||
"FI": "Finland",
|
||||
"FJ": "Fiji",
|
||||
"FK": "Falkland Islands",
|
||||
"FM": "Micronesia",
|
||||
"FO": "Faroe Islands",
|
||||
"FR": "France",
|
||||
"GA": "Gabon",
|
||||
"GB": "United Kingdom",
|
||||
"GD": "Grenada",
|
||||
"GE": "Georgia",
|
||||
"GF": "French Guiana",
|
||||
"GG": "Guernsey",
|
||||
"GH": "Ghana",
|
||||
"GI": "Gibraltar",
|
||||
"GL": "Greenland",
|
||||
"GM": "Gambia",
|
||||
"GN": "Guinea",
|
||||
"GP": "Guadeloupe",
|
||||
"GQ": "Equatorial Guinea",
|
||||
"GR": "Greece",
|
||||
"GS": "South Georgia",
|
||||
"GT": "Guatemala",
|
||||
"GU": "Guam",
|
||||
"GW": "Guinea-Bissau",
|
||||
"GY": "Guyana",
|
||||
"HK": "Hong Kong",
|
||||
"HM": "Heard and McDonald Islands",
|
||||
"HN": "Honduras",
|
||||
"HR": "Croatia",
|
||||
"HT": "Haiti",
|
||||
"HU": "Hungary",
|
||||
"ID": "Indonesia",
|
||||
"IE": "Ireland",
|
||||
"IL": "Israel",
|
||||
"IM": "Isle of Man",
|
||||
"IN": "India",
|
||||
"IO": "Chagos Islands",
|
||||
"IQ": "Iraq",
|
||||
"IR": "Iran",
|
||||
"IS": "Iceland",
|
||||
"IT": "Italy",
|
||||
"JE": "Jersey",
|
||||
"JM": "Jamaica",
|
||||
"JO": "Jordan",
|
||||
"JP": "Japan",
|
||||
"KE": "Kenya",
|
||||
"KG": "Kyrgyzstan",
|
||||
"KH": "Cambodia",
|
||||
"KI": "Kiribati",
|
||||
"KM": "Comoros",
|
||||
"KN": "Saint Kitts and Nevis",
|
||||
"KP": "North Korea",
|
||||
"KR": "South Korea",
|
||||
"KW": "Kuwait",
|
||||
"KY": "Cayman Islands",
|
||||
"KZ": "Kazakhstan",
|
||||
"LA": "Laos",
|
||||
"LB": "Lebanon",
|
||||
"LC": "Saint Lucia",
|
||||
"LI": "Liechtenstein",
|
||||
"LK": "Sri Lanka",
|
||||
"LR": "Liberia",
|
||||
"LS": "Lesotho",
|
||||
"LT": "Lithuania",
|
||||
"LU": "Luxembourg",
|
||||
"LV": "Latvia",
|
||||
"LY": "Libyan Arab Jamahiriya",
|
||||
"MA": "Morocco",
|
||||
"MC": "Monaco",
|
||||
"MD": "Moldova",
|
||||
"ME": "Montenegro",
|
||||
"MF": "Saint Martin (French part)",
|
||||
"MG": "Madagascar",
|
||||
"MH": "Marshall Islands",
|
||||
"MK": "Macedonia",
|
||||
"ML": "Mali",
|
||||
"MM": "Myanmar",
|
||||
"MN": "Mongolia",
|
||||
"MO": "Macao",
|
||||
"MP": "Northern Mariana Islands",
|
||||
"MQ": "Martinique",
|
||||
"MR": "Mauritania",
|
||||
"MS": "Montserrat",
|
||||
"MT": "Malta",
|
||||
"MU": "Mauritius",
|
||||
"MV": "Maldives",
|
||||
"MW": "Malawi",
|
||||
"MX": "Mexico",
|
||||
"MY": "Malaysia",
|
||||
"MZ": "Mozambique",
|
||||
"NA": "Namibia",
|
||||
"NC": "New Caledonia",
|
||||
"NE": "Niger",
|
||||
"NF": "Norfolk Island",
|
||||
"NG": "Nigeria",
|
||||
"NI": "Nicaragua",
|
||||
"NL": "Netherlands",
|
||||
"NO": "Norway",
|
||||
"NP": "Nepal",
|
||||
"NR": "Nauru",
|
||||
"NU": "Niue",
|
||||
"NZ": "New Zealand",
|
||||
"OM": "Oman",
|
||||
"PA": "Panama",
|
||||
"PE": "Peru",
|
||||
"PF": "French Polynesia",
|
||||
"PG": "Papua New Guinea",
|
||||
"PH": "Philippines",
|
||||
"PK": "Pakistan",
|
||||
"PL": "Poland",
|
||||
"PM": "Saint Pierre and Miquelon",
|
||||
"PN": "Pitcairn",
|
||||
"PR": "Puerto Rico",
|
||||
"PS": "Palestinian Territory",
|
||||
"PT": "Portugal",
|
||||
"PW": "Palau",
|
||||
"PY": "Paraguay",
|
||||
"QA": "Qatar",
|
||||
"RE": "Reunion",
|
||||
"RO": "Romania",
|
||||
"RS": "Serbia",
|
||||
"RU": "Russian Federation",
|
||||
"RW": "Rwanda",
|
||||
"SA": "Saudi Arabia",
|
||||
"SB": "Solomon Islands",
|
||||
"SC": "Seychelles",
|
||||
"SD": "Sudan",
|
||||
"SE": "Sweden",
|
||||
"SG": "Singapore",
|
||||
"SH": "St. Helena and Dependencies",
|
||||
"SI": "Slovenia",
|
||||
"SJ": "Svalbard and Jan Mayen",
|
||||
"SK": "Slovakia",
|
||||
"SL": "Sierra Leone",
|
||||
"SM": "San Marino",
|
||||
"SN": "Senegal",
|
||||
"SO": "Somalia",
|
||||
"SR": "Suriname",
|
||||
"ST": "Sao Tome and Principe",
|
||||
"SV": "El Salvador",
|
||||
"SY": "Syrian Arab Republic",
|
||||
"SZ": "Swaziland",
|
||||
"TC": "Turks and Caicos Islands",
|
||||
"TD": "Chad",
|
||||
"TF": "French Southern Territories",
|
||||
"TG": "Togo",
|
||||
"TH": "Thailand",
|
||||
"TJ": "Tajikistan",
|
||||
"TK": "Tokelau",
|
||||
"TL": "Timor-Leste",
|
||||
"TM": "Turkmenistan",
|
||||
"TN": "Tunisia",
|
||||
"TO": "Tonga",
|
||||
"TR": "Turkey",
|
||||
"TT": "Trinidad and Tobago",
|
||||
"TV": "Tuvalu",
|
||||
"TW": "Taiwan",
|
||||
"TZ": "Tanzania",
|
||||
"UA": "Ukraine",
|
||||
"UG": "Uganda",
|
||||
"UM": "U.S. Minor Outlying Islands",
|
||||
"US": "United States",
|
||||
"UY": "Uruguay",
|
||||
"UZ": "Uzbekistan",
|
||||
"VA": "Vatican City State",
|
||||
"VC": "St. Vincent and Grenadines",
|
||||
"VE": "Venezuela",
|
||||
"VG": "Virgin Islands, British",
|
||||
"VI": "Virgin Islands, U.S.",
|
||||
"VN": "Viet Nam",
|
||||
"VU": "Vanuatu",
|
||||
"WF": "Wallis and Futuna",
|
||||
"WS": "Samoa",
|
||||
"YE": "Yemen",
|
||||
"YT": "Mayotte",
|
||||
"ZA": "South Africa",
|
||||
"ZM": "Zambia",
|
||||
"ZW": "Zimbabwe"
|
||||
}
|
||||
@@ -0,0 +1,729 @@
|
||||
{
|
||||
"$id": "https://openwrt.org/wifi.device.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "OpenWrt WiFi Device Schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"acs_chan_bias": {
|
||||
"description": "Can be used to increase (or decrease) the likelihood of a specific channel to be selected by the ACS algorithm",
|
||||
"type": "string"
|
||||
},
|
||||
"acs_exclude_dfs": {
|
||||
"description": "Exclude DFS channels from ACS",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"airtime_mode": {
|
||||
"description": "Set the airtime policy operating mode",
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 3
|
||||
},
|
||||
"antenna_gain": {
|
||||
"description": "Reduction in antenna gain from regulatory maximum in dBi",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"assoc_sa_query_max_timeout": {
|
||||
"description": "Association SA Query maximum timeout",
|
||||
"type": "number"
|
||||
},
|
||||
"assoc_sa_query_retry_timeout": {
|
||||
"description": "Association SA Query retry timeout",
|
||||
"type": "number"
|
||||
},
|
||||
"auth_cache": {
|
||||
"type": "alias",
|
||||
"default": "okc"
|
||||
},
|
||||
"background_radar": {
|
||||
"type": "alias",
|
||||
"default": "enable_background_radar"
|
||||
},
|
||||
"band": {
|
||||
"description": "The wireless band thatthe radio shall operate on",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"2g",
|
||||
"5g",
|
||||
"6g",
|
||||
"60g"
|
||||
]
|
||||
},
|
||||
"basic_rate": {
|
||||
"type": "alias",
|
||||
"default": "basic_rates"
|
||||
},
|
||||
"basic_rates": {
|
||||
"description": "Set the supported basic rates. Each basic_rate is measured in kb/s. This option only has an effect on ap and adhoc wifi-ifaces. ",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"beacon_int": {
|
||||
"description": "Set the beacon interval. This is the time interval between beacon frames, measured in units of 1.024 ms. hostapd permits this to be set between 15 and 65535. This option only has an effect on ap and adhoc wifi-ifaces",
|
||||
"type": "number",
|
||||
"default": 100,
|
||||
"minimum": 15,
|
||||
"maximum": 65535
|
||||
},
|
||||
"beacon_rate": {
|
||||
"description": "Beacon frame TX rate configuration",
|
||||
"type": "string"
|
||||
},
|
||||
"beamformee_antennas": {
|
||||
"description": "Beamformee antenna override",
|
||||
"type": "number",
|
||||
"default": 4
|
||||
},
|
||||
"beamformer_antennas": {
|
||||
"description": "Beamformer antenna override",
|
||||
"type": "number",
|
||||
"default": 4
|
||||
},
|
||||
"bssid": {
|
||||
"description": "Overrides the MAC address used for the Wi-Fi interface. Warning: if the MAC address specified is a multicast address, this override will fail silently. To avoid this problem, ensure that the mac address specified is a valid unicast mac address",
|
||||
"type": "string"
|
||||
},
|
||||
"cell_density": {
|
||||
"description": "Configures data rates based on the coverage cell density. Normal configures basic rates to 6, 12, 24 Mbps if legacy_rates is 0, else to 5.5, 11 Mbps. High configures basic rates to 12, 24 Mbps if legacy_rates is 0, else to the 11 Mbps rate. Very High configures 24 Mbps as the basic rate. Supported rates lower than the minimum basic rate are not offered. The basic_rate and supported_rates options overrides this option. 0 = Disabled, 1 = Normal, 2 = High, 3 = Very High",
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 3
|
||||
},
|
||||
"chanbw": {
|
||||
"description": "Specifies a narrow channel width in MHz, possible values are: 5, 10, 20",
|
||||
"type": "number",
|
||||
"enum": [ 5, 10, 20 ]
|
||||
},
|
||||
"channel": {
|
||||
"description": "Specifies the wireless channel. “auto” defaults to the lowest available channel, or utilizes the ACS algorithm depending on hardware/driver support",
|
||||
"type": "string"
|
||||
},
|
||||
"channels": {
|
||||
"type": "alias",
|
||||
"default": "chanlist"
|
||||
},
|
||||
"channel_list": {
|
||||
"type": "alias",
|
||||
"default": "chanlist"
|
||||
},
|
||||
"chanlist": {
|
||||
"description": "Use specific channels, when channel is in “auto” mode. This option allows hostapd to select one of the provided channels when a channel should be automatically selected. Channels can be provided as range using hyphen ('-') or individual channels can be specified by space (' ') separated values",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"country": {
|
||||
"type": "alias",
|
||||
"default": "country_code"
|
||||
},
|
||||
"country3": {
|
||||
"description": "The third octet of the Country String (dot11CountryString)",
|
||||
"type": "string"
|
||||
},
|
||||
"country_code": {
|
||||
"description": "Specifies the country code, affects the available channels and transmission powers. For types mac80211 and broadcom a two letter country code is used (EN or DE). The madwifi driver expects a numeric code",
|
||||
"type": "string"
|
||||
},
|
||||
"country_ie": {
|
||||
"type": "alias",
|
||||
"default": "ieee80211d"
|
||||
},
|
||||
"disabled": {
|
||||
"description": "When set to 1, wireless network is disabled",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"distance": {
|
||||
"description": "Distance between the ap and the furthest client in meters",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"doth": {
|
||||
"type": "alias",
|
||||
"default": "ieee80211h"
|
||||
},
|
||||
"dsss_cck_40": {
|
||||
"description": "DSSS/CCK Mode in 40 MHz allowed in Beacon, Measurement Pilot and Probe Response frames",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"enable_background_radar": {
|
||||
"description": "This feature allows CAC to be run on dedicated radio RF chains",
|
||||
"type": "boolean"
|
||||
},
|
||||
"frag": {
|
||||
"description": "Fragmentation threshold",
|
||||
"type": "number"
|
||||
},
|
||||
"greenfield": {
|
||||
"description": "Receive Greenfield - treats pre-80211n traffic as noise",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"he_bss_color": {
|
||||
"description": "BSS color to be announced",
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 128,
|
||||
"default": 128
|
||||
},
|
||||
"he_bss_color_enabled": {
|
||||
"description": "Enable BSS color",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"he_default_pe_duration": {
|
||||
"description": "The duration of PE field in an HE PPDU in us",
|
||||
"type": "number",
|
||||
"default": 4,
|
||||
"enum": [ 4, 8, 12, 16 ]
|
||||
},
|
||||
"he_mu_beamformer": {
|
||||
"description": "HE multiple user beamformer support",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"he_mu_edca_ac_be_aci": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"he_mu_edca_ac_be_aifsn": {
|
||||
"type": "number",
|
||||
"default": 8
|
||||
},
|
||||
"he_mu_edca_ac_be_ecwmax": {
|
||||
"type": "number",
|
||||
"default": 10
|
||||
},
|
||||
"he_mu_edca_ac_be_ecwmin": {
|
||||
"type": "number",
|
||||
"default": 9
|
||||
},
|
||||
"he_mu_edca_ac_be_timer": {
|
||||
"type": "number",
|
||||
"default": 255
|
||||
},
|
||||
"he_mu_edca_ac_bk_aci": {
|
||||
"type": "number",
|
||||
"default": 1
|
||||
},
|
||||
"he_mu_edca_ac_bk_aifsn": {
|
||||
"type": "number",
|
||||
"default": 15
|
||||
},
|
||||
"he_mu_edca_ac_bk_ecwmax": {
|
||||
"type": "number",
|
||||
"default": 10
|
||||
},
|
||||
"he_mu_edca_ac_bk_ecwmin": {
|
||||
"type": "number",
|
||||
"default": 9
|
||||
},
|
||||
"he_mu_edca_ac_bk_timer": {
|
||||
"type": "number",
|
||||
"default": 255
|
||||
},
|
||||
"he_mu_edca_ac_vi_aci": {
|
||||
"type": "number",
|
||||
"default": 2
|
||||
},
|
||||
"he_mu_edca_ac_vi_aifsn": {
|
||||
"type": "number",
|
||||
"default": 5
|
||||
},
|
||||
"he_mu_edca_ac_vi_ecwmax": {
|
||||
"type": "number",
|
||||
"default": 7
|
||||
},
|
||||
"he_mu_edca_ac_vi_ecwmin": {
|
||||
"type": "number",
|
||||
"default": 5
|
||||
},
|
||||
"he_mu_edca_ac_vi_timer": {
|
||||
"type": "number",
|
||||
"default": 255
|
||||
},
|
||||
"he_mu_edca_ac_vo_aci": {
|
||||
"type": "number",
|
||||
"default": 3
|
||||
},
|
||||
"he_mu_edca_ac_vo_aifsn": {
|
||||
"type": "number",
|
||||
"default": 5
|
||||
},
|
||||
"he_mu_edca_ac_vo_ecwmax": {
|
||||
"type": "number",
|
||||
"default": 7
|
||||
},
|
||||
"he_mu_edca_ac_vo_ecwmin": {
|
||||
"type": "number",
|
||||
"default": 5
|
||||
},
|
||||
"he_mu_edca_ac_vo_timer": {
|
||||
"type": "number",
|
||||
"default": 255
|
||||
},
|
||||
"he_mu_edca_qos_info_param_count": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"he_mu_edca_qos_info_q_ack": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"he_mu_edca_qos_info_queue_request": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"he_mu_edca_qos_info_txop_request": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"he_oper_centr_freq_seg0_idx": {
|
||||
"description": "",
|
||||
"type": "string"
|
||||
},
|
||||
"he_oper_chwidth": {
|
||||
"description": "",
|
||||
"type": "string"
|
||||
},
|
||||
"he_6ghz_reg_pwr_type": {
|
||||
"description": "This config is to set the 6 GHz Access Point type.",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 4,
|
||||
"default": 0
|
||||
},
|
||||
"he_rts_threshold": {
|
||||
"description": "Duration of STA transmission",
|
||||
"type": "number",
|
||||
"default": 1023
|
||||
},
|
||||
"he_spr_non_srg_obss_pd_max_offset": {
|
||||
"description": "",
|
||||
"type": "number"
|
||||
},
|
||||
"he_spr_psr_enabled": {
|
||||
"description": "",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"he_spr_sr_control": {
|
||||
"description": "",
|
||||
"type": "number",
|
||||
"default": 3
|
||||
},
|
||||
"he_su_beamformee": {
|
||||
"description": "",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"he_su_beamformer": {
|
||||
"description": "",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"he_twt_required": {
|
||||
"description": "",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"hostapd_options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ht_coex": {
|
||||
"description": "Disable honoring 40 MHz intolerance in coexistence flags of stations",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"htc_vht": {
|
||||
"description": "STA supports receiving a VHT variant HT Control field",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"htmode": {
|
||||
"description": "Specifies the high throughput mode",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"NOHT", "HT20", "HT40-", "HT40+", "HT40",
|
||||
"VHT20", "VHT40", "VHT80", "VHT160",
|
||||
"HE20", "HE40", "HE80", "HE160",
|
||||
"EHT20", "EHT40", "EHT80", "EHT160", "EHT320" ]
|
||||
},
|
||||
"hwmode": {
|
||||
"type": "alias",
|
||||
"default": "hw_mode"
|
||||
},
|
||||
"hw_mode": {
|
||||
"description": "Legacy way, use the band property instead",
|
||||
"type": "string",
|
||||
"enum": [ "11a", "11b", "11g", "11ad" ]
|
||||
},
|
||||
"ieee80211d": {
|
||||
"description": "Enables IEEE 802.11d country IE (information element) advertisement in beacon and probe response frames. This IE contains the country code and channel/power map. Requires country",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"ieee80211h": {
|
||||
"description": "This enables radar detection and DFS support",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"ieee80211w": {
|
||||
"description": "Whether management frame protection (MFP) is enabled",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
},
|
||||
"ieee80211w_max_timeout": {
|
||||
"type": "alias",
|
||||
"default": "assoc_sa_query_max_timeout"
|
||||
},
|
||||
"ieee80211w_mgmt_cipher": {
|
||||
"description": "Cypher used for MFP",
|
||||
"type": "string"
|
||||
},
|
||||
"ieee80211w_retry_timeout": {
|
||||
"type": "alias",
|
||||
"default": "assoc_sa_query_retry_timeout"
|
||||
},
|
||||
"ifname_prefix": {
|
||||
"description": "Default ifname prefix for this radio",
|
||||
"type": "string"
|
||||
},
|
||||
"iface_max_num_sta": {
|
||||
"description": "Limits the maximum allowed number of associated clients",
|
||||
"type": "number"
|
||||
},
|
||||
"ldpc": {
|
||||
"description": " LDPC (Low-Density Parity-Check code) capability ",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"legacy_rates": {
|
||||
"description": "Allow legacy 802.11b data rates (used by cell_density)",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"local_pwr_constraint": {
|
||||
"description": "Add Power Constraint element to Beacon and Probe Response frame",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"log_80211": {
|
||||
"description": "Enable IEEE 802.11 logging",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"log_8021x": {
|
||||
"description": "Enable IEEE 802.1X logging",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"log_driver": {
|
||||
"description": "Enable driver interface logging",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"log_iapp": {
|
||||
"description": "Enable iapp logging",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"log_level": {
|
||||
"description": "Log severity",
|
||||
"type": "number",
|
||||
"default": 2,
|
||||
"minimum": 0,
|
||||
"maximum": 4
|
||||
},
|
||||
"log_mlme": {
|
||||
"description": "Enable MLME logging",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"log_radius": {
|
||||
"description": "Enable Radius logging",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"log_wpa": {
|
||||
"description": "Enable WPA logging",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"logger_stdout": {
|
||||
"description": "Log to stdout",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"logger_stdout_level": {
|
||||
"description": "Log severity",
|
||||
"type": "number",
|
||||
"default": 2,
|
||||
"minimum": 0,
|
||||
"maximum": 4
|
||||
},
|
||||
"logger_syslog": {
|
||||
"description": "Log to syslog",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"logger_syslog_level": {
|
||||
"description": "Syslog severity",
|
||||
"type": "number",
|
||||
"default": 2,
|
||||
"minimum": 0,
|
||||
"maximum": 4
|
||||
},
|
||||
"macaddr": {
|
||||
"type": "alias",
|
||||
"default": "bssid"
|
||||
},
|
||||
"macaddr_base": {
|
||||
"type": "string",
|
||||
"description": "Base MAC address used for deriving interface MAC addresses"
|
||||
},
|
||||
"max_amsdu": {
|
||||
"description": "Maximum A-MSDU length of 7935 octects (3839 octets if option set to 0)",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"maxassoc": {
|
||||
"type": "alias",
|
||||
"default": "iface_max_num_sta"
|
||||
},
|
||||
"mbssid": {
|
||||
"description": "Multiple BSSID Advertisement in IEEE 802.11ax IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces on a common radio transmitting individual Beacon frames, those interfaces can form a set with a common Beacon frame transmitted for all Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection",
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
},
|
||||
"min_tx_power": {
|
||||
"description": "Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"mu_beamformee": {
|
||||
"description": "Supports operation as an MU beamformee",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"mu_beamformer": {
|
||||
"description": " Supports operation as an MU beamformer",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"multiple_bssid": {
|
||||
"type": "alias",
|
||||
"default": "mbssid"
|
||||
},
|
||||
"num_global_macaddr": {
|
||||
"description": "The number of MACs that this radio can use",
|
||||
"type": "number",
|
||||
"default": 1
|
||||
},
|
||||
"no_probe_resp_if_max_sta": {
|
||||
"description": "Do not answer probe requests if iface_max_num_sta was reached",
|
||||
"type": "boolean"
|
||||
},
|
||||
"noscan": {
|
||||
"description": "Do not scan for overlapping BSSs in HT40+/- mode.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"okc": {
|
||||
"description": "Enable Opportunistic Key Caching",
|
||||
"type": "boolean"
|
||||
},
|
||||
"path": {
|
||||
"description": "Alternative to phy used to identify the device based paths in /sys/devices",
|
||||
"type": "string"
|
||||
},
|
||||
"phy": {
|
||||
"description": "Name of the phy, as described in board.json",
|
||||
"type": "string"
|
||||
},
|
||||
"radio": {
|
||||
"description": "Index of the phy radio (for multi-radio PHYs)",
|
||||
"type": "number",
|
||||
"default": -1
|
||||
},
|
||||
"reg_power_type": {
|
||||
"type": "alias",
|
||||
"default": "he_6ghz_reg_pwr_type"
|
||||
},
|
||||
"require_mode": {
|
||||
"description": "Sets the minimum client capability level mode that connecting clients must support to be allowed to connect",
|
||||
"type": "string",
|
||||
"enum": [ "ht", "ac", "ax" ]
|
||||
},
|
||||
"rnr_beacon": {
|
||||
"description": "",
|
||||
"type": "string"
|
||||
},
|
||||
"rsn_preauth": {
|
||||
"description": "Enable IEEE 802.11i/RSN/WPA2 pre-authentication",
|
||||
"type": "boolean"
|
||||
},
|
||||
"rssi_ignore_probe_request": {
|
||||
"description": "Ignore Probe Request frames if RSSI is below given threshold (in dBm)",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"rssi_reject_assoc_rssi": {
|
||||
"description": "Reject STA association if RSSI is below given threshold (in dBm)",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"rts": {
|
||||
"description": "Override the RTS/CTS threshold",
|
||||
"type": "number"
|
||||
},
|
||||
"rts_threshold": {
|
||||
"description": "RTS/CTS threshold",
|
||||
"type": "number",
|
||||
"minimum": -1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"rx_antenna_pattern": {
|
||||
"description": "Rx antenna pattern does not change during the lifetime of an association",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"rx_stbc": {
|
||||
"description": "Supports reception of PPDUs using STBC",
|
||||
"type": "number",
|
||||
"default": 3,
|
||||
"minimum": 0,
|
||||
"maximum": 4
|
||||
},
|
||||
"rxantenna": {
|
||||
"description": "Specifies the antenna for receiving, the value may be driver specific, usually it is 1 for the first and 2 for the second antenna. Specifying 0 enables automatic selection by the driver if supported. This option has no effect if diversity is enabled",
|
||||
"type": "number"
|
||||
},
|
||||
"rxldpc": {
|
||||
"description": "Supports receiving LDPC coded pkts",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"short_gi_160": {
|
||||
"description": "Short GI for 160 MHz",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"short_gi_20": {
|
||||
"description": "Short GI for 20 MHz",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"short_gi_40": {
|
||||
"description": "Short GI for 40 MHz",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"short_gi_80": {
|
||||
"description": "Short GI for 80 MHz",
|
||||
"type": "boolean"
|
||||
},
|
||||
"spectrum_mgmt_required": {
|
||||
"description": "Set Spectrum Management subfield in the Capability Information field",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"stationary_ap": {
|
||||
"description": "Stationary AP config indicates that the AP doesn't move hence location data can be considered as always up to date.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"su_beamformee": {
|
||||
"description": "Single user beamformee",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"su_beamformer": {
|
||||
"description": "Single user beamformer",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"supported_rates": {
|
||||
"description": "Set the supported data rates. Each supported rate is measured in kb/s. This option only has an effect on ap and adhoc wifi-ifaces. This must be a superset of the rates set in basic_rate. The minimum basic rate should also be the minimum supported rate. It is recommended to use the cell_density option instead",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"tx_antenna_pattern": {
|
||||
"description": "Tx antenna pattern does not change during the lifetime of an association",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"tx_burst": {
|
||||
"type": "alias",
|
||||
"default": "tx_queue_data2_burst"
|
||||
},
|
||||
"tx_queue_data2_burst": {
|
||||
"description": "",
|
||||
"type": "number"
|
||||
},
|
||||
"tx_stbc": {
|
||||
"description": "Transmit STBC (Space-Time Block Coding)",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"tx_stbc_2by1": {
|
||||
"description": "Supports transmission of at least 2×1 STBC",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"txantenna": {
|
||||
"description": "Specifies the antenna for transmitting, values are identical to rxantenna",
|
||||
"type": "number"
|
||||
},
|
||||
"txpower": {
|
||||
"description": "Specifies the maximum desired transmission power in dBm. The actual txpower used depends on regulatory requirements",
|
||||
"type": "number"
|
||||
},
|
||||
"vht160": {
|
||||
"description": "Supported channel widths. 0 == 160MHz and 80+80 MHz not supported, 1 == 160 MHz supported, 2 == 160MHz and 80+80 MHz supported",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 2,
|
||||
"default": 2
|
||||
},
|
||||
"vht_link_adapt": {
|
||||
"description": "TA supports link adaptation using VHT variant HT Control field",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 3
|
||||
},
|
||||
"vht_max_a_mpdu_len_exp": {
|
||||
"description": "Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv",
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 7
|
||||
},
|
||||
"vht_max_mpdu": {
|
||||
"description": "Maximum MPDU length",
|
||||
"type": "number",
|
||||
"enum": [ 3895, 7991, 11454 ],
|
||||
"default": 11454
|
||||
},
|
||||
"vht_txop_ps": {
|
||||
"description": "VHT TXOP PS mode",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$id": "https://openwrt.org/wifi.station.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "OpenWrt WiFi Station Schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mac": {
|
||||
"description": "The stations MAC",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
"description": "The passphrase that shall be used",
|
||||
"type": "string"
|
||||
},
|
||||
"vid": {
|
||||
"description": "The VLAN Id used by the station",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$id": "https://openwrt.org/wifi.vlan.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "OpenWrt WiFi VLAN Schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "VLAN name",
|
||||
"type": "string"
|
||||
},
|
||||
"vid": {
|
||||
"description": "VLAN ID",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,602 @@
|
||||
'use strict';
|
||||
|
||||
import * as nl80211 from 'nl80211';
|
||||
import * as libubus from 'ubus';
|
||||
import { readfile, stat } from "fs";
|
||||
|
||||
let wifi_devices = json(readfile('/usr/share/wifi_devices.json'));
|
||||
let countries = json(readfile('/usr/share/iso3166.json'));
|
||||
let board_data = json(readfile('/etc/board.json'));
|
||||
|
||||
export let phys = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, nl80211.const.NLM_F_DUMP, { split_wiphy_dump: true });
|
||||
let interfaces = nl80211.request(nl80211.const.NL80211_CMD_GET_INTERFACE, nl80211.const.NLM_F_DUMP);
|
||||
|
||||
let ubus = libubus.connect();
|
||||
let wireless_status = ubus.call('network.wireless', 'status');
|
||||
|
||||
function find_phy(wiphy) {
|
||||
for (let k, phy in phys)
|
||||
if (phy.wiphy == wiphy)
|
||||
return phy;
|
||||
return null;
|
||||
}
|
||||
|
||||
function get_noise(iface) {
|
||||
for (let phy in phys) {
|
||||
let channels = nl80211.request(nl80211.const.NL80211_CMD_GET_SURVEY, nl80211.const.NLM_F_DUMP, { dev: iface.ifname });
|
||||
for (let k, channel in channels)
|
||||
if (channel.survey_info.frequency == iface.wiphy_freq)
|
||||
return channel.survey_info.noise;
|
||||
}
|
||||
|
||||
return -100;
|
||||
}
|
||||
|
||||
function get_country(iface) {
|
||||
let reg = nl80211.request(nl80211.const.NL80211_CMD_GET_REG, 0, { dev: iface.ifname });
|
||||
|
||||
return reg.reg_alpha2 ?? '';
|
||||
}
|
||||
|
||||
function get_max_power(iface) {
|
||||
let phy = find_phy(iface.wiphy);
|
||||
|
||||
for (let k, band in phy.wiphy_bands)
|
||||
if (band)
|
||||
for (let freq in band.freqs)
|
||||
if (freq.freq == iface.wiphy_freq)
|
||||
return freq.max_tx_power;;
|
||||
return 0;
|
||||
}
|
||||
|
||||
function get_hardware_id(iface) {
|
||||
let hw = {
|
||||
type: 'nl80211',
|
||||
id: 'Generic MAC80211',
|
||||
power_offset: 0,
|
||||
channel_offset: 0,
|
||||
};
|
||||
|
||||
let path = `/sys/class/ieee80211/phy${iface.wiphy}/device/`;
|
||||
if (stat(path + 'vendor')) {
|
||||
let data = [];
|
||||
for (let lookup in [ 'vendor', 'device', 'subsystem_vendor', 'subsystem_device' ])
|
||||
push(data, trim(readfile(path + lookup), '\n'));
|
||||
|
||||
for (let device in wifi_devices.pci) {
|
||||
let match = 0;
|
||||
for (let i = 0; i < 4; i++)
|
||||
if (lc(data[i]) == lc(device[i]))
|
||||
match++;
|
||||
if (match == 4) {
|
||||
hw.type = `${data[0]}:${data[1]} ${data[2]}:${data[3]}`;
|
||||
hw.power_offset = device[4];
|
||||
hw.channel_offset = device[5];
|
||||
hw.id = `${device[6]} ${device[7]}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let compatible = trim(readfile(`/sys/class/net/${iface.ifname}/device/of_node/compatible`), '\n');
|
||||
if (compatible && wifi_devices.compatible[compatible]) {
|
||||
hw.id = wifi_devices.compatible[compatible][0] + ' ' + wifi_devices.compatible[compatible][1];
|
||||
hw.compatible = compatible;
|
||||
hw.type = 'embedded';
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
const iftypes = [
|
||||
'Unknown', 'Ad-Hoc', 'Client', 'Master', 'Master (VLAN)',
|
||||
'WDS', 'Monitor', 'Mesh Point', 'P2P Client', 'P2P Go',
|
||||
];
|
||||
|
||||
export let ifaces = {};
|
||||
for (let k, v in interfaces) {
|
||||
let iface = ifaces[v.ifname] = v;
|
||||
|
||||
iface.mode = iftypes[iface.iftype] ?? 'unknonw',
|
||||
iface.noise = get_noise(iface);
|
||||
iface.country = get_country(iface);
|
||||
iface.max_power = get_max_power(iface);
|
||||
iface.assoclist = nl80211.request(nl80211.const.NL80211_CMD_GET_STATION, nl80211.const.NLM_F_DUMP, { dev: v.ifname }) ?? [];
|
||||
iface.hardware = get_hardware_id(iface);
|
||||
|
||||
iface.bss_info = ubus.call('hostapd', 'bss_info', { iface: v.ifname });
|
||||
if (!iface.bss_info)
|
||||
iface.bss_info = ubus.call('wpa_supplicant', 'bss_info', { iface: v.ifname });
|
||||
}
|
||||
|
||||
for (let radio, data in wireless_status)
|
||||
for (let k, v in data.interfaces) {
|
||||
if (!v.ifname || !ifaces[v.ifname])
|
||||
continue;
|
||||
|
||||
ifaces[v.ifname].ssid = v.config.ssid || v.config.mesh_id;
|
||||
ifaces[v.ifname].radio = data.config;
|
||||
|
||||
let bss_info = ifaces[v.ifname].bss_info;
|
||||
let owe_transition_ifname = bss_info?.owe_transition_ifname;
|
||||
|
||||
if (v.config.owe_transition && ifaces[owe_transition_ifname]) {
|
||||
ifaces[v.ifname].owe_transition_ifname = owe_transition_ifname;
|
||||
ifaces[owe_transition_ifname].ssid = v.config.ssid;
|
||||
ifaces[owe_transition_ifname].radio = data.config;
|
||||
ifaces[owe_transition_ifname].owe_transition_ifname = v.ifname
|
||||
}
|
||||
}
|
||||
|
||||
function format_channel(freq) {
|
||||
if (freq < 1000)
|
||||
return 0;
|
||||
if (freq == 2484)
|
||||
return 14;
|
||||
if (freq == 5935)
|
||||
return 2;
|
||||
if (freq < 2484)
|
||||
return (freq - 2407) / 5;
|
||||
if (freq >= 4910 && freq <= 4980)
|
||||
return (freq - 4000) / 5;
|
||||
if (freq < 5950)
|
||||
return (freq - 5000) / 5;
|
||||
if (freq <= 45000)
|
||||
return (freq - 5950) / 5;
|
||||
if (freq >= 58320 && freq <= 70200)
|
||||
return (freq - 56160) / 2160;
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
function format_band(freq) {
|
||||
if (freq == 5935)
|
||||
return '6';
|
||||
if (freq < 2484)
|
||||
return '2.4';
|
||||
if (freq < 5950)
|
||||
return '5';
|
||||
if (freq <= 45000)
|
||||
return '6';
|
||||
|
||||
return '60';
|
||||
}
|
||||
|
||||
function format_frequency(freq) {
|
||||
return freq ? sprintf('%.03f', freq / 1000.0) : 'unknown';
|
||||
}
|
||||
|
||||
function format_rate(rate) {
|
||||
return rate ? sprintf('%.01f', rate / 10.0) : 'unknown';
|
||||
}
|
||||
|
||||
function format_mgmt_key(key) {
|
||||
switch(+key) {
|
||||
case 1:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
return '802.1x';
|
||||
|
||||
case 2:
|
||||
return 'WPA PSK';
|
||||
|
||||
case 4:
|
||||
return 'FT PSK';
|
||||
|
||||
case 6:
|
||||
return 'WPA PSK2';
|
||||
|
||||
case 8:
|
||||
return 'SAE';
|
||||
|
||||
case 18:
|
||||
return 'OWE';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function assoc_flags(data) {
|
||||
const assoc_mhz = {
|
||||
width_40: 40,
|
||||
width_80: 80,
|
||||
width_80p80: '80+80',
|
||||
width_160: 160,
|
||||
width_320: 320,
|
||||
width_10: 10,
|
||||
width_5: 5
|
||||
};
|
||||
|
||||
let mhz = 'unknown';
|
||||
for (let k, v in assoc_mhz)
|
||||
if (data[k])
|
||||
mhz = v;
|
||||
|
||||
const assoc_flags = {
|
||||
mcs: {
|
||||
mcs: 'MCS',
|
||||
},
|
||||
vht_mcs: {
|
||||
vht_mcs: 'VHT-MCS',
|
||||
vht_nss: 'VHT-NSS',
|
||||
},
|
||||
he_mcs: {
|
||||
he_mcs: 'HE-MCS',
|
||||
he_nss: 'HE-NSS',
|
||||
he_gi: 'HE-GI',
|
||||
he_dcm: 'HE-DCM',
|
||||
},
|
||||
eht_mcs: {
|
||||
eht_mcs: 'EHT-MCS',
|
||||
eht_nss: 'EHT-NSS',
|
||||
eht_gi: 'EHT-GI',
|
||||
},
|
||||
};
|
||||
|
||||
let flags = [];
|
||||
for (let k, v in assoc_flags) {
|
||||
if (!data[k])
|
||||
continue;
|
||||
|
||||
let first = 0;
|
||||
for (let name, flag in v) {
|
||||
if (data[name] == null)
|
||||
continue;
|
||||
push(flags, `${flag} ${data[name]}`);
|
||||
if (!first++)
|
||||
push(flags, `${mhz}MHz`);
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
function dbm2mw(dbm) {
|
||||
const LOG10_MAGIC = 1.25892541179;
|
||||
let res = 1.0;
|
||||
let ip = dbm / 10;
|
||||
let fp = dbm % 10;
|
||||
|
||||
for (let k = 0; k < ip; k++)
|
||||
res *= 10;
|
||||
for (let k = 0; k < fp; k++)
|
||||
res *= LOG10_MAGIC;
|
||||
|
||||
return int(res);
|
||||
}
|
||||
|
||||
function dbm2quality(dbm) {
|
||||
let quality = dbm;
|
||||
|
||||
if (quality < -110)
|
||||
quality = -110;
|
||||
else if (quality > -40)
|
||||
quality = -40;
|
||||
quality += 110;
|
||||
|
||||
return quality;
|
||||
}
|
||||
|
||||
function hwmodelist(name) {
|
||||
const mode = { 'HT*': 'n', 'VHT*': 'ac', 'HE*': 'ax' };
|
||||
let iface = ifaces[name];
|
||||
let phy = board_data.wlan?.['phy' + iface.wiphy];
|
||||
if (!phy)
|
||||
return '';
|
||||
let htmodes = phy.info.bands[uc(iface.radio.band)].modes;
|
||||
let list = [];
|
||||
if (iface.radio.band == '2g' && 'NOHT' in htmodes)
|
||||
push(list, 'g/b');
|
||||
for (let k, v in mode)
|
||||
for (let htmode in htmodes)
|
||||
if (wildcard(htmode, k))
|
||||
push(list, v);
|
||||
|
||||
return join('/', reverse(uniq(list)));
|
||||
}
|
||||
|
||||
export function assoclist(dev) {
|
||||
let stations = ifaces[dev].assoclist;
|
||||
let ret = {};
|
||||
|
||||
for (let station in stations) {
|
||||
let sta = {
|
||||
mac: uc(station.mac),
|
||||
signal: station.sta_info.signal_avg,
|
||||
noise: ifaces[dev].noise,
|
||||
snr: station.sta_info.signal_avg - ifaces[dev].noise,
|
||||
inactive_time: station.sta_info.inactive_time,
|
||||
rx: {
|
||||
bitrate: format_rate(station.sta_info.rx_bitrate.bitrate),
|
||||
bitrate_raw: station.sta_info.rx_bitrate.bitrate,
|
||||
packets: station.sta_info.rx_packets,
|
||||
flags: assoc_flags(station.sta_info.rx_bitrate),
|
||||
},
|
||||
tx: {
|
||||
bitrate: format_rate(station.sta_info.tx_bitrate.bitrate),
|
||||
bitrate_raw: station.sta_info.tx_bitrate.bitrate,
|
||||
packets: station.sta_info.tx_packets,
|
||||
flags: assoc_flags(station.sta_info.tx_bitrate),
|
||||
},
|
||||
expected_throughput: station.sta_info.expected_throughput ?? 'unknown',
|
||||
};
|
||||
ret[sta.mac] = sta;
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
export function freqlist(name) {
|
||||
const freq_flags = {
|
||||
no_10mhz: 'NO_10MHZ',
|
||||
no_20mhz: 'NO_20MHZ',
|
||||
no_ht40_minus: 'NO_HT40-',
|
||||
no_ht40_plus: 'NO_HT40+',
|
||||
no_80mhz: 'NO_80MHZ',
|
||||
no_160mhz: 'NO_160MHZ',
|
||||
indoor_only: 'INDOOR_ONLY',
|
||||
no_ir: 'NO_IR',
|
||||
no_he: 'NO_HE',
|
||||
radar: 'RADAR_DETECTION',
|
||||
};
|
||||
|
||||
let iface = ifaces[name];
|
||||
let phy = find_phy(iface.wiphy);
|
||||
let channels = [];
|
||||
|
||||
for (let k, band in phy.wiphy_bands) {
|
||||
if (!band)
|
||||
continue;
|
||||
|
||||
let band_name = format_band(band.freqs[0].freq);
|
||||
for (let freq in band.freqs) {
|
||||
if (freq.disabled)
|
||||
continue;
|
||||
|
||||
let channel = {
|
||||
freq: format_frequency(freq.freq),
|
||||
band: band_name,
|
||||
channel: format_channel(freq.freq),
|
||||
flags: [],
|
||||
active: iface.wiphy_freq == freq.freq,
|
||||
};
|
||||
|
||||
for (let k, v in freq_flags)
|
||||
if (freq[k])
|
||||
push(channel.flags, v);
|
||||
|
||||
push(channels, channel);
|
||||
}
|
||||
}
|
||||
|
||||
return channels;
|
||||
};
|
||||
|
||||
export function info(name) {
|
||||
let order = [];
|
||||
for (let iface, data in ifaces)
|
||||
push(order, iface);
|
||||
|
||||
let list = [];
|
||||
for (let iface in sort(order)) {
|
||||
if (name && iface != name)
|
||||
continue;
|
||||
let data = ifaces[iface];
|
||||
let dev = {
|
||||
iface,
|
||||
ssid: data.ssid,
|
||||
mac: data.mac,
|
||||
mode: data.mode,
|
||||
channel: format_channel(data.wiphy_freq),
|
||||
freq: format_frequency(data.wiphy_freq),
|
||||
htmode: data.radio.htmode,
|
||||
center_freq1: format_channel(data.center_freq1) || 'unknown',
|
||||
center_freq2: format_channel(data.center_freq2) || 'unknown',
|
||||
txpower: data.wiphy_tx_power_level / 100,
|
||||
noise: data.noise,
|
||||
signal: 0,
|
||||
bitrate: 0,
|
||||
encryption: 'unknown',
|
||||
hwmode: hwmodelist(iface),
|
||||
phy: 'phy' + data.wiphy,
|
||||
vaps: 'no',
|
||||
hw_type: data.hardware.type,
|
||||
hw_id: data.hardware.id,
|
||||
power_offset: data.hardware.power_offset || 'none',
|
||||
channel_offset: data.hardware.channel_offset || 'none',
|
||||
};
|
||||
|
||||
let phy = find_phy(data.wiphy);
|
||||
for (let limit in phy.interface_combinations[0]?.limits)
|
||||
if (limit.types?.ap && limit.max > 1)
|
||||
dev.vaps = 'yes';
|
||||
|
||||
if (data.bss_info) {
|
||||
if (data.bss_info.wpa_key_mgmt && data.bss_info.wpa_pairwise)
|
||||
dev.encryption = `${replace(data.bss_info.wpa_key_mgmt, ' ', ' / ')} (${data.bss_info.wpa_pairwise})`;
|
||||
else if (data.owe_transition_ifname)
|
||||
dev.encryption = 'none (OWE transition)';
|
||||
else
|
||||
dev.encryption = 'none';
|
||||
}
|
||||
|
||||
let stations = assoclist(iface);
|
||||
for (let k, station in stations) {
|
||||
dev.signal += station.signal;
|
||||
dev.bitrate += station.tx.bitrate_raw;
|
||||
}
|
||||
dev.signal /= length(data.assoclist) || 1;
|
||||
dev.bitrate /= length(data.assoclist) || 1;
|
||||
dev.bitrate = format_rate(dev.bitrate);
|
||||
dev.quality = dbm2quality(dev.signal);
|
||||
|
||||
if (data.owe_transition_ifname)
|
||||
dev.owe_transition_ifname = data.owe_transition_ifname;
|
||||
|
||||
push(list, dev);
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
export function htmodelist(name) {
|
||||
let iface = ifaces[name];
|
||||
let phy = board_data.wlan?.['phy' + iface.wiphy];
|
||||
if (!phy)
|
||||
return [];
|
||||
|
||||
return filter(phy.info.bands[uc(iface.radio.band)].modes, (v) => v != 'NOHT');
|
||||
};
|
||||
|
||||
export function txpowerlist(name) {
|
||||
let iface = ifaces[name];
|
||||
let max_power = iface.max_power / 100;
|
||||
let match = iface.wiphy_tx_power_level / 100;
|
||||
let list = [];
|
||||
|
||||
for (let power = 0; power <= max_power; power++) {
|
||||
let txpower = {
|
||||
dbm: power,
|
||||
mw: dbm2mw(power),
|
||||
active: power == match,
|
||||
};
|
||||
push(list, txpower);
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
export function countrylist(dev) {
|
||||
let iface = ifaces[dev];
|
||||
|
||||
let list = {
|
||||
active: iface.country,
|
||||
countries,
|
||||
};
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
export function scan(dev) {
|
||||
const rsn_cipher = [ 'NONE', 'WEP-40', 'TKIP', 'WRAP', 'CCMP', 'WEP-104', 'AES-OCB', 'CKIP', 'GCMP', 'GCMP-256', 'CCMP-256' ];
|
||||
const ht_chan_offset = [ 'no secondary', 'above', '[reserved]', 'below' ];
|
||||
const vht_chan_width = [ '20 or 40 MHz', '80 MHz', '80+80 MHz', '160 MHz' ];
|
||||
const ht_chan_width = [ '20 MHz', '40 MHz or higher' ];
|
||||
const SCAN_FLAG_AP = (1<<2);
|
||||
|
||||
let params = {
|
||||
dev,
|
||||
scan_flags: SCAN_FLAG_AP,
|
||||
scan_ssids: [ '' ],
|
||||
};
|
||||
|
||||
let res = nl80211.request(nl80211.const.NL80211_CMD_TRIGGER_SCAN, 0, params);
|
||||
if (res === false) {
|
||||
printf("Unable to trigger scan: " + nl80211.error() + "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
res = nl80211.waitfor([
|
||||
nl80211.const.NL80211_CMD_NEW_SCAN_RESULTS,
|
||||
nl80211.const.NL80211_CMD_SCAN_ABORTED
|
||||
], 5000);
|
||||
|
||||
if (!res) {
|
||||
printf("Netlink error while awaiting scan results: " + nl80211.error() + "\n");
|
||||
exit(1);
|
||||
} else if (res.cmd == nl80211.const.NL80211_CMD_SCAN_ABORTED) {
|
||||
printf("Scan aborted by kernel\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let scan = nl80211.request(nl80211.const.NL80211_CMD_GET_SCAN, nl80211.const.NLM_F_DUMP, { dev });
|
||||
|
||||
let cells = [];
|
||||
for (let k, bss in scan) {
|
||||
bss = bss.bss;
|
||||
let cell = {
|
||||
bssid: uc(bss.bssid),
|
||||
frequency: format_frequency(bss.frequency),
|
||||
band: format_band(bss.frequency),
|
||||
channel: format_channel(bss.frequency),
|
||||
dbm: bss.signal_mbm / 100,
|
||||
|
||||
};
|
||||
|
||||
if (bss.capability & (1 << 1))
|
||||
cell.mode = 'Ad-Hoc';
|
||||
else if (bss.capability & (1 << 0))
|
||||
cell.mode = 'Master';
|
||||
else
|
||||
cell.mode = 'Mesh Point';
|
||||
|
||||
cell.quality = dbm2quality(cell.dbm);
|
||||
|
||||
for (let ie in bss.information_elements)
|
||||
switch(ie.type) {
|
||||
case 0:
|
||||
case 114:
|
||||
cell.ssid = ie.data;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
cell.country = substr(ie.data, 0, 2);
|
||||
break;
|
||||
|
||||
case 48:
|
||||
cell.crypto = {
|
||||
group: rsn_cipher[ord(ie.data, 5)] ?? '',
|
||||
pair: [],
|
||||
key_mgmt: [],
|
||||
};
|
||||
|
||||
let offset = 6;
|
||||
let count = ord(ie.data, offset);
|
||||
offset += 2;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
let key = rsn_cipher[ord(ie.data, offset + 3)];
|
||||
if (key)
|
||||
push(cell.crypto.pair, key);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
count = ord(ie.data, offset);
|
||||
offset += 2;
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
let key = format_mgmt_key(ord(ie.data, offset + 3));
|
||||
if (key)
|
||||
push(cell.crypto.key_mgmt, key);
|
||||
offset += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 61:
|
||||
cell.ht = {
|
||||
primary_channel: ord(ie.data, 0),
|
||||
secondary_chan_off: ht_chan_offset[ord(ie.data, 1) & 0x3],
|
||||
chan_width: ht_chan_width[(ord(ie.data, 1) & 0x4) >> 2],
|
||||
};
|
||||
break;
|
||||
|
||||
case 192:
|
||||
cell.vht = {
|
||||
chan_width: vht_chan_width[ord(ie.data, 0)],
|
||||
center_chan_1: ord(ie.data, 1),
|
||||
center_chan_2: ord(ie.data, 2),
|
||||
};
|
||||
break;
|
||||
};
|
||||
|
||||
|
||||
|
||||
push(cells, cell);
|
||||
}
|
||||
|
||||
return cells;
|
||||
};
|
||||
@@ -0,0 +1,481 @@
|
||||
'use strict';
|
||||
|
||||
import * as libuci from 'uci';
|
||||
import { md5 } from 'digest';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { append, append_raw, append_value, append_vars, comment, push_config, set_default, touch_file } from 'wifi.common';
|
||||
import * as netifd from 'wifi.netifd';
|
||||
import * as iface from 'wifi.iface';
|
||||
|
||||
function iface_setup(config) {
|
||||
switch(config.fixup) {
|
||||
case 'owe':
|
||||
config.ignore_broadcast_ssid = true;
|
||||
config.ssid = config.ssid + 'OWE';
|
||||
break;
|
||||
|
||||
case 'owe-transition':
|
||||
let ifname = config.ifname;
|
||||
config.ifname = config.owe_transition_ifname;
|
||||
config.owe_transition_ifname = ifname;
|
||||
config.owe_transition_ssid = config.ssid + 'OWE';
|
||||
config.encryption = 'none';
|
||||
config.ignore_broadcast_ssid = false;
|
||||
iface.prepare(config);
|
||||
break;
|
||||
}
|
||||
|
||||
comment('Setup interface: ' + config.ifname);
|
||||
|
||||
config.bridge = config.network_bridge;
|
||||
config.snoop_iface = config.network_ifname;
|
||||
if (!config.wds)
|
||||
config.wds_bridge = null;
|
||||
else
|
||||
config.wds_sta = true;
|
||||
|
||||
if (!config.idx)
|
||||
append('interface', config.ifname);
|
||||
else
|
||||
append('bss', config.ifname);
|
||||
|
||||
if (config.multicast_to_unicast || config.proxy_arp)
|
||||
config.ap_isolate = 1;
|
||||
|
||||
append('bssid', config.macaddr);
|
||||
|
||||
append_vars(config, [
|
||||
'ctrl_interface', 'ap_isolate', 'max_num_sta', 'ap_max_inactivity', 'airtime_bss_weight',
|
||||
'airtime_bss_limit', 'airtime_sta_weight', 'bss_load_update_period', 'chan_util_avg_period',
|
||||
'disassoc_low_ack', 'skip_inactivity_poll', 'ignore_broadcast_ssid', 'uapsd_advertisement_enabled',
|
||||
'utf8_ssid', 'multi_ap', 'ssid', 'tdls_prohibit', 'bridge', 'wds_sta', 'wds_bridge',
|
||||
'snoop_iface', 'vendor_elements', 'nas_identifier', 'radius_acct_interim_interval',
|
||||
'ocv', 'multicast_to_unicast', 'preamble', 'wmm_enabled', 'proxy_arp', 'per_sta_vif', 'mbo',
|
||||
'bss_transition', 'wnm_sleep_mode', 'wnm_sleep_mode_no_keys', 'qos_map_set', 'max_listen_int',
|
||||
'dtim_period',
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_authentication_server(config) {
|
||||
for (let server in config.auth_server_addr) {
|
||||
append('auth_server_addr', server);
|
||||
append_vars(config, [ 'auth_server_port', 'auth_server_shared_secret' ]);
|
||||
}
|
||||
|
||||
append_vars(config, [ 'radius_auth_req_attr' ]);
|
||||
}
|
||||
|
||||
function iface_accounting_server(config) {
|
||||
for (let server in config.acct_server_addr) {
|
||||
append('acct_server_addr', server);
|
||||
append_vars(config, [ 'acct_server_port', 'acct_server_shared_secret' ]);
|
||||
}
|
||||
|
||||
append_vars(config, [ 'radius_acct_req_attr' ]);
|
||||
}
|
||||
|
||||
function iface_auth_type(config) {
|
||||
iface.parse_encryption(config);
|
||||
|
||||
if (config.auth_type in [ 'sae', 'owe', 'eap2', 'eap192' ]) {
|
||||
config.ieee80211w = 2;
|
||||
config.sae_require_mfp = 1;
|
||||
config.sae_pwe = 2;
|
||||
}
|
||||
|
||||
if (config.auth_type in [ 'psk-sae', 'eap-eap2' ]) {
|
||||
config.ieee80211w = 1;
|
||||
config.sae_require_mfp = 1;
|
||||
config.sae_pwe = 2;
|
||||
}
|
||||
|
||||
if (config.own_ip_addr)
|
||||
config.dynamic_own_ip_addr = null;
|
||||
|
||||
if (!config.wpa)
|
||||
config.wpa_disable_eapol_key_retries = null;
|
||||
|
||||
switch(config.auth_type) {
|
||||
case 'none':
|
||||
case 'owe':
|
||||
config.wps_possible = 1;
|
||||
config.wps_state = 1;
|
||||
|
||||
if (config.owe_transition_ssid)
|
||||
config.owe_transition_ssid = `"${config.owe_transition_ssid}"`;
|
||||
|
||||
append_vars(config, [
|
||||
'owe_transition_ssid', 'owe_transition_bssid', 'owe_transition_ifname',
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'psk':
|
||||
case 'psk2':
|
||||
case 'sae':
|
||||
case 'psk-sae':
|
||||
config.vlan_possible = 1;
|
||||
config.wps_possible = 1;
|
||||
|
||||
if (config.auth_type == 'psk' && config.ppsk) {
|
||||
iface_authentication_server(config);
|
||||
config.macaddr_acl = 2;
|
||||
config.wpa_psk_radius = 2;
|
||||
} else if (length(config.key) == 64) {
|
||||
config.wpa_psk = key;
|
||||
} else if (length(config.key) >= 8) {
|
||||
config.wpa_passphrase = config.key;
|
||||
} else if (!config.wpa_psk_file) {
|
||||
netifd.setup_failed('INVALID_WPA_PSK');
|
||||
}
|
||||
|
||||
set_default(config, 'wpa_psk_file', `/var/run/hostapd-${config.ifname}.psk`);
|
||||
touch_file(config.wpa_psk_file);
|
||||
set_default(config, 'dynamic_vlan', 0);
|
||||
break;
|
||||
|
||||
case 'eap':
|
||||
case 'eap2':
|
||||
case 'eap-eap2':
|
||||
case 'eap192':
|
||||
config.vlan_possible = 1;
|
||||
|
||||
if (config.fils) {
|
||||
set_default(config, 'erp_domain', substr(md5(config.ssid), 0, 4));
|
||||
set_default(config, 'fils_realm', config.erp_domain);
|
||||
set_default(config, 'erp_send_reauth_start', 1);
|
||||
set_default(config, 'fils_cache_id', substr(md5(config.fils_realm), 0, 4));
|
||||
}
|
||||
|
||||
if (!config.eap_server) {
|
||||
iface_authentication_server(config);
|
||||
iface_accounting_server(config);
|
||||
}
|
||||
|
||||
if (config.radius_das_client && config.radius_das_secret) {
|
||||
set_default(config, 'radius_das_port', 3799);
|
||||
set_default(config, 'radius_das_client', `${config.radius_das_client} ${config.radius_das_secret}`);
|
||||
}
|
||||
|
||||
set_default(config, 'eapol_version', config.wpa & 1);
|
||||
if (!config.eapol_version)
|
||||
config.eapol_version = null;
|
||||
append('eapol_key_index_workaround', '1');
|
||||
append('ieee8021x', '1');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
append_vars(config, [
|
||||
'sae_require_mfp', 'sae_pwe', 'time_advertisement', 'time_zone',
|
||||
'wpa_group_rekey', 'wpa_ptk_rekey', 'wpa_gmk_rekey', 'wpa_strict_rekey',
|
||||
'macaddr_acl', 'wpa_psk_radius', 'wpa_psk', 'wpa_passphrase', 'wpa_psk_file',
|
||||
'eapol_version', 'dynamic_vlan', 'radius_request_cui', 'eap_reauth_period',
|
||||
'radius_das_client', 'radius_das_port', 'own_ip_addr', 'dynamic_own_ip_addr',
|
||||
'wpa_disable_eapol_key_retries', 'auth_algs', 'wpa', 'wpa_pairwise',
|
||||
'erp_domain', 'fils_realm', 'erp_send_reauth_start', 'fils_cache_id'
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_ppsk(config) {
|
||||
if (!(config.auth_type in [ 'none', 'owe', 'psk', 'sae', 'psk-sae', 'wep' ]) || !config.auth_server_addr)
|
||||
return;
|
||||
|
||||
iface_authentication_server(config);
|
||||
append('macaddr_acl', '2');
|
||||
}
|
||||
|
||||
function iface_wps(config) {
|
||||
push_config(config, 'config_methods', 'wps_pushbutton', 'push_button');
|
||||
push_config(config, 'config_methods', 'wps_label', 'label');
|
||||
|
||||
if (config.multi_ap == 1)
|
||||
config.wps_possible = false;
|
||||
|
||||
if (config.wps_possible && length(config.config_methods)) {
|
||||
config.eap_server = 1;
|
||||
set_default(config, 'wps_state', 2);
|
||||
|
||||
if (config.ext_registrar && config.network_bridge)
|
||||
set_default(config, 'upnp_iface', config.network_bridge);
|
||||
|
||||
if (config.multi_ap && config.multi_ap_backhaul_ssid) {
|
||||
append_vars(config, [ 'multi_ap_backhaul_ssid' ]);
|
||||
if (length(config.multi_ap_backhaul_key) == 64)
|
||||
append('multi_ap_backhaul_wpa_psk', config.multi_ap_backhaul_key);
|
||||
else if (length(config.multi_ap_backhaul_key) > 8)
|
||||
append('multi_ap_backhaul_wpa_passphrase', config.multi_ap_backhaul_key);
|
||||
else
|
||||
netifd.setup_failed('INVALID_WPA_PSK');
|
||||
}
|
||||
|
||||
append_vars(config, [
|
||||
'wps_state', 'device_type', 'device_name', 'config_methods', 'wps_independent', 'eap_server',
|
||||
'ap_pin', 'ap_setup_locked', 'upnp_iface'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function iface_rrm(config) {
|
||||
set_default(config, 'rrm_neighbor_report', config.ieee80211k);
|
||||
set_default(config, 'rrm_beacon_report', config.ieee80211k);
|
||||
|
||||
append_vars(config, [
|
||||
'rrm_neighbor_report', 'rrm_beacon_report', 'rnr', 'ftm_responder',
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_ftm(config, phy_features) {
|
||||
if (!phy_features.ftm_responder || !config.ftm_responder)
|
||||
return;
|
||||
|
||||
append_vars(config, [
|
||||
'ftm_responder', 'lci', 'civic'
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_macfilter(config) {
|
||||
let path = `/var/run/hostapd-${config.ifname}.maclist`;
|
||||
|
||||
switch(config.macfilter) {
|
||||
case 'allow':
|
||||
append('accept_mac_file', path);
|
||||
append('macaddr_acl', 1);
|
||||
config.vlan_possible = 1;
|
||||
break;
|
||||
|
||||
case 'deny':
|
||||
append('deny_mac_file', path);
|
||||
append('macaddr_acl', 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
let file = fs.open(path, 'w');
|
||||
if (!file) {
|
||||
warn(`Failed to open ${path}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.maclist)
|
||||
file.write(join('\n', config.maclist));
|
||||
|
||||
let macfile = fs.readfile(config.macfile);
|
||||
if (macfile)
|
||||
file.write(macfile);
|
||||
file.close();
|
||||
}
|
||||
|
||||
function iface_vlan(interface, config, vlans) {
|
||||
let path = `/var/run/hostapd-${config.ifname}.vlan`;
|
||||
|
||||
let file = fs.open(path, 'w');
|
||||
for (let k, vlan in vlans)
|
||||
if (vlan.config.name && vlan.config.vid) {
|
||||
let ifname = `${config.ifname}-${vlan.config.name}`;
|
||||
file.write(`${vlan.config.vid} ${ifname}\n`);
|
||||
netifd.set_vlan(interface, k, ifname);
|
||||
}
|
||||
file.close();
|
||||
|
||||
set_default(config, 'vlan_file', path);
|
||||
append_vars(config, [ 'vlan_file' ]);
|
||||
|
||||
if (!config.vlan_possible || !config.dynamic_vlan)
|
||||
return;
|
||||
|
||||
set_default(config, 'vlan_no_bridge', !config.vlan_bridge);
|
||||
|
||||
append_vars(config, [
|
||||
'dynamic_vlan', 'vlan_naming', 'vlan_bridge', 'vlan_no_bridge',
|
||||
'vlan_tagged_interface'
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_stations(config, stas) {
|
||||
if (!length(stas))
|
||||
return;
|
||||
|
||||
let path = `/var/run/hostapd-${config.ifname}.psk`;
|
||||
|
||||
let file = fs.open(path, 'w');
|
||||
for (let k, sta in stas)
|
||||
if (sta.config.mac && sta.config.key) {
|
||||
let station = `${sta.config.mac} ${sta.config.key}\n`;
|
||||
if (sta.config.vid)
|
||||
station = `vlanid=${sta.config.vid} ` + station;
|
||||
file.write(station);
|
||||
}
|
||||
file.close();
|
||||
|
||||
set_default(config, 'wpa_psk_file', path);
|
||||
}
|
||||
|
||||
function iface_eap_server(config) {
|
||||
if (!config.eap_server)
|
||||
return;
|
||||
|
||||
set_default(config, 'eap_server', true);
|
||||
set_default(config, 'eap_server_erp', true);
|
||||
|
||||
append_vars(config, [
|
||||
'eap_server', 'eap_server_erp', 'eap_user_file', 'ca_cert', 'server_cert',
|
||||
'private_key', 'private_key_passwd', 'server_id',
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_roaming(config) {
|
||||
if (!config.ieee80211r || config.wpa < 2)
|
||||
return;
|
||||
|
||||
set_default(config, 'mobility_domain', substr(md5(config.ssid), 0, 4));
|
||||
set_default(config, 'ft_psk_generate_local', config.auth_type == 'psk');
|
||||
set_default(config, 'ft_iface', config.network_ifname);
|
||||
|
||||
if (!config.ft_psk_generate_local) {
|
||||
if (!config.r0kh || !config.r1kh) {
|
||||
if (!config.auth_secret && !config.key)
|
||||
netifd.setup_failed('FT_KEY_CANT_BE_DERIVED');
|
||||
|
||||
let ft_key = md5(`${config.mobility_domain}/${config.auth_secret ?? config.key}`);
|
||||
|
||||
set_default(config, 'r0kh', 'ff:ff:ff:ff:ff:ff * ' + ft_key);
|
||||
set_default(config, 'r1kh', '00:00:00:00:00:00 00:00:00:00:00:00 ' + ft_key);
|
||||
}
|
||||
|
||||
append_vars(config, [
|
||||
'r0kh', 'r1kh', 'r1_key_holder', 'r0_key_lifetime', 'pmk_r1_push'
|
||||
]);
|
||||
}
|
||||
|
||||
append_vars(config, [
|
||||
'mobility_domain', 'ft_psk_generate_local', 'ft_over_ds', 'reassociation_deadline',
|
||||
'ft_iface'
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_mfp(config) {
|
||||
if (!config.ieee80211w || config.wpa < 2) {
|
||||
append('ieee80211w', 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.auth_type == 'eap192')
|
||||
config.group_mgmt_cipher = 'BIP-GMAC-256';
|
||||
else
|
||||
config.group_mgmt_cipher = config.ieee80211w_mgmt_cipher ?? 'AES-128-CMAC';
|
||||
|
||||
append_vars(config, [
|
||||
'ieee80211w', 'group_mgmt_cipher', 'assoc_sa_query_max_timeout', 'assoc_sa_query_retry_timeout'
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_key_caching(config) {
|
||||
if (config.wpa < 2)
|
||||
return;
|
||||
|
||||
if (config.network_bridge && config.rsn_preauth) {
|
||||
set_default(config, 'okc', true);
|
||||
config.rsn_preauth_interfaces = config.network_bridge;
|
||||
|
||||
append_vars(config, [
|
||||
'rsn_preauth', 'rsn_preauth_interfaces'
|
||||
]);
|
||||
} else {
|
||||
set_default(config, 'okc', (config.auth_type in [ 'sae', 'psk-sae', 'owe' ]));
|
||||
}
|
||||
|
||||
if (!config.okc && !config.fils)
|
||||
config.disable_pmksa_caching = 1;
|
||||
|
||||
append_vars(config, [
|
||||
'okc', 'disable_pmksa_caching'
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_hs20(config) {
|
||||
if (!config.hs20)
|
||||
return;
|
||||
|
||||
let uci = libuci.cursor();
|
||||
let icons = uci.get_all('wireless');
|
||||
for (let k, icon in icons)
|
||||
if (icon['.type'] == 'hs20-icon')
|
||||
append('hs20_icon', `${icon.width}:${icon.heigth}:${icon.lang}:${icon.type}:${k}:${icon.path}`);
|
||||
|
||||
append_vars(config, [
|
||||
'hs20', 'disable_dgaf', 'osen', 'anqp_domain_id', 'hs20_deauth_req_timeout', 'osu_ssid',
|
||||
'hs20_wan_metrics', 'hs20_operating_class', 'hs20_t_c_filename', 'hs20_t_c_timestamp',
|
||||
'hs20_t_c_server_url', 'hs20_oper_friendly_name', 'hs20_conn_capab', 'osu_provider',
|
||||
'operator_icon'
|
||||
]);
|
||||
}
|
||||
|
||||
function iface_interworking(config) {
|
||||
if (!config.iw_enabled)
|
||||
return;
|
||||
|
||||
config.interworking = true;
|
||||
|
||||
if (config.domain_name)
|
||||
config.domain_name = join(',', config.domain_name);
|
||||
|
||||
if (config.anqp_3gpp_cell_net)
|
||||
config.domain_name = join(',', config.anqp_3gpp_cell_net);
|
||||
|
||||
append_vars(config, [
|
||||
'interworking', 'internet', 'asra', 'uesa', 'access_network_type', 'hessid', 'venue_group',
|
||||
'venue_type', 'network_auth_type', 'gas_address3', 'roaming_consortium', 'anqp_elem', 'nai_realm',
|
||||
'venue_name', 'venue_url', 'domain_name', 'anqp_3gpp_cell_net',
|
||||
]);
|
||||
}
|
||||
|
||||
export function generate(interface, config, vlans, stas, phy_features) {
|
||||
config.ctrl_interface = '/var/run/hostapd';
|
||||
|
||||
iface_stations(config, stas);
|
||||
|
||||
iface_setup(config);
|
||||
|
||||
iface_auth_type(config);
|
||||
|
||||
iface_accounting_server(config);
|
||||
|
||||
iface_ppsk(config);
|
||||
|
||||
iface_wps(config);
|
||||
|
||||
iface_rrm(config);
|
||||
|
||||
iface_ftm(config, phy_features);
|
||||
|
||||
iface_macfilter(config);
|
||||
|
||||
iface_vlan(interface, config, vlans);
|
||||
|
||||
iface_eap_server(config);
|
||||
|
||||
iface_roaming(config);
|
||||
|
||||
iface_mfp(config);
|
||||
|
||||
iface_key_caching(config);
|
||||
|
||||
iface_hs20(config);
|
||||
|
||||
iface_interworking(config);
|
||||
|
||||
iface.wpa_key_mgmt(config);
|
||||
append_vars(config, [
|
||||
'wpa_key_mgmt'
|
||||
]);
|
||||
|
||||
/* raw options */
|
||||
for (let raw in config.hostapd_options)
|
||||
append_raw(raw);
|
||||
|
||||
if (config.default_macaddr)
|
||||
append_raw('#default_macaddr');
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
'use strict';
|
||||
|
||||
import * as libubus from 'ubus';
|
||||
import * as fs from 'fs';
|
||||
|
||||
global.ubus = libubus.connect();
|
||||
|
||||
let config_data = '';
|
||||
let network_data = '';
|
||||
|
||||
export function log(msg) {
|
||||
printf(`wifi-scripts: ${msg}\n`);
|
||||
};
|
||||
|
||||
export function append_raw(value) {
|
||||
config_data += value + '\n';
|
||||
};
|
||||
|
||||
export function append(key, value) {
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
switch (type(value)) {
|
||||
case 'array':
|
||||
value = join(' ', value);
|
||||
break;
|
||||
case 'bool':
|
||||
value = value ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
append_raw(key + '=' + value);
|
||||
};
|
||||
|
||||
export function append_vars(dict, keys) {
|
||||
for (let key in keys)
|
||||
append(key, dict[key]);
|
||||
};
|
||||
|
||||
export function network_append_raw(value) {
|
||||
network_data += value + '\n';
|
||||
};
|
||||
|
||||
export function network_append(key, value) {
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
switch (type(value)) {
|
||||
case 'array':
|
||||
value = join(' ', value);
|
||||
break;
|
||||
case 'bool':
|
||||
value = value ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
network_append_raw('\t' + key + '=' + value);
|
||||
};
|
||||
|
||||
export function network_append_vars(dict, keys) {
|
||||
for (let key in keys)
|
||||
network_append(key, dict[key]);
|
||||
};
|
||||
|
||||
export function set_default(dict, key, value) {
|
||||
if (dict[key] == null)
|
||||
dict[key] = value;
|
||||
};
|
||||
|
||||
export function push_config(dict, key, option, value) {
|
||||
if (!dict[option])
|
||||
return;
|
||||
|
||||
dict[key] ??= [];
|
||||
push(dict[key], value);
|
||||
};
|
||||
|
||||
export function touch_file(filename) {
|
||||
let file = fs.open(filename, "a");
|
||||
if (file)
|
||||
file.close();
|
||||
else
|
||||
log('Failed to touch ' + filename);
|
||||
};
|
||||
|
||||
export function append_value(config, key, value) {
|
||||
if (!config[key])
|
||||
config[key] = value;
|
||||
else
|
||||
config[key] += ' ' + value;
|
||||
};
|
||||
|
||||
export function comment(comment) {
|
||||
append_raw('\n# ' + comment);
|
||||
};
|
||||
|
||||
export function dump_config(file) {
|
||||
if (file)
|
||||
fs.writefile(file, config_data);
|
||||
|
||||
return config_data;
|
||||
};
|
||||
|
||||
export function dump_network(file) {
|
||||
config_data += 'network={\n';
|
||||
config_data += network_data;;
|
||||
config_data += '}\n';
|
||||
|
||||
if (file)
|
||||
fs.writefile(file, config_data);
|
||||
|
||||
return config_data;
|
||||
};
|
||||
|
||||
export function flush_config() {
|
||||
config_data = '';
|
||||
};
|
||||
|
||||
export function flush_network() {
|
||||
config_data = '';
|
||||
network_data = '';
|
||||
};
|
||||
@@ -0,0 +1,578 @@
|
||||
'use strict';
|
||||
|
||||
import { append, append_raw, append_vars, dump_config, flush_config, set_default } from 'wifi.common';
|
||||
import { validate } from 'wifi.validate';
|
||||
import * as netifd from 'wifi.netifd';
|
||||
import * as iface from 'wifi.iface';
|
||||
import * as nl80211 from 'nl80211';
|
||||
import * as ap from 'wifi.ap';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER = 33;
|
||||
const NL80211_EXT_FEATURE_RADAR_BACKGROUND = 61;
|
||||
|
||||
let phy_features = {};
|
||||
let phy_capabilities = {};
|
||||
|
||||
/* make sure old style UCI and hwmode and newer band properties are correctly resolved */
|
||||
function set_device_defaults(config) {
|
||||
/* validate the hw mode */
|
||||
if (config.hw_mode in [ '11a', '11b', '11g', '11ad' ])
|
||||
config.hw_mode = substr(config.hw_mode, 2);
|
||||
else if (config.channel > 14)
|
||||
config.hw_mode = 'a';
|
||||
else
|
||||
config.hw_mode = 'g';
|
||||
|
||||
/* validate band */
|
||||
if (config.band == '2g')
|
||||
config.hw_mode = 'g';
|
||||
else if (config.band in [ '5g', '6g', '60g' ])
|
||||
config.hw_mode = 'a';
|
||||
else
|
||||
switch (config.hw_mode) {
|
||||
case 'a':
|
||||
config.band = '5g';
|
||||
break;
|
||||
|
||||
case 'ad':
|
||||
config.band = '60g';
|
||||
break;
|
||||
|
||||
default:
|
||||
config.band = '2g';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* setup sylog / stdout */
|
||||
function device_log_append(config) {
|
||||
let log_mask = 0;
|
||||
|
||||
for (let k in [ 'log_mlme', 'log_iapp', 'log_driver', 'log_wpa', 'log_radius', 'log_8021x', 'log_80211' ]) {
|
||||
log_mask <<= 1;
|
||||
log_mask |= config[k] ? 1 : 0;
|
||||
}
|
||||
|
||||
append('logger_syslog', log_mask);
|
||||
append('logger_syslog_level', config.log_level);
|
||||
append('logger_stdout', log_mask);
|
||||
append('logger_stdout_level', config.log_level);
|
||||
}
|
||||
|
||||
/* setup country code */
|
||||
function device_country_code(config) {
|
||||
let status = global.ubus.call('network.wireless', 'status');
|
||||
for (let name, radio in status) {
|
||||
if (!radio.config.country)
|
||||
continue;
|
||||
config.country_code = radio.config.country;
|
||||
}
|
||||
|
||||
if (!exists(config, 'country_code'))
|
||||
return;
|
||||
|
||||
if (config.hw_mode != 'a')
|
||||
delete config.ieee80211h;
|
||||
append_vars(config, [ 'country_code', 'country3', 'ieee80211h' ]);
|
||||
if (config.ieee80211d)
|
||||
append_vars(config, [ 'ieee80211d', 'local_pwr_constraint', 'spectrum_mgmt_required' ]);
|
||||
}
|
||||
|
||||
|
||||
/* setup cell density */
|
||||
function device_cell_density_append(config) {
|
||||
switch (config.hw_mode) {
|
||||
case 'b':
|
||||
if (config.cell_density == 1) {
|
||||
config.supported_rates = [ 5500, 11000 ];
|
||||
config.basic_rates = [ 5500, 11000 ];
|
||||
} else if (config.cell_density > 2) {
|
||||
config.supported_rates = [ 11000 ];
|
||||
config.basic_rates = [ 11000 ];
|
||||
}
|
||||
;;
|
||||
case 'g':
|
||||
if (config.cell_density in [ 0, 1 ]) {
|
||||
if (!config.legacy_rates) {
|
||||
config.supported_rates = [ 6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 6000, 12000, 24000 ];
|
||||
} else if (config.cell_density == 1) {
|
||||
config.supported_rates = [ 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 5500, 11000 ];
|
||||
}
|
||||
} else if (config.cell_density == 2 || (config.cell_density > 3 && config.legacy_rates)) {
|
||||
if (!config.legacy_rates) {
|
||||
config.supported_rates = [ 12000, 18000, 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 12000, 24000 ];
|
||||
} else {
|
||||
config.supported_rates = [ 11000, 12000, 18000, 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 11000 ];
|
||||
}
|
||||
} else if (config.cell_density > 2) {
|
||||
config.supported_rates = [ 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 24000 ];
|
||||
}
|
||||
;;
|
||||
case 'a':
|
||||
switch (config.cell_density) {
|
||||
case 1:
|
||||
config.supported_rates = [ 6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 6000, 12000, 24000 ];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
config.supported_rates = [ 12000, 18000, 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 12000, 24000 ];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
config.supported_rates = [ 24000, 36000, 48000, 54000 ];
|
||||
config.basic_rates = [ 24000 ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function device_rates(config) {
|
||||
for (let key in [ 'supported_rates', 'basic_rates' ])
|
||||
config[key] = map(config[key], x => x / 100);
|
||||
|
||||
append_vars(config, [ 'beacon_rate', 'supported_rates', 'basic_rates' ]);
|
||||
}
|
||||
|
||||
function device_htmode_append(config) {
|
||||
config.channel_offset = config.band == '6g' ? 1 : 0;
|
||||
|
||||
/* 802.11n */
|
||||
config.ieee80211n = 0;
|
||||
if (config.band != '6g') {
|
||||
if (config.htmode in [ 'VHT20', 'HT20', 'HE20', 'EHT20' ])
|
||||
config.ieee80211n = 1;
|
||||
if (config.htmode in [ 'HT40', 'HT40+', 'HT40-', 'VHT40', 'VHT80', 'VHT160', 'HE40', 'HE80', 'HE160', 'EHT40', 'EHT80', 'EHT160' ]) {
|
||||
config.ieee80211n = 1;
|
||||
if (!config.channel)
|
||||
config.ht_capab = '[HT40+]';
|
||||
else
|
||||
switch (config.hw_mode) {
|
||||
case 'a':
|
||||
switch (((config.channel / 4) + config.channel_offset) % 2) {
|
||||
case 0:
|
||||
config.ht_capab = '[HT40-]';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
config.ht_capab = '[HT40+]';
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (config.htmode) {
|
||||
case 'HT40+':
|
||||
case 'HT40-':
|
||||
config.ht_capab = '[' + config.htmode + ']';
|
||||
break;
|
||||
|
||||
default:
|
||||
if (config.channel < 7)
|
||||
config.ht_capab = '[HT40+]';
|
||||
else
|
||||
config.ht_capab = '[HT40-]';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.ieee80211n) {
|
||||
let ht_capab = phy_capabilities.ht_capa;
|
||||
|
||||
if (ht_capab & 0x1 && config.ldpc)
|
||||
config.ht_capab += '[LDPC]';
|
||||
if (ht_capab & 0x10 && config.greenfield)
|
||||
config.ht_capab += '[GF]';
|
||||
if (ht_capab & 0x20 && config.short_gi_20)
|
||||
config.ht_capab += '[SHORT-GI-20]';
|
||||
if (ht_capab & 0x40 && config.short_gi_40)
|
||||
config.ht_capab += '[SHORT-GI-40]';
|
||||
if (ht_capab & 0x80 && config.tx_stbc)
|
||||
config.ht_capab += '[TX-STBC]';
|
||||
if (ht_capab & 0x800 && config.max_amsdu)
|
||||
config.ht_capab += '[MAX-AMSDU-7935]';
|
||||
if (ht_capab & 0x1000 && config.dsss_cck_40)
|
||||
config.ht_capab += '[DSSS_CCK-40]';
|
||||
let rx_stbc = [ '', '[RX-STBC1]', '[RX-STBC12]', '[RX-STBC123]' ];
|
||||
config.ht_capab += rx_stbc[min(config.rx_stbc, (ht_capab >> 8) & 3)];
|
||||
|
||||
append_vars(config, [ 'ieee80211n', 'ht_coex', 'ht_capab' ]);
|
||||
}
|
||||
}
|
||||
|
||||
/* 802.11ac */
|
||||
config.ieee80211ac = 1;
|
||||
config.vht_oper_centr_freq_seg0_idx = 0;
|
||||
config.vht_oper_chwidth = 0;
|
||||
|
||||
switch (config.htmode) {
|
||||
case 'VHT20':
|
||||
case 'HE20':
|
||||
case 'EHT20':
|
||||
break;
|
||||
|
||||
case 'VHT40':
|
||||
case 'HE40':
|
||||
case 'EHT40':
|
||||
config.vht_oper_centr_freq_seg0_idx = config.channel + (((config.channel / 4) + config.channel_offset) % 2 ? 2 : -2);
|
||||
break;
|
||||
|
||||
case 'VHT80':
|
||||
case 'HE80':
|
||||
case 'EHT80':
|
||||
let delta = [ -6, 6, 2, -2 ];
|
||||
config.vht_oper_centr_freq_seg0_idx = config.channel + delta[((config.channel / 4) + config.channel_offset) % 4];
|
||||
config.vht_oper_chwidth = 1;
|
||||
break;
|
||||
|
||||
case 'VHT160':
|
||||
case 'HE160':
|
||||
case 'EHT160':
|
||||
let vht_oper_centr_freq_seg0_idx_map = [[ 64, 50 ], [ 128, 114 ], [ 177, 163 ]];
|
||||
if (config.band == '6g')
|
||||
vht_oper_centr_freq_seg0_idx_map = [
|
||||
[ 29, 15 ], [ 61, 47 ], [ 93, 79 ], [ 125, 111 ],
|
||||
[ 157, 143 ], [ 189, 175 ], [ 221, 207 ]];
|
||||
for (let k, v in vht_oper_centr_freq_seg0_idx_map)
|
||||
if (v[0] <= config.channel) {
|
||||
config.vht_oper_centr_freq_seg0_idx = v[1];
|
||||
break;
|
||||
}
|
||||
config.vht_oper_chwidth = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
config.ieee80211ac = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
config.eht_oper_chwidth = config.vht_oper_chwidth;
|
||||
config.eht_oper_centr_freq_seg0_idx = config.vht_oper_centr_freq_seg0_idx;
|
||||
|
||||
if (config.band == '6g') {
|
||||
config.ieee80211ac = 0;
|
||||
|
||||
switch(config.htmode) {
|
||||
case 'HE20':
|
||||
case 'EHT20':
|
||||
config.op_class = 131;
|
||||
break;
|
||||
|
||||
case 'EHT320':
|
||||
let eht_center_seg0_map = [
|
||||
[ 61, 31 ], [ 125, 95 ], [ 189, 159 ], [ 221, 191 ]
|
||||
];
|
||||
|
||||
for (let k, v in eht_center_seg0_map)
|
||||
if (v[0] <= config.channel) {
|
||||
config.eht_oper_centr_freq_seg0_idx = v[1];
|
||||
break;
|
||||
}
|
||||
config.op_class = 137;
|
||||
config.eht_oper_chwidth = 7;
|
||||
break;
|
||||
|
||||
case 'HE40':
|
||||
case 'HE80':
|
||||
case 'HE160':
|
||||
case 'EHT40':
|
||||
case 'EHT80':
|
||||
case 'EHT160':
|
||||
config.op_class = 132 + config.eht_oper_chwidth;
|
||||
break;
|
||||
}
|
||||
|
||||
append_vars(config, [ 'op_class' ]);
|
||||
}
|
||||
|
||||
if (config.ieee80211ac && config.hw_mode == 'a') {
|
||||
/* VHT capab */
|
||||
if (config.vht_oper_chwidth < 2) {
|
||||
config.vht160 = 0;
|
||||
config.short_gi_160 = 0;
|
||||
}
|
||||
|
||||
config.tx_queue_data2_burst = '2.0';
|
||||
|
||||
let vht_capab = phy_capabilities.vht_capa;
|
||||
|
||||
config.vht_capab = '';
|
||||
if (vht_capab & 0x10 && config.rxldpc)
|
||||
config.vht_capab += '[RXLDPC]';
|
||||
if (vht_capab & 0x20 && config.short_gi_80)
|
||||
config.vht_capab += '[SHORT-GI-80]';
|
||||
if (vht_capab & 0x40 && config.short_gi_160)
|
||||
config.vht_capab += '[SHORT-GI-160]';
|
||||
if (vht_capab & 0x80 && config.tx_stbc_2by1)
|
||||
config.vht_capab += '[TX-STBC-2BY1]';
|
||||
if (vht_capab & 0x800 && config.su_beamformer)
|
||||
config.vht_capab += '[SU-BEAMFORMER]';
|
||||
if (vht_capab & 0x1000 && config.su_beamformee)
|
||||
config.vht_capab += '[SU-BEAMFORMEE]';
|
||||
if (vht_capab & 0x80000 && config.mu_beamformer)
|
||||
config.vht_capab += '[MU-BEAMFORMER]';
|
||||
if (vht_capab & 0x100000 && config.mu_beamformee)
|
||||
config.vht_capab += '[MU-BEAMFORMEE]';
|
||||
if (vht_capab & 0x200000 && config.vht_txop_ps)
|
||||
config.vht_capab += '[VHT-TXOP-PS]';
|
||||
if (vht_capab & 0x400000 && config.htc_vht)
|
||||
config.vht_capab += '[HTC-VHT]';
|
||||
if (vht_capab & 0x10000000 && config.rx_antenna_pattern)
|
||||
config.vht_capab += '[RX-ANTENNA-PATTERN]';
|
||||
if (vht_capab & 0x20000000 && config.tx_antenna_pattern)
|
||||
config.vht_capab += '[TX-ANTENNA-PATTERN]';
|
||||
let rx_stbc = [ '', '[RX-STBC1]', '[RX-STBC12]', '[RX-STBC123]', '[RX-STBC-1234]' ];
|
||||
config.vht_capab += rx_stbc[min(config.rx_stbc, (vht_capab >> 8) & 7)];
|
||||
|
||||
if (vht_capab & 0x800 && config.su_beamformer)
|
||||
config.vht_capab += '[SOUNDING-DIMENSION-' + min(((vht_capab >> 16) & 3) + 1, config.beamformer_antennas) + ']';
|
||||
if (vht_capab & 0x1000 && config.su_beamformee)
|
||||
config.vht_capab += '[BF-ANTENNA-' + min(((vht_capab >> 13) & 3) + 1, config.beamformer_antennas) + ']';
|
||||
|
||||
/* supported Channel widths */
|
||||
if (vht_capab & 0xc == 8 && config.vht160 <= 2)
|
||||
config.vht_capab += '[VHT160-80PLUS80]';
|
||||
else if (vht_capab & 0xc == 4 && config.vht160 <= 1)
|
||||
config.vht_capab += '[VHT160]';
|
||||
|
||||
/* maximum MPDU length */
|
||||
if (vht_capab & 3 > 1 && config.vht_max_mpdu > 11454)
|
||||
config.vht_capab += '[MAX-MPDU-11454]';
|
||||
else if (vht_capab & 3 && config.vht_max_mpdu > 7991)
|
||||
config.vht_capab += '[MAX-MPDU-7991]';
|
||||
|
||||
/* maximum A-MPDU length exponent */
|
||||
let max_a_mpdu_len_exp = (vht_capab >> 20) & 0x38;
|
||||
for (let exp = 7; exp; exp--)
|
||||
if (max_a_mpdu_len_exp >= (0x8 * exp) && exp <= config.vht_max_a_mpdu_len_exp) {
|
||||
config.vht_capab += '[MAX-A-MPDU-LEN-EXP' + exp + ']';
|
||||
break;
|
||||
}
|
||||
|
||||
/* whether or not the STA supports link adaptation using VHT variant */
|
||||
let vht_link_adapt = vht_capab & 0xC000000;
|
||||
if (vht_link_adapt >= 0xC000000 && config.vht_link_adapt > 3)
|
||||
config.vht_capab += '[VHT-LINK-ADAPT-3]';
|
||||
if (vht_link_adapt >= 0x8000000 && config.vht_link_adapt > 2)
|
||||
config.vht_capab += '[VHT-LINK-ADAPT-2]';
|
||||
|
||||
append_vars(config, [
|
||||
'ieee80211ac', 'vht_oper_chwidth', 'vht_oper_centr_freq_seg0_idx',
|
||||
'vht_capab'
|
||||
]);
|
||||
}
|
||||
|
||||
/* 802.11ax */
|
||||
if (wildcard(config.htmode, 'HE*') || wildcard(config.htmode, 'EHT*')) {
|
||||
let he_phy_cap = phy_capabilities.he_phy_cap;
|
||||
let he_mac_cap = phy_capabilities.he_mac_cap;
|
||||
|
||||
config.ieee80211ax = true;
|
||||
|
||||
if (config.hw_mode == 'a') {
|
||||
config.he_oper_chwidth = config.vht_oper_chwidth;
|
||||
config.he_oper_centr_freq_seg0_idx = config.vht_oper_centr_freq_seg0_idx;
|
||||
}
|
||||
|
||||
if (config.he_bss_color_enabled) {
|
||||
if (config.he_spr_non_srg_obss_pd_max_offset)
|
||||
config.he_spr_sr_control |= 1 << 2;
|
||||
if (!config.he_spr_psr_enabled)
|
||||
config.he_spr_sr_control |= 1;
|
||||
append_vars(config, [ 'he_bss_color', 'he_spr_non_srg_obss_pd_max_offset', 'he_spr_sr_control' ]);
|
||||
}
|
||||
|
||||
if (!(he_phy_cap[3] & 0x80))
|
||||
config.he_su_beamformer = false;
|
||||
if (!(he_phy_cap[4] & 0x1))
|
||||
config.he_su_beamformee = false;
|
||||
if (!(he_phy_cap[4] & 0x2))
|
||||
config.he_mu_beamformer = false;
|
||||
if (!(he_phy_cap[7] & 0x1))
|
||||
config.he_spr_psr_enabled = false;
|
||||
if (!(he_mac_cap[0] & 0x1))
|
||||
config.he_twt_required= false;
|
||||
|
||||
append_vars(config, [
|
||||
'ieee80211ax', 'he_oper_chwidth', 'he_oper_centr_freq_seg0_idx',
|
||||
'he_su_beamformer', 'he_su_beamformee', 'he_mu_beamformer', 'he_twt_required',
|
||||
'he_default_pe_duration', 'he_rts_threshold', 'he_mu_edca_qos_info_param_count',
|
||||
'he_mu_edca_qos_info_q_ack', 'he_mu_edca_qos_info_queue_request', 'he_mu_edca_qos_info_txop_request',
|
||||
'he_mu_edca_ac_be_aifsn', 'he_mu_edca_ac_be_aci', 'he_mu_edca_ac_be_ecwmin',
|
||||
'he_mu_edca_ac_be_ecwmax', 'he_mu_edca_ac_be_timer', 'he_mu_edca_ac_bk_aifsn',
|
||||
'he_mu_edca_ac_bk_aci', 'he_mu_edca_ac_bk_ecwmin', 'he_mu_edca_ac_bk_ecwmax',
|
||||
'he_mu_edca_ac_bk_timer', 'he_mu_edca_ac_vi_ecwmin', 'he_mu_edca_ac_vi_ecwmax',
|
||||
'he_mu_edca_ac_vi_aifsn', 'he_mu_edca_ac_vi_aci', 'he_mu_edca_ac_vi_timer',
|
||||
'he_mu_edca_ac_vo_aifsn', 'he_mu_edca_ac_vo_aci', 'he_mu_edca_ac_vo_ecwmin',
|
||||
'he_mu_edca_ac_vo_ecwmax', 'he_mu_edca_ac_vo_timer',
|
||||
]);
|
||||
}
|
||||
|
||||
if (wildcard(config.htmode, 'EHT*')) {
|
||||
config.ieee80211be = true;
|
||||
append_vars(config, [ 'ieee80211be' ]);
|
||||
|
||||
if (config.hw_mode == 'a')
|
||||
append_vars(config, [ 'eht_oper_chwidth', 'eht_oper_centr_freq_seg0_idx' ]);
|
||||
|
||||
if (config.band == "6g") {
|
||||
config.stationary_ap = true;
|
||||
append_vars(config, [ 'he_6ghz_reg_pwr_type', ]);
|
||||
}
|
||||
}
|
||||
|
||||
append_vars(config, [ 'tx_queue_data2_burst', 'stationary_ap' ]);
|
||||
}
|
||||
|
||||
function device_extended_features(data, flag) {
|
||||
return !!(data[flag / 8] | (1 << (flag % 8)));
|
||||
}
|
||||
|
||||
function device_capabilities(phy) {
|
||||
let idx = +fs.readfile(`/sys/class/ieee80211/${phy}/index`);
|
||||
phy = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, nl80211.const.NLM_F_DUMP, { wiphy: idx, split_wiphy_dump: true });
|
||||
if (!phy)
|
||||
return;
|
||||
for (let band in phy.wiphy_bands) {
|
||||
if (!band)
|
||||
continue;
|
||||
phy_capabilities.ht_capa = band.ht_capa ?? 0;
|
||||
phy_capabilities.vht_capa = band.vht_capa ?? 0;
|
||||
for (let iftype in band.iftype_data) {
|
||||
if (!iftype.iftypes.ap)
|
||||
continue;
|
||||
phy_capabilities.he_mac_cap = iftype.he_cap_mac;
|
||||
phy_capabilities.he_phy_cap = iftype.he_cap_phy;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
phy_features.ftm_responder = device_extended_features(phy.extended_features, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
|
||||
phy_features.radar_background = device_extended_features(phy.extended_features, NL80211_EXT_FEATURE_RADAR_BACKGROUND);
|
||||
}
|
||||
|
||||
function generate(config) {
|
||||
if (!config.phy)
|
||||
die(`${config.path} is an unknown phy`);
|
||||
|
||||
device_capabilities(config.phy);
|
||||
|
||||
append('driver', 'nl80211');
|
||||
|
||||
set_device_defaults(config);
|
||||
|
||||
device_log_append(config);
|
||||
|
||||
device_country_code(config);
|
||||
|
||||
device_cell_density_append(config);
|
||||
|
||||
device_rates(config);
|
||||
|
||||
/* beacon */
|
||||
append_vars(config, [ 'beacon_int', 'beacon_rate', 'rnr_beacon' ]);
|
||||
|
||||
/* wpa_supplicant co-exist */
|
||||
append_vars(config, [ 'noscan' ]);
|
||||
|
||||
/* airtime */
|
||||
append_vars(config, [ 'airtime_mode' ]);
|
||||
|
||||
/* assoc/thresholds */
|
||||
append_vars(config, [ 'rssi_reject_assoc_rssi', 'rssi_ignore_probe_request', 'iface_max_num_sta', 'no_probe_resp_if_max_sta' ]);
|
||||
|
||||
/* ACS / Radar*/
|
||||
if (!phy_features.radar_background || config.band != '5g')
|
||||
delete config.enable_background_radar;
|
||||
else
|
||||
set_default(config, 'enable_background_radar', phy_features.radar_background);
|
||||
|
||||
append_vars(config, [ 'acs_chan_bias', 'acs_exclude_dfs', 'enable_background_radar' ]);
|
||||
|
||||
/* TX Power */
|
||||
append_vars(config, [ 'min_tx_power' ]);
|
||||
|
||||
/* hwmode, channel, op_class, ... */
|
||||
append_vars(config, [ 'hw_mode', 'channel', 'rts_threshold', 'chanlist' ]);
|
||||
if (config.hw_mode in [ 'a', 'g' ] && config.require_mode in [ 'n', 'ac', 'ax' ]) {
|
||||
let require_mode = { n: 'require_ht', ac: 'require_vht', ax: 'require_he' };
|
||||
|
||||
config.legacy_rates = false;
|
||||
append(require_mode[config.require_mode], 1);
|
||||
}
|
||||
device_htmode_append(config);
|
||||
|
||||
if (config.ieee80211ax || config.ieee80211be)
|
||||
append_vars(config, [ 'mbssid' ]);
|
||||
|
||||
/* 6G power mode */
|
||||
if (config.band != '6g')
|
||||
append_vars(config, [ 'reg_power_type' ]);
|
||||
|
||||
/* raw options */
|
||||
for (let raw in config.hostapd_options)
|
||||
append_raw(raw);
|
||||
}
|
||||
|
||||
let iface_idx = 0;
|
||||
function setup_interface(interface, config, vlans, stas, phy_features, fixup) {
|
||||
config = { ...config, fixup };
|
||||
|
||||
config.idx = iface_idx++;
|
||||
ap.generate(interface, config, vlans, stas, phy_features);
|
||||
}
|
||||
|
||||
export function setup(data) {
|
||||
let file_name = `/var/run/hostapd-${data.phy}${data.vif_phy_suffix}.conf`;
|
||||
|
||||
flush_config();
|
||||
|
||||
if (fs.stat(file_name))
|
||||
fs.rename(file_name, file_name + '.prev');
|
||||
|
||||
data.config.phy = data.phy;
|
||||
|
||||
generate(data.config);
|
||||
|
||||
if (data.config.num_global_macaddr)
|
||||
append('\n#num_global_macaddr', data.config.num_global_macaddr);
|
||||
if (data.config.macaddr_base)
|
||||
append('\n#macaddr_base', data.config.macaddr_base);
|
||||
|
||||
for (let k, interface in data.interfaces) {
|
||||
if (interface.config.mode != 'ap')
|
||||
continue;
|
||||
|
||||
interface.config.network_bridge = interface.bridge;
|
||||
interface.config.network_ifname = interface['bridge-ifname'];
|
||||
|
||||
let owe = interface.config.encryption == 'owe' && interface.config.owe_transition;
|
||||
|
||||
setup_interface(k, interface.config, interface.vlans, interface.stas, phy_features, owe ? 'owe' : null );
|
||||
if (owe)
|
||||
setup_interface(k, interface.config, interface.vlans, interface.stas, phy_features, 'owe-transition');
|
||||
}
|
||||
|
||||
let config = dump_config(file_name);
|
||||
|
||||
let msg = {
|
||||
phy: data.phy,
|
||||
radio: data.config.radio,
|
||||
config: file_name,
|
||||
prev_config: file_name + '.prev'
|
||||
};
|
||||
let ret = global.ubus.call('hostapd', 'config_set', msg);
|
||||
|
||||
if (ret)
|
||||
netifd.add_process('/usr/sbin/hostapd', ret.pid, true, true);
|
||||
else
|
||||
netifd.setup_failed('HOSTAPD_START_FAILED');
|
||||
};
|
||||
@@ -0,0 +1,194 @@
|
||||
'use strict';
|
||||
|
||||
import { append_value, log } from 'wifi.common';
|
||||
import * as fs from 'fs';
|
||||
|
||||
export function parse_encryption(config) {
|
||||
let encryption = split(config.encryption, '+', 2);
|
||||
|
||||
config.wpa_pairwise = (config.hw_mode == 'ad') ? 'GCMP' : 'CCMP';
|
||||
|
||||
switch(encryption[1]){
|
||||
case 'tkip+aes':
|
||||
case 'tkip+ccmp':
|
||||
case 'aes+tkip':
|
||||
case 'ccmp+tkip':
|
||||
config.wpa_pairwise = 'CCMP TKIP';
|
||||
break;
|
||||
|
||||
case 'ccmp256':
|
||||
config.wpa_pairwise = 'CCMP-256';
|
||||
break;
|
||||
|
||||
case 'aes':
|
||||
case 'ccmp':
|
||||
config.wpa_pairwise = 'CCMP';
|
||||
break;
|
||||
|
||||
case 'tkip':
|
||||
config.wpa_pairwise = 'TKIP';
|
||||
break;
|
||||
|
||||
case 'gcmp256':
|
||||
config.wpa_pairwise = 'GCMP-256';
|
||||
break;
|
||||
|
||||
case 'gcmp':
|
||||
config.wpa_pairwise = 'GCMP';
|
||||
break;
|
||||
|
||||
default:
|
||||
if (config.encryption == 'wpa3-192')
|
||||
config.wpa_pairwise = 'GCMP-256';
|
||||
break;
|
||||
}
|
||||
|
||||
config.wpa = 0;
|
||||
for (let k, v in { 'wpa2*': 2, 'wpa3*': 2, '*psk2*': 2, 'psk3*': 2, 'sae*': 2,
|
||||
'owe*': 2, 'wpa*mixed*': 3, '*psk*mixed*': 3, 'wpa*': 1, '*psk*': 1, })
|
||||
if (wildcard(config.encryption, k)) {
|
||||
config.wpa = v;
|
||||
break;
|
||||
}
|
||||
if (!config.wpa)
|
||||
config.wpa_pairwise = null;
|
||||
|
||||
config.auth_type = encryption[0] ?? 'none';
|
||||
switch(config.auth_type) {
|
||||
case 'owe':
|
||||
config.auth_type = 'owe';
|
||||
break;
|
||||
|
||||
case 'wpa3-192':
|
||||
config.auth_type = 'eap192';
|
||||
break;
|
||||
|
||||
case 'wpa3-mixed':
|
||||
config.auth_type = 'eap-eap2';
|
||||
break;
|
||||
|
||||
case 'wpa3':
|
||||
config.auth_type = 'eap2';
|
||||
break;
|
||||
|
||||
case 'sae-mixed':
|
||||
config.auth_type = 'psk-sae';
|
||||
break;
|
||||
|
||||
case 'wpa':
|
||||
case 'wpa2':
|
||||
config.auth_type = 'eap';
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export function wpa_key_mgmt(config) {
|
||||
if (!config.wpa)
|
||||
return;
|
||||
|
||||
switch(config.auth_type) {
|
||||
case 'psk':
|
||||
case 'psk2':
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-PSK');
|
||||
if (config.wpa >= 2 && config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-PSK');
|
||||
if (config.ieee80211w)
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-PSK-SHA256');
|
||||
break;
|
||||
|
||||
case 'eap':
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-EAP');
|
||||
if (config.wpa >= 2 && config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-EAP');
|
||||
if (config.ieee80211w)
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256');
|
||||
break;
|
||||
|
||||
case 'eap192':
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SUITE-B-192');
|
||||
if (config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-EAP-SHA384');
|
||||
break;
|
||||
|
||||
case 'eap-eap2':
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-EAP');
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256');
|
||||
if (config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-EAP');
|
||||
break;
|
||||
|
||||
case 'eap2':
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256');
|
||||
if (config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-EAP');
|
||||
break;
|
||||
|
||||
case 'sae':
|
||||
append_value(config, 'wpa_key_mgmt', 'SAE');
|
||||
if (config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-SAE');
|
||||
break;
|
||||
|
||||
case 'psk-sae':
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-PSK');
|
||||
append_value(config, 'wpa_key_mgmt', 'SAE');
|
||||
if (config.ieee80211w)
|
||||
append_value(config, 'wpa_key_mgmt', 'WPA-PSK-SHA256');
|
||||
if (config.ieee80211r) {
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-PSK');
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-SAE');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'owe':
|
||||
append_value(config, 'wpa_key_mgmt', 'OWE');
|
||||
break;
|
||||
}
|
||||
|
||||
if (config.fils) {
|
||||
switch(config.auth_type) {
|
||||
case 'eap192':
|
||||
append_value(config, 'wpa_key_mgmt', 'FILS-SHA384');
|
||||
if (config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-FILS-SHA384');
|
||||
break;
|
||||
|
||||
case 'eap-eap2':
|
||||
case 'eap2':
|
||||
case 'eap':
|
||||
append_value(config, 'wpa_key_mgmt', 'FILS-SHA256');
|
||||
if (config.ieee80211r)
|
||||
append_value(config, 'wpa_key_mgmt', 'FT-FILS-SHA256');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
config.key_mgmt = config.wpa_key_mgmt;
|
||||
};
|
||||
|
||||
function macaddr_random() {
|
||||
let f = open("/dev/urandom", "r");
|
||||
let addr = f.read(6);
|
||||
|
||||
addr = map(split(addr, ""), (v) => ord(v));
|
||||
addr[0] &= ~1;
|
||||
addr[0] |= 2;
|
||||
|
||||
return join(":", map(addr, (v) => sprintf("%02x", v)));
|
||||
}
|
||||
|
||||
let mac_idx = 0;
|
||||
export function prepare(data, phy, num_global_macaddr, macaddr_base) {
|
||||
if (!data.macaddr) {
|
||||
let pipe = fs.popen(`ucode /usr/share/hostap/wdev.uc ${phy} get_macaddr id=${mac_idx} num_global=${num_global_macaddr} mbssid=${data.mbssid ?? 0} macaddr_base=${macaddr_base}`);
|
||||
|
||||
data.macaddr = trim(pipe.read("all"), '\n');
|
||||
pipe.close();
|
||||
|
||||
data.default_macaddr = true;
|
||||
mac_idx++;
|
||||
} else if (data.macaddr == 'random')
|
||||
data.macaddr = macaddr_random();
|
||||
|
||||
log(`Preparing interface: ${data.ifname} with MAC: ${data.macaddr}`);
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
import { log } from 'wifi.common';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const CMD_UP = 0;
|
||||
const CMD_SET_DATA = 1;
|
||||
const CMD_PROCESS_ADD = 2;
|
||||
const CMD_PROCESS_KILL_ALL = 3;
|
||||
const CMD_SET_RETRY = 4;
|
||||
|
||||
export function notify(command, params, data) {
|
||||
params ??= {};
|
||||
data ??= {};
|
||||
|
||||
global.ubus.call('network.wireless', 'notify', { command, device: global.radio, ...params, data });
|
||||
};
|
||||
|
||||
export function set_up() {
|
||||
notify(CMD_UP);
|
||||
};
|
||||
|
||||
export function set_data(data) {
|
||||
notify(CMD_SET_DATA, null, data);
|
||||
};
|
||||
|
||||
export function add_process(exe, pid, required, keep) {
|
||||
exe = fs.realpath(exe);
|
||||
|
||||
notify(CMD_PROCESS_ADD, null, { pid, exe, required, keep });
|
||||
};
|
||||
|
||||
export function set_retry(retry) {
|
||||
notify(CMD_SET_RETRY, null, { retry });
|
||||
};
|
||||
|
||||
export function set_vif(interface, ifname) {
|
||||
notify(CMD_SET_DATA, { interface }, { ifname });
|
||||
};
|
||||
|
||||
export function set_vlan(interface, ifname, vlan) {
|
||||
notify(CMD_SET_DATA, { interface, vlan }, { ifname });
|
||||
};
|
||||
|
||||
export function setup_failed(reason) {
|
||||
log(`Device setup failed: ${reason}`);
|
||||
printf('%s\n', reason);
|
||||
set_retry(false);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user