#!/bin/sh
# Copyright (C) BlueWave Projects and Services 2015-2024
#
#	This software is released under the GNU General Public License version 3 or any later version.
#	This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation,
#	either version 3 of the License, or (at your option) any later version.
#
#	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.
#
#	To obtain a copy of the GNU General Public License, see <https://www.gnu.org/licenses/>.
#
# mesh11sd daemon
#
version="4.1.1"
fixup1=0
ip4pingfailcount=0
network_restart=0
tmpdir="/tmp/mesh11sd"
mkdir -p "$tmpdir"


get_mesh_iflist () {
	iflist=""
	all_ifcs=$(iw dev | awk -F "Interface " '$2>0{printf "%s " $2}')

	for iface in $all_ifcs; do
		iftype=$(iw dev $iface info 2> /dev/null | grep "type" | awk '{printf "%s", $2}')

		if [ ! -z "$iftype" ] && [ "$iftype" = "mesh" ]; then
			iflist="$iflist $iface"
		fi
	done
}

check_mesh_phantom () {
	nodelist=$(iw dev $iface mpath dump | awk '{printf "%s,%s ", $1, $2}')

	for node in $nodelist; do

		debugtype="debug"
		syslogmessage="node [$node]"
		write_to_syslog

		phantom=$(echo "$node" | awk -F"," '$2 == "00:00:00:00:00:00" {printf $1 }')

		if [ ! -z "$phantom" ]; then
			debugtype="info"
			syslogmessage="Phantom meshnode detected [$phantom] - deleting"
			write_to_syslog
			iw dev $iface mpath del $phantom
		fi
	done
}

get_params () {
	params=$(iw dev $iface mesh_param dump 2> /dev/null)

	if [ "$?" -ne 0 ]; then
		buffer="/tmp/"$(date | sha256sum | awk '{printf $1}')
		param_list=$(iw dev $iface get mesh_param 2> /dev/null | grep " - " | awk -F" - " '{printf "%s ", $2}')
		params=""


		for param in $param_list; do
			paramval=$(iw dev $iface get mesh_param $param 2> /dev/null)
			if [ "$?" -eq 0 ]; then
				paramline="$param = $paramval"
				echo "$paramline" >> $buffer
			fi
		done



		if [ -f "$buffer" ]; then
			params=$(cat $buffer)
			rm "$buffer"
		fi
	fi
}

check_mesh_params () {

	for param in $params; do

		conf=$(uci get $uciname.$param 2> /dev/null)

		if [ -z "$conf" ]; then
			continue
		fi

		param_value=$(iw dev $iface get mesh_param $param 2> /dev/null | awk '{printf "%s", $1}')

		if [ -z "$param_value" ]; then
			debugtype="info"
			syslogmessage="Failed to get current value of $param, mesh interface not established."
			write_to_syslog
			continue
		fi

		if [ "$param_value" != "$conf" ]; then

			if [ "$param" = "mesh_rssi_threshold" ]; then
				if [ ! -f "/tmp/mesh_rssi_threshold" ]; then
					debugtype="info"
					syslogmessage="Old value:$param=$param_value, Setting new value:$param=$conf"
					write_to_syslog
					iwstatus=$(iw dev $iface set mesh_param $param "$conf" 2>&1)
					mesh_rssi_threshold=$conf
					echo "meshinterface=\"$iface\"" > /tmp/meshinterface
					all_nodes_rssi_update
				fi
			elif [ "$param" != "mesh_rssi_threshold" ]; then
				debugtype="info"
				syslogmessage="Old value:$param=$param_value, Setting new value:$param=$conf"
				write_to_syslog
				iwstatus=$(iw dev $iface set mesh_param $param "$conf" 2>&1)
			fi


			if [ ! -z "$iwstatus" ]; then
				debugtype="err"
				syslogmessage="$param: $iwstatus"
				write_to_syslog
			fi
		fi
	done
}

restart_mesh () {
	set_txpower
	mesh_gate_state
	wifi
	wait_for_mesh

	if [ -f "$tmpdir/devicemac" ]; then
		. $tmpdir/devicemac
		ip link set "$device" arp on
		ip link set "$device" multicast on
	fi

}

get_current_setup () {
	debuglevel=$(uci get mesh11sd.setup.debuglevel 2> /dev/null | awk '{printf "%i", $1}')

	if [ -z "$debuglevel" ]; then
		debuglevel=1
	fi

	syslogmessage="Reading configuration"
	debugtype="notice"
	write_to_syslog

	enabled=$(uci get mesh11sd.setup.enabled 2> /dev/null)

	if [ -z "$enabled" ]; then
		enabled=1
	fi

	syslogmessage="option enabled [ $enabled ]"
	debugtype="info"
	write_to_syslog

	#####
	syslogmessage="option debuglevel [ $debuglevel ]"
	debugtype="info"
	write_to_syslog

	#####
	checkinterval=$(uci get mesh11sd.setup.checkinterval 2> /dev/null)

	if [ -z "$checkinterval" ] || [ "$checkinterval" -lt 10 ]; then
		checkinterval=10
	fi

	syslogmessage="option checkinterval [ $checkinterval ]"
	debugtype="info"
	write_to_syslog

	#####
	portal_detect=$(uci get mesh11sd.setup.portal_detect 2> /dev/null)

	if [ -z "$portal_detect" ]; then
		portal_detect=1
	fi

	syslogmessage="option portal_detect [ $portal_detect ]"
	debugtype="info"
	write_to_syslog

	#####
	portal_channel=$(uci get mesh11sd.setup.portal_channel 2> /dev/null)

	if [ -z "$portal_channel" ]; then
		portal_channel="default"
	fi

	syslogmessage="option portal_channel [ $portal_channel ]"
	debugtype="info"
	write_to_syslog

	#####
	channel_tracking_checkinterval=$(uci get mesh11sd.setup.channel_tracking_checkinterval 2> /dev/null)

	if [ -z "$channel_tracking_checkinterval" ]; then
		channel_tracking_checkinterval="30"
	fi

	syslogmessage="option channel_tracking_checkinterval [ $channel_tracking_checkinterval ]"
	debugtype="info"
	write_to_syslog

	#####
	portal_detect_threshold=$(uci get mesh11sd.setup.portal_detect_threshold 2> /dev/null)

	if [ -z "$portal_detect_threshold" ]; then
		portal_detect_threshold=0
	fi

	syslogmessage="option portal_detect_threshold [ $portal_detect_threshold ]"
	debugtype="info"
	write_to_syslog

	#####
	get_mesh_path_cost

	#####
	interface_timeout=$(uci get mesh11sd.setup.interface_timeout 2> /dev/null)

	if [ -z "$interface_timeout" ] || [ "$interface_timeout" -lt 10 ]; then
		interface_timeout=10
	fi

	syslogmessage="option interface_timeout [ $interface_timeout ]"
	debugtype="info"
	write_to_syslog

	#####
	auto_config=$(uci get mesh11sd.setup.auto_config 2> /dev/null)

	if [ -z "$auto_config" ]; then
		auto_config=0
	elif [ "$auto_config" -ne 0 ]; then
		auto_config=1
	fi

	syslogmessage="option auto_config [ $auto_config ]"
	debugtype="info"
	write_to_syslog

	#####
	auto_mesh_id=$(uci get mesh11sd.setup.auto_mesh_id 2> /dev/null | awk '{printf "%s", $1}')

	if [ -z "$auto_mesh_id" ]; then
		auto_mesh_id="--__"
	fi

	auto_mesh_id=$(printf "$auto_mesh_id" | sha256sum | awk '{printf $1}' | tail -c55 | head -c30)

	syslogmessage="auto_mesh_id hash [ $auto_mesh_id ]"
	debugtype="info"
	write_to_syslog

	#####
	auto_mesh_band=$(uci get mesh11sd.setup.auto_mesh_band 2> /dev/null | awk '{printf "%s", $1}')

	if [ -z "$auto_mesh_band" ]; then
		auto_mesh_band="2g40"
	fi

	bandlist="2g 5g 6g 60g"
	bandcheck=0

	for band in $bandlist; do

		if [ "$band" = "$auto_mesh_band" ]; then
			bandcheck=1
			break
		fi

	done

	if [ "$bandcheck" = 0 ]; then
		auto_mesh_band="2g40"
	fi

	syslogmessage="option auto_mesh_band [ $auto_mesh_band ]"
	debugtype="info"
	write_to_syslog

	#####
	auto_mesh_key=$(uci get mesh11sd.setup.auto_mesh_key 2> /dev/null | awk '{printf "%s", $1}')

	if [ -z "$auto_mesh_key" ]; then
		auto_mesh_key=$(echo "$auto_mesh_id""91b39a9b41e918e9bce1c8d5d7d3e071d6f1f8855a7c0214f687550177c5d5b8" | sha256sum | awk '{printf "%s", $1}')
	else
		auto_mesh_key=$(echo "$auto_mesh_id""$auto_mesh_key" | sha256sum | awk '{printf "%s", $1}')
	fi

	syslogmessage="option auto_mesh_key [ $auto_mesh_key ]"
	debugtype="info"
	write_to_syslog

	#####
	# Get the default lan mac address
	auto_mesh_network=lan
	refresh_bridgemac
	. $tmpdir/devicemac

	auto_mesh_network=$(uci get mesh11sd.setup.auto_mesh_network 2> /dev/null)

	if [ -z "$auto_mesh_network" ]; then
		auto_mesh_network="lan"

		if [ "$auto_config" -eq 0 ]; then
			syslogmessage="option auto_mesh_network is not configured, defaulting to [ $auto_mesh_network ]. Is this what you intended?"
			debugtype="warn"
			write_to_syslog
		fi
	fi

	# Block wan and wan6 as valid network zones for mesh unless portal_detect - 3 (CPE mode)

	if [ "$portal_detect"  -ne 3 ]; then

		if [ "$auto_mesh_network" = "wan" ] || [ "$auto_mesh_network" = "wan6" ]; then
			auto_mesh_network="lan"
		fi

	elif [ "$portal_detect"  -eq 3 ] && [ "$auto_mesh_network" = "lan" ]; then
		auto_mesh_network="wan"
	fi

	zone_status=$(uci show firewall | grep -w "name='$auto_mesh_network'" &>/dev/null ; echo -n "$?")

	if [ "$zone_status" -eq 1 ]; then
		syslogmessage="network zone [ $auto_mesh_network ] does not exist"
		debugtype="warn"
		write_to_syslog
		auto_mesh_network="lan"
	else
		syslogmessage="option auto_mesh_network [ $auto_mesh_network ]"
		debugtype="info"
		write_to_syslog
	fi
	syslogmessage="option auto_mesh_network [ $auto_mesh_network ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_basename=$(uci get mesh11sd.setup.mesh_basename 2> /dev/null)

	if [ -z "$mesh_basename" ]; then
		mesh_basename="m-11s-"
	else
		#remove non alphanumeric
		mesh_basename=$(echo "$mesh_basename" | sed 's/[^a-zA-Z0-9]//g')
		#get first 4 chars
		mesh_basename="m-${mesh_basename:0:4}-"
		#convert to lower case
		mesh_basename=$(printf $mesh_basename | tr '[A-Z]' '[a-z]')
	fi

	syslogmessage="option mesh_basename [ $mesh_basename ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_gate_encryption=$(uci get mesh11sd.setup.mesh_gate_encryption 2> /dev/null)
	installed_wpad=$(opkg list-installed | grep "wpad" | awk '{printf "%s", $1}' | awk -F "-" '{print $2}')

	if [ -z "$installed_wpad" ]; then
		installed_wpad="none"
	fi

	if [ -z "$mesh_gate_encryption" ]; then
		mesh_gate_encryption=0
	fi

	if [ "$mesh_gate_encryption" -eq 4 ]; then
		case $installed_wpad in
			"mesh") mesh_gate_encryption=0;;
			"mbedtls") mesh_gate_encryption=4;;
			"wolfssl") mesh_gate_encryption=4;;
			"openssl") mesh_gate_encryption=4;;
			*) mesh_gate_encryption=0;;
		esac
	fi


	if [ "$mesh_gate_encryption" -le 4 ]; then
		syslogmessage="option mesh_gate_encryption [ $mesh_gate_encryption ]"
		debugtype="info"
		write_to_syslog
	else
		syslogmessage="option mesh_gate_encryption must be 0 (none), 1 (sae, aka wpa3), 2 (sae-mixed, aka wpa2/wpa3), 3 (psk2, aka wpa2) or 4 (owe)"
		debugtype="err"
		write_to_syslog
	fi

	#####

	#####
	mesh_gate_key=$(uci get mesh11sd.setup.mesh_gate_key 2> /dev/null)

	if [ -z "$mesh_gate_key" ]; then
		mesh_gate_key=""
	fi

	if [ "$mesh_gate_encryption" -eq 4 ]; then
		mesh_gate_key="owe_null_key"
	fi

	keylen=$((${#mesh_gate_key}))

	if [ "$keylen" -le 7 ] && [ "$keylen" -gt 0 ]; then
		syslogmessage="mesh_gate_key [ $mesh_gate_key ] is too short, it must be 8 or more characters in length"
		debugtype="err"
		write_to_syslog
		mesh_gate_key=""
	else
		syslogmessage="option mesh_gate_key [ $mesh_gate_key ]"
		debugtype="info"
		write_to_syslog
	fi

	#####

	#####
	mesh_gate_enable=$(uci get mesh11sd.setup.mesh_gate_enable 2> /dev/null)

	if [ -z "$mesh_gate_enable" ]; then
		mesh_gate_enable="1"
	fi

	syslogmessage="option mesh_gate_enable [ $mesh_gate_enable ]"
	debugtype="info"
	write_to_syslog

	#####

	#####
	# mesh_gate_only deprecated as a config option - use mesh_leechmode_enable instead as the config option
	mesh_gate_only=$(uci get mesh11sd.setup.mesh_leechmode_enable 2> /dev/null)

	if [ -z "$mesh_gate_only" ]; then
		mesh_gate_only=$(uci get mesh11sd.setup.mesh_gate_only 2> /dev/null)
	fi

	if [ -z "$mesh_gate_only" ]; then
		mesh_gate_only="0"
	fi

	if [ "$mesh_gate_only" -eq 1 ] && [ "$mesh_gate_enable" -eq 0 ]; then
		mesh_gate_only="0"
	fi

	syslogmessage="option mesh_gate_only [ $mesh_gate_only ]"
	debugtype="info"
	write_to_syslog

	#####

	txpower=$(uci get mesh11sd.setup.txpower 2> /dev/null)

	if [ ! -z "$txpower" ]; then
		syslogmessage="option txpower [ $txpower ]"
		debugtype="info"
		write_to_syslog
	fi

	#####
	ssid_suffix_enable=$(uci get mesh11sd.setup.ssid_suffix_enable 2> /dev/null)

	if [ -z "$ssid_suffix_enable" ]; then
		ssid_suffix_enable="1"
	fi

	syslogmessage="option ssid_suffix_enable [ $ssid_suffix_enable ]"
	debugtype="info"
	write_to_syslog

	#####
	watchdog_nonvolatile_log=$(uci get mesh11sd.setup.watchdog_nonvolatile_log 2> /dev/null)

	if [ -z "$watchdog_nonvolatile_log" ]; then
		watchdog_nonvolatile_log="0"
	fi

	syslogmessage="option watchdog_nonvolatile_log [ $watchdog_nonvolatile_log ]"
	debugtype="info"
	write_to_syslog

	if [ "$watchdog_nonvolatile_log" -gt 0 ]; then
		syslogmessage="******WARNING******: Irrepairable flash wear will occur and storage space will be used up. Please disable watchdog nonvolatile logging as soon as possible."
		debugtype="warn"
		write_to_syslog
		syslogmessage="******WARNING******: Irrepairable flash wear will occur and storage space will be used up by watchdog debug log at /mesh11sd_log/watchdog.log"
		debugtype="warn"
		write_to_syslog
		mkdir -p /mesh11sd_log
	fi

	#####
	mesh_path_stabilisation=$(uci get mesh11sd.setup.mesh_path_stabilisation 2> /dev/null)

	if [ -z "$mesh_path_stabilisation" ]; then
		mesh_path_stabilisation="1"
	fi

	syslogmessage="option mesh_path_stabilisation [ $mesh_path_stabilisation ]"
	debugtype="info"
	write_to_syslog
}

check_config_params() {
	################
	# Set default parameters if not in config

	#####
	mesh_fwding=$(uci get mesh11sd.mesh_params.mesh_fwding 2> /dev/null)

	if [ -z "$mesh_fwding" ]; then
		mesh_fwding="1"
	fi

	if [ "$mesh_fwding" -eq 1 ] && [ "$mesh_gate_only" -eq 1 ]; then
		mesh_fwding="0"
	fi

	echo "set mesh11sd.mesh_params.mesh_fwding='$mesh_fwding'" | uci batch

	syslogmessage="option mesh_fwding [ $mesh_fwding ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_rssi_threshold=$(uci get mesh11sd.mesh_params.mesh_rssi_threshold 2> /dev/null)

	if [ -z "$mesh_rssi_threshold" ] || [ "$mesh_rssi_threshold" -gt 0 ]; then
		mesh_rssi_threshold="-65"
		echo "set mesh11sd.mesh_params.mesh_rssi_threshold='$mesh_rssi_threshold'" | uci batch
	fi

	syslogmessage="option mesh_rssi_threshold [ $mesh_rssi_threshold ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_gate_announcements=$(uci get mesh11sd.mesh_params.mesh_gate_announcements 2> /dev/null)

	if [ -z "$mesh_gate_announcements" ]; then
		mesh_gate_announcements="1"
	fi

	if [ "$mesh_gate_announcements" -eq 1 ] && [ "$mesh_gate_enable" -eq 0 ]; then
		mesh_gate_announcements="0"
	fi

	if [ "$mesh_gate_only" -gt 0 ]; then
		mesh_gate_announcements="0"
	fi

	echo "set mesh11sd.mesh_params.mesh_gate_announcements='$mesh_gate_announcements'" | uci batch

	syslogmessage="option mesh_gate_announcements [ $mesh_gate_announcements ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_hwmp_rootmode=$(uci get mesh11sd.mesh_params.mesh_hwmp_rootmode 2> /dev/null)

	if [ -z "$mesh_hwmp_rootmode" ]; then
		mesh_hwmp_rootmode="4"
		echo "set mesh11sd.mesh_params.mesh_hwmp_rootmode='$mesh_hwmp_rootmode'" | uci batch
	fi

	syslogmessage="option mesh_hwmp_rootmode [ $mesh_hwmp_rootmode ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_hwmp_rann_interval=$(uci get mesh11sd.mesh_params.mesh_hwmp_rann_interval 2> /dev/null)

	if [ -z "$mesh_hwmp_rann_interval" ]; then
		mesh_hwmp_rann_interval="5000"
		echo "set mesh11sd.mesh_params.mesh_hwmp_rann_interval='$mesh_hwmp_rann_interval'" | uci batch
	fi

	syslogmessage="option mesh_hwmp_rann_interval [ $mesh_hwmp_rann_interval ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_hwmp_root_interval=$(uci get mesh11sd.mesh_params.mesh_hwmp_root_interval 2> /dev/null)

	if [ -z "$mesh_hwmp_root_interval" ]; then
		mesh_hwmp_root_interval="5000"
		echo "set mesh11sd.mesh_params.mesh_hwmp_root_interval='$mesh_hwmp_root_interval'" | uci batch
	fi

	syslogmessage="option mesh_hwmp_root_interval [ $mesh_hwmp_root_interval ]"
	debugtype="info"
	write_to_syslog

	#####
	mesh_hwmp_active_path_timeout=$(uci get mesh11sd.mesh_params.mesh_hwmp_active_path_timeout 2> /dev/null)

	if [ -z "$mesh_hwmp_active_path_timeout" ]; then
		mesh_hwmp_active_path_timeout="5000"
		echo "set mesh11sd.mesh_params.mesh_hwmp_active_path_timeout='$mesh_hwmp_active_path_timeout'" | uci batch
	fi

	syslogmessage="option mesh_hwmp_active_path_timeout [ $mesh_hwmp_active_path_timeout ]"
	debugtype="info"
	write_to_syslog

	#####

	mesh_hwmp_active_path_to_root_timeout=$(uci get mesh11sd.mesh_params.mesh_hwmp_active_path_to_root_timeout 2> /dev/null)

	if [ -z "$mesh_hwmp_active_path_to_root_timeout" ]; then
		mesh_hwmp_active_path_to_root_timeout="6000"
		echo "set mesh11sd.mesh_params.mesh_hwmp_active_path_to_root_timeout='$mesh_hwmp_active_path_to_root_timeout'" | uci batch
	fi

	syslogmessage="option mesh_hwmp_active_path_to_root_timeout [ $mesh_hwmp_active_path_to_root_timeout ]"
	debugtype="info"
	write_to_syslog

	#####

	mesh_max_peer_links=$(uci get mesh11sd.mesh_params.mesh_max_peer_links 2> /dev/null)

	if [ -z "$mesh_max_peer_links" ]; then
		mesh_max_peer_links="16"
		echo "set mesh11sd.mesh_params.mesh_max_peer_links='$mesh_max_peer_links'" | uci batch
	fi

	syslogmessage="option mesh_max_peer_links [ $mesh_max_peer_links ]"
	debugtype="info"
	write_to_syslog

	#####

	mesh_plink_timeout=$(uci get mesh11sd.mesh_params.mesh_plink_timeout 2> /dev/null)

	if [ -z "$mesh_plink_timeout" ]; then
		mesh_plink_timeout="$checkinterval"
		echo "set mesh11sd.mesh_params.mesh_plink_timeout='$mesh_plink_timeout'" | uci batch
	fi

	syslogmessage="option mesh_plink_timeout [ $mesh_plink_timeout ]"
	debugtype="info"
	write_to_syslog

}

get_mesh_path_cost () {
	mesh_path_cost=$(uci get mesh11sd.setup.mesh_path_cost 2> /dev/null)

	if [ -z "$mesh_path_cost" ]; then
		mesh_path_cost="10"
	fi

	syslogmessage="option mesh_path_cost [ $mesh_path_cost ]"
	debugtype="info"
	write_to_syslog
}

wait_for_interface () {
	local ifname="$1"
	local timeout=$interface_timeout

	for i in $(seq $timeout); do
		if [ $(ip link show $ifname 2> /dev/null | grep -c -w "state UP") -eq 1 ]; then
			ifstatus="up"
			break
		fi
		sleep 1
		if [ $i == $timeout ] ; then
			syslogmessage="$ifname is not up - giving up for now."
			debugtype="notice"
			write_to_syslog
			ifstatus="down"
		fi
	done
}

# Write debug message to syslog
# $syslogmessage contains the string to log
# $debugtype contains the debug level string: debug, info, warn, notice, err, emerg.
write_to_syslog() {

	if [ "$mute" = 0 ]; then
		debuglevel=$(uci get mesh11sd.setup.debuglevel 2> /dev/null)

		if [ -z "$debuglevel" ]; then
			debuglevel=1
		fi

		if [ ! -z "$syslogmessage" ]; then

			case $debugtype in
				"emerg") debugnum=0;;
				"err") debugnum=0;;
				"notice") debugnum=1;;
				"warn") debugnum=1;;
				"info") debugnum=2;;
				"debug") debugnum=3;;
				*) debugnum=1; debugtype="notice";;
			esac

			if [ "$debuglevel" -ge "$debugnum" ]; then
				echo "$syslogmessage" | logger -p "daemon.$debugtype" -s -t "mesh11sd[$mesh11sdpid]"
			fi
		fi
	else
		mute=0
	fi
}

write_to_watchdog_nonvolatile_log() {

	if [ "$watchdog_nonvolatile_log" -gt 0 ]; then
		mkdir -p /mesh11sd_log
		echo "$(date) $syslogmessage" >> /mesh11sd_log/mesh11sd.log
	fi
}


mesh_gate_state() {
	aplist=$(uci show wireless | grep "mode='ap'" | awk -F "." '{printf "%s ", $2}')

	for gate in $aplist; do
		config_state=$(echo "get wireless.$gate.disabled" | uci batch 2> /dev/null)

		if [ -z "$config_state" ] && [ "$mesh_gate_enable" -eq 1 ]; then
			ucibatch="set wireless.$gate.disabled='0'"
			echo "$ucibatch" | uci batch
		elif [ -z "$config_state" ] && [ "$mesh_gate_enable" -eq 0 ]; then
			ucibatch="set wireless.$gate.disabled='1'"
			echo "$ucibatch" | uci batch
		fi
	done
}

set_txpower() {

	if [ ! -z "$txpower" ]; then
		radiolist=$(uci show wireless | grep "wifi-device" | awk -F "=" '{printf "%s ", $1}')

		for radio in $radiolist; do
			config_state=$(echo "get $radio.txpower" | uci batch 2> /dev/null)

			if [ -z "$config_state" ]; then
				ucibatch="set $radio.txpower='$txpower'"
				echo "$ucibatch" | uci batch
			fi
		done
	fi
}


check_gate() {
	is_gate=$(iw dev | grep -w "type AP")

	if [ -z "$is_gate" ]; then
		uci set mesh11sd.mesh_params.mesh_connected_to_gate='0'
	else
		uci set mesh11sd.mesh_params.mesh_connected_to_gate='1'
	fi
}

check_channel() {
	# Can we see the portal?
	link_to_portal=0

	# We need to scan for working channel if we cannot see a portal
	# Check for portal every channel_tracking_checkinterval seconds

	timenow=$(date +%s)

	debugtype="debug"
	syslogmessage="checking for working channel...."
	write_to_syslog

	if [ -z $cctimestamp ]; then
		cctimestamp=$(date +%s)
	fi

	elapsed_time=$(($timenow - $cctimestamp))
	mininterval=$channel_tracking_checkinterval

	if [ "$mininterval" -le "$elapsed_time" ]; then
		ifaces=$(uci export wireless | grep "config wifi-iface" | awk -F"'" '$2 != "" {printf "%s ",$2}')

		for iface in $ifaces; do
			ucibatch="get wireless.$iface.mode"
			mode=$(echo "$ucibatch" | uci batch)

			if [ "$mode" = "mesh" ]; then
				ucibatch="get wireless.$iface.network"
				network=$(echo "$ucibatch" | uci batch)
				ucibatch="get network.$network.device"
				device=$(echo "$ucibatch" | uci batch)

				if [ -f "$tmpdir/dhcp6probe" ]; then
					mv "$tmpdir/dhcp6probe" "$tmpdir/dhcp6probe.prev"
				fi

				odhcp6c -p /var/run/odhcp6c-renew-$device.pid -e -v -k "$device" 2>$tmpdir/dhcp6probe &

				local retries=20

				for retry in $(seq $retries); do

					if [ -f "$tmpdir/dhcp6probe" ]; then
						sleep 4
						break
					else
						sleep 1
						continue
					fi
				done

				link_to_portal=$(cat $tmpdir/dhcp6probe | grep -q -w "Got a valid ADVERTISE" ; echo -n "$?")

				# NOTE: odhcp6c -p option does not work and pid is not recorded, so we have to look up the pid using ps utility
				instances=$(ps | grep "odhcp6c" | grep "/var/run/odhcp6c-renew-$device.pid" | awk '{printf "%s ", $1}')

				for instance in $instances; do
					kill "$instance"
				done

				debugtype="debug"

				if [ "$link_to_portal" -eq 0 ]; then
					syslogmessage="portal detected"
				else
					syslogmessage="portal not detected"
				fi

				write_to_syslog
				cctimestamp=""
				scan_channel
				continue
			fi
		done
	fi
}

scan_channel() {
	debugtype="debug"
	syslogmessage="Entering scan channel...."
	write_to_syslog

	if [ "$link_to_portal" -gt 0 ]; then
		# No link to portal. Maybe we are on the wrong channel, so scan for meshid to get channel
		meshconfigs=$(uci show wireless 2> /dev/null | grep "mode='mesh'" | awk -F ".mode='mesh'" '{printf "%s " $1}')

		if [ ! -z "$meshconfigs" ]; then

			for meshconfig in $meshconfigs; do
				ifname=$(uci get $meshconfig.ifname)
				our_channel=$(iw dev $ifname info 2> /dev/null | grep -w "channel" | awk -F " " '{printf "%s", $2}')
				mesh_id=$(uci get $meshconfig.mesh_id)
				scanned_channels=$(iw dev $ifname scan 2> /dev/null | grep -F -w -B 20 "MESH ID: $mesh_id" | awk -F "primary channel: " '$2 != "" {printf "%s ",$2}')

				if [ ! -z "$our_channel" ] && [ "$our_channel" -le 14 ]; then
					band="2g"
				else
					band=""
				fi

				if [ ! -z "$our_channel" ] && [ ! -z "$scanned_channels" ]; then

					for channel in $scanned_channels; do

						if [ "$channel" -gt 14 ] && [ "$band" = "2g" ]; then
							continue
						fi

						if [ "$channel" -eq "$our_channel" ]; then
							continue
						else
							device=$(uci get $meshconfig.device)
							echo "set wireless.$device.channel='$channel'" | uci batch

							debugtype="notice"
							syslogmessage="Tracking channel from [ $our_channel ] to [ $channel ]"
							write_to_syslog

							restart_mesh
							break
						fi
					done
				fi

				ucibatch=""
			done

		fi
	fi
}

get_portal_state() {
	debugtype="debug"
	syslogmessage="In get_portal_state. firstloop=$firstloop..."
	write_to_syslog
	. $tmpdir/devicemac

	if [ "$firstloop" -eq 1 ] && [ "$portal_detect" -eq 1 ]; then
		# 1 - check if portal
		local retries=10

		for retry in $(seq $retries); do
			default_gw=$(ip route | grep "default via")

			if [ -z "$default_gw" ]; then
				debugtype="debug"
				syslogmessage="In Startup - portal upstream link check - iteration [ $retry ] ...."
				write_to_syslog
				sleep 1
				continue
			fi
		done

	elif [ "$portal_detect" -eq 2 ] || [ "$portal_detect" -eq 3 ]; then
		# 2 - force peer mode , 3 - force CPE peer mode
		uci set dhcp.@dnsmasq[0].authoritative='0'
		default_gw=""

	elif [ "$portal_detect" -eq 0 ]; then
		# 0 - force portal mode
		default_gw=$(ip route | grep "default via")

		if [ -z "$default_gw" ]; then
			dhcpdevice=$(uci get network.wan.device | awk '{printf "%s", $1}')
			dhcp4_renew
		fi

		default_gw=$(ip route | grep "default via")
	fi

	debugtype="debug"
	syslogmessage="default_gw=$default_gw...."
	write_to_syslog

	config_ipaddr=$(uci get network.$auto_mesh_network.ipaddr)
	brg_check=$(echo "$default_gw" | grep -q -w "$device"; echo -n "$?" ) # 0 if contains $device, 1 if does not
	gw_ip=$(echo "$default_gw" | awk -F" " '{printf "%s", $3}')

	if [ -z "$default_gw" ] || [ "$brg_check" -eq 0 ]; then
		is_portal=""
		gwstatus=""
	else

		if [ -z "$gw_ip" ] && [ "$config_ipaddr" = "$gw_ip" ]; then
			is_portal=""
		else

			gwproto=$(echo "$default_gw" | grep -q -w "proto"; echo -n "$?" ) # 0 if contains proto, 1 if does not
			gwsrc=$(echo "$default_gw" | grep -q -w "src"; echo -n "$?" ) # 0 if contains src, 1 if does not

			if [ "$gwproto" -eq 1 ] || [ "$gwsrc" -eq 1 ]; then
				# must test if upstream gateway is actually up
				# On an ethernet link to eg an isp router, trigger arp with a ping:
				gwstatus=$(ping -q -c 2 -W 1 "$gw_ip" &>/dev/null; ip neigh | grep -w "$gw_ip" | awk 'NR==1 {printf "%s", $NF}')

			else
				gwstatus="REACHABLE"
			fi

			if [ -z "$gwstatus" ]; then
				is_portal=""
			elif [ "$gwstatus" = "REACHABLE" ] || [ "$gwstatus" = "DELAY" ] || [ "$gwstatus" = "STALE" ]; then
				is_portal=$gwstatus
			elif [ "$gwstatus" = "PROBE" ] || [ "$gwstatus" = "INCOMPLETE" ] || [ "$gwstatus" = "FAILED" ]; then
				is_portal=""
			fi
		fi
	fi

	# Set detected state
	if [ -z "$is_portal" ] && [ "$portal_detect" -eq 1 ]; then
		# do portal detect with watchdog:
		detected_state="peer"

		#Check ipv4 connectivity to portal
		pingresult=$(ping -q -W 1 -c 2 "$gw_ip" &>/dev/null; echo $?)

		if [ "$pingresult" -eq 1 ]; then
			ip4pingfailcount=$(($ip4pingfailcount + 1))

			if [ "$portal_detect_threshold" -eq 0 ] || [ "$portal_detect_threshold" -gt "$ip4pingfailcount" ]; then
				dhcpdevice=$(echo "get network.$auto_mesh_network.device" | uci batch | awk '{printf "%s", $1}')

				debugtype="debug"
				syslogmessage="ipV4 link to portal fail, attempting to (re)establish via device [ $dhcpdevice ], iteration [ $ip4pingfailcount ]"
				write_to_syslog

				dhcp4_renew

			elif [ "$portal_detect_threshold" -le "$ip4pingfailcount" ]; then
				# we have reached the portal detect threshold. This either means there is no portal, or something has stopped working

				if [ "$network_restart" -eq 0 ]; then
					# Try clearing the routing table:
					dhcpdevice=$(echo "get network.$auto_mesh_network.device" | uci batch | awk '{printf "%s", $1}')
					debugtype="err"
					syslogmessage="portal detect threshold reached, flushing routing tables"
					write_to_syslog
					write_to_watchdog_nonvolatile_log
					network_restart=1
					ip neigh flush dev "$device"
					dhcp4_renew

				elif [ "$network_restart" -eq 1 ]; then
					dhcpdevice=$(echo "get network.$auto_mesh_network.device" | uci batch | awk '{printf "%s", $1}')
					debugtype="notice"
					syslogmessage="portal detect threshold exceeded, restarting wpad..."
					write_to_syslog
					write_to_watchdog_nonvolatile_log
					network_restart=2
					/sbin/service wpad restart
					wait_for_mesh
					dhcp4_renew

				elif [ "$network_restart" -eq 2 ]; then
					dhcpdevice=$(echo "get network.$auto_mesh_network.device" | uci batch | awk '{printf "%s", $1}')
					debugtype="notice"
					syslogmessage="portal detect threshold exceeded, restarting network..."
					write_to_syslog
					write_to_watchdog_nonvolatile_log
					network_restart=3
					/sbin/service network restart
					wait_for_mesh
					dhcp4_renew

				elif [ "$network_restart" -eq 3 ]; then
					# restarting the network did not work so:
					debugtype="err"
					syslogmessage="portal detect threshold exceeded, restarting network did not work... rebooting node"
					write_to_syslog
					write_to_watchdog_nonvolatile_log
					reboot
				fi

			fi
		else
			ip4pingfailcount=0
			network_restart=0
		fi

	elif [ -z "$is_portal" ] && [ "$portal_detect" -eq 3 ]; then
		# CPE mode required
		detected_state="cpe_peer"
		debugtype="debug"
		syslogmessage="CPE mode..."
		write_to_syslog

	else
		detected_state="portal"
	fi

	debugtype="debug"
	syslogmessage="leaving get_portal_state - is_portal=$is_portal.. gwstatus=$gwstatus.. gw_ip=$gw_ip.."
	write_to_syslog
}

restore_ipv4() {
	. $tmpdir/devicemac
	config_ipaddr=$(uci get network.$auto_mesh_network.ipaddr)
	active_ipaddr=$(ip addr show dev $device | grep -w "$config_ipaddr" | awk '{printf "%s", $2}' | awk -F"/" '{printf "%s", $1}')

	if [ "$config_ipaddr" != "$active_ipaddr" ]; then
		config_netmask=$(uci get network.$auto_mesh_network.netmask)
		cdir_netmask=$(echo "$config_netmask" | awk -F"." '{for(i=1; i<=NF; ++i) {mask+=8-log(2**8-$i)/log(2)} {printf "/%.0f", mask}}')
		cdir_ip="$config_ipaddr""$cdir_netmask"

		eval $(echo "$config_ipaddr" | awk -F"." '{printf "i1=%s i2=%s i3=%s i4=%s", $1 ,$2, $3, $4}')
		eval $(echo "$config_netmask" | awk -F"." '{printf "m1=%s m2=%s m3=%s m4=%s", $1 ,$2, $3, $4}')
		network_address="$(( $i1 & $m1 )).$(( $i2 & $m2 )).$(( $i3 & $m3 )).$(( $i4 & $m4 ))"
		eval $(echo "$network_address" | awk -F"." '{printf "n1=%s n2=%s n3=%s n4=%s", $1 ,$2, $3, $4}')
		broadcast_mask="$(( 255 ^ $m1 )).$(( 255 ^ $m2 )).$(( 255 ^ $m3 )).$(( 255 ^ $m4 ))"
		eval $(echo "$broadcast_mask" | awk -F"." '{printf "b1=%s b2=%s b3=%s b4=%s", $1 ,$2, $3, $4}')
		broadcast_address="$(( $n1 ^ $b1 )).$(( $n2 ^ $b2 )).$(( $n3 ^ $b3 )).$(( $n4 ^ $b4 ))"

		debugtype="debug"
		syslogmessage=" addr add \"$cdir_ip\" broadcast \"$broadcast_address\" dev \"$device\""
		write_to_syslog

		ip addr add "$cdir_ip" broadcast "$broadcast_address" dev "$device"
		ip link set "$device" arp on
		ip link set "$device" multicast on
	fi
}

dhcp4_renew() {
	hostname=$(uci get system.@system[0].hostname 2>/dev/null)
	udhcpc -p /var/run/udhcpc-renew-$dhcpdevice.pid -f -q -n -t0 -A 0 -i $dhcpdevice -x hostname:$hostname &
	sleep 6

	if [ -f "/var/run/udhcpc-renew-$dhcpdevice.pid" ]; then
		debugtype="debug"
		syslogmessage="Killing dhcp client-renew as it failed on [ $dhcpdevice ] server not found"
		write_to_syslog

		kill $(cat /var/run/udhcpc-renew-$dhcpdevice.pid)
	else
		/sbin/service dnsmasq reload
	fi
}

check_dns_server() {
	default_gw=$(ip route | grep "default via")

	if [ ! -z "$default_gw" ]; then
		gw_ip=$(echo "$default_gw" | awk -F" " '{printf "%s", $3}')

		if [ ! -z "$gw_ip" ]; then
			dns_server_config=$(uci get dhcp.@dnsmasq[0].server &> /dev/null; echo -n "$?")

			if [ "$dns_server_config" -eq 1 ]; then
				echo "add_list dhcp.@dnsmasq[0].server='$gw_ip'" | uci batch
				uci set dhcp.@dnsmasq[0].authoritative='0'
				/sbin/service dnsmasq reload
			fi
		fi
	fi
}

check_portal() {
	is_portal=""
	debugtype="debug"
	syslogmessage="Entering check portal.... $auto_mesh_network"
	write_to_syslog

	if [ "$enabled" -eq 1 ]; then
		get_portal_state
		. $tmpdir/devicemac

		if [ -z "$is_portal" ]; then
			# This IS NOT a layer 3 mesh portal
			uci set mesh11sd.mesh_params.mesh_connected_to_as='0'

			if [ "$detected_state" = "peer" ] && [ "$last_state" = "initial" ]; then
				last_state="portal"
			fi

			if [ "$detected_state" = "peer" ] && [ "$last_state" = "portal" ]; then
				last_state="peer"
				debugtype="debug"
				syslogmessage="This meshnode is NOT a portal"
				write_to_syslog

				if [ -f "/var/run/udhcpc-$device.pid" ]; then
					kill $(cat /var/run/udhcpc-$device.pid)
				fi

				ip route flush default
				hostname=$(uci get system.@system[0].hostname 2>/dev/null)

				# Start the dhcp client
				dhcpstatus=$(udhcpc -p /var/run/udhcpc-$device.pid -b -t 3 -i $device -x hostname:$hostname -C -R -O 121)
				echo "$dhcpstatus" | grep "setting default routers"
				dhcptest=$?

				if [ "$dhcptest" -eq 0 ]; then
					debugtype="debug"
					syslogmessage="Remote dhcpv4 server found"
					write_to_syslog
				fi

				uci set dhcp.@dnsmasq[0].authoritative='0'
				echo "set dhcp.$auto_mesh_network.ignore='1'" | uci batch
				echo "set dhcp.$auto_mesh_network.ra_default='2'" | uci batch
				echo "set dhcp.$auto_mesh_network.dhcpv6='disabled'" | uci batch
				echo "set dhcp.$auto_mesh_network.dhcpv4='disabled'" | uci batch
				echo "set dhcp.$auto_mesh_network.ra='disabled'" | uci batch
				uci set dhcp.@dnsmasq[0].logfacility='-'
				uci set dhcp.@dnsmasq[0].quietdhcp='1'

				if [ "$mesh_gate_only" -eq 0 ]; then
					non_portal_mesh_hwmp_rootmode="2"
				else
					non_portal_mesh_hwmp_rootmode="0"
				fi

				echo "set mesh11sd.mesh_params.mesh_hwmp_rootmode='$non_portal_mesh_hwmp_rootmode'" | uci batch

				/sbin/service dnsmasq restart
				/sbin/service odhcpd restart

				local retries=10

				for retry in $(seq $retries); do
					default_gw=$(ip route | grep "default via")

					if [ -z "$default_gw" ]; then
						debugtype="debug"
						syslogmessage="Waiting for ipv4 default gateway - iteration [ $retry ] ...."
						write_to_syslog
						sleep 1
						continue
					else
						gw_ip=$(echo "$default_gw" | awk -F" " '{printf "%s", $3}')
						break
					fi
				done

				if [ ! -z "$gw_ip" ]; then
					echo "add_list dhcp.@dnsmasq[0].server='$gw_ip'" | uci batch
					uci set dhcp.@dnsmasq[0].authoritative='0'
				fi

				/sbin/service dnsmasq reload
				/sbin/service system restart
			fi

			check_dns_server
			check_channel

		else
			# This IS a layer 3 mesh portal
			uci set mesh11sd.mesh_params.mesh_connected_to_as='1'

			if [ -f "/var/run/udhcpc-$device.pid" ]; then
				kill $(cat /var/run/udhcpc-$device.pid)
			fi

			if [ "$detected_state" = "portal" ] && [ "$last_state" = "initial" ]; then
				last_state="peer"
			fi

			if [ "$detected_state" = "portal" ] && [ "$last_state" = "peer" ]; then
				last_state="portal"
				debugtype="debug"
				syslogmessage="This meshnode is an upstream portal"
				write_to_syslog

				uci set dhcp.@dnsmasq[0].authoritative='1'
				echo "set dhcp.$auto_mesh_network.ignore='0'" | uci batch
				echo "set dhcp.$auto_mesh_network.ra_default='2'" | uci batch
				echo "set dhcp.$auto_mesh_network.dhcpv6='server'" | uci batch
				echo "set dhcp.$auto_mesh_network.dhcpv4='server'" | uci batch
				echo "set dhcp.$auto_mesh_network.ra='server'" | uci batch
				uci set dhcp.@dnsmasq[0].logfacility='-'
				uci set dhcp.@dnsmasq[0].quietdhcp='1'
				echo "del_list dhcp.@dnsmasq[0].server='$config_ipaddr'" | uci batch

				if [ "$mesh_gate_only" -eq 0 ]; then
					mesh_hwmp_rootmode="4"
				else
					mesh_hwmp_rootmode="0"
				fi

				echo "set mesh11sd.mesh_params.mesh_hwmp_rootmode='$mesh_hwmp_rootmode'" | uci batch

				restore_ipv4
				/sbin/service dnsmasq restart
				/sbin/service odhcpd restart
				/sbin/service system restart

				if [ "$daemon_startup" -eq 1 ]; then
					daemon_startup=0
				fi
			fi
		fi
	fi

	debugtype="debug"
	syslogmessage="Leaving check portal...."
	write_to_syslog

}

check_hwmp() {
	get_mesh_iflist

	for iface in $iflist; do
		mesh_hwmp_active_path_timeout=$(iw dev $iface get mesh_param mesh_hwmp_active_path_timeout | awk '{printf "%s", $1}')
		mesh_hwmp_active_path_to_root_timeout=$(iw dev $iface get mesh_param mesh_hwmp_active_path_to_root_timeout | awk '{printf "%s", $1}')
		mesh_hwmp_rann_interval=$(iw dev $iface get mesh_param mesh_hwmp_rann_interval | awk '{printf "%s", $1}')
		mesh_hwmp_root_interval=$(iw dev $iface get mesh_param mesh_hwmp_root_interval | awk '{printf "%s", $1}')

		if [ "$mesh_hwmp_rann_interval" -gt "$mesh_hwmp_active_path_timeout" ]; then
			debugtype="warn"
			syslogmessage="mesh_hwmp_rann_interval is too large, reducing...."
			write_to_syslog
			echo "set mesh11sd.mesh_params.mesh_hwmp_rann_interval='$mesh_hwmp_active_path_timeout'" | uci batch
		fi

		if [ "$mesh_hwmp_root_interval" -gt "$mesh_hwmp_active_path_to_root_timeout" ]; then
			debugtype="warn"
			syslogmessage="mesh_hwmp_root_interval is too large, reducing...."
			write_to_syslog
			echo "set mesh11sd.mesh_params.mesh_hwmp_root_interval='$mesh_hwmp_active_path_to_root_timeout'" | uci batch
		fi

	done
}

wait_for_nodes() {
	local tics=5

	echo -n " Building node list * "

	ccpy_setup

	for tic in $(seq $tics); do
		ndp_scan_peer
		echo -n "* "
	done

	sleep 1
	echo
}

convert_to_la() {
	local mac_to_convert="$1"

	eval $(echo "$mac_to_convert" | awk -F":" '{printf "p1=%s p2=%s p3=%s p4=%s p5=%s p6=%s", $1 ,$2, $3, $4, $5, $6}')

	la_check=$(printf '%x\n' "$(( 0x2 & 0x$p1 ))")

	if [ "$la_check" -eq 0 ]; then
		octet=$(printf '%x\n' "$(( 0x2 | 0x$p1 ))")
	else
		octet="$p1"
	fi

	mac_la="$octet:$p2:$p3:$p4:$p5:$p6"
}

convert_from_la() {
	local mac_to_convert="$1"

	eval $(echo "$mac_to_convert" | awk -F":" '{printf "p1=%s p2=%s p3=%s p4=%s p5=%s p6=%s", $1 ,$2, $3, $4, $5, $6}')

	la_check=$(printf '%x\n' "$(( 0x2 & 0x$p1 ))")

	if [ "$la_check" -eq 2 ]; then
		octet=$(printf '%x\n' "$(( 0x2 ^ 0x$p1 ))")
	else
		octet="$p1"
	fi

	mac_from_la="$octet:$p2:$p3:$p4:$p5:$p6"
}

make_indexed_mac() {
	local mac_to_convert="$1"
	local index="$2"
	eval $(echo "$mac_to_convert" | awk -F":" '{printf "p1=%s p2=%s p3=%s p4=%s p5=%s p6=%s", $1 ,$2, $3, $4, $5, $6}')
	indexed_octet=$(printf '%x\n' "$(( 0x$index + 0x$p4 ))")
	local len=${#indexed_octet}
	indexed_octet=${indexed_octet:$(($len-2)):2}

	if [ "$len" -eq 1 ]; then
		indexed_octet="0$indexed_octet"
	fi

	mac_indexed="$p1:$p2:$p3:$indexed_octet:$p5:$p6"
}


wait_for_mesh() {
	fixup1=1
	get_mesh_iflist

	local retries=16

	for iface in $iflist; do

		for retry in $(seq $retries); do
			wait_for_interface "$iface"

			if [ "$ifstatus" = "down" ]; then
				sleep 1
				continue
			fi
		done

		if [ "$ifstatus" = "down" ] && [ "$fixup1" -eq 0 ]; then
			fixup1=1
			debugtype="err"
			syslogmessage="First attempt at fixup: Mesh interface $iface failed - Possible wireless driver bug...."
			write_to_syslog

			. $tmpdir/devicemac
			convert_to_la "$devicemac"

			uci_section_name=$(uci show wireless | grep "ifname='$iface'" | awk -F "." '{printf "%s", $2}')
			radio=$(uci show wireless | grep "$uci_section_name" | grep "device=" | awk -F "'" '{printf "%s", $2}')
			wifiifaces=$(uci show wireless | grep "device='$radio'" | awk -F "." '{printf "%s ", $2}')

			for wifiiface in $wifiifaces; do

				if [ "$wifiiface" = "$uci_section_name" ]; then
					continue
				else
					debugtype="notice"
					syslogmessage="Attempting fixup: Setting locally administered mac address"
					write_to_syslog
					sleep 1
					echo "set wireless.$wifiiface.macaddr='$mac_la'" | uci batch
					wifi
				fi
			done

		elif [ "$ifstatus" = "down" ] && [ "$fixup1" -eq 1 ]; then
			fixup1=2
			debugtype="err"
			syslogmessage="Second attempt at fixup: Mesh interface $iface failed - Possible wireless driver bug...."
			write_to_syslog
			uci_section_name=$(uci show wireless | grep "ifname='$iface'" | awk -F "." '{printf "%s", $2}')
			radio=$(uci show wireless | grep "$uci_section_name" | grep "device=" | awk -F "'" '{printf "%s", $2}')
			wifiifaces=$(uci show wireless | grep "device='$radio'" | awk -F "." '{printf "%s ", $2}')

			for wifiiface in $wifiifaces; do

				if [ "$wifiiface" = "$uci_section_name" ]; then
					continue
				else
					debugtype="notice"
					syslogmessage="Attempting fixup: Disabling mesh gate for this node"
					write_to_syslog
					sleep 1
					echo "set wireless.$wifiiface.disabled='1'" | uci batch
					wifi
				fi
			done
		fi

		###########
		# Process htmode if needed
		#uci_section_name=$(uci show wireless | grep "ifname='$iface'" | awk -F "." '{printf "%s", $2}')
		#radio=$(uci show wireless | grep "$uci_section_name" | grep "device=" | awk -F "'" '{printf "%s", $2}')

		#htmode_config=$(echo "get wireless.$radio.htmode" | uci batch)
		#echo "iface=$iface! uci_section_name=$uci_section_name! radio=$radio! wifiifaces=$wifiifaces! htmode_config=$htmode_config!"
		###########
	done
}

all_nodes_rssi_update() {

	if [ "$auto_config" -gt 0 ]; then

		if [ -f "/tmp/meshinterface" ]; then

			if [ ! -f "/tmp/mesh_rssi_threshold" ]; then
				debugtype="debug"
				syslogmessage="Disconnecting nodes"
				write_to_syslog

				rm /tmp/meshinterface

				get_wiphys

				if [ ! -z "$wiphys" ]; then

					for wiphy in $wiphys; do
						mesh_capable=$(iw phy $wiphy info | grep -A 15 "Supported interface modes:" | grep -w "mesh point")

						if [ -z "$mesh_capable" ]; then
							continue
						fi

						phyindex=$(echo "$wiphy" | awk -F "phy" '{printf "%s", $2}')
						phyindex=$(printf "%x" $phyindex)

						echo "set wireless.m11s$phyindex.mesh_rssi_threshold='$mesh_rssi_threshold'" | uci batch
					done
				fi

				restart_mesh
			fi
		fi
	fi
}

get_peers() {
	get_mesh_iflist

	for miface in $iflist; do
		wait_for_interface "$miface"

		if [ "$ifstatus" = "down" ]; then
			continue
		fi

		peers=$(iw dev $miface mpath dump | grep -c -w $miface)
		macrouting=$(iw dev $miface mpath dump | awk -F" " 'NR>1 {printf "%s/%s ",$1,$2}')

		for peer in $macrouting; do
			peermac=$(echo "$peer" | awk -F"/" '{printf "%s", $1}')
			peerlist="$peerlist ""$peermac"
			mute=1
			convert_from_la "$peermac"
			peerlist="$peerlist ""$mac_from_la"
		done
	done
}

ccpy_setup() {
	get_peers

	meshconfigs=$(uci show wireless 2> /dev/null | grep "mode='mesh'" | awk -F ".mode='mesh'" '{printf "%s " $1}')
	connectlist=""

	if [ ! -z "$meshconfigs" ]; then
		for meshconfig in $meshconfigs; do
			networks=$(uci get $meshconfig.network)

			for network in $networks; do
				device=$(uci get network.$network.device)

				if [ "$network" != "$network_previous" ]; then
					connectlist="$connectlist ""$(ip -6 neigh | grep "fe80::" | grep "$device" | grep "lladdr" | awk '{printf "%s%s%s,%s ", $1, "%", $3, $5}')"
				fi

				network_previous=$network
			done

			# Stop after the first mesh network - there should only be one but more might have been added in error
			break
		done
	fi
}

ndp_scan_peer() {
	# NDP - Send linklocal multicast ip6-allrouters
	if [ -f "$tmpdir/devicemac" ]; then
		. $tmpdir/devicemac
		response=$(ping -q -c 8 "ff02::2%$device" &>/dev/null &)
	fi
}

get_wiphys() {
	# get list of physical wireless interfaces and reverse the list order
	wiphys=$(iw list | grep -w "Wiphy" | awk -F "Wiphy " '{printf "%s ", $2}' | awk '{ for (i = NF; i > 0; i = i - 1) printf("%s ", $i) }')
}

refresh_bridgemac() {
	# get the device device mac and write it to $tmpdir/devicemac
	device=$(uci get network.$auto_mesh_network.device)
	wait_for_interface "$device"
	devicemac=$(ip link | grep -A 1 "$device:" | grep -w "link/ether" | awk '{printf "%s", $2}')
	echo "device=\"$device\" ; devicemac=\"$devicemac\"" > $tmpdir/devicemac
}

auto_config() {
	debugtype="debug"
	syslogmessage="Entering auto config...."
	write_to_syslog
	autoconfig=0
	dfs_etsi="GB"
	meshifenabled=0

	# Are we using ath10k drivers?
	ath10k_ct=$(opkg list-installed | grep "ath10k"| grep -c "\-ct")

	if [ "$ath10k_ct" -gt 0 ]; then
		debugtype="err"
		syslogmessage="Unable to autoconfigure. Please install ath10k NON ct drivers for mesh support"
		write_to_syslog
		exit 1
	fi

	if [ "$autoconfig" -eq 0 ]; then

		# do we have a mesh supporting wpad?
		installed_wpad=$(opkg list-installed | grep "wpad" | awk '{printf "%s", $1}' | awk -F "-" '{print $2}')

		if [ "$installed_wpad" = "mesh" ] || [ "$installed_wpad" = "mbedtls" ] || [ "$installed_wpad" = "wolfssl" ] || [ "$installed_wpad" = "openssl" ]; then

			refresh_bridgemac
			. $tmpdir/devicemac
			get_wiphys

			if [ ! -z "$wiphys" ]; then
				for wiphy in $wiphys; do
					mesh_capable=$(iw phy $wiphy info | grep -A 15 "Supported interface modes:" | grep -w "mesh point")

					if [ -z "$mesh_capable" ]; then
						continue
					fi

					# Prerequisites met so we can autoconfigure
					phyindex=$(echo "$wiphy" | awk -F "phy" '{printf "%s", $2}')

					phyindex=$(printf "%x" $phyindex)
					mesh_ifname="$mesh_basename""$phyindex"


					echo "set wireless.m11s$phyindex=wifi-iface" | uci batch
					echo "set wireless.m11s$phyindex.device='radio$phyindex'" | uci batch
					echo "set wireless.m11s$phyindex.mode='mesh'" | uci batch
					echo "set wireless.m11s$phyindex.encryption='sae'" | uci batch
					echo "set wireless.m11s$phyindex.mesh_id='$auto_mesh_id'" | uci batch
					echo "set wireless.m11s$phyindex.key='$auto_mesh_key'" | uci batch
					echo "set wireless.m11s$phyindex.network='$auto_mesh_network'" | uci batch
					echo "set wireless.m11s$phyindex.ifname='$mesh_ifname'" | uci batch
					echo "set wireless.m11s$phyindex.mesh_rssi_threshold='$mesh_rssi_threshold'" | uci batch
					echo "set wireless.radio$phyindex.disabled='0'" | uci batch
					echo "set wireless.radio$phyindex.log_level='0'" | uci batch


					country=$(uci get wireless.radio$phyindex.country 2> /dev/null | awk '{printf "%s", $1}')

					if [ -z "$country" ]; then
						echo "set wireless.radio$phyindex.country='$dfs_etsi'" | uci batch
						syslogmessage="WARNING - country code not set - interoperability with other mesh nodes may be compromised or fail altogether...."
						debugtype="warn"
						write_to_syslog
						syslogmessage="WARNING - country code defaulting to [ DFS-ETSI ]...."
						debugtype="warn"
						write_to_syslog
						country="$dfs_etsi"
					fi


					band=$(uci get wireless.radio$phyindex.band 2> /dev/null | awk '{printf "%s", $1}')

					if [ "$auto_mesh_band" = "2g40" ]; then
						mesh_band="2g"
					else
						mesh_band=$auto_mesh_band
					fi

					if [ "$band" = "$mesh_band" ] && [ "$meshifenabled" -eq 0 ]; then
						echo "set wireless.m11s$phyindex.disabled='0'" | uci batch
						meshifenabled=1
					else
						echo "set wireless.m11s$phyindex.disabled='1'" | uci batch
					fi

					if [ "$band" = "2g" ]; then
						get_portal_state

						if [ "$auto_mesh_band" = "2g40" ]; then
							originalhtmode=$(echo "get wireless.radio$phyindex.htmode" | uci batch)
							he_mode=$(echo "$originalhtmode" | grep -q "HE"; echo -n "$?")

							if [ "$he_mode" -eq 0 ]; then
								htmode="HE40"
							else
								htmode="HT40"
							fi

							if [ ! -z "$country" ]; then
								echo "set wireless.radio$phyindex.noscan='1'" | uci batch
								echo "set wireless.radio$phyindex.htmode='$htmode'" | uci batch
							else
								echo "set wireless.radio$phyindex.noscan='0'" | uci batch
								echo "set wireless.radio$phyindex.htmode='$originalhtmode'" | uci batch
							fi

						fi

						if [ ! -z "$is_portal" ] || [ "$portal_detect" -eq 0 ]; then

							if [ "$portal_channel" = "auto" ] && [ "$band" = "2g" ]; then

								for i in $(seq 9 1 64); do
									#choose start point of sequence away from end eg "9"
									chan=$((0x$(printf "$devicemac" | sha256sum | awk '{printf $1}' | tail -c$i | head -c1)))

									#Check for max
									if [ "$chan" -gt 13 ]; then
										continue
									fi

									#Check for min
									if [ "$chan" -le 0 ]; then
										continue
									fi

									echo "set wireless.radio$phyindex.channel='$chan'" | uci batch
									break
								done

							elif [ "$portal_channel" != "auto" ] && [ "$portal_channel" != "default" ] && [ "$band" = "2g" ]; then
								chan="$portal_channel"

								#Check for max
								if [ "$chan" -gt 13 ]; then
									chan=13
								fi

								#Check for min
								if [ "$chan" -le 0 ]; then
									chan=1
								fi

								echo "set wireless.radio$phyindex.channel='$chan'" | uci batch
							fi
						fi
					fi
				done

				# get list of access points
				aplist=$(uci show wireless 2> /dev/null | grep "='ap'" | awk -F "." '{printf "%s.%s ", $1, $2}')

				#Add suffix to ssid
				if [ "$ssid_suffix_enable" -eq 1 ]; then
					suffix=$(echo $devicemac | awk -F":" '{printf "%s%s", $5, $6}')

					for ap in $aplist; do
						radio=$(uci get "$ap.device" 2> /dev/null)
						band=$(uci get "wireless.$radio.band" 2> /dev/null)
						ssid=$(uci get "$ap.ssid" 2> /dev/null | awk '{printf "%s", $1}')
						echo "set $ap.ssid='$ssid-$band-$suffix'" | uci batch
					done

					echo "set system.@system[0].hostname='meshnode-$suffix'" | uci batch
					/sbin/service system restart
				fi

				#Configure gate encryption
				case $mesh_gate_encryption in
					0) encryption_type="none";;
					1) encryption_type="sae";;
					2) encryption_type="sae-mixed+aes";;
					3) encryption_type="psk2+aes";;
					4) encryption_type="owe";;
					*) encryption_type="none";;
				esac

				if [ "$encryption_type" = "owe" ] || [ "$encryption_type" = "none" ]; then
					wpad_pkg=$(opkg list-installed | grep "wpad" | awk '{printf "%s", $1}')

					if [ $wpad_pkg = "wpad-mbedtls" ] || [ $wpad_pkg = "wpad-wolfssl" ] || [ $wpad_pkg = "wpad-openssl" ]; then
						# We have a full version so owe is supported
						owe_able=1
						debugtype="notice"
						syslogmessage="$wpad_pkg is installed, owe supported"
						write_to_syslog
					else
						encryption_type="none"
						owe_able=0
						debugtype="err"
						syslogmessage="$wpad_pkg does not support owe, install a full version of wpad"
						write_to_syslog
					fi

					for ap in $aplist; do
						radio=$(uci get "$ap.device" 2> /dev/null)
						echo "set $ap.encryption='$encryption_type'" | uci batch
						echo "set $ap.key='$mesh_gate_key'" | uci batch

						if [ "$encryption_type" = "none" ]; then
							# setup owe transition if wpad supports it

							if [ "$owe_able" -eq 1 ]; then
								owe_transition
							fi
						fi
					done

				fi


				debugtype="debug"
				syslogmessage="auto config complete...."
				write_to_syslog

				# set changed flag to signify a mesh restart is needed
				changed=1

			else
				debugtype="err"
				syslogmessage="Unable to autoconfigure. No physical wireless interfaces found"
				write_to_syslog
			fi
		else
			debugtype="err"
			syslogmessage="Unable to autoconfigure. Please install package wpad-mbedtls, wpad-wolfssl, wpad-openssl or an equivalent mesh only version"
			write_to_syslog
			exit 1
		fi

		# TODO If we want to call auto_config from cli then we can stop it happening more than once by uncommenting the following:
		#autoconfig=1
	fi
}

owe_transition() {
	section_ap=$(uci show "$ap")
	section_list=$(echo "$section_ap" | awk '{printf "%s ", $1}')
	radio_index=$(echo "$ap" | awk -F "radio" '{printf "%s", $2}')

	echo "set $ap.ifname='open-$radio_index'" | uci batch
	echo "set $ap.owe_transition_ifname='owe-$radio_index'" | uci batch

	for section_item in $section_list; do
		oweap="s/$ap/wireless.owe$radio_index/g"
		uci_option=$(echo "$section_item" | sed "$oweap")
		echo "set $uci_option" | uci batch
	done

	echo "set wireless.owe$radio_index.ifname='owe-$radio_index'" | uci batch
	echo "set wireless.owe$radio_index.owe_transition_ifname='open-$radio_index'" | uci batch
	echo "set wireless.owe$radio_index.hidden='1'" | uci batch
	echo "set wireless.owe$radio_index.encryption='owe'" | uci batch

}

urlencode() {
	entitylist="
		s/%/%25/g
		s/\s/%20/g
		s/\"/%22/g
		s/:/%3A/g
		s/>/%3E/g
		s/</%3C/g
		s/'/%27/g
		s/\`/%60/g
	"
	local buffer="$1"

	for entity in $entitylist; do
		urlencoded=$(echo "$buffer" | sed "$entity")
		buffer=$urlencoded
	done

	urlencoded=$(echo "$buffer" | awk '{ gsub(/\$/, "\\%24"); print }')
}

urldecode() {
	entitylist="
		s/%22/\"/g
		s/%3A/:/g
		s/%3E/>/g
		s/%3C/</g
		s/%27/'/g
		s/%60/\`/g
		s/%25/%/g
	"
	local buffer="$1"

	for entity in $entitylist; do
		urldecoded=$(echo "$buffer" | sed "$entity")
		buffer=$urldecoded
	done

	buffer=$(echo "$buffer" | awk '{ gsub(/%24/, "$"); print }')
	urldecoded=$(echo "$buffer" | awk '{ gsub(/%20/, " "); print }')
}

arp_setup() {
	refresh_bridgemac
	echo 1 > /proc/sys/net/ipv4/conf/all/arp_accept
	echo 1 > /proc/sys/net/ipv4/conf/default/arp_accept
	echo 1 > /proc/sys/net/ipv4/conf/$device/arp_accept
	echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
	echo 2 > /proc/sys/net/ipv4/conf/default/arp_announce
	echo 2 > /proc/sys/net/ipv4/conf/$device/arp_announce
	echo 0 > /proc/sys/net/ipv4/conf/all/arp_filter
	echo 0 > /proc/sys/net/ipv4/conf/default/arp_filter
	echo 0 > /proc/sys/net/ipv4/conf/$device/arp_filter
	echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
	echo 0 > /proc/sys/net/ipv4/conf/default/arp_ignore
	echo 0 > /proc/sys/net/ipv4/conf/$device/arp_ignore
	echo 1 > /proc/sys/net/ipv4/conf/all/arp_notify
	echo 1 > /proc/sys/net/ipv4/conf/default/arp_notify
	echo 1 > /proc/sys/net/ipv4/conf/$device/arp_notify
	echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp
	echo 1 > /proc/sys/net/ipv4/conf/default/proxy_arp
	echo 1 > /proc/sys/net/ipv4/conf/$device/proxy_arp
	echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp_pvlan
	echo 1 > /proc/sys/net/ipv4/conf/default/proxy_arp_pvlan
	echo 1 > /proc/sys/net/ipv4/conf/$device/proxy_arp_pvlan
	echo 1 > /proc/sys/net/ipv4/conf/all/bc_forwarding
	echo 1 > /proc/sys/net/ipv4/conf/default/bc_forwarding
	echo 1 > /proc/sys/net/ipv4/conf/$device/bc_forwarding

	echo 2 > /proc/sys/net/ipv6/conf/all/accept_ra
	echo 2 > /proc/sys/net/ipv6/conf/default/accept_ra
	echo 2 > /proc/sys/net/ipv6/conf/$device/accept_ra
	echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
	echo 1 > /proc/sys/net/ipv6/conf/default/forwarding
	echo 1 > /proc/sys/net/ipv6/conf/$device/forwarding
	echo 1 > /proc/sys/net/ipv6/conf/all/proxy_ndp
	echo 1 > /proc/sys/net/ipv6/conf/default/proxy_ndp
	echo 1 > /proc/sys/net/ipv6/conf/$device/proxy_ndp
	echo 5 > /proc/sys/net/ipv6/conf/all/router_solicitations
	echo 5 > /proc/sys/net/ipv6/conf/default/router_solicitations
	echo 5 > /proc/sys/net/ipv6/conf/$device/router_solicitations


}
check_path_changes() {
	# get list of interfaces
	get_mesh_iflist

	if [ -f "$tmpdir/devicemac" ]; then
		. $tmpdir/devicemac
	fi

	for iface in $iflist; do
		wait_for_interface "$iface"

		if [ "$ifstatus" = "down" ]; then
			continue
		fi

		# get list of mesh parameters for this interface
		get_params

		if [ -z "$params" ]; then
			# this is not a mesh interface
			continue
		else
			macrouting=$(iw dev $iface mpath dump 2>/dev/null | awk -F" " 'NR>1 {printf "%s/%s/%s/%s/%s ",$1,$2,$5,$11,$12}')

			if [ ! -z "$macrouting" ]; then
				for peer in $macrouting; do
					peermac=$(echo "$peer" | awk -F"/" '{printf "%s", $1}')
					peermac_id=$(echo -n "$peermac" | sha256sum | awk '{printf $1}')

					next_hop=$(echo "$peer" | awk -F"/" '{printf "%s", $2}')

					hop_count=$(echo "$peer" | awk -F"/" '{printf "%s", $4}')

					path_change_count=$(echo "$peer" | awk -F"/" '{printf "%s", $5}')

					metric=$(echo "$peer" | awk -F"/" '{printf "%s", $3}')

					if [ -f "$tmpdir/$peermac_id" ]; then
						. $tmpdir/$peermac_id
					else
						previous_path_change_count=1
					fi

					if [ "$path_change_count" -ne "$previous_path_change_count" ]; then

						if [ "$hop_count" -gt 1 ] && [ "$path_change_count" -gt 1 ]; then

							is_connected=$(iw dev $iface station dump | grep -q "$peermac"; echo -n $?)

							if [ "$is_connected" -eq 0 ]; then
								debugtype="notice"
								syslogmessage="Station [ $peermac ] is [ $hop_count ] hops away and [ $path_change_count ] path_change(s) for station have been detected"
								write_to_syslog
								debugtype="debug"
								syslogmessage="Station [ $peermac ] has an incrementing path change count, consider its location or adjust txpower and/or rssi_threshold"
								write_to_syslog

								if [ "$mesh_path_stabilisation" -eq 1 ]; then
									# If we want reactive path stabilisation:
									debugtype="notice"
									syslogmessage="Stabilsing path to node [ $peermac ]"
									write_to_syslog
									iw dev $iface station del $peermac
								fi
							fi

						elif [ "$hop_count" -eq 1 ] && [ "$path_change_count" -gt 1 ]; then
							debugtype="notice"
							syslogmessage="Station [ $peermac ] is an immediate neighbour, but has had [ $path_change_count ] path_change(s) detected"
							write_to_syslog
							debugtype="debug"
							syslogmessage="Station [ $peermac ], consider its location or adjust txpower and/or rssi_threshold"
							write_to_syslog
						fi

						echo "previous_path_change_count=$path_change_count" > $tmpdir/$peermac_id
					else
						debugtype="info"
						syslogmessage="Path to station [ $peermac ] is stable"
						write_to_syslog
					fi
				done
			fi
		fi
	done
}

block_bridge_loops() {
	rule_status=0
	refresh_bridgemac
	table_ruleset=$(nft -a list table bridge mesh11s 2> /dev/null)

	if [ "$?" -gt 0 ]; then
		# Create the table
		nft add table bridge mesh11s
		# Create the chain
		nft add chain bridge mesh11s mesh_PRE { type filter hook prerouting priority -350\; }
	fi

	. $tmpdir/devicemac
	local mac_changed=0
	local br_iface
	local br_ifaces=$(brctl showstp "$device" | grep -B 1 -w "port id" | grep "(" | awk '{printf "%s ", $1}')

	if [ ! -e "/tmp/mesh11sd/brmac_la" ]; then
		#br_ifaces="$br_ifaces $device"
		touch "/tmp/mesh11sd/brmac_la"
	fi

	get_mesh_iflist

	br_mac_list=""

	for br_iface in $br_ifaces; do
		rulecount=$(nft -a list table bridge mesh11s 2> /dev/null | grep -w -c "$br_iface" | awk '{printf "%s", $1}')

		if [ "$rulecount" -lt 2 ]; then
			rule_status=$(nft add rule bridge mesh11s mesh_PRE meta iifname { "\"$br_iface\"" } ether saddr "\"$devicemac\"" counter drop 2> /dev/null; echo -n $?)
			rule_status=$(nft add rule bridge mesh11s mesh_PRE meta iifname { "\"$br_iface\"" } counter accept 2> /dev/null; echo -n $?)
		fi

		convert_to_la "$devicemac"
		is_meshif=$(echo "$iflist" | grep -q "$br_iface"; echo -n $?)

		# If kernel version is 6 or higher we have to ensure there are no duplicate bridge interface mac addresses
		# But it is safe to fix up mac addresses for kernel < 6 if we do it correctly:
		macfixenable=6
		# macfixenable=$kmajor # uncomment to only fixup macs if kernel is version 6 or greater

		if [ "$macfixenable" -ge 6 ]; then
			if [ $is_meshif -ne 0 ]; then
				# This is not a mesh interface
				local br_iface_mac=$(ip link | grep -A 1 "$br_iface" | grep "link/ether" | awk 'NR==1 {printf "%s", $2}')
				is_same=$(echo "$br_mac_list" | grep -q "$br_iface_mac"; echo -n $?)

				if [ "$is_same" -eq 0 ]; then
					#This is a duplicate mac address so change it
					index=$(($index + 1))
					make_indexed_mac "$mac_la" "$index"

					ip link set $br_iface down; ip link set $br_iface up address $mac_indexed
					mac_changed=1
				else
					#Not a duplicate so save it in the list
					br_mac_list="$br_mac_list $br_iface_mac"
				fi
			fi
		fi
	done

	check_rule_status
	refresh_bridgemac

	# we do not and need not restart the mesh here
}

check_rule_status() {

	if [ "$rule_status" -gt 0 ]; then
		debugtype="info"
		syslogmessage="-------------------------------------------------------------------------------------------------------------------------"
		write_to_syslog
		debugtype="info"
		syslogmessage="******* WARNING ******* Unable to add nftables rule(s) - error code [ $rule_status ]. Is the kmod-nft-bridge package installed?"
		write_to_syslog
		debugtype="info"
		syslogmessage="******* WARNING ******* A severe mesh bridge-loop storm is likely to occur if any non-mesh backhaul segments are used!"
		write_to_syslog
		debugtype="info"
		syslogmessage="-------------------------------------------------------------------------------------------------------------------------"
		write_to_syslog
	fi
}

check_if_peer() {
	ispeer=1
	eval $(echo "$ndpmac" | awk -F":" '{printf "p1=%s p2=%s p3=%s p4=%s p5=%s p6=%s", $1 ,$2, $3, $4, $5, $6}')
	local ndpmacid="$p2-$p3-$p5-$p6"

	for peermac in $peerlist; do
		eval $(echo "$peermac" | awk -F":" '{printf "p1=%s p2=%s p3=%s p4=%s p5=%s p6=%s", $1 ,$2, $3, $4, $5, $6}')
		local peermacid="$p2-$p3-$p5-$p6"

		if [ "$peermacid" = "$ndpmacid" ]; then
			ispeer=0
			break
		fi
	done
}

get_kernel_version() {
	if [ -e "/proc/version" ]; then
		kmajor=$(awk '{print $3}' /proc/version | awk -F"." '{printf "%s", $1}')
		kminor=$(awk '{print $3}' /proc/version | awk -F"." '{printf "%s", $2}')
		kpatch=$(awk '{print $3}' /proc/version | awk -F"." '{printf "%s", $3}')
		debugtype="debug"
		syslogmessage="Kernel version: Major [ $kmajor ], Minor [ $kminor ], Patch [ $kpatch ]"
		write_to_syslog
	else
		kmajor=0
		kminor=0
		kpatch=0
		debugtype="warn"
		syslogmessage="WARNING: Unable to determine kernel version"
		write_to_syslog
	fi
}

probe_interface_mac() {
	# Create a wireless probe interface
	wifi down
	get_wiphys
	dsa_mesh_maclist=""

	for wiphy in $wiphys; do
		iw phy "$wiphy" interface add probe type mesh mesh_id "probe"
		# Get the probe mac address
		meshmac=$(iw dev | grep -A 5 "Interface probe" | grep -w "addr" | awk '{printf "%s", $2}')
		dsa_mesh_maclist="$dsa_mesh_maclist $meshmac"
		# Delete the probe interface
		iw dev "probe" del
	done

	debugtype="debug"
	syslogmessage="dsa_mesh_maclist [ $dsa_mesh_maclist ]"
	write_to_syslog
}

check_mesh_gate_only() {
	current_mgo_option=$(uci get mesh11sd.setup.mesh_leechmode_enable 2> /dev/null | awk '{printf "%s", $1}')

	if [ "$current_mgo_option" -ne "$mesh_gate_only" ]; then
		#option has changed

		if [ "$current_mgo_option" -eq 1 ]; then
			echo "set mesh11sd.mesh_params.mesh_fwding='0'" | uci batch
			echo "set mesh11sd.mesh_params.mesh_hwmp_rootmode='0'" | uci batch
			echo "set mesh11sd.mesh_params.mesh_gate_announcements='0'" | uci batch
		elif [ "$current_mgo_option" -eq 0 ]; then

			if [ -z "$is_portal" ]; then
				# This IS NOT a layer 3 mesh portal
				rootmode=2
			else
				rootmode=4
			fi

			echo "set mesh11sd.mesh_params.mesh_fwding='1'" | uci batch
			echo "set mesh11sd.mesh_params.mesh_hwmp_rootmode='$rootmode'" | uci batch

			current_ctg_option=$(uci get mesh11sd.mesh_params.mesh_connected_to_gate 2> /dev/null | awk '{printf "%s", $1}')

			if [ "$current_ctg_option" -eq 1 ]; then
				echo "set mesh11sd.mesh_params.mesh_gate_announcements='1'" | uci batch
			fi
		fi

		mesh_gate_only=$current_mgo_option
	fi
}

##############
# Start point
##############

if [ -f "/var/run/mesh11sd.pid" ]; then
	mesh11sdpid=$(cat /var/run/mesh11sd.pid)
else
	mesh11sdpid=$(pgrep -f "/bin/sh /usr/sbin/mesh11sd")
fi

get_current_setup 2> /dev/null

if [ -z "$1" ] || [ "$1" = "-h" ] || [ $1 = "--help" ] || [ $1 = "help" ]; then
	echo "
  Usage: mesh11sd [option] [argument...]]

  Option: -h --help help
  Returns: This help information

  Option: -v --version version
  Returns: The mesh11sd version

  Option: debuglevel
  Argument: 0 - silent, 1 - notice, 2 - info, 3 - debug
  Returns: The mesh11sd debug level

  Option: enable
  Returns: \"1\" and exit code 0 if successful, exit code 1 if was already enabled

  Option: disable
  Returns: \"0\" and exit code 0 if successful, exit code 1 if was already disabled

  Option: status
  Returns: the mesh status in json format

  Option: connect
  Connect a remote terminal session on a remote meshnode
  Usage: mesh11sd connect [remote_meshnode_macaddress]
    If the remote meshnode mac address is omitted, a list of meshnode mac addresses available for connection is listed

  Option: copy
  Copy a file to /tmp on a remote meshnode
  Usage: mesh11sd copy [remote_meshnode_macaddress] [path_of_source_file]
    If the remote meshnode mac address is null, or both arguments are omitted, a list of meshnode mac addresses available for copy is listed

  Option: txpower
  Change the mesh transmit power
  Usage: mesh11sd txpower [+|-]
    where \"+\" increments by 3dBm and \"-\" decrements by 3dBm
    Takes effect immediately

  Option: stations
  List all mesh peer stations directly connected to this mesh peer station (one hop)
  Usage: mesh11sd stations

  Option: mesh_rssi_threshold
  Change the mesh rssi threshold
  Usage: mesh11sd mesh_rssi_threshold [+|-] [force]
    where \"+\" increments by 3dBm and \"-\" decrements by 3dBm
    Takes effect immediately on NEW connections
    The keyword \"force\" forces the new threshold on all connected peers
    Warning - \"force\" will briefly remove this node from the mesh network, taking a few seconds to rejoin

  Option: mesh_leechmode
  Usage: mesh11sd mesh_leechmode [enable/disable]
  If enabled, the mesh node connects to the mesh backhaul but does not forward packets or contribute to the mesh.

  Option: commit_changes
  Usage: mesh11sd commit_changes commit
    Commits changes to mesh_leechmode, txpower and rssi_threshold to non volatile configuration (make permanent)

  Option: opkg_force_ipv4
  Usage: mesh11sd opkg_force_ipv4
    Forces opkg to use ipv4 for its downloads

  Option: opkg_revert_to_default
  Usage: mesh11sd opkg_revert_to_default
    Reverts opkg to default for its downloads

  Option: dhcp4_renew
  Usage: mesh11sd dhcp4_renew
    Renews the current dhcp4 lease

  For further documentation, see: https://github.com/openNDS/mesh11sd#readme

"

elif [ "$1" = "-v" ] || [ $1 = "--version" ] || [ $1 = "version" ]; then
	echo "mesh11sd version $version"

elif [ "$1" = "debuglevel" ]; then

	if [ -z "$2" ];then
		echo "$debuglevel"
	else

		if [ "$2" -ge 0 ] && [ "$2" -le 3 ]; then
			ucibatch="set mesh11sd.setup.debuglevel='$2'"
			echo "$ucibatch" | uci batch
			echo "$2"
		else
			echo "Invalid debuglevel requested"
		fi
	fi

elif [ "$1" = "enable" ]; then

	if [ "$enabled" -eq 1 ]; then
		echo "1"
		exit 1
	else
		ucibatch="set mesh11sd.setup.enabled='1'"
		echo "$ucibatch" | uci batch
		echo "1"
		exit 0
	fi

elif [ "$1" = "disable" ]; then

	if [ "$enabled" -eq 0 ]; then
		echo "0"
		exit 1
	else
		ucibatch="set mesh11sd.setup.enabled='0'"
		echo "$ucibatch" | uci batch
		echo "0"
		exit 0
	fi

elif [ "$1" = "status" ]; then
	# get list of interfaces
	get_mesh_iflist

	if [ -f "$tmpdir/devicemac" ]; then
		. $tmpdir/devicemac
	fi

	procd_status=$(/etc/init.d/mesh11sd status)

	echo "{"
	echo "  \"setup\":{"
	echo "    \"version\":\"$version\","
	echo "    \"enabled\":\"$enabled\","
	echo "    \"procd_status\":\"$procd_status\","
	echo "    \"portal_detect\":\"$portal_detect\","
	echo "    \"portal_detect_threshold\":\"$portal_detect_threshold\","
	echo "    \"portal_channel\":\"$portal_channel\","
	echo "    \"channel_tracking_checkinterval\":\"$channel_tracking_checkinterval\","
	echo "    \"mesh_basename\":\"$mesh_basename\","
	echo "    \"auto_config\":\"$auto_config\","
	echo "    \"auto_mesh_network\":\"$auto_mesh_network\","
	echo "    \"auto_mesh_band\":\"$auto_mesh_band\","
	echo "    \"auto_mesh_id\":\"$auto_mesh_id\","
	echo "    \"mesh_gate_enable\":\"$mesh_gate_enable\","
	echo "    \"mesh_leechmode_enable\":\"$mesh_gate_only\","
	echo "    \"mesh_gate_encryption\":\"$mesh_gate_encryption\","

	# get list of interfaces
	get_mesh_iflist

	for iface in $iflist; do
		wait_for_interface "$iface"

		if [ "$ifstatus" = "down" ]; then
			continue
		fi

		txpower=$(iwinfo | grep -A 7 "$iface" | grep -w "Tx-Power:" | awk '{printf "%s", $2}')
		break
	done


	echo "    \"txpower\":\"$txpower\","
	echo "    \"mesh_path_cost\":\"$mesh_path_cost\","
	echo "    \"mesh_path_stabilisation\":\"$mesh_path_stabilisation\","
	echo "    \"checkinterval\":\"$checkinterval\","
	echo "    \"interface_timeout\":\"$interface_timeout\","
	echo "    \"ssid_suffix_enable\":\"$ssid_suffix_enable\","
	echo "    \"debuglevel\":\"$debuglevel\""
	echo "  },"
	echo "  \"interfaces\":{"

	for iface in $iflist; do
		wait_for_interface "$iface"

		if [ "$ifstatus" = "down" ]; then
			continue
		fi

		# get list of mesh parameters for this interface
		get_params

		if [ -z "$params" ]; then
			# this is not a mesh interface
			continue
		else
			params=$(echo "$params" | awk -F" " '{printf "      \"%s\":\"%s\",\n", $1, $3}')
			echo "    \"$iface\":{"
			echo "$params"

			meshconfig=$(uci show wireless | grep "ifname='$iface'" | awk -F ".ifname='$iface'" '{printf "%s", $1}')

			if [ -z "$meshconfig" ]; then
				echo "      \"interface\":\"ERROR: mesh interface is unnamed in wireless config\""
				echo "      \"error\":\" interface must be named to see further status information\""
				echo "    }"
			else
				device=$(uci get $meshconfig.device 2> /dev/null)
				channel=$(uci show wireless | grep "$device.channel" | awk -F "'" '{printf "%s", $2}')
				meshid=$(uci get $meshconfig.mesh_id 2> /dev/null)

				echo "      \"mesh_id\":\"$meshid\","
				echo "      \"device\":\"$device\","
				echo "      \"channel\":\"$channel\","

				tx_packets=$(devstatus $iface 2>/dev/null | grep "tx_packets" | awk -F": " '{print $2}' | tr -d ",")
				echo "      \"tx_packets\":\"$tx_packets\","

				tx_bytes=$(devstatus $iface 2>/dev/null | grep "tx_bytes" | awk -F": " '{print $2}' | tr -d ",")
				echo "      \"tx_bytes\":\"$tx_bytes\","

				rx_packets=$(devstatus $iface 2>/dev/null | grep "rx_packets" | awk -F": " '{print $2}' | tr -d ",")
				echo "      \"rx_packets\":\"$rx_packets\","

				rx_bytes=$(devstatus $iface 2>/dev/null | grep "rx_bytes" | awk -F": " '{print $2}' | tr -d ",")
				echo "      \"rx_bytes\":\"$rx_bytes\","

				peernum=0
				peers=$(iw dev $iface mpath dump 2>/dev/null | grep -c -w $iface)
				macrouting=$(iw dev $iface mpath dump 2>/dev/null | awk -F" " 'NR>1 {printf "%s/%s/%s/%s/%s ",$1,$2,$5,$11,$12}')
				peer_macs="$devicemac ""$(iw dev $iface mpath dump 2>/dev/null | awk -F" " 'NR>1 {printf "%s ",$1}')"

				echo "      \"this_node\":\"$devicemac\","
				echo "      \"active_peers\":\"$peers\","
				echo "      \"peers\":{"

				for peer in $macrouting; do
					peernum=$((peernum+1))
					peermac=$(echo "$peer" | awk -F"/" '{printf "%s", $1}')
					echo "        \"$peermac\":{"

					next_hop=$(echo "$peer" | awk -F"/" '{printf "%s", $2}')
					echo "          \"next_hop\":\"$next_hop\","

					hop_count=$(echo "$peer" | awk -F"/" '{printf "%s", $4}')
					echo "          \"hop_count\":\"$hop_count\","

					path_change_count=$(echo "$peer" | awk -F"/" '{printf "%s", $5}')
					echo "          \"path_change_count\":\"$path_change_count\","

					metric=$(echo "$peer" | awk -F"/" '{printf "%s", $3}')
					echo "          \"metric\":\"$metric\""

					if [ "$peers" = "$peernum" ]; then
						echo "        }"
					else
						echo "        },"
					fi
				done
				echo "      },"

				ap_ifaces=$(iw dev | grep -B 7 "type AP"| grep "Interface" | awk '{printf "%s ", $2}')

				for ap_iface in $ap_ifaces; do
					ap_sta=$(iw dev $ap_iface station dump | grep "Station" | awk  '{printf "%s ", $2}')
					ap_stas="$ap_stas""$ap_sta"
				done

				for ap_sta in $ap_stas; do
					starouting="$starouting""$ap_sta/$devicemac "
				done

				stanum=0
				stations=0
				starouting="$starouting"$(iw dev $iface mpp dump | awk -F" " 'NR>1 {printf "%s/%s ",$1,$2}')
				stas=$(iw dev $iface mpp dump | awk -F" " 'NR>1 {printf "%s ",$1}')
				stas="$ap_stas""$stas"

				for sta in $stas; do
					# strip off first octet
					sta=$(printf "%s" "$sta" | awk -F ":" '{printf "%s:%s:%s:%s:%s", $2, $3, $4, $5, $6}')
					inpeermacs=$(echo "$peer_macs" | grep "$sta")

					if [ "$inpeermacs" = "$peer_macs" ]; then
						continue
					else
						stations=$((stations+1))
					fi
				done

				echo "      \"active_stations\":\"$stations\","
				echo "      \"stations\":{"

				for staroute in $starouting; do
					sta="${staroute%/*}"
					inpeermacs=$(echo "$peer_macs" | grep "$sta")

					if [ "$inpeermacs" = "$peer_macs" ]; then
						continue
					fi

					stamac=$(echo "$sta" | awk -F"/" '{printf "%s", $1}')
					proxy_node=$(echo "$sta" | awk -F"/" '{printf "%s", $2}')
					proxy_node="${staroute##*/}"

					stamacid=$(printf "%s" "$stamac" | awk -F ":" '{printf "%s%s%s%s%s", $2, $3, $4, $5, $6}')
					proxy_nodeid=$(printf "%s" "$proxy_node" | awk -F ":" '{printf "%s%s%s%s%s", $2, $3, $4, $5, $6}')

					if [ "$stamacid" = "$proxy_nodeid" ]; then
						continue
					fi

					stanum=$((stanum+1))
					echo "        \"$stamac\":{"
					echo "          \"proxy_node\":\"$proxy_node\""

					if [ "$stations" = "$stanum" ]; then
						echo "        }"
					else
						echo "        },"
					fi

				done
				echo "      }"
				echo "    }"
			fi
		fi
	done

	echo "  }"
	echo "}"

elif [ "$1" = "connect" ]; then

	if [ "$auto_config" -eq 0 ]; then
		echo "======================================================================"
		echo "Unable to connect -  enable auto_config to connect to other meshnodes"
		echo "======================================================================"
		exit 1
	fi

	nodeaddr=$(printf "%s" "$2" | tr "-" ":" | tr "[A-Z]" "[a-z]")

	echo "==========================================================================="

	echo " Connect a remote terminal session on a remote meshnode"
	echo "    Usage: mesh11sd connect [remote_meshnode_macaddress]"
	echo
	wait_for_nodes
	echo

	if [ -z "$nodeaddr" ]; then
		echo " If the node you are looking for is not in the list - re-run this command."
		echo "==========================================================================="
		echo " The following meshnodes are available for remote connection:"
	fi

	if [ ! -z "$peerlist" ]; then
		# peerlist is a list of mac addresses of peers, both la and non la

		for connectto in $connectlist; do
			linklocal="${connectto%,*}"
			ndpmac="${connectto##*,}"

			check_if_peer

			if [ "$ispeer" -ne 0 ]; then
				continue
			fi

			ndpmacf=$(printf "%s" "$ndpmac" | tr ":" "-")
			ip6addr=$(echo "$linklocal" | awk -F "%" '{printf "%s", $1}')

			if [ -z "$nodeaddr" ]; then
				echo "	$ndpmacf	[ ip address: $ip6addr ]"
			elif [ ! -z "$nodeaddr" ]; then

				if [ "$nodeaddr" = "$ndpmac" ]; then
					echo
					echo "Trying to connect to meshnode \"$ndpmacf\"....."
					ssh "root@$linklocal"
					echo
					echo "Disconnected from meshnode \"$ndpmacf\""
					echo
					break
				fi
			fi
		done
	fi

	echo "==========================================================================="
	echo

	exit 0

elif [ "$1" = "copy" ]; then

	if [ "$auto_config" -eq 0 ]; then
		echo "================================================================"
		echo "Unable to copy -  enable auto_config to copy to other meshnodes"
		echo "================================================================"
		exit 1
	fi
	nodeaddr=$(printf "%s" "$2" | tr "-" ":" | tr "[A-Z]" "[a-z]")
	filepath=$3
	filename=$(echo "$filepath" | awk -F "/" '{printf $NF}')

	echo "==========================================================================="

	echo " Copy a file to /tmp on a remote meshnode"
	echo "    Usage: mesh11sd copy [remote_meshnode_macaddress] [path_of_source_file]"
	echo
	wait_for_nodes
	echo

	if [ -z "$nodeaddr" ]; then
		echo " If the node you are looking for is not in the list - re-run this command."
		echo "==========================================================================="
		echo " The following meshnodes are available for remote copy:"

	fi

	if [ ! -z "$peerlist" ]; then

		for connectto in $connectlist; do
			linklocal="${connectto%,*}"
			ndpmac="${connectto##*,}"

			check_if_peer

			if [ "$ispeer" -ne 0 ]; then
				continue
			fi

			ndpmacf=$(printf "%s" "$ndpmac" | tr ":" "-")
			ip6addr=$(echo "$linklocal" | awk -F "%" '{printf "%s", $1}')

			if [ -z "$nodeaddr" ]; then
				echo "	$ndpmacf	[ ip address: $ip6addr ]"
			elif [ ! -z "$nodeaddr" ]; then

				if [ "$nodeaddr" = "$ndpmac" ] && [ ! -z "$filepath" ]; then
					echo
					echo "Trying to copy to meshnode \"$ndpmacf\"....."
					scp "$filepath" "root@[$linklocal]:/tmp/$filename"
					echo
					echo "Disconnected from meshnode \"$ndpmacf\""
					echo
					break
				fi
			fi
		done
	fi

	echo "==========================================================================="
	echo

	exit 0

elif [ "$1" = "txpower" ]; then
	# get list of interfaces
	get_mesh_iflist
	new_current_power=""

	for iface in $iflist; do
		wait_for_interface "$iface"

		if [ "$ifstatus" = "down" ]; then
			continue
		fi

		current_power=$(iwinfo | grep -A 7 "$iface" | grep -w "Tx-Power:" | awk '{printf "%s", $2}')
		break
	done

	echo "==========================================================================="

	echo "Change the mesh transmit power"

	if [ -z "$2" ]; then
		echo "    Current TX power [ $current_power ] dBm "
		echo "    Usage: mesh11sd txpower [+|-] "
		echo "    where \"+\" increments by 3dBm and \"-\" decrements by 3dBm"

	elif [ "$2" = "+" ]; then
		echo "    Previous TX power [ $current_power ] dBm "
		new_power=$(($current_power + 3))
		iw dev $iface set txpower fixed "$(($new_power * 100))"
		new_current_power=$(iwinfo | grep -A 7 "$iface" | grep -w "Tx-Power:" | awk '{printf "%s", $2}')
		echo
		echo "    New TX power - [ $new_current_power ] dBm "

	elif [ "$2" = "-" ]; then
		echo "    Previous TX power [ $current_power ] dBm "
		new_power=$(($current_power - 3))
		iw dev $iface set txpower fixed "$(($new_power * 100))"
		new_current_power=$(iwinfo | grep -A 7 "$iface" | grep -w "Tx-Power:" | awk '{printf "%s", $2}')
		echo
		echo "    New TX power - [ $new_current_power ] dBm "
	fi

	if [ ! -z "$new_current_power" ]; then
		echo "set mesh11sd.setup.txpower='$new_current_power'" | uci batch
	fi

	echo "==========================================================================="
	echo
	exit 0

elif [ "$1" = "stations" ]; then
	# get list of interfaces
	get_mesh_iflist

	echo "==========================================================================="

	echo "Mesh backhaul stations connected to this node:"

	for iface in $iflist; do
		wait_for_interface "$iface"

		if [ "$ifstatus" = "down" ]; then
			continue
		fi

		iw dev $iface station dump
	done

	echo "==========================================================================="
	echo
	exit 0

elif [ "$1" = "mesh_leechmode" ]; then

	if [ -z "$2" ]; then
		echo "Usage: mesh11sd mesh_leechmode [enable/disable]"
		outputstring="Option mesh_leechmode_enable current value [ $mesh_gate_only ]"
	elif [ "$2" = "enable" ]; then
		mesh_gate_only=1
		echo "set mesh11sd.setup.mesh_leechmode_enable='$mesh_gate_only'" | uci batch
		outputstring="Option mesh_leechmode_enable set to [ $mesh_gate_only ]"
	elif [ "$2" = "disable" ]; then
		mesh_gate_only=0
		echo "set mesh11sd.setup.mesh_leechmode_enable='$mesh_gate_only'" | uci batch
		outputstring="Option mesh_leechmode_enable set to [ $mesh_gate_only ]"
	else
		outputstring="Invalid option [ $2 ]"
	fi

	echo "==========================================================================="

	echo "$outputstring"

	echo "==========================================================================="
	echo
	exit 0


elif [ "$1" = "commit_changes" ]; then

	rssi_change_flag=0
	txpower_change_flag=0
	mesh_gate_only_change_flag=0
	debuglevel_change_flag=0

	changes=$(uci changes mesh11sd)
	changelist=$(echo "$changes" | awk '{printf "%s ", $1}')

	debuglevel_change=$(echo "$changes" | grep "debuglevel" | tail -n 1)
	mesh_rssi_threshold_change=$(echo "$changes" | grep "mesh_rssi_threshold" | tail -n 1)
	txpower_change=$(echo "$changes" | grep "txpower" | tail -n 1)
	mesh_gate_only_change=$(echo "$changes" | grep "mesh_leechmode_enable" | tail -n 1)

	echo "==========================================================================="

	echo "Commit changes, making them non volatile on restart/reboot"

	if [ -z "$2" ] || [ "$2" != "commit" ]; then
		echo "    Usage: mesh11sd commit_changes commit "
		echo "    Writes changes to configuration file "
	elif [ "$2" = "commit" ]; then
		uci revert mesh11sd

		if [ ! -z "$debuglevel_change" ]; then
			echo "set $debuglevel_change" | uci batch
			debuglevel_change_flag=1
		fi

		if [ ! -z "$mesh_rssi_threshold_change" ]; then
			echo "set $mesh_rssi_threshold_change" | uci batch
			rssi_change_flag=1
		fi

		if [ ! -z "$txpower_change" ]; then
			echo "set $txpower_change" | uci batch
			txpower_change_flag=1
		fi

		if [ ! -z "$mesh_gate_only_change" ]; then
			echo "set $mesh_gate_only_change" | uci batch
			mesh_gate_only_change_flag=1
		fi

		uci commit mesh11sd

		for change in $changelist; do
			is_debuglevel=$(echo "$change" | grep -q "debuglevel"; echo -n $?)
			is_txpower=$(echo "$change" | grep -q "txpower"; echo -n $?)
			is_mesh_rssi_threshold=$(echo "$change" | grep -q "mesh_rssi_threshold"; echo -n $?)
			is_mesh_gate_only=$(echo "$change" | grep -q "mesh_gate_only"; echo -n $?)

			if [ "$is_txpower" -eq 0 ] || [ "$is_mesh_rssi_threshold" -eq 0 ] || [ "$is_mesh_gate_only" -eq 0 ]; then
				continue
			fi

			echo "set $change" | uci batch

		done

		if [ "$debuglevel_change_flag" -eq 1 ]; then
			echo "Debuglevel change committed"
		fi

		if [ "$txpower_change_flag" -eq 1 ]; then
			echo "TX power change committed"
		fi

		if [ "$rssi_change_flag" -eq 1 ]; then
			echo "Mesh RSSI change committed"
		fi

		if [ "$mesh_gate_only_change_flag" -eq 1 ]; then
			echo "Mesh Leechmode change committed"
		fi

		if [ "$debuglevel_change_flag" -eq 0 ] && [ "$rssi_change_flag" -eq 0 ] && [ "$txpower_change_flag" -eq 0 ] && [ "$mesh_gate_only_change_flag" -eq 0 ]; then
			echo "No changes found"
		fi

	fi


	echo "==========================================================================="
	echo
	exit 0

elif [ "$1" = "mesh_rssi_threshold" ]; then
	# get list of interfaces
	get_mesh_iflist

	for iface in $iflist; do
		wait_for_interface "$iface"

		if [ "$ifstatus" = "down" ]; then
			continue
		fi

		current_rssi=$(iw dev $iface get mesh_param mesh_rssi_threshold | awk '{printf "%s", $1}')
		break
	done

	echo "==========================================================================="

	echo "Change the mesh rssi threshold"

	if [ -z "$2" ]; then
		echo "    Current threshold for new connections [ $current_rssi ] dBm "
		echo "    Usage: mesh11sd mesh_rssi_threshold [+|-] [force]"
		echo "    where \"+\" increments by 3dBm and \"-\" decrements by 3dBm"
		echo "    The keyword \"force\" forces the new threshold on all peers"

	elif [ "$2" = "+" ]; then
		new_rssi=$(($current_rssi + 3))
		echo "    Previous threshold [ $current_rssi ] dBm "

		if [ -z "$3" ]; then
			touch /tmp/mesh_rssi_threshold
			iw dev $iface set mesh_param mesh_rssi_threshold $new_rssi
			echo "set mesh11sd.mesh_params.mesh_rssi_threshold='$new_rssi'" | uci batch
			new_current_rssi=$(iw dev $iface get mesh_param mesh_rssi_threshold | awk '{printf "%s", $1}')

		elif [ "$3" = "force" ]; then
			echo "set mesh11sd.mesh_params.mesh_rssi_threshold='$new_rssi'" | uci batch
			echo
			echo "    Forcing new threshold on all peers..."

			if [ -f "/tmp/mesh_rssi_threshold" ]; then
				rm /tmp/mesh_rssi_threshold
			fi

			new_current_rssi=$new_rssi
		fi

		echo
		echo "    New threshold - [ $new_current_rssi ] dBm "

	elif [ "$2" = "-" ]; then
		new_rssi=$(($current_rssi - 3))
		echo "    Previous threshold [ $current_rssi ] dBm "

		if [ -z "$3" ]; then
			touch /tmp/mesh_rssi_threshold
			iw dev $iface set mesh_param mesh_rssi_threshold $new_rssi
			echo "set mesh11sd.mesh_params.mesh_rssi_threshold='$new_rssi'" | uci batch
			new_current_rssi=$(iw dev $iface get mesh_param mesh_rssi_threshold | awk '{printf "%s", $1}')

		elif [ "$3" = "force" ]; then
			echo "set mesh11sd.mesh_params.mesh_rssi_threshold='$new_rssi'" | uci batch
			echo
			echo "    Forcing new threshold on all peers..."

			if [ -f "/tmp/mesh_rssi_threshold" ]; then
				rm /tmp/mesh_rssi_threshold
			fi

			new_current_rssi=$new_rssi
		fi

		echo
		echo "    New threshold - [ $new_current_rssi ] dBm "
	fi

	echo "==========================================================================="
	echo
	exit 0

elif [ "$1" = "opkg_force_ipv4" ]; then

	if ! grep "#!/bin/sh" /usr/bin/wget; then
		mv /usr/bin/wget /usr/bin/wget.bak
		echo -e "#!/bin/sh\n/usr/bin/wget.bak -4 \"\$@\"" > /usr/bin/wget && chmod +x /usr/bin/wget
	fi

	exit 0

elif [ "$1" = "opkg_revert_to_default" ]; then

	if grep "#!/bin/sh" /usr/bin/wget; then
		rm /usr/bin/wget
		mv /usr/bin/wget.bak /usr/bin/wget
	fi

	exit 0

elif [ "$1" = "dhcp4_renew" ]; then
	dhcpdevice=$(echo "get network.$auto_mesh_network.device" | uci batch | awk '{printf "%s", $1}')
	dhcp4_renew
	exit 0

elif [ "$1" = "daemon" ]; then
	debugtype="notice"
	syslogmessage="mesh11sd is in startup"
	write_to_syslog

	get_kernel_version
	cpe_conf=0



	if [ "$auto_config" -gt 0 ]; then
		# We do not know the current state so reinitialise everything

		debugtype="info"
		syslogmessage="Initialising state for auto_config"
		write_to_syslog

		uci revert mesh11sd
		uci revert wireless
		uci revert dhcp
		uci revert network
		uci revert firewall

		# Check the configured ipv4 address and change it if left at default of 192.168.1.1
		# For now, only chack in CPE mode.
		# Possibly make this active for portal devices (via config option?)
		setipaddr=$(uci get network.lan.ipaddr)

		if [ "$setipaddr"  = "192.168.1.1" ] && [ "$portal_detect" -eq 3 ]; then
			. $tmpdir/devicemac

			for i in $(seq 9 1 64); do
				#choose start point of sequence away from end eg "9"
				cpipsubnet=$((0x$(printf "$devicemac" | sha256sum | awk '{printf $1}' | tail -c$i | head -c2)))

				#Check for max
				if [ $cpipsubnet -ge 255 ];then
					continue
				fi

				#Skip 168, 167, 0
				if [ $cpipsubnet -eq 168 ] || [ $cpipsubnet -eq 167 ] || [ $cpipsubnet -eq 0 ];then
					continue
				fi

				break
			done

			newipaddr="192.168.$cpipsubnet.1"
			echo "set network.lan.ipaddr='$newipaddr'" | uci batch
		fi


		# Before restarting the network, check if CPE mode is requested
		if [ "$portal_detect" -eq 3 ]; then
			#CPE mode, so setup network config accordingly
			wanif=$(uci get network.wan.device)
			wan6if=$(uci get network.wan6.device)

			uci set network.cpewan=device
			uci set network.cpewan.name='br-wan'
			uci set network.cpewan.type='bridge'
			echo "add_list network.cpewan.ports='$wanif'" | uci batch

			if [ "$wanif" != "$wan6if" ]; then
				echo "add_list network.cpewan.ports='$wan6if'" | uci batch
			fi

			uci set network.wan.device='br-wan'
			uci set network.wan6.device='br-wan'

			# Refresh the ipaddr
			setipaddr=$(uci get network.lan.ipaddr)

			debugtype="notice"
			syslogmessage="lan ip address set to [ $setipaddr ]"
			write_to_syslog

			zones=7

			for zoneindex in $(seq 0 1 $zones); do
				zone=$(echo "get firewall.@zone[$zoneindex].name" | uci batch)

				if [ "$zone" = "wan" ]; then
					wanzoneindex=$zoneindex
					break
				else
					wanzoneindex=$((zones + 1))
				fi
			done

			if [ "$wanzoneindex" -le "$zones" ]; then
				echo "set firewall.@zone[$wanzoneindex].input='ACCEPT'" | uci batch
			else
				debugtype="err"
				syslogmessage="Unable to find wan zone"
				write_to_syslog
			fi

			suffix=$(echo $devicemac | awk -F":" '{printf "%s%s", $5, $6}')
			echo "set network.wan.hostname='meshnode-$suffix'" | uci batch
			echo "set network.wan6.hostname='meshnode-$suffix'" | uci batch


		fi

		/sbin/service network restart
		/sbin/service dnsmasq restart
		/sbin/service firewall restart
		sleep 5

		probe_interface_mac
	fi

	if [ -e "/tmp/mesh11sd/brmac_la" ]; then
		rm "/tmp/mesh11sd/brmac_la"
	fi

	if [ -f "/tmp/mesh_rssi_threshold" ]; then
		rm /tmp/mesh_rssi_threshold
	fi

	if [ -f "$tmpdir/dhcp6probe" ]; then
		mv "$tmpdir/dhcp6probe" "$tmpdir/dhcp6probe.prev"
	fi

	#Default flags
	startup=4 # bit 2
	statusmode=2 # bit 1
	enabled=1 #bit 0

	# Initial conditions
	statusmode=0
	changed=0
	firstloop=1 # Set if we have just started
	daemon_startup=1 # For future watchdog tests
	autoconfig=0
	macfixup=0 # Used if we need to fix the mesh interface mac address
	mute=0 # Mute some debug messages in function calls
	previous_path_change_count=1
	index=0

	# Clear the dhcp authoritative flag
	uci delete dhcp.@dnsmasq[0].authoritative 2>/dev/null

	# default state
	last_state="initial"

	# Initial Mode Flag
	mode=$(($startup + $statusmode + $enabled ))
	lastmode=0
	ucinamecheck=0

	check_config_params

	arp_setup

	# Start the main loop
	while true; do
		mode=$(($startup + $statusmode + $enabled))

		syslogmessage=""

		if [ $mode -eq 5 ]; then
			# startup=4, statusmode=0, enabled=1
			startup=0
			statusmode=0
			mode=1
			syslogmessage="mesh11sd v$version has started: mesh management mode $mode"

		elif [ $mode -eq 4 ]; then
			# startup=4, statusmode=0, enabled=0
			startup=0
			statusmode=2
			mode=0
			syslogmessage="mesh11sd v$version has started: mesh status mode $mode"

		elif [ $mode -eq 3 ]; then
			# startup=0, statusmode=2, enabled=1
			startup=0
			statusmode=0
			mode=1
			syslogmessage="mesh11sd v$version has started: mesh management mode $mode"

		elif [ $mode -eq 2 ]; then
			# startup=0, statusmode=2, enabled=0
			startup=0
			statusmode=2
			mode=0
			syslogmessage="mesh11sd v$version has started: mesh status mode $mode"

		elif [ $mode -eq 1 ]; then
			# startup=0, statusmode=0, enabled=1
			startup=0
			statusmode=0
			mode=1
			syslogmessage="mesh11sd v$version has started, mesh management mode $mode"

		elif [ $mode -eq 0 ]; then
			# startup=0, statusmode=0, enabled=0
			startup=0
			statusmode=2
			mode=0
			syslogmessage="mesh11sd v$version has started: mesh status mode $mode"
		fi

		if [ $mode -ne $lastmode ]; then
			debugtype="notice"
			write_to_syslog
		fi

		lastmode=$mode
		meshindex=0
		meshconfigs=""

		if [ "$enabled" = 1 ]; then
			#get list of mesh configs
			meshconfigs=$(uci show wireless 2> /dev/null | grep "mode='mesh'" | awk -F ".mode='mesh'" '{printf "%s " $1}')

			if [ -z "$meshconfigs" ]; then
				# no mesh configuration yet
				debugtype="info"
				syslogmessage="No mesh interfaces detected yet.... Attempting auto configure"
				write_to_syslog

				############# Autoconfig

				if [ "$auto_config" -eq 1 ]; then
					auto_config
				else
					debugtype="err"
					syslogmessage="auto_config is disabled. Please configure a mesh interface or enable auto_config...."
					write_to_syslog
					sleep $checkinterval
				fi

				########################
			fi

			# Is the list of meshconfigs still empty?
			if [ -z "$meshconfigs" ]; then
				meshconfigs=$(uci show wireless 2> /dev/null | grep "mode='mesh'" | awk -F ".mode='mesh'" '{printf "%s " $1}')
			fi

			if [ ! -z "$meshconfigs" ]; then
				# we have an existing mesh config

				for meshconfig in $meshconfigs; do

					if [ $meshindex -gt 15 ]; then
						# Max number of mesh interfaces exceeded - abort
						debugtype="warn"
						syslogmessage="Maximum number of mesh interfaces exceeded"
						write_to_syslog
						break
					fi

					meshindex=$(($meshindex+1))
				done

				# set mesh mac address for this meshconfig
				refresh_bridgemac
				. $tmpdir/devicemac
				get_wiphys

				#### The mesh interface MUST have a unique mac address ie not duplicated from another interface.
				# We will set it ip as a locally administered version of the bridge mac for facilitating connect/copy functionality
				# If manually configured, let the user figure it out

				if [ "$macfixup" -eq 0 ] && [ "$auto_config" -gt 0 ]; then

					for wiphy in $wiphys; do
						ucimeshconfig=$(uci get $meshconfig.macaddr 2> /dev/null)

						if [ -z "$ucimeshconfig" ]; then
							# No mac address fixup, so add one
							phyindex=$(echo "$wiphy" | awk -F "phy" '{printf "%s", $2}')
							phyindex=$(printf "%x" $phyindex)
							mesh_ifname="$mesh_basename""$phyindex"
							convert_to_la "$devicemac"
							debugtype="notice"
							syslogmessage="Setting mac address of mesh interface $mesh_ifname to [ $mac_la ]"
							write_to_syslog

							ucibatch="set wireless.m11s$phyindex.macaddr='$mac_la'"
							echo "$ucibatch" | uci batch
							changed=1
						fi
					done

					# do the same for ap interfaces but index the la mac
					aplist=$(uci show wireless | grep "mode='ap'" | awk -F "." '{printf "%s ", $2}')

					convert_to_la "$devicemac"

					for ap in $aplist; do
						index=$(($index + 1))
						make_indexed_mac "$mac_la" "$index"
						echo "set wireless.$ap.macaddr=$mac_indexed" | uci batch
					done

					macfixup=1
				fi
			else
				continue
			fi

			if [ "$firstloop" -eq 1 ] || [ "$changed" -eq 1 ]; then
				firstloop=0
				changed=0

				touch /tmp/meshinterface
				all_nodes_rssi_update
			fi
			# get a list of interfaces
			get_mesh_iflist

			for iface in $iflist; do
				wait_for_interface "$iface"

				if [ "$ifstatus" = "down" ]; then
					continue
				fi

				debugtype="debug"
				syslogmessage="interface $iface is $ifstatus"
				write_to_syslog

				# get list of mesh parameters for this interface
				get_params

				if [ -z "$params" ]; then
					# this is not a mesh interface
					continue
				else
					# Check if this interface has a uci ifname
					uciname=$(uci show wireless | grep "ifname='$iface'" | awk -F "." '{printf "wireless.%s" $2}')

					if [ -z "$uciname" ]; then
						# Error - No interface name in config, auto config would have added one
						if [ "$ucinamecheck" -eq 0 ]; then
							ucinamecheck=1
							uciname=$iface
							debugtype="err"
							syslogmessage="ERROR: Mesh interface name not set in wireless config - using autogenerated name [ $iface ]"
							write_to_syslog
						fi
					fi
				fi

				# Set stp path cost
				mute=1
				get_mesh_path_cost

				if [ "$mesh_path_cost" -gt 0 ] && [ "$mesh_path_cost" -lt 65535 ]; then
					# Make sure STP is on
					stpstatus=$(brctl show $device | grep "yes" | awk '{printf "%s", $3}')

					if [ -z "$stpstatus" ] || [ "$stpstatus" != "yes" ]; then
						brctl stp "$device" yes
					fi

					brctl setpathcost "$device" "$iface" "$mesh_path_cost"

					br_ifaces=$(brctl showstp "$device" | grep -B 1 -w "port id" | grep "(" | awk '{printf "%s ", $1}')

					for br_iface in $br_ifaces; do

						if [ "$br_iface" = "$iface" ]; then
							continue
						fi

						other_path_cost=$(( 65535 - $mesh_path_cost))
						brctl setpathcost "$device" "$br_iface" "$other_path_cost"

					done
				elif [ "$mesh_path_cost" -eq 0 ]; then
					brctl stp "$device" no
				fi

				#Do NOT configure parameters found in wireless config
				# so change the value of uciname before calling check_mesh_params.
				#
				#Override wireless config and/or set parameters to those found in mesh11sd config
				uciname="mesh11sd.mesh_params"
				check_mesh_params
				check_mesh_phantom
			done

			if [ "$auto_config" -eq 1 ]; then

				if [ "$portal_detect" -eq 1 ]; then
					check_portal

				elif [ "$portal_detect" -eq 0 ]; then
					# portal_detect is not enabled - force portal mode:
					authoritative=$(uci get dhcp.@dnsmasq[0].authoritative 2>/dev/null | awk '{printf "%d", $1}')

					if [ -z "$authoritative" ]; then
						authoritative=0
					fi

					uci set mesh11sd.mesh_params.mesh_connected_to_as='1'

					if [ -z "$authoritative" ] || [ "$authoritative" -eq 0 ]; then
						debugtype="notice"
						syslogmessage="Portal detection is disabled, forcing portal mode"
						write_to_syslog

						if [ -f "/var/run/udhcpc-$device.pid" ]; then
							kill $(cat /var/run/udhcpc-$device.pid)
						fi

						restore_ipv4

						uci set dhcp.@dnsmasq[0].authoritative='1'
						echo "set dhcp.$auto_mesh_network.ignore='0'" | uci batch
						echo "set dhcp.$auto_mesh_network.ra_default='2'" | uci batch
						echo "set dhcp.$auto_mesh_network.dhcpv6='server'" | uci batch
						echo "set dhcp.$auto_mesh_network.ra='server'" | uci batch
						uci set dhcp.@dnsmasq[0].logfacility='-'
						uci set dhcp.@dnsmasq[0].quietdhcp='1'

						if [ "$mesh_gate_only" -eq 0 ]; then
							mesh_hwmp_rootmode="4"
						else
							mesh_hwmp_rootmode="0"
						fi

						echo "set mesh11sd.mesh_params.mesh_hwmp_rootmode='$mesh_hwmp_rootmode'" | uci batch

						/sbin/service dnsmasq restart
						/sbin/service odhcpd restart
						restart_mesh
					fi

				elif [ "$portal_detect" -eq 3 ]; then

					if [ "$cpe_conf" -eq 0 ]; then

						# portal_detect is set to CPE mode - this is a router where the wan interface is the mesh backhaul:
						authoritative=$(uci get dhcp.@dnsmasq[0].authoritative 2>/dev/null | awk '{printf "%d", $1}')

						if [ -z "$authoritative" ]; then
							authoritative=0
						fi

						# To other meshnodes, this looks like a peer
						uci set mesh11sd.mesh_params.mesh_connected_to_as='0'

						if [ -z "$authoritative" ] || [ "$authoritative" -eq 0 ]; then
							debugtype="notice"
							syslogmessage="CPE mode"
							write_to_syslog
						fi

						if [ "$mesh_gate_only" -eq 0 ]; then
							non_portal_mesh_hwmp_rootmode="2"
						else
							non_portal_mesh_hwmp_rootmode="0"
						fi

						echo "set mesh11sd.mesh_params.mesh_hwmp_rootmode='$non_portal_mesh_hwmp_rootmode'" | uci batch

						echo "set dhcp.lan.ignore='0'" | uci batch
						echo "set dhcp.lan.ra_default='2'" | uci batch
						echo "set dhcp.lan.dhcpv6='server'" | uci batch
						echo "set dhcp.lan.ra='server'" | uci batch
						uci set dhcp.@dnsmasq[0].logfacility='-'
						uci set dhcp.@dnsmasq[0].quietdhcp='1'

						/sbin/service dnsmasq restart
						/sbin/service odhcpd restart
						restart_mesh

						cpe_conf=1
					fi
				fi
			fi

			check_gate
			check_mesh_gate_only
			check_hwmp
			wait_for_mesh
			block_bridge_loops
			check_path_changes

			if [ "$portal_detect" -eq 3 ]; then
				check_dns_server
				check_channel
			fi


		fi

		debugtype="debug"
		syslogmessage="checkinterval $checkinterval seconds"
		write_to_syslog

		sleep $checkinterval
	done
	exit 0

else
	echo "Unrecognised command - For help, try mesh11sd --help "
fi
