You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
349 lines
9.9 KiB
Bash
349 lines
9.9 KiB
Bash
#!/bin/sh
|
|
# Copyright (c) 2016 Qualcomm Atheros, Inc.
|
|
#
|
|
# All Rights Reserved.
|
|
# Qualcomm Atheros Confidential and Proprietary.
|
|
|
|
|
|
# NOTE: At boot, even if we add 'list interface "wan"' to /etc/config/lldpd,
|
|
# lldpd doesn't listen on eth0. We have to restart lldpd and then it starts
|
|
# listening.
|
|
|
|
NETDET_DEBUG_OUTOUT=0
|
|
|
|
NETDET_MODE_DB=/etc/ap.mode
|
|
|
|
NETDET_RESULT_ROOTAP=0
|
|
NETDET_RESULT_RE=1
|
|
NETDET_RESULT_INDETERMINATE=2
|
|
|
|
NETDET_CAP_BRIDGE_ROUTER_RESULT_ROUTER=0
|
|
NETDET_CAP_BRIDGE_ROUTER_RESULT_BRIDGE=1
|
|
|
|
NETDET_IS_WIFISON_DEVICE_VISIBLE_TRUE=0
|
|
NETDET_IS_WIFISON_DEVICE_VISIBLE_FALSE=1
|
|
|
|
NETDET_LLDP_WIFISON_CUSTOM_TLV_OUI=33,44,55
|
|
NETDET_LLDP_WIFISON_CUSTOM_TLV_SUBTYPE=44
|
|
NETDET_LLDP_WIFISON_CUSTOM_TLV_DATA=45,45,45,45,45
|
|
|
|
NETDET_CURRENT_MODE_ROOTAP=0
|
|
NETDET_CURRENT_MODE_RE=1
|
|
|
|
#Note: On some systems, the lan bridge might be named br0 or something
|
|
#else other than br-lan
|
|
NETDET_LANBRIDGE="br-lan"
|
|
|
|
# Emit a message at debug level.
|
|
# input: $1 - the message to log
|
|
__netdet_debug() {
|
|
local stderr=''
|
|
if [ "$NETDET_DEBUG_OUTOUT" -gt 0 ]; then
|
|
stderr='-s'
|
|
fi
|
|
|
|
logger $stderr -t repacd.netdet -p user.debug "$1"
|
|
}
|
|
|
|
# Check to see if lldpd is listening on a particular port
|
|
__netdet_is_lldpd_listening() {
|
|
local port=$1
|
|
lldpcli show configuration | grep "Interface pattern: " | grep $port > /dev/null
|
|
}
|
|
|
|
# Are there any Wi-Fi SON neighbors reachable via a particular port?
|
|
__netdet_has_wifison_neighbors() {
|
|
local port=$1
|
|
lldpcli show neighbors ports $port details | grep "TLV:.*OUI: ${NETDET_LLDP_WIFISON_CUSTOM_TLV_OUI}, SubType: ${NETDET_LLDP_WIFISON_CUSTOM_TLV_SUBTYPE},.* ${NETDET_LLDP_WIFISON_CUSTOM_TLV_DATA}$" > /dev/null
|
|
}
|
|
|
|
# Does a particular interface have an IPv4 address?
|
|
__netdet_has_address() {
|
|
local intf=$1
|
|
ifconfig $intf | grep "inet addr:[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" > /dev/null
|
|
}
|
|
|
|
# Is dhcpc running on a particular interface?
|
|
__netdet_is_running_dhcp_client() {
|
|
local intf=$1
|
|
ps -w | grep dhcpc | grep $intf > /dev/null
|
|
}
|
|
|
|
# Does a particular interface have a DHCP-assigned IPv4 address?
|
|
__netdet_has_dhcp_address() {
|
|
local intf=$1
|
|
__netdet_is_running_dhcp_client $intf && __netdet_has_address $intf
|
|
}
|
|
|
|
# Can you see WiFiSON devices on a particular port?
|
|
__netdet_is_wifison_device_visible() {
|
|
local port=$1
|
|
if ! __netdet_is_lldpd_listening $port; then
|
|
__netdet_debug "warning: lldpd wasn't listening on $port so restarting"
|
|
repacd_netdet_lldpd_init restart
|
|
fi
|
|
local timeout=30 # secs
|
|
local currtime=$(date +%s)
|
|
local timeouttime=$(($currtime + $timeout))
|
|
while [ $currtime -le $timeouttime ]; do
|
|
if __netdet_has_wifison_neighbors $port; then
|
|
return $NETDET_IS_WIFISON_DEVICE_VISIBLE_TRUE
|
|
fi
|
|
sleep 1
|
|
currtime=$(date +%s)
|
|
done
|
|
return $NETDET_IS_WIFISON_DEVICE_VISIBLE_FALSE
|
|
}
|
|
|
|
# Return a list of all the network interfaces that we care about
|
|
__netdet_get_interfaces() {
|
|
ifconfig | grep "^\(eth\|ath\|br\)" | awk '{ print $1 }'
|
|
}
|
|
|
|
# Enable/disable DHCP server
|
|
__repacd_netdet_dhcpd() {
|
|
case $1 in
|
|
disable | off | stop)
|
|
uci set dhcp.lan.ignore=1
|
|
;;
|
|
enable | on | start)
|
|
uci set dhcp.lan.ignore=0
|
|
;;
|
|
*)
|
|
echo "error: unknown parameter: $1" >&2
|
|
return 2
|
|
;;
|
|
esac
|
|
uci commit dhcp
|
|
/etc/init.d/dnsmasq restart
|
|
}
|
|
|
|
# Returns the determined mode (cap, re, or unknown)
|
|
netdet_get_mode_db() {
|
|
local mode="unknown"
|
|
if [ -f $NETDET_MODE_DB ]; then
|
|
mode="$(cat $NETDET_MODE_DB)"
|
|
fi
|
|
echo $mode
|
|
}
|
|
|
|
# Saves the given mode to the database
|
|
netdet_set_mode_db() {
|
|
local mode="$1"
|
|
local tmpfile="$(dirname $NETDET_MODE_DB)/.$(basename $NETDET_MODE_DB)"
|
|
echo "$mode" > $tmpfile
|
|
mv $tmpfile $NETDET_MODE_DB
|
|
}
|
|
|
|
# Add our custom WiFi SON TLV to lldpd
|
|
netdet_set_custom_wifison_lldp_tlv() {
|
|
# remove any existing custom TLVs
|
|
lldpcli unconfigure lldp custom-tlv > /dev/null
|
|
lldpcli configure lldp custom-tlv oui $NETDET_LLDP_WIFISON_CUSTOM_TLV_OUI subtype $NETDET_LLDP_WIFISON_CUSTOM_TLV_SUBTYPE oui-info $NETDET_LLDP_WIFISON_CUSTOM_TLV_DATA > /dev/null
|
|
}
|
|
|
|
# Set lldpd interfaces
|
|
netdet_set_lldpd_interfaces() {
|
|
lldpcli configure system interface pattern $(__netdet_get_interfaces | tr '\n' ',')
|
|
}
|
|
|
|
# Set lldp tx interval
|
|
# input: $1 - the interval in seconds
|
|
netdet_set_lldpd_tx_interval() {
|
|
lldpcli configure lldp tx-interval $1
|
|
}
|
|
|
|
# Do WAN/LAN detection
|
|
netdet_wan_lan_detect() {
|
|
__netdet_debug "running wan/lan detection"
|
|
local is_uplink_no_wifison="false"
|
|
local is_uplink_with_wifison="false"
|
|
local int="eth0"
|
|
__netdet_is_wifison_device_visible $int
|
|
case $? in
|
|
$NETDET_IS_WIFISON_DEVICE_VISIBLE_TRUE)
|
|
is_uplink_with_wifison="true"
|
|
__netdet_debug "$int: LAN (with visible Wi-Fi SON device)"
|
|
;;
|
|
$NETDET_IS_WIFISON_DEVICE_VISIBLE_FALSE)
|
|
is_uplink_no_wifison="true"
|
|
__netdet_debug "$int: WAN"
|
|
;;
|
|
*)
|
|
__netdet_debug "got unknown return from __netdet_is_wifison_device_visible"
|
|
;;
|
|
esac
|
|
if [ "$is_uplink_no_wifison" == "true" ]; then
|
|
__netdet_debug "looks like a root AP"
|
|
return $NETDET_RESULT_ROOTAP
|
|
elif [ "$is_uplink_with_wifison" == "true" ]; then
|
|
__netdet_debug "looks like a range extender"
|
|
return $NETDET_RESULT_RE
|
|
else
|
|
__netdet_debug "indeterminate"
|
|
return $NETDET_RESULT_INDETERMINATE
|
|
fi
|
|
}
|
|
|
|
# determines if the local device should be configured for bridge mode or router
|
|
# mode. the decision is based on whether the WAN interface is configured on
|
|
# a private network.
|
|
netdet_detect_cap_bridge_router_mode() {
|
|
local dev
|
|
local ipaddr
|
|
local net
|
|
local privnets
|
|
|
|
__netdet_debug "detecting whether this cap should be a bridge or router"
|
|
|
|
dev=$(uci get network.wan.ifname 2>/dev/null)
|
|
[ -z "${dev}" ] && {
|
|
dev=$NETDET_LANBRIDGE
|
|
}
|
|
|
|
ipaddr=$(ip addr show dev $dev | grep "inet " | awk '{print $2}')
|
|
[ -z '${ipaddr}' ] && {
|
|
# assume router so the firewall will be up when the interface comes up
|
|
__netdet_debug "no IP addr configured, should configure as router"
|
|
return $NETDET_CAP_BRIDGE_ROUTER_RESULT_ROUTER
|
|
}
|
|
net=$(ipcalc.sh ${ipaddr} | grep NETWORK)
|
|
|
|
privnets=$(uci get repacd.repacd.rfc1918 2>/dev/null)
|
|
[ -z "${privnets}" ] && {
|
|
privnets='10.0.0.0/8 172.16.0.0/12 192.168.0.0/16'
|
|
}
|
|
|
|
__netdet_debug "checking the wan iface against the list of private networks"
|
|
for privcidr in ${privnets}; do
|
|
local privnet=$(ipcalc.sh ${privcidr} | grep NETWORK)
|
|
[ "${net}" = "${privnet}" ] && {
|
|
__netdet_debug "the wan iface is on a private network, should configure as bridge"
|
|
return $NETDET_CAP_BRIDGE_ROUTER_RESULT_BRIDGE
|
|
}
|
|
done
|
|
|
|
__netdet_debug "should configure as router"
|
|
return $NETDET_CAP_BRIDGE_ROUTER_RESULT_ROUTER
|
|
}
|
|
|
|
# modifies the local device to run in bridge mode
|
|
netdet_configure_cap_bridge_mode() {
|
|
__netdet_debug "configuring cap in bridge mode"
|
|
uci set dhcp.lan.ignore=1
|
|
uci commit dhcp
|
|
/etc/init.d/dnsmasq restart
|
|
|
|
uci set network.lan.ifname='eth0 eth1'
|
|
uci set network.lan.proto='dhcp'
|
|
uci delete network.wan
|
|
uci commit network
|
|
/etc/init.d/network restart
|
|
|
|
uci set repacd.GatewayConnectedMode='CAP'
|
|
uci commit repacd
|
|
/etc/init.d/repacd restart
|
|
}
|
|
|
|
# modifies the local device to run in router mode
|
|
netdet_configure_cap_router_mode() {
|
|
__netdet_debug "configuring cap in router mode"
|
|
uci set network.lan.ifname='eth1'
|
|
uci set network.lan.proto='static'
|
|
uci set network.lan.ipaddr='192.168.1.1'
|
|
|
|
uci set network.wan=interface
|
|
uci set network.wan.ifname='eth0'
|
|
uci set network.wan.proto='dhcp'
|
|
|
|
uci commit network
|
|
/etc/init.d/network restart
|
|
|
|
uci delete dhcp.lan.ignore
|
|
uci commit dhcp
|
|
/etc/init.d/dnsmasq restart
|
|
/etc/init.d/repacd restart
|
|
}
|
|
|
|
# setup lldpd parameters since these don't persist across restart
|
|
repacd_netdet_lldpd_setup() {
|
|
netdet_set_lldpd_interfaces
|
|
netdet_set_lldpd_tx_interval 10
|
|
netdet_set_custom_wifison_lldp_tlv
|
|
}
|
|
|
|
repacd_netdet_init() {
|
|
repacd_netdet_lldpd_setup
|
|
}
|
|
|
|
repacd_netdet_lldpd_init() {
|
|
/etc/init.d/lldpd $1
|
|
if [ $1 != "stop" ]; then
|
|
while ! [ -e /var/run/lldpd.socket ]; do
|
|
sleep 1
|
|
done
|
|
repacd_netdet_lldpd_setup
|
|
fi
|
|
}
|
|
|
|
# Get the device's currently configured mode
|
|
repacd_netdet_get_current_device_mode() {
|
|
if uci get network.wan > /dev/null; then
|
|
return $NETDET_CURRENT_MODE_ROOTAP
|
|
else
|
|
return $NETDET_CURRENT_MODE_RE
|
|
fi
|
|
}
|
|
|
|
# Configure this device as either a rootap or an re
|
|
repacd_netdet_set_current_device_mode() {
|
|
local mode="$1"
|
|
case $mode in
|
|
rootap)
|
|
netdet_detect_cap_bridge_router_mode
|
|
local result=$?
|
|
case $result in
|
|
$NETDET_CAP_BRIDGE_ROUTER_RESULT_ROUTER)
|
|
netdet_configure_cap_router_mode
|
|
;;
|
|
$NETDET_CAP_BRIDGE_ROUTER_RESULT_BRIDGE)
|
|
netdet_configure_cap_bridge_mode
|
|
;;
|
|
*)
|
|
echo "error: unknown mode: $result" >&2
|
|
return 3
|
|
;;
|
|
esac
|
|
;;
|
|
re)
|
|
__repacd_netdet_dhcpd disable
|
|
uci set network.lan.ifname='eth0 eth1'
|
|
uci set network.lan.proto=dhcp
|
|
uci delete network.wan
|
|
uci commit network
|
|
/etc/init.d/network restart
|
|
/etc/init.d/repacd restart
|
|
;;
|
|
*)
|
|
echo "error: unknown mode: $mode" >&2
|
|
return 2
|
|
;;
|
|
esac
|
|
}
|
|
|
|
repacd_netdet_wait_for_dhcp_addr() {
|
|
local intf=$1
|
|
local timeout=$2
|
|
if [ -z "$timeout" ]; then
|
|
timeout=15
|
|
fi
|
|
local endtime=$(( $(date +%s) + $timeout ))
|
|
while ! __netdet_has_dhcp_address $intf; do
|
|
sleep 1
|
|
if [ $(date +%s) -gt $endtime ]; then
|
|
return 1
|
|
fi
|
|
done
|
|
return 0
|
|
}
|