#!/bin/sh
# Copyright (C) BlueWave Projects and Services 2015-2025
#
#	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
#
last_version="5.1.3~be7a"
version="5.1.3"
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 "%s", $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="$tmpdir/"$(date | sha256sum | awk '{printf "%s", $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 "$tmpdir/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\"" > "$tmpdir/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"
	mute="$mutestate"
	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"
	mute="$mutestate"
	write_to_syslog

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

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

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

	syslogmessage="option commit_all [ $commit_all ]"
	debugtype="info"
	mute="$mutestate"
	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"
	mute="$mutestate"
	write_to_syslog

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

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

	syslogmessage="option portal_detect [ $portal_detect ]"
	debugtype="info"
	mute="$mutestate"
	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"
	mute="$mutestate"
	write_to_syslog

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

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

	syslogmessage="option portal_use_default_ipv4 [ $portal_use_default_ipv4 ]"
	debugtype="info"
	mute="$mutestate"
	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"
	mute="$mutestate"
	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=10
	fi

	syslogmessage="option portal_detect_threshold [ $portal_detect_threshold ]"
	debugtype="info"
	mute="$mutestate"
	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"
	mute="$mutestate"
	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"
	mute="$mutestate"
	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 "%s", $1}' | tail -c55 | head -c30)

	syslogmessage="auto_mesh_id hash [ $auto_mesh_id ]"
	debugtype="info"
	mute="$mutestate"
	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"

	mute="$mutestate"
	write_to_syslog

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

	if [ ! -z "$mesh_phy_index" ]; then
		is_num=$(echo "$mesh_phy_index" | grep -E '^[0-9]+$' &>/dev/null; echo $?)
		if [ "$is_num" -ne 0 ]; then
			syslogmessage="option mesh_phy_index must be an integer - ignoring setup value of [ $mesh_phy_index ]"
			debugtype="info"
			mute="$mutestate"
			write_to_syslog
			mesh_phy_index=""
		else
			num_wiphys=$(iw list | grep -c "Wiphy")

			if [ "$mesh_phy_index" -ge "$num_wiphys" ]; then
				syslogmessage="option mesh_phy_index is invalid, phy does not exist - ignoring setup value of [ $mesh_phy_index ]"
				debugtype="info"
				mute="$mutestate"
				write_to_syslog
				mesh_phy_index=""
			fi
		fi

	fi

	syslogmessage="option mesh_phy_index [ $mesh_phy_index ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

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

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

	#####
	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"
	mute="$mutestate"
	write_to_syslog

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

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


	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?"
			mute="$mutestate"
			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"
		mute="$mutestate"
		write_to_syslog
		auto_mesh_network="lan"
	fi

	syslogmessage="option auto_mesh_network [ $auto_mesh_network ]"
	debugtype="info"
	mute="$mutestate"
	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"
	mute="$mutestate"
	write_to_syslog

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

	if [ "$ssid_suffix_enable" -eq 1 ]; then
		maxlen=22
	else
		maxlen=30
	fi

	mesh_gate_base_ssid=$(echo -n "$mesh_gate_base_ssid" | tr -d " " | head -c "$maxlen")

	if [ -z "$mesh_gate_base_ssid" ]; then
		syslogmessage="option mesh_gate_base_ssid [ Not Set ] Using default"
		debugtype="info"
		mute="$mutestate"
		write_to_syslog

	else
		syslogmessage="option mesh_gate_base_ssid [ $mesh_gate_base_ssid ] "
		debugtype="info"
		mute="$mutestate"
		write_to_syslog
	fi

	#####
	mesh_gate_encryption=$(uci get mesh11sd.setup.mesh_gate_encryption 2> /dev/null)
	package_list="wpad-mbedtls wpad-wolfssl wpad-openssl"
	check_package_list
	installed_wpad=$?

	if [ "$installed_wpad" -gt 0 ]; then
		package_list="wpad-mesh-mbedtls wpad-mesh-wolfssl wpad-mesh-openssl wpad-mbedtls wpad-wolfssl wpad-openssl"
		check_package_list
		installed_mesh_wpad=$?

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

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

	if [ "$mesh_gate_encryption" -eq 4 ] && [ "$installed_wpad" -gt 0 ]; then
		mesh_gate_encryption=0
	fi

	if [ "$mesh_gate_encryption" -le 4 ]; then
		syslogmessage="option mesh_gate_encryption [ $mesh_gate_encryption ]"
		debugtype="info"
		mute="$mutestate"
		write_to_syslog
	else
		syslogmessage="option mesh_gate_encryption must be 0 (none/owe_transition), 1 (sae, aka wpa3), 2 (sae-mixed, aka wpa2/wpa3), 3 (psk2, aka wpa2) or 4 (owe)"
		debugtype="err"
		mute="$mutestate"
		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"
		mute="$mutestate"
		write_to_syslog
		mesh_gate_key=""
	else
		syslogmessage="option mesh_gate_key [ $mesh_gate_key ]"
		debugtype="info"
		mute="$mutestate"
		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"
	mute="$mutestate"
	write_to_syslog

	####
	# vxlan configs

	#####

	package_list="ip-full vxlan"
	check_package_list

	if [ "$ip_full" -eq 0 ] && [ "$vxlan" -eq 0 ]; then # we have the required packages for vxlan and it is enabled

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

		if [ -z "$vtun_enable" ]; then
			vtun_enable=1
		elif [ "$vtun_enable" -gt 1 ]; then
			vtun_enable=1
		else
			vtun_enable=0
		fi

		if [ "$portal_detect" -eq 3 ]; then
			uci set mesh11sd.setup.vtun_enable='0'
			vtun_enable=0
			syslogmessage="option vtun_enable is disabled because cpe mode is enabled"
			debugtype="info"
			mute="$mutestate"
			write_to_syslog
		else
			syslogmessage="option vtun_enable [ $vtun_enable ]"
			debugtype="info"
			mute="$mutestate"
			write_to_syslog
		fi

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

		if [ -z "$tun_id" ]; then
			tun_id="69"
		fi

		# Change any leading zero to 42

		if [ "${tun_id:0:1}" -eq 0 ]; then
			tun_id="42${tun_id:1:9}"
		fi

		syslogmessage="option tun_id [ $tun_id ]"
		debugtype="info"
		mute="$mutestate"
		write_to_syslog


		#####
		vtun_ip=$(uci get mesh11sd.setup.vtun_ip 2> /dev/null)
		vtun_ip_net=$(uci get network.vtunlan.ipaddr 2> /dev/null)

		if [ -z "$vtun_ip_net" ] && [ -z "$vtun_ip" ]; then

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

			is_ipv4addr_valid "$vtun_ip"

			if [ -z "$checkip" ]; then
				generate_ipv4_base "$auto_mesh_key"
				vtun_ip="$newipaddr"
			fi

		elif [ -z "$vtun_ip" ]; then
			vtun_ip="$vtun_ip_net"
		fi

		syslogmessage="option vtun_ip [ $vtun_ip ]"
		debugtype="info"
		mute="$mutestate"
		write_to_syslog

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

		if [ -z "$vtun_mask" ]; then
			vtun_mask="255.255.255.0"
		fi

		is_ipv4mask_valid "$vtun_mask"

		if [ "$?" -gt 0 ]; then
			vtun_mask="255.255.255.0"
		fi

		syslogmessage="option vtun_mask [ $vtun_mask ]"
		debugtype="info"
		mute="$mutestate"
		write_to_syslog

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

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

		if [ "$vtun_gate_encryption" -eq 4 ] && [ "$installed_wpad" -gt 0 ]; then
			vtun_gate_encryption=0
		fi

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

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

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

		if [ "$vtun_gate_encryption" -eq 4 ]; then
			vtun_gate_key="owe_null_key"
		fi

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

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

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

		if [ -z "$vtun_base_ssid" ]; then
			vtun_base_ssid="Guest"
		fi

		if [ "$ssid_suffix_enable" -eq 1 ]; then
			maxlen=22
		else
			maxlen=30
		fi

		vtun_base_ssid=$(echo -n "$vtun_base_ssid" | tr -d " " | head -c "$maxlen")
		syslogmessage="option vtun_base_ssid [ $vtun_base_ssid ]"
		debugtype="info"
		mute="$mutestate"
		write_to_syslog

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

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

		syslogmessage="option vtun_path_cost [ $vtun_path_cost ]"
		debugtype="info"
		mute="$mutestate"
		write_to_syslog

	else
		vtun_enable=0
		syslogmessage="option vtun_enable is disabled because required dependencies [ ip-full vxlan ] are not met"
		debugtype="info"
		mute="$mutestate"
		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

	if [ "$mesh_gate_enable" -eq 1 ]; then
		ifdisable=0
	else
		ifdisable=1
	fi

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

	#####
	# mesh_leechmode_enable
	# 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_leechmode_enable [ $mesh_gate_only ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

	#####

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

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

	#####
	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"
	mute="$mutestate"
	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"
		mute="$mutestate"
		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"
		mute="$mutestate"
		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"
	mute="$mutestate"
	write_to_syslog

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

	if [ -z "$reactive_path_stabilisation_threshold" ] || [ "$reactive_path_stabilisation_threshold" -eq 0 ]; then
		reactive_path_stabilisation_threshold="5"
	fi

	syslogmessage="option reactive_path_stabilisation_threshold [ $reactive_path_stabilisation_threshold ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

	#####

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

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

	if [ "$mesh_mac_forced_forwarding" -ne 0 ]; then
		mesh_mac_forced_forwarding="1"
	fi

	syslogmessage="option mesh_mac_forced_forwarding [ $mesh_mac_forced_forwarding ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

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

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

	if [ "$gateway_proxy_arp" -ne 0 ]; then
		gateway_proxy_arp="1"
	fi

	syslogmessage="option gateway_proxy_arp [ $gateway_proxy_arp ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

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

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

	if [ "$reboot_on_error" -ne 0 ]; then
		reboot_on_error="1"
	fi

	syslogmessage="option reboot_on_error [ $reboot_on_error ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

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

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

	if [ "$stop_on_error" -ne 0 ]; then
		stop_on_error="1"
	fi

	syslogmessage="option stop_on_error [ $stop_on_error ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

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

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

	syslogmessage="option apmond_enable [ $apmond_enable ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

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

	if [ -z "$apmond_cgi_dir" ]; then
		apmond_cgi_dir="/www/cgi-bin"
	fi

	strlen=$((${#apmon_cgi_dir}));
	lastchar=${apmond_cgi_dir:$strlen -1 :1}

	if [ "$lastchar" != "/" ]; then
		apmond_cgi_dir="$apmond_cgi_dir/"
	fi

	if [ ! -e "$apmond_cgi_dir" ]; then
		mkdir -p "$apmond_cgi_dir"
	fi

	syslogmessage="option apmond_cgi_dir [ $apmond_cgi_dir ]"
	debugtype="info"
	mute="$mutestate"
	write_to_syslog

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

	if [ -z "$mesh_backhaul_led" ]; then
		mesh_backhaul_led="auto"
	fi

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

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

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_retry_timeout=$(uci get mesh11sd.mesh_params.mesh_retry_timeout 2> /dev/null)

	if [ -z "$mesh_retry_timeout" ]; then
		mesh_retry_timeout="255"
	fi

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

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

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

	if [ -z "$mesh_confirm_timeout" ]; then
		mesh_confirm_timeout="255"
	fi

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

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

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

	if [ -z "$mesh_holding_timeout" ]; then
		mesh_holding_timeout="255"
	fi

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

	syslogmessage="option mesh_holding_timeout [ $mesh_holding_timeout ]"
	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

	config_max_peer_links="$mesh_max_peer_links"
	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="65525"
	fi

	syslogmessage="option mesh_path_cost [ $mesh_path_cost ]"

	if [ "$mute" -eq  0 ]; then
		mute="$mutestate"
	fi

	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; log_to_stderr="-s";;
				"err") debugnum=0; log_to_stderr="-s";;
				"notice") debugnum=1; log_to_stderr="";;
				"warn") debugnum=1; log_to_stderr="-s";;
				"info") debugnum=2; log_to_stderr="";;
				"debug") debugnum=3; log_to_stderr="-s";;
				*) debugnum=1; debugtype="notice"; log_to_stderr="";;
			esac

			if [ "$debuglevel" -ge "$debugnum" ]; then
				logger -p "daemon.$debugtype" "$log_to_stderr" -t "mesh11sd[$mesh11sdpid]" "$syslogmessage"
			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
	default_gw=$(ip route | grep "default via")

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

		for retry in $(seq $retries); do

			if [ -z "$default_gw" ]; then
				debugtype="debug"

				if [ "$firstloop" -eq 1 ]; then
					syslogmessage="In Startup - portal upstream link check [$zone] - iteration [ $retry ] ...."
				elif [ "$firstloop" -eq 0 ]; then
					syslogmessage="Portal upstream link check  [$zone] - iteration [ $retry ] ...."
				fi

				write_to_syslog
				sleep 1

				case $portal_detect in
					"0") zone="wan";;
					"1") zone="wan";;
					"3") zone="wan";;
					"4") zone="lan";;
					"5") zone="lan";;
					*) zone="";;
				esac


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

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

			break
		done

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

	elif [ "$portal_detect" -eq 0 ] || [ "$portal_detect" -eq 4 ]; then
		# 0 - force portal mode, 4 - force portal bridge mode

		if [ "$portal_detect" -eq 0 ]; then
			zone="wan"
		elif [ "$portal_detect" -eq 4 ]; then
			zone="lan"
		fi

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

		if [ -z "$default_gw" ]; then
			dhcpdevice=$(uci get network."$zone".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" -ge 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 $?)

		debugtype="debug"
		syslogmessage="ipV4 gateway status [ $pingresult ]"
		write_to_syslog


		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 [ "$leechmode" -eq 1 ]; then
					echo "set mesh11sd.setup.mesh_leechmode_enable='0'" | uci batch
					leechmode=0
					# Reset ip4pingfailcount to go around again to the portal_detect_threshold, giving HWMP some cycles to establish a path
					ip4pingfailcount=0

					debugtype="err"
					syslogmessage="portal detect threshold reached, enabling HWMP announcments"
					write_to_syslog
					write_to_watchdog_nonvolatile_log

				elif [ "$network_restart" -eq 0 ]; then
					dhcpdevice=$(echo "get network.$auto_mesh_network.device" | uci batch | awk '{printf "%s", $1}')
					debugtype="err"
					syslogmessage="portal detect threshold reached, watchdog is monitoring"
					write_to_syslog
					write_to_watchdog_nonvolatile_log
					network_restart=1
					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, watchdog continuing to monitor..."
					write_to_syslog
					write_to_watchdog_nonvolatile_log
					network_restart=2
					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, watchdog is restarting the 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"

					if [ "$stop_on_error" -gt 0 ]; then
						syslogmessage="portal detect threshold exceeded, restarting network did not work... disabling mesh management, changing to mesh status mode"
						enabled=0
						write_to_syslog
						write_to_watchdog_nonvolatile_log
					elif [ "$reboot_on_error" -gt 0 ]; then
						syslogmessage="portal detect threshold exceeded, restarting network did not work... rebooting node"
						write_to_syslog
						write_to_watchdog_nonvolatile_log
						reboot
					else
						#Reset the portal detect threshold. Keep trying to find a portal...
						ip4pingfailcount=0
						network_restart=0
					fi
				fi

			fi
		else
			ip4pingfailcount=0
			network_restart=0
		fi

	else
		detected_state="portal"
	fi

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

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

	if [ -z "$is_portal" ] && [ -e "$tmpdir/is_portal" ]; then
		if [ -e "/$tmpdir/is_portal" ]; then
			rm /$tmpdir/is_portal
		fi
	elif [ ! -z "$is_portal" ] && [ ! -e "$tmpdir/is_portal" ]; then
		touch /$tmpdir/is_portal
	fi
}

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 ] && [ "$commit_all" -eq 0 ]; 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

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

			if [ "$detected_state" = "peer" ] && [ "$last_state" = "portal" ]; then
				# We have become a peer
				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)

				echo "set network.$auto_mesh_network.proto='dhcp'" | uci batch
				set_ula_prefix "revert"
				/sbin/service network reload
				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

				if [ "$vtunnel" = "configured" ]; then
					uci set dhcp.vtunlan.dhcpv4='disabled'
					uci set dhcp.vtunlan.dhcpv6='disabled'
					uci set dhcp.vtunlan.ra='disabled'
					uci set dhcp.vtunlan.ignore='1'
				fi

				/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="Mesh startup watchdog - iteration [ $retry ] ...."
						write_to_syslog
						sleep 3
						continue
					else
						gw_ip=$(echo "$default_gw" | awk -F" " '{printf "%s", $3}')
						break
					fi
				done

				if [ ! -z "$gw_ip" ] && [ "$commit_all" -eq 0 ]; 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

				# Just become a peer so stop opennds if it is installed and enabled
				manage_opennds stop

			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

				if [ "$leechmode" -eq 1 ]; then
					uci set mesh11sd.setup.mesh_leechmode_enable='0'
					leechmode=0
				fi

				last_state="portal"
				debugtype="debug"
				syslogmessage="This meshnode is an upstream portal"
				write_to_syslog

				echo "set network.$auto_mesh_network.proto='static'" | uci batch
				set_ula_prefix "set"
				/sbin/service network reload

				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 [ "$vtunnel" = "configured" ]; then
					uci set dhcp.vtunlan.dhcpv4='server'
					uci set dhcp.vtunlan.dhcpv6='server'
					uci set dhcp.vtunlan.ra='server'
					uci set dhcp.vtunlan.ignore='0'
				fi

				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

				# Just become a portal so start opennds if it is installed and enabled
				manage_opennds start
			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

	local len=${#octet}
	if [ "$len" -eq 1 ]; then
		octet="0$octet"
	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

	local len=${#octet}
	if [ "$len" -eq 1 ]; then
		octet="0$octet"
	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 "$tmpdir/meshinterface" ]; then

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

				rm "$tmpdir/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) }')
	mkdir -p "$tmpdir/radios"

	for wiphy in $wiphys; do
		radioindex=${wiphy:3:10}
		band=$(echo "get wireless.radio$radioindex.band" | uci batch)
		mesh_capable=$(iw phy "$wiphy" info | grep -w -q  "mesh point"; echo -n "$?")
		total_ifaces=$(iw phy $wiphy info | grep -w "total <=" | awk -F"," '{print $1}' | awk '{print $3}')

		echo "mesh_capable=$mesh_capable; total_ifaces=$total_ifaces; radioindex=$radioindex; band=$band" > "$tmpdir/radios/radio$radioindex"

		if [ $mesh_capable -gt 0 ]; then
			debugtype="info"
			syslogmessage="WARNING - phy [ $wiphy ] does not support mesh interfaces."
			write_to_syslog
		fi

		if [ -z "$total_ifaces" ] || [ $total_ifaces -lt 5 ]; then
			debugtype="info"
			syslogmessage="WARNING - phy [ $wiphy ] only supports [ $total_ifaces ] interfaces - possibly some or all configured wireless APs will be missing."
			write_to_syslog
		fi
	done
}

refresh_bridgemac() {
	# get the device device mac and write it to $tmpdir/devicemac
	device=$(uci get network.$auto_mesh_network.device)
	configured_mac=$(uci get network.$auto_mesh_network.macaddr 2>/dev/null)

	if [ -z "$device" ]; then
		device="br-lan"
	fi

	wait_for_interface "$device"
	devicemac=$(ip link | grep -A 1 "$device:" | grep -w "link/ether" | awk '{printf "%s", $2}')

	if [ ! -f "/etc/factory_mac" ]; then
		echo "factory_mac=\"$devicemac\"" > /etc/factory_mac

		if [ -z "$configured_mac" ]; then
			echo "set network.$auto_mesh_network.macaddr='$devicemac'" | uci batch
			uci commit network
		fi

	fi

	. /etc/factory_mac

	if [ "$factory_mac" != "$devicemac" ]; then
		devicemac="$factory_mac"
		ip link set $device down; ip link set $device up address $devicemac
	fi

	echo "device=\"$device\" ; devicemac=\"$devicemac\"" > $tmpdir/devicemac
}

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

	# Set the default region to DFS-ETSI (safer than DFS-UNSET for a mesh)
	# Code EU is not recognised in current OpenWrt releases, so use first alphabetically valid code ie Andorra
	dfs_etsi="AD"
	meshifenabled=0

	# Are we using ath10k drivers?
	is_installed "kmod-ath10k-ct"

	if [ "$exitcode" -eq 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
		# Set the odhcpd loglevel
		uci set dhcp.odhcpd.loglevel='3'

		# mute dnsmasq logging
		uci set dhcp.@dnsmasq[0].logfacility='-'
		uci set dhcp.@dnsmasq[0].quietdhcp='1'


		# Add vxlan wireless interface(s)
		package_list="ip-full vxlan"
		check_package_list

		if [ "$ip_full" -eq 0 ] && [ "$vxlan" -eq 0 ] && [ "$vtun_enable" -eq 1 ]; then
			# we have the required packages for vxlan
			aplist=$(uci show wireless | grep "mode='ap'" | awk -F "." '{printf "%s ", $2}')

			for ap in $aplist; do
				radio_index=$(echo "show wireless.$ap" | uci batch 2> /dev/null | grep "device=" | awk -F "'" '{printf "%s", $2}' | awk -F "radio" '{printf "%s", $2}')

				echo "set wireless.vxradio$radio_index=wifi-iface" | uci batch
				echo "set wireless.vxradio$radio_index.device='radio$radio_index'" | uci batch
				echo "set wireless.vxradio$radio_index.network='vtunlan'" | uci batch
				echo "set wireless.vxradio$radio_index.mode='ap'" | uci batch
				echo "set wireless.vxradio$radio_index.ifname='vxradio$radio_index'" | uci batch
				echo "set wireless.vxradio$radio_index.ssid='$vtun_base_ssid'" | uci batch
				echo "set wireless.vxradio$radio_index.encryption='none'" | uci batch
				echo "set wireless.vxradio$radio_index.disabled='$ifdisable'" | uci batch
			done
		fi

		# do we have a mesh supporting wpad?
		package_list="wpad-mbedtls wpad-wolfssl wpad-openssl wpad-mesh-mbedtls wpad-mesh-wolfssl wpad-mesh-openssl"
		check_package_list

		if [ "$?" -eq 0 ]; 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)

					if [ ! -z "$mesh_phy_index" ] && [ "$phyindex" != "$mesh_phy_index" ]; then
						syslogmessage="option mesh_phy_index [ $mesh_phy_index ] does not match phyindex [ $phyindex ] - skipping this phy"
						debugtype="info"
						mute="$mutestate"
						write_to_syslog
						continue
					fi

					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

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

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

					if [ ! -z "$country" ]; then
						echo "set wireless.radio$phyindex.country='$country'" | uci batch
					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

						if [ ! -f "$tmpdir/active_mesh_ifname" ]; then
							echo "active_mesh_ifname=\"$mesh_basename$phyindex\"" > "$tmpdir/active_mesh_ifname"
						fi
					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
									#Generate a channel, choosing start point of sequence away from end eg "9"
									chan=$((0x$(printf "$devicemac" | sha256sum | awk '{printf "%s", $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 ssid and suffix
				suffix=$(echo $devicemac | awk -F":" '{printf "%s%s", $5, $6}')

				ifindex=0

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

					if [ -z "$ifname" ]; then
						ifname="phy$radioindex-ap$ifindex"
						ifindex=$((ifindex+1))
						echo "set $ap.ifname='$ifname'" | uci batch
					fi

					if [ "$ssid" != "$vtun_base_ssid" ] && [ ! -z "$mesh_gate_base_ssid" ]; then
						ssid="$mesh_gate_base_ssid"
					fi

					if [ "$ssid_suffix_enable" -eq 1 ]; then
						echo "set $ap.ssid='$ssid-$band-$suffix'" | uci batch
					else
						echo "set $ap.ssid='$ssid'" | uci batch
					fi
				done

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

				#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

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

				if [ "$encryption_type" = "owe" ] || [ "$encryption_type" = "none" ] || [ "$vx_encryption_type" = "owe" ] || [ "$vx_encryption_type" = "none" ]; then

					if [ "$wpad_mbedtls" -eq 0 ] || [ "$wpad_wolfssl" -eq 0 ] || [ "$wpad_openssl" -eq 0 ]; then

						# We have a full version so owe is supported
						owe_able=1
						debugtype="notice"
						syslogmessage="full version of wpad is installed, owe supported"
						write_to_syslog
					else
						encryption_type="none"
						vx_encryption_type="none"
						owe_able=0
						debugtype="err"
						syslogmessage="owe not supported, install a full version of wpad"
						write_to_syslog
					fi
				fi

				for ap in $aplist; do
					radio=$(uci get "$ap.device" 2> /dev/null)
					. "$tmpdir/radios/$radio"

					is_vx=$(echo "$ap" | grep -c "vxradio")

					if [ "$is_vx" -eq 0 ]; then
						echo "set $ap.encryption='$encryption_type'" | uci batch
						echo "set $ap.key='$mesh_gate_key'" | uci batch

					elif [ "$is_vx" -eq 1 ]; then
						echo "set $ap.encryption='$vx_encryption_type'" | uci batch
						echo "set $ap.key='$vtun_gate_key'" | uci batch
					fi

					if [ "$encryption_type" = "none" ] || [ "$vx_encryption_type" = "none" ]; then

						if [ "$total_ifaces" -ge 5 ]; then
							# setup owe transition if wpad supports it

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

				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() {
	local enc_type=$(uci get $ap.encryption)

	if [ "$enc_type" = "none" ]; then
		section_ap=$(uci show "$ap")
		section_list=$(echo "$section_ap" | awk '{printf "%s ", $1}')

		radio_index=$(echo "$section_ap" | grep "radio" | awk -F "'" '{printf "%s", $2}' | awk -F "radio" '{printf "%i", $2}')

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

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

		echo "set wireless.owe$transition_count$radio_index.ifname='owe$transition_count-$radio_index'" | uci batch
		echo "set wireless.owe$transition_count$radio_index.hidden='1'" | uci batch
		echo "set wireless.owe$transition_count$radio_index.encryption='owe'" | uci batch
		transition_count=$(($transition_count + 1))
	fi
}

urlencode() {
	entitylist="
		s/%/%25/g
		s/\s/%20/g
		s/\"/%22/g
		s/-/%2D/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/%2D/-/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
	# Set arp and ndp defaults
	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 0 > /proc/sys/net/ipv4/conf/all/proxy_arp
	echo 0 > /proc/sys/net/ipv4/conf/default/proxy_arp
	echo 1 > /proc/sys/net/ipv4/conf/$device/proxy_arp
	echo 0 > /proc/sys/net/ipv4/conf/all/proxy_arp_pvlan
	echo 0 > /proc/sys/net/ipv4/conf/default/proxy_arp_pvlan
	echo 0 > /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 "%s", $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 [ -z "$is_portal" ]; then
									syslogmessage=" ..... or, if not already enabled, consider enabling mesh_leechmode on this node"
									write_to_syslog
								fi

								# Reactive path stabilisation:

								if [ "$mesh_path_stabilisation" -eq 1 ]; then
									mrstloopcount=$(eval echo "\$node$peermac_id")
									debugtype="debug"
									syslogmessage="mrstloopcount [ $mrstloopcount ]"
									write_to_syslog

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

									if [ "$mrstloopcount" -ge "$reactive_path_stabilisation_threshold" ]; then
										debugtype="notice"
										syslogmessage="Stabilsing path to node [ $peermac ]"
										write_to_syslog
										iw dev $iface station del $peermac
										eval "node$peermac_id"="0"

										if [ -z "$is_portal" ]; then
											uci set mesh11sd.setup.mesh_leechmode_enable='1'
											leechmode=1
										fi
									else
										debugtype="notice"
										syslogmessage="Mesh Reactive Stabilisation Threshold counter [ $mrstloopcount/$reactive_path_stabilisation_threshold ]"
										write_to_syslog
										mrstloopcount="$((mrstloopcount + 1))"
										eval "node$peermac_id"="$mrstloopcount"
									fi
								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

							if [ -z "$is_portal" ]; then
								syslogmessage=" ..... or, if not already enabled, consider enabling mesh_leechmode on this node"
								write_to_syslog
							fi
						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

	local bridgelist=$(brctl show | awk 'NF==4 {printf "%s ", $1}')

	for device in $bridgelist; do
		local devicemac=$(ip link show dev "$device" | grep "link/ether" | awk '{printf "%s", $2}')
		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 "$tmpdir/brmac_la" ]; then
			touch "$tmpdir/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
	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}')

	debugtype="debug"
	syslogmessage="mesh_leechmode status [ $current_mgo_option ]"
	write_to_syslog

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

	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
			echo "set mesh11sd.mesh_params.mesh_max_peer_links='1'" | 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
			echo "set mesh11sd.mesh_params.mesh_max_peer_links='$config_max_peer_links'" | 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

	elif [ "$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
		echo "set mesh11sd.mesh_params.mesh_max_peer_links='1'" | uci batch
		leechmode=1

	elif [ "$current_mgo_option" -eq 0 ]; then
		leechmode=0

		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_hwmp_rootmode='$rootmode'" | uci batch
		echo "set mesh11sd.mesh_params.mesh_max_peer_links='$config_max_peer_links'" | uci batch
	fi
}

is_installed() {
	# Check if a package is installed
	package="$1"
	is_opkg=$(type "opkg" &> /dev/null; echo $?)
	is_apk=$(type "apk" &> /dev/null; echo $?)

	if [ -z "$package" ]; then
		exitcode=2
	elif [ "$is_opkg" -eq 0 ]; then
		matches=$(opkg list-installed | grep -w "$package"" ")
		urlencode "$matches"; encmatches="$urlencoded"
		urlencode "$package"; encpackage="$urlencoded"
		exitcode=$(echo "$encmatches" | grep -w -q "$encpackage"; echo $?)
	elif [ "$is_apk" -eq 0 ]; then
		exitcode=$(apk list -I "$package" 2>/dev/null  | grep -w -q "$package"; echo $?)
	else
		exitcode=127
	fi
}

check_package_list() {
	# Expects $package_list, a space separated list of package names to check
	# eg package_list="wpad-mbedtls wpad-wolfssl wpad-openssl"
	# returns 0 if any of the listed packages is installed
	# sets a variable-name equal to the package name (with hyphens translated to underscores) with value 0 if installed or 1 if not

	if [ -z "$package_list" ]; then
		return 127
	fi

	retval=1

	for package in $package_list; do
		# translate any hyphens to underscores
		pkg=$(echo "$package" | sed s/-/_/g)
		is_installed "$package"
		eval $pkg=$exitcode

		if [ "$exitcode" -eq 0 ]; then
			retval=0
		fi
	done

	return $retval
}

create_vxlan_if() {
	debugtype="debug"
	syslogmessage="create_vxlan_if [ vxlan$tun_id ], address [ $vxmac_indexed ], local [ $link_local_addr ], group [ ff02::$tun_id ]"
	write_to_syslog

	ip -6 link add "vxlan$tun_id" \
		address "$vxmac_indexed" \
		type vxlan \
		id "$tun_id" \
		dstport 4789 \
		local "$link_local_addr" \
		group "ff02::$tun_id" \
		dev "$device" \
		ttl 5

	ip link set "vxlan$tun_id" up

	ip link set "$active_mesh_ifname" mtu 1600
	ip link set "$device" mtu 1600
	ip link set "vxlan$tun_id" mtu 1500
}

check_vtunnel() {
	# Check if vxlan tunnel is required and set it up

	if [ ! -f "$tmpdir/active_mesh_ifname" ]; then
		return
	fi

	if [ "$vtun_enable" = 1 ]; then
		debugtype="debug"
		syslogmessage="check_vtunnel"
		write_to_syslog

		vxlan_status=$(ip link show vxlan$tun_id &> /dev/null; echo $?)

		if [ "$vxlan_status" -eq 0 ]; then
			vtunnel=""
		fi

		package_list="ip-full vxlan"
		check_package_list

		if [ "$ip_full" -eq 0 ] && [ "$vxlan" -eq 0 ] && [ -z "$vtunnel" ] && [ -z "$vxlan_if" ]; then

			# we have ip-full and vxlan packages
			debugtype="debug"
			syslogmessage="vxtunnel configuration"
			write_to_syslog

			. $tmpdir/active_mesh_ifname
			. $tmpdir/devicemac

			if [ "$portal_detect" -eq 0 ] || [ "$portal_detect" -eq 4 ] || [ ! -z "$is_portal" ]; then
				proto="static"
			else
				proto="none"
			fi

			uci set network.vtunnel=device
			echo "set network.vtunnel.name='br-tun$tun_id'" | uci batch
			uci set network.vtunnel.type='bridge'

			if [ "$commit_all" -eq 0 ]; then
				echo "add_list network.vtunnel.ports='vxlan$tun_id'" | uci batch
			fi

			uci set network.vtunlan=interface
			echo "set network.vtunlan.device='br-tun$tun_id'" | uci batch
			echo "set network.vtunlan.ipaddr='$vtun_ip'" | uci batch
			echo "set network.vtunlan.netmask='$vtun_mask'" | uci batch
			echo "set network.vtunlan.proto='$proto'" | uci batch
			uci set network.vtunlan.ip6assign='60'

			uci set dhcp.vtunlan=dhcp
			uci set dhcp.vtunlan.interface='vtunlan'
			uci set dhcp.vtunlan.start='100'
			uci set dhcp.vtunlan.limit='150'
			uci set dhcp.vtunlan.leasetime='12h'
			uci set dhcp.vtunlan.ra_slaac='1'

			if [ "$commit_all" -eq 0 ]; then
				uci add_list dhcp.vtunlan.ra_flags='managed-config'
				uci add_list dhcp.vtunlan.ra_flags='other-config'
			fi

			uci set dhcp.vtunlan.ignore='1'
			uci set dhcp.vtunlan.ra_default='2'

			uci set firewall.vtunlan='zone'
			uci set firewall.vtunlan.name='vtunlan'
			uci set firewall.vtunlan.network='vtunlan'
			uci set firewall.vtunlan.input='ACCEPT'
			uci set firewall.vtunlan.output='ACCEPT'
			uci set firewall.vtunlan.forward='ACCEPT'

			uci set firewall.dhcptun$tun_id=rule
			uci set firewall.dhcptun$tun_id.name='VTUN-DHCP-Renew'
			uci set firewall.dhcptun$tun_id.src='vtunlan'
			uci set firewall.dhcptun$tun_id.proto='udp'
			uci set firewall.dhcptun$tun_id.dest_port='67'
			uci set firewall.dhcptun$tun_id.target='ACCEPT'
			uci set firewall.dhcptun$tun_id.family='ipv4'

			uci set firewall.dnstun$tun_id=rule
			uci set firewall.dnstun$tun_id.name='VTUN-Allow-DNS'
			uci set firewall.dnstun$tun_id.src='vtunlan'
			uci set firewall.dnstun$tun_id.proto='udp tcp'
			uci set firewall.dnstun$tun_id.dest_port='53'
			uci set firewall.dnstun$tun_id.target='ACCEPT'
			uci set firewall.dnstun$tun_id.family='ipv4'

			uci set firewall.vxlan=rule
			uci set firewall.vxlan.name='Allow-vxlan'
			uci set firewall.vxlan.src='lan'
			uci set firewall.vxlan.proto='udp'
			uci set firewall.vxlan.dest_port='4789'
			uci set firewall.vxlan.target='ACCEPT'

			uci set firewall.vxlan_fwd=forwarding
			uci set firewall.vxlan_fwd.src='vtunlan'
			uci set firewall.vxlan_fwd.dest='wan'

			if [ "$portal_detect" -eq 4 ] && [ "$commit_all" -eq 0 ]; then
				echo "set network.wan.disabled='1'" | uci batch
				echo "set network.wan6.disabled='1'" | uci batch
				wanif=$(uci get network.wan.device)
				echo "add_list network.vtunnel.ports='$wanif'" | uci batch
				echo "set network.vtunlan.proto='dhcp'" | uci batch
				uci set firewall.vtunlan.forward='ACCEPT'
			fi

			if [ "$portal_detect" -eq 5 ] && [ "$commit_all" -eq 0 ]; then
				echo "set network.wan.disabled='1'" | uci batch
				echo "set network.wan6.disabled='1'" | uci batch
				wanif=$(uci get network.wan.device)
				echo "add_list network.vtunnel.ports='$wanif'" | uci batch
			fi

			vtunnel="configured"
			/sbin/service firewall restart
			/sbin/service network reload

			convert_to_la "$devicemac"
			index=$(($index + 1))
			make_indexed_mac "$mac_la" "$index"
			vxmac_indexed="$mac_indexed"
			link_local_addr=$(ip addr show "$device" | grep "inet6 fe80" | awk '{printf "%s", $2}' | awk -F "/" '{printf "%s", $1}')
			create_vxlan_if
			vxlan_if="created"

			if [ "$portal_detect" -eq 0 ] || [ "$portal_detect" -eq 4 ] || [ ! -z "$is_portal" ]; then
				uci set dhcp.vtunlan.dhcpv4='server'
				uci set dhcp.vtunlan.dhcpv6='server'
				uci set dhcp.vtunlan.ra='server'
				uci set dhcp.vtunlan.ignore='0'
			else
				uci set dhcp.vtunlan.dhcpv4='disabled'
				uci set dhcp.vtunlan.dhcpv6='disabled'
				uci set dhcp.vtunlan.ra='disabled'
				uci set dhcp.vtunlan.ignore='1'

			fi

			echo 1 > /proc/sys/net/ipv4/conf/$device/proxy_arp
			/sbin/service dnsmasq reload


			vxiflist=$(uci show wireless | grep "network='vtunlan'" | awk -F "." '{printf "%s.%s ", $1, $2}')

			for vxif in $vxiflist; do
				vxifname=$(echo "get $vxif.ifname" | uci batch | awk '{printf "%s", $1}')
				brctl addif "$device" "$vxifname"
			done

			set_iface_path_cost "$vtun_path_cost" "$device" "vxlan$tun_id"

			. $tmpdir/devicemac
		fi
	fi
}

is_ipv4addr_valid() {
	checkip=$(echo -n "$1" | \
		awk '/^([0-9]{1,3}[.])([0-9]{1,3}[.]){2}([0-9]{1,3})$/{printf "%s", $1}' | \
		awk -F "." '($1+0<255) && ($2+0<255) && ($3+0<255) && ($4+0<255) {printf "%i.%i.%i.%i", $1, $2, $3, $4}')

	if [ "$1" = "$checkip" ]; then
		return 0
	else
		return 1
	fi
}

is_ipv4mask_valid() {
	checkmask=$(echo -n "$1" | \
		awk '/^([0-9]{1,3}[.])([0-9]{1,3}[.]){2}([0-9]{1,3})$/{printf "%s", $1}' | \
		awk -F "." '($1+0<256) && ($2+0<256) && ($3+0<256) && ($4+0<255) {printf "%i.%i.%i.%i", $1, $2, $3, $4}')

	if [ "$1" = "$checkmask" ]; then
		return 0
	else
		return 1
	fi
}

set_ula_prefix() {

	if [ -z "$1" ]; then
		return 1
	fi

	current_prefix="$(uci get network.globals.ula_prefix)"

	if [ "$1" = "revert" ]; then
		ula_prefix=$(cat /etc/config/network | grep "ula_prefix" | awk -F "'" '{printf "%s", $2}')

	elif [ "$1" = "set" ] || [ "$1" = "get" ]; then
		first=${auto_mesh_id:9:2}
		second=${auto_mesh_id:11:4}
		third=${auto_mesh_id:15:4}
		ula_prefix="fd$first:$second:$third::/48"
	else
		return 1
	fi

	if [ -z "$current_prefix" ] || [ "$current_prefix" != "$ula_prefix" ]; then

		if [ "$1" != "get" ]; then
			echo "set network.globals.ula_prefix='$ula_prefix'" | uci batch
		fi
	fi
}

get_portal_ula() {
	set_ula_prefix "get"
	portal_ula="$(echo "$ula_prefix" | awk -F "/" '{printf "%s", $1}')""1"
}

str_to_hex() {
	local input="$1"
	local i=0
	local char=""
	local hex=""
	local hexstr=""
	local inputlen=$((${#input}))

	while true; do
		char=${input:$i:1}

		if [ -z "$char" ]; then
			break
		fi

		hex=$(printf "%02x" "'$char")
		hexstr="$hexstr$hex"
		i=$((i+1))

		if [ "$i" -ge "$inputlen" ]; then
			break
		fi
	done

	echo -n "$hexstr" > "$tmpdir/apmond/hexencoded"
}

hex_to_str() {
	local input="$1"
	local i=0
	local hex=""
	local hexstr=""
	local inputlen=$((${#input}))

	is_hex "$input"
	retval=$?

	if [ "$retval" -ne 0 ]; then
		str=""
		return 1
	fi

	while true; do
		hex="\x${input:$i:2}"
		hexstr="$hexstr$hex"
		i=$((i+2))

		if [ "$i" -ge "$inputlen" ]; then
			break
		fi
	done

	str=$(printf "$hexstr")
}

is_hex() {
	local input="$1"
	# Check if input is empty

	if [ -z "$input" ]; then
		return 1
	fi

	# Check if input contains only valid hex characters (0-9, a-f, A-F)
	echo "$input" | grep -E '^[0-9a-fA-F]+$' >/dev/null

	if [ $? -ne 0 ]; then
		return 1
	fi
}

write_node_data() {
	node_id="$1"
	data_raw="$2"
	maxchunksize=16
	strindex=0
	chunkstr=""
	data_raw_len=$((${#data_raw}))
	data_checked=""
	cumulative_transfer=0
	node_type=$(echo "$node_id" | awk -F ";" '{printf "%s", $1}')
	node_hostname=$(echo "$node_id" | awk -F ";" '{printf "%s", $2}')
	node_mac=$(echo "$node_id" | awk -F ";" '{printf "%s", $3}' | awk -F ":" 'NF==6 {printf "%s%s%s%s%s%s%s", $1, $2, $3, $4, $5, $6}')
	chunkstatus=$(echo "$node_id" | awk -F ";" '{printf "%s", $4}')
	strindex=$(echo "$node_id" | awk -F ";" '{printf "%s", $5}')

	while true; do
		# get a chunk
		chunk=${data_raw:$strindex:$maxchunksize}
		chunksize="%.$((${#chunk}))x"

		if [ -z "$chunk" ]; then
			break
		fi


		hextest=$(printf "$chunksize" "0x$chunk")

		if [ "$hextest" = "$chunk" ]; then
			# Increment the pointer
			strindex=$((strindex+$maxchunksize))

			continue
		else
			status="nack"
			retval=127
			echo -n "$status"
			return $retval
		fi
	done

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

		if [ "$node_type" = "apmond" ]; then

			if [ "$chunkstatus" = "begin" ]; then
				echo -n "$node_id $data_raw" > "$tmpdir/$node_type/ap/$node_mac"
				status="* "
				echo -n "$status"
				retval=0
			elif [ "$chunkstatus" = "chunk" ]; then
				echo -n "$data_raw" >> "$tmpdir/$node_type/ap/$node_mac"
				status="* "
				echo -n "$status"
				retval=0
			elif [ "$chunkstatus" = "end" ]; then
				echo " $node_id" >> "$tmpdir/$node_type/ap/$node_mac"
				debugtype="info"
				syslogmessage="apmond data received from node [$node_hostname] id [ $node_mac ]"
				write_to_syslog
				status="ack"
				echo -n "$status"
				retval=0
			fi
		else
			status="nack"
			retval=1
		fi
	else
		status="nack"
		retval=127
	fi

	if [ "$retval" -gt 0 ]; then
		debugtype="warn"
		syslogmessage="WARNING! Invalid remote data format - rejecting..."
		write_to_syslog
	fi

	if [ "$status" = "nack" ]; then
		echo -n "ERROR 418: Invalid HTCPCP"
	fi

	return $retval
}

setup_apmon_cgi() {
	apmon_cgi_status=127

	if [ -e "$apmond_cgi_dir" ]; then
		cgiuhttp="$apmond_cgi_dir""apmon.cgi"
		cgitmp="$tmpdir/apmon.cgi"

		if [ -f "$cgiuhttp" ]; then
			apmon_cgi_status=$(apmon_cgi "$cgitmp"; echo -n $?)
			cgitmphash=$(sha256sum "$cgitmp" | awk '{printf "%s", $1}')
			cgihash=$(sha256sum "$cgiuhttp" | awk '{printf "%s", $1}')

			if [ "$cgitmphash" != "$cgihash" ]; then
				cp "$cgitmp" "$cgiuhttp"
			fi
		else
			apmon_cgi_status=$(apmon_cgi "$cgiuhttp"; echo -n $?)
		fi
	fi

	return $apmon_cgi_status
}

apmon_cgi() {
	local cgi=$1

	if [ -z "$cgi" ]; then
		return 127
	fi

	echo "#!/bin/sh" > "$cgi"
	echo "printf \"%s\n%s\n\n\" \"Content-type: text/html\"" >> "$cgi"
	echo "node_id=\"\$HTTP_USER_AGENT\"" >> "$cgi"
	echo "querystring=\"\$QUERY_STRING\"" >> "$cgi"
	echo "status=\$(mesh11sd write_node_data \"\$node_id\" \"\$querystring\")" >> "$cgi"
	echo "echo \"\$status\"" >> "$cgi"
	chmod 755 "$cgi"
	mkdir -p "$tmpdir/apmond"
	mkdir -p "$tmpdir/apmond/ap"
	return $?
}

restore_luci_cgi() {
	luci_cgi_status=127

	if [ -e "$apmond_cgi_dir" ]; then
		cgiuhttp="$apmond_cgi_dir""luci"
		cgioriginal="$apmond_cgi_dir""luci.original"

		if [ -f "$cgioriginal" ]; then
			cgiorghash=$(sha256sum "$cgioriginal" | awk '{printf "%s", $1}')
			cgihash=$(sha256sum "$cgiuhttp" | awk '{printf "%s", $1}')

			if [ "$cgitmphash" != "$cgihash" ]; then
				cp "$cgioriginal" "$cgiuhttp"
				chmod 755 "$cgiuhttp"
				luci_cgi_status=0
			else
				luci_cgi_status=1
			fi
		fi

	fi

	return $luci_cgi_status

}

setup_luci_cgi() {
	luci_cgi_status=127

	if [ -e "$apmond_cgi_dir" ]; then
		cgiuhttp="$apmond_cgi_dir""luci"
		cgitmp="$tmpdir/luci"

		if [ ! -f "$cgiuhttp.original" ]; then
			mv "$cgiuhttp" "$cgiuhttp.original"
			chmod 444 "$cgiuhttp.original"
		fi

		if [ -f "$cgiuhttp" ]; then
			luci_cgi_status=$(luci_cgi "$cgitmp"; echo -n $?)
			cgitmphash=$(sha256sum "$cgitmp" | awk '{printf "%s", $1}')
			cgihash=$(sha256sum "$cgiuhttp" | awk '{printf "%s", $1}')

			if [ "$cgitmphash" != "$cgihash" ]; then
				cp "$cgitmp" "$cgiuhttp"
			fi
		else
			luci_cgi_status=$(luci_cgi "$cgiuhttp"; echo -n $?)
		fi
	fi

	return $luci_cgi_status
}

luci_cgi() {
	local cgi=$1

	if [ -z "$cgi" ]; then
		return 127
	fi

	echo "#!/bin/sh" > "$cgi"
	echo "printf \"%s\n\n\" \"Content-type: text/html\"" >> "$cgi"
	echo -e "status=\$(mesh11sd -v)" >> "$cgi"
	echo -e "hostname=\$(uci get system.@system[0].hostname)" >> "$cgi"
	echo -e "portal_ula=\$(mesh11sd get_portal_ula)" >> "$cgi"
	echo -e "host=\"\$HTTP_HOST\"" >> "$cgi"
	echo -e "echo -e \"<!DOCTYPE html>\"" >> "$cgi"
	echo -e "echo -e \"<html>\"" >> "$cgi"
	echo -e "echo -e \"<head>\"" >> "$cgi"
	echo -e "echo -e \"<meta http-equiv=\"Cache-Control\" content=\"no-cache, no-store, must-revalidate\">\"" >> "$cgi"
	echo -e "echo -e \"<meta http-equiv=\\\"Pragma\\\" content=\\\"no-cache\\\">\"" >> "$cgi"
	echo -e "echo -e \"<meta http-equiv=\\\"Expires\\\" content=\\\"0\\\">\"" >> "$cgi"
	echo -e "echo -e \"<meta charset=\\\"utf-8\\\">\"" >> "$cgi"
	echo -e "echo -e \"<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\">\"" >> "$cgi"
	echo -e "echo -e \"<title>\$hostname</title>\"" >> "$cgi"
	echo -e "echo -e \"</head>\"" >> "$cgi"
	echo -e "echo -e \"<body>\"" >> "$cgi"
	echo -e "echo \"<br><hr><b>\"" >> "$cgi"
	echo -e "echo \"Hostname: [\$hostname] <br><br> \"" >> "$cgi"
	echo -e "echo \"Host ula: \$host <br><br> \"" >> "$cgi"
	echo -e "echo \"Portal ula: [\$portal_ula] <br>\"" >> "$cgi"
	echo -e "echo \"<hr> <br> \$status <br> <hr>\"" >> "$cgi"
	echo -e "echo \"</b>\"" >> "$cgi"
	echo -e "echo \"</body>\"" >> "$cgi"
	echo -e "echo \"</html>\"" >> "$cgi"

	chmod 755 "$cgi"
}

send_ap_data() {

	if [ "$apmond_enable" -eq 0 ]; then
		retcode=1
		return "$retcode"
	fi

	maxchunksize=4096
	strindex=0
	chunkstr=""
	hostname=$(uci get system.@system[0].hostname 2> /dev/null | awk '{printf "%s", $1}')
	. $tmpdir/devicemac
	str_data=$(get_ap_data)

	str_to_hex "$str_data"
	hexencoded=$(cat "$tmpdir/apmond/hexencoded")
	hexencoded_len=$((${#hexencoded}))

	if [ "$hexencoded_len" -le 10 ]; then
		retcode=0
		return 0
	fi

	debugtype="debug"
	syslogmessage="apmond sending chunked data"
	write_to_syslog

	get_portal_ula

	while true; do
		# get a chunk
		chunk=${hexencoded:$strindex:$maxchunksize}
		chunksize="%.$((${#chunk}))x"

		if [ -z "$chunk" ]; then
			chunkstatus="end"
			send_status=$(wget -6 -q -O - -U "apmond;$hostname;$devicemac;$chunkstatus;$strindex" --no-check-certificate https://[$portal_ula]/cgi-bin/apmon.cgi)
			retcode=$?
			echo "$send_status" | awk '{printf "%s", $1}'
			break
		elif [ "$strindex" -eq 0 ]; then
			chunkstatus="begin"
		else
			chunkstatus="chunk"
		fi

		send_status=$(wget -6 -q -O - -U "apmond;$hostname;$devicemac;$chunkstatus;$strindex" --no-check-certificate https://[$portal_ula]/cgi-bin/apmon.cgi?"$chunk")
		retcode=$?

		# Increment the pointer
		strindex=$((strindex+$maxchunksize))
	done

	return "$retcode"
}

get_ap_data() {
	aplist=$(uci show wireless | grep "mode='ap'" | awk -F "." '{printf "%s ", $2}')
	json_init=1
	first_ap=1
	sta_flag=0

	for ap in $aplist; do
		first_sta=1
		ap_ifname=$(uci get wireless."$ap".ifname)
		ap_ssid=$(uci get wireless."$ap".ssid)
		iw dev "$ap_ifname" station dump > $tmpdir/stations

		if [ ! -s "$tmpdir/stations" ]; then
			continue
		else
			sta_flag=1
		fi

		if [ "$json_init" -eq 1 ]; then
			echo -n "{"
			json_init=0
		fi

		cat /tmp/mesh11sd/stations | while read line; do

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

			is_station_id=$(echo "$line" | grep "Station")

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

				if [ "$first_ap" -eq 0 ]; then
					echo -n ","
				fi

				if [ "$first_sta" -eq 1 ]; then
					echo -e "\n  \"$ap_ssid@$ap_ifname@$devicemac\":{"
				else
					echo ","
				fi

				echo "$line" | awk '{printf "    \"%s\":{", $2}'; echo
			else
				ap_param_str=$(echo "$line" | tr -d \\t | tr -s " " "_" | awk -F ":" '{printf "\"%s\":\"%s\"", $1, $2}'; echo)
				ap_param=$(echo "$ap_param_str" | awk -F "\"" '{printf "%s", $2}')

				case $ap_param in
					"rx_bytes") echo	"      $ap_param_str,";;
					"tx_bytes") echo	"      $ap_param_str,";;
					"tx_retries") echo	"      $ap_param_str,";;
					"signal_avg") echo	"      $ap_param_str,";;
					"tx_bitrate") echo	"      $ap_param_str,";;
					"rx_bitrate") echo	"      $ap_param_str,";;
					"avg_ack_signal") echo	"      $ap_param_str,";;
					"connected_time") echo	"      $ap_param_str,";;
					"current_time") \
						ap_param_str=$(echo -n "$ap_param_str" | sed s/current_time/timestamp/g);\
						echo "      $ap_param_str,";\
						ms_to_dt "$ap_param_str"
						echo "      \"date_time\":\"$date_time\"";\
						echo -n "    }"\
					;;
				esac
			fi

			first_sta=0
		done

		first_ap=0
		echo -n -e "\n  }"

	done

	if [ "$sta_flag" -eq 1 ]; then
		echo -e "\n}"
	fi
}

is_default() {
	configs=" mesh11sd wireless dhcp network firewall"

	for config in $configs; do

		if [ -f "/etc/config/$config.mesh11sd.default" ]; then
			currenthash=$(sha256sum "/etc/config/$config" | awk '{printf "%s", $1}')
			defaulthash=$(sha256sum "/etc/config/$config.mesh11sd.default" | awk '{printf "%s", $1}')

			if [ "$currenthash" = "$defaulthash" ]; then
				is_default="$is_default $config"
			fi

		else
			return 127
		fi

	done

	if [ "$configs" = "$is_default" ]; then
		all_default=1
	else
		all_default=0
	fi
}

set_led() {

	if [ "$mesh_backhaul_led" = "none" ] || [ "$auto_config" -eq 0 ]; then
		return 0
	fi

	if [ -z "$1" ]; then
		return 127
	fi

	led_action="$1"
	leds=$(ls "/sys/class/leds")

	#initialise leds
	if [ "$led_action" = "init" ]; then

		for led in $leds; do
			ledaction=$(cat "/sys/class/leds/$led/trigger" | awk -F "[" '{printf "%s", $2}' | awk -F "]" '{printf "%s", $1}')

			if [ "$ledaction" = "none" ] || [ "$ledaction" = "heartbeat" ]; then
				echo "default-on" > "/sys/class/leds/$led/trigger"

				sleep 1
				echo "none" > "/sys/class/leds/$led/trigger"
			fi
		done

		sleep 3
		return 0
	fi


	if [ "$led_action" = "off" ] || [ "$led_action" = "none" ]; then
		led_action="none"
	elif [ "$led_action" = "on" ] || [ "$led_action" = "default-on" ]; then
		led_action="default-on"
	elif [ "$led_action" = "beat" ] || [ "$led_action" = "heartbeat" ]; then
		led_action="heartbeat"
	fi

	if [ "$mesh_backhaul_led" != "auto" ] && [ -e "/sys/class/leds/$mesh_backhaul_led/" ]; then
		echo "$led_action" > "/sys/class/leds/$mesh_backhaul_led/trigger"
		return 0
	fi

	for led in $leds; do
		last_param=$(echo "$led" | awk -F":" '{printf "%s", $NF}')

		if [ "$last_param" = "power" ] || [ "$last_param" = "pwr" ] || [ "$last_param" = "system" ] || [ "$last_param" = "status" ] || [ "$last_param" = "run" ]; then
			echo "$led_action" > "/sys/class/leds/$led/trigger"
			break
		elif [ "$led" = "green-2" ] || [ "$led" = "pwr" ] || [ "$led" = "system" ] || [ "$led" = "status" ] || [ "$led" = "run" ]; then
			echo "$led_action" > "/sys/class/leds/$led/trigger"
			break

		fi
	done
}

check_mesh_active_led() {

	if [ ! -f "$tmpdir/active_mesh_ifname" ]; then
		return
	fi

	. $tmpdir/active_mesh_ifname
	active_peers=$(iw dev $active_mesh_ifname mpath dump | grep -c -w $active_mesh_ifname)

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

		if [ -z "$heartbeatflag" ] || [ "$heartbeatflag" -eq 0 ]; then
			heartbeatflag=1
			set_led heartbeat
		fi
	else
		heartbeatflag=0
		set_led on
	fi
}

ms_to_dt() {
	local time_stamp="$1"
	local ms=$(echo "$time_stamp" | awk -F "\"" '{printf "%s", $4}')
	local secs=$(echo "$ms" | head -c 10)
	date_time="$(date -d "@$secs")"
	# translate any spaces to underscores
	date_time=$(echo ${date_time// /_})
}

set_iface_path_cost() {
	local path_cost="$1"
	local device="$2"
	local iface="$3"

	if [ "$path_cost" -gt 0 ] && [ "$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" "$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 - $path_cost))
			brctl setpathcost "$device" "$br_iface" "$other_path_cost"

		done

	elif [ "$path_cost" -eq 0 ]; then
		brctl stp "$device" no
	fi
}

generate_ipv4_base() {
	local seed="$1"

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

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

		#Skip 168, 167, 1, 0
		skiplist="168 167 8 1 0"

		for skip in $skiplist; do

			if [ $cpipsubnet -eq $skip ];then
				cpipsubnet=0
				break
			fi
		done

		if [ $cpipsubnet -eq 0 ];then
			continue
		fi

		newipaddr="192.168.$cpipsubnet.1"

		# is newipaddr configured elsewhere?
		is_used=$(uci show network | grep -c "$newipaddr")

		if [ "$is_used" -gt 0 ]; then
			continue
		fi

		break
	done

	syslogmessage="Validated ipv4 address [ $newipaddr ] using seed value [ $seed ]"
	debugtype="debug"
	write_to_syslog
}

manage_opennds () {

	if [ "$manage_opennds_startup" -eq 1 ]; then
		# Is opennnds installed?
		opennds_installed=$(is_installed "opennds"; echo -n $?)

		if [ "$opennds_installed" -eq 0 ]; then
			local action=$1
			# action  can be stop, start, restart

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

				if [ "$action" = "stop" ]; then
					opennds_enabled=$(/sbin/service | grep "opennds" | grep "enabled" &> /dev/null ; echo $?)
					opennds_running=$(/sbin/service opennds info | grep -A2 "instance1" | grep "running" | grep "true" &> /dev/null ; echo $?)

					if [ "$opennds_enabled" -eq 0 ]; then
						syslogmessage="Disabling auto-startup of opennds"
						debugtype="debug"
						write_to_syslog
						/sbin/service opennds disable
					fi

					if [ "$opennds_running" -eq 0 ]; then
						syslogmessage="The opennds daemon is running, stopping it"
						debugtype="debug"
						write_to_syslog
						/sbin/service opennds stop
					fi
				fi

				if [ "$action" = "start" ] || [ "$action" = "restart" ]; then
						syslogmessage="Restarting the opennds daemon"
						debugtype="debug"
						write_to_syslog
						/sbin/service opennds restart
				fi
			fi
		fi
	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

if [ "$1" = "daemon" ]; then
	mutestate=0
else
	mutestate=1
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: auto_config
  Configure auto config mode
  Usage:
    mesh11sd auto_config test | enable | disable
      Takes immediate effect, any current connection is likely to be lost, requiring re-connection on possibly a different ipv4 address 
      test - turn on auto config test mode. A reboot will revert the auto configuration.
      enable - enable auto config mode.
      disable - disable auto config mode.

  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 $tmpdir/ 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: commit_all
  Usage: mesh11sd commit_all commit
    Writes all changes made by auto_config to configuration file
    Active only when auto_config is enabled

  Option: revert_all
  Usage: mesh11sd revert_all revert
    Reverts all changes made by commit_all
    Active only when auto_config is enabled

  Option: force_ipv4_download
  Usage: mesh11sd force_ipv4_download
    Forces opkg or apk to use ipv4 for its downloads

  Option: download_revert_to_default
  Usage: mesh11sd download_revert_to_default
    Reverts opkg or apk to default for its downloads

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

  Option: is_installed
  Usage: mesh11sd is_installed [packagename]
    Checks if \"packagename\" is installed
    Returns the installation status of the package and exit code 0 if installed

  Option: get_portal_ula
  Usage: mesh11sd get_portal_ula
    Gets the portal unique local ipv6 address (ula)

  Option: set_ula_prefix
  Usage: mesh11sd set_ula_prefix [get|set|revert]
    get - gets the current ula prefix
    set - sets the ula prefix for the mesh backhaul based on the mesh id
    revert - reverts a previously set ula prefix

  Option: str_to_hex
  Usage: mesh11sd str_to_hex [access_point_data_string]
    Run length hex encodes access_point_data from apmond format

  Option: hex_to_str
  Usage: mesh11sd hex_to_str [hex encoded_access_point_data_string]
    Decode run length hex encoded access_point_data to apmond format

  Option: write_node_data
  Usage: mesh11sd write_node_data [node_id] [querystring]
    Called from apmond cgi script. Writes node data received by web server

  Option: send_ap_data
  Usage: mesh11sd send_ap_data
    Sends hex encoded apmon data to portal/apmond web server

  Option: get_ap_data
  Usage: mesh11sd get_ap_data
    Get json format access point data for this node

  Option: show_ap_data
  Usage: mesh11sd show_ap_data [node_id | all]
    Shows json format access point data for requested node | all nodes
    Valid on portal/apmond node

  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" = "auto_config" ]; then

	if [ -z "$2" ]; then
		echo
		echo "Usage:"
		echo "mesh11sd auto_config test - turn on auto config test mode "
		echo "mesh11sd auto_config enable - configure auto config mode "
		echo "mesh11sd auto_config disable - disable auto config mode "
		echo
		exit 1
	fi

	if [ "$auto_config" -eq 1 ] && [ "$2" = "test" ];  then
		echo "auto_config is already enabled"
		exit 0
	fi

	if [ "$auto_config" -eq 1 ] && [ "$2" = "enable" ];  then
		echo "auto_config is already enabled"
		exit 0
	fi

	if [ "$auto_config" -eq 0 ] && [ "$2" = "disable" ];  then
		echo "auto_config is already disabled"
		exit 0
	fi

	if [ -e "$tmpdir/auto_config_test" ] && [ "$auto_config" -eq 0 ] && [ "$2" != "enable" ]; then
		echo "Auto config is already running in test mode!"
		exit 1
	fi

	if [ "$2" = "test" ]; then

		if [ -e "$tmpdir/auto_config_test" ]; then
			echo "Auto config test mode is already running!"
			exit 1
		fi

		echo
		echo "This will test autoconfiguration."
		echo "Rebooting will revert the test autoconfiguration."
		echo
		echo "    Do you want to continue? [yes/no] "
		echo

		read reply

		if [ "$reply" = "yes" ]; then
			touch "$tmpdir/auto_config_test"
		fi

		exit 0

	elif [ "$2" = "enable" ]; then
		echo
		echo "This will enable and start autoconfiguration."
		echo "Autoconfiguration will start immediately and again on every restart."
		echo
		echo "    Do you want to continue? [yes/no] "
		echo

		read reply

		if [ "$reply" = "yes" ]; then
			touch "$tmpdir/auto_config_test"
			changes=$(uci changes mesh11sd)
			changelist=$(echo "$changes" | awk '{printf "%s ", $1}')

			uci revert mesh11sd
			uci set mesh11sd.setup.auto_config='1'
			uci commit mesh11sd

			for change in $changes; do
				echo "set $change" | uci batch
			done
		fi

	elif [ "$2" = "disable" ]; then
		echo
		echo "This will disable and stop autoconfiguration."
		echo "You must restart the device for this to take effect."
		echo
		echo "    Do you want to continue? [yes/no] "
		echo

		read reply

		if [ "$reply" = "yes" ]; then

			if [ -e "$tmpdir/auto_config_test" ]; then
				rm "$tmpdir/auto_config_test 2> /dev/null"
			fi

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

			uci revert mesh11sd
			uci set mesh11sd.setup.auto_config='0'
			uci commit mesh11sd

			for change in $changes; do
				echo "set $change" | uci batch
			done
		fi

		exit 0
	else
		echo "Invalid option...."
		exit 1
	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 "    \"portal_use_default_ipv4\":\"$portal_use_default_ipv4\","
	echo "    \"channel_tracking_checkinterval\":\"$channel_tracking_checkinterval\","
	echo "    \"mesh_mac_forced_forwarding\":\"$mesh_mac_forced_forwarding\","
	echo "    \"gateway_proxy_arp\":\"$gateway_proxy_arp\","
	echo "    \"reboot_on_error\":\"$reboot_on_error\","
	echo "    \"stop_on_error\":\"$stop_on_error\","
	echo "    \"watchdog_nonvolatile_log\":\"$watchdog_nonvolatile_log\","
	echo "    \"mesh_basename\":\"$mesh_basename\","
	echo "    \"auto_config\":\"$auto_config\","
	echo "    \"auto_mesh_network\":\"$auto_mesh_network\","
	echo "    \"auto_mesh_band\":\"$auto_mesh_band\","

	if [ ! -z "$mesh_phy_index" ]; then
		echo "    \"mesh_phy_index\":\"$mesh_phy_index\","
	fi

	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\","
	echo "    \"mesh_backhaul_led\":\"$mesh_backhaul_led\","

	# check if opennds is installed:
	type opennds &>/dev/null
	opennds_installed=$?

	if [ "$opennds_installed" -eq 0 ]; then
		echo "    \"manage_opennds_startup\":\"$manage_opennds_startup\","
	fi

	# vxlan configs
	package_list="ip-full vxlan"
	check_package_list
	echo "    \"vtun_enable\":\"$vtun_enable\","

	if [ "$ip_full" -eq 0 ] && [ "$vxlan" -eq 0 ]; then # we have the required packages for vxlan
		echo "    \"tun_id\":\"$tun_id\","
		echo "    \"vtun_ip\":\"$vtun_ip\","
		echo "    \"vtun_mask\":\"$vtun_mask\","
		echo "    \"vtun_gate_encryption\":\"$vtun_gate_encryption\","
		echo "    \"vtun_base_ssid\":\"$vtun_base_ssid\","
		echo "    \"vtun_path_cost\":\"$vtun_path_cost\","
	fi


	# 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 "    \"reactive_path_stabilisation_threshold\":\"$reactive_path_stabilisation_threshold\","
	echo "    \"checkinterval\":\"$checkinterval\","
	echo "    \"interface_timeout\":\"$interface_timeout\","
	echo "    \"ssid_suffix_enable\":\"$ssid_suffix_enable\","
	echo "    \"apmond_enable\":\"$apmond_enable\","
	echo "    \"apmond_cgi_dir\":\"$apmond_cgi_dir\","
	echo "    \"debuglevel\":\"$debuglevel\""
	echo "  },"
	echo "  \"mesh_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
					stations=$((stations+1))
				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}')
					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 "  \"layer2_connections\":{"

	devicelist=$(uci show network | grep "type='bridge'" | awk -F "." '{printf "%s.%s ", $1, $2}')
	devicecount=$( echo "$devicelist" | awk '{printf "%s", NF}')

	for devicesection in $devicelist; do
		devicecount=$((devicecount - 1))
		bridge=$(uci get "$devicesection".name)
		echo "    \"$bridge\":{"
		bridgeportlist=$(brctl showstp "$bridge" 2>/dev/null | grep " (" | grep ")" | awk '{printf "interface=%s;port=%s ", $1, $2}'| tr -d "(" | tr -d ")")
		firstmac=1

		for bridgeport in $bridgeportlist; do
			eval "$bridgeport"
			allmacs=$(brctl showmacs "$bridge" | awk -v bridge="$bridge" '$3=="no" {printf "%s,%s,%s ", bridge, $1, $2}')

			for clientmac in $allmacs; do
				cmac=$(echo "$clientmac" | awk -v port="$port" -F "," '$2==port {printf "%s", $3}')

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

					if [ "$firstmac" -eq 0 ]; then
						echo ","
					else
						firstmac=0
					fi

					echo -n "      \"$cmac\":\"$interface\""
				fi
			done
		done

		if [ -z "$allmacs" ]; then
			echo -n -e "    }"
		else
			echo -n -e "\n    }"
		fi

		if [ "$devicecount" -eq 0 ]; then
			echo
		else
			echo ","
		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 "%s", $NF}')

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

	echo " Copy a file to $tmpdir/ 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 [ $tmpdir/$filename ] to meshnode [ $ndpmacf ]....."
					scp "$filepath" "root@[$linklocal]:$tmpdir/$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" = "commit_all" ]; then

	if [ "$auto_config" -eq 0 ]; then
		echo "Auto config is not enabled - aborting..."
		exit 1
	fi

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

	echo "Commit ***ALL*** changes, including auto_configuration changes, making them non volatile on restart/reboot"

	if [ -z "$2" ] || [ "$2" != "commit" ]; then
		echo "    Usage: mesh11sd commit_all commit "
		echo "    Writes changes to configuration file "
		echo "    Active only when auto_config is enabled "

	elif [ "$2" = "commit" ] && [ "$auto_config" -eq 1 ]; then

		echo "    Dynamic auto_configure options will be written to non volatile storage and LuCi UI will be enabled..... "
		echo "    This is for advanced users, continue at your own risk."
		echo "    This process can be reverted with the \"revert_all\" command."
		echo
		echo "    Do you want to continue? [yes/no] "

		read reply

		if [ "$reply" = "yes" ]; then
			configs="mesh11sd wireless dhcp network firewall"

			echo "set mesh11sd.setup.commit_all='1'" | uci batch

			for config in $configs; do
				uci commit "$config"
			done

			restore_luci_cgi
		else
			echo "Aborting commit_all"
		fi
	fi

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

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

	if [ "$auto_config" -eq 0 ]; then
		echo "Auto config is not enabled - aborting..."
		exit 1
	fi

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

	echo "Revert ***ALL*** changes previously committed by a commit_all command"

	if [ -z "$2" ] || [ "$2" != "revert" ]; then
		echo "    Usage: mesh11sd revert_all revert "
		echo "    Reverts previously committed changes "
		echo "    Active only when auto_config is enabled "
		echo "    Connection will be lost if you proceed as node will restart..... "

	elif [ "$2" = "revert" ] && [ "$auto_config" -eq 1 ]; then

		echo "    Connection will be lost if you proceed as node will restart..... "
		echo "    Do you want to continue? [yes/no] "

		read reply

		if [ "$reply" = "yes" ]; then
			configs="mesh11sd wireless dhcp network firewall"

			for config in $configs; do

				if [ -f "/etc/config/$config.mesh11sd.default" ]; then
					cp "/etc/config/$config.mesh11sd.default" "/etc/config/$config"
				fi

			done

			setup_luci_cgi
			echo "Revert complete, auto configuration will rebuild - restarting......"
			reboot
		else
			echo "Aborting revert_all"
		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 "$tmpdir/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 "$tmpdir/mesh_rssi_threshold" ]; then
				rm "$tmpdir/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 "$tmpdir/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 "$tmpdir/mesh_rssi_threshold" ]; then
				rm "$tmpdir/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" = "force_ipv4_download" ]; 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
		exit 0
	fi

	exit 127

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

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

	exit 127

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" = "get_portal_ula" ]; then
	get_portal_ula
	echo -n "$portal_ula"
	exit 0

elif [ "$1" = "set_ula_prefix" ]; then
	set_ula_prefix "$2"
	retval=$?
	echo -n "$ula_prefix"
	exit $retval

elif [ "$1" = "str_to_hex" ]; then
	str_to_hex "$2"

	if [ -f "$tmpdir/apmond/hexencoded" ]; then
		cat "$tmpdir/apmond/hexencoded"
	fi

	exit 0

elif [ "$1" = "hex_to_str" ]; then
	hex_to_str "$2"
	echo -n "$str"
	exit 0

elif [ "$1" = "is_hex" ]; then
	is_hex "$2"
	exit $?

elif [ "$1" = "is_ipv4addr_valid" ]; then
	is_ipv4addr_valid "$2"
	retval=$?
	echo -n "$checkip"
	exit $retval

elif [ "$1" = "is_installed" ]; then
	is_installed "$2"

	case $exitcode in
		0) echo "Package [ $2 ] is installed";;
		1) echo "Package [ $2 ] is NOT installed";;
		2) echo "Package NOT specified";;
		127) echo "Error: Package manager cannot be identified";;
		*) echo "Unexpected Error.....";;
	esac

	exit $exitcode

elif [ "$1" = "write_node_data" ]; then
	write_node_data "$2" "$3"
	exit 0

elif [ "$1" = "send_ap_data" ]; then
	send_ap_data
	exit $retcode

elif [ "$1" = "get_ap_data" ]; then
	get_ap_data
	exit 0

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

	if [ "$auto_config" -eq 0 ] && [ ! -e "$tmpdir/auto_config_test" ]; then
		echo "================================================================================"
		echo "Unable to collect access point data -  enable auto_config for this functionality"
		echo "================================================================================"
		exit 1
	fi

	data_nodes=$(ls "$tmpdir/apmond/ap/" | awk '{printf "%s ", $1}')

	if [ -z "$data_nodes" ]; then
		exit 0
	fi

	if [ "$2" = "all" ]; then
		all_first=1

		for data_node in $data_nodes; do
			hex_to_str "$(awk '{printf "%s", $2}'  "$tmpdir/apmond/ap/$data_node" 2>/dev/null)"

			if [ ! -z "$str" ]; then
				str=$(echo -n "$str" | tail -n +2 | head -n -2)

				if [ "$all_first" -eq 1 ]; then
					echo "{"
					echo -n "$str"
					all_first=0
				else
					echo -e -n "\n  },\n$str"
				fi
			fi

		done

		echo -e "\n  }\n}"
	fi

	if [ -z "$2" ]; then
		echo "===================================================================================================================="

		echo " Show access point usage data"
		echo "    Usage: mesh11sd show_ap_data [ap_mac_id]"
		echo "       or: mesh11sd show_ap_data all"
		echo

		if [ ! -z "$data_nodes" ]; then
			echo " If the node you are looking for is not in the list - it probably has not had any connections yet - try again later."
			echo "===================================================================================================================="
			echo " The following access points have sent usage data:"

			for data_node in $data_nodes; do
				echo "===================================================================================================================="
				echo
				echo "Access point ID (ap_mac_id)	$data_node"
			done

			echo "===================================================================================================================="
		else
			echo " If the node you are looking for is not shown - it probably has not had any connections yet - try again later."
			echo "===================================================================================================================="
		fi

		exit 1

	elif [ "$2" != "all" ]; then
		hex_to_str "$(awk '{printf "%s", $2}'  "$tmpdir/apmond/ap/$2" 2>/dev/null)"

		if [ ! -z "$str" ]; then
			echo "$str"
		fi
	fi

	exit 0

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

	/sbin/service network reload

	set_led init

	set_led on

	get_kernel_version
	cpe_conf=0

	if [ -f "$tmpdir/active_mesh_ifname" ]; then
		rm "$tmpdir/active_mesh_ifname"
	fi

	# unconditionally try to stop openNDS
	manage_opennds stop

	if [ "$auto_config" -gt 0 ]; then
		# redirect luci web ui
		setup_luci_cgi
		# We do not know the current state so reinitialise everything
		debugtype="info"
		syslogmessage="Initialising state for auto_config"
		write_to_syslog

		configs="mesh11sd wireless dhcp network firewall"

		for config in $configs; do
			uci revert "$config"

			if [ ! -f "/etc/config/$config.mesh11sd.default" ]; then
				cp "/etc/config/$config" "/etc/config/$config.mesh11sd.default"
			fi

		done

		# Do we have a previously commited auto_config? If so get the active_mesh_ifname.
		meshifs=$(uci show wireless | grep "mode='mesh'" | awk -F "." '{printf "%s.%s ", $1, $2}')

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

			for meshif in $meshifs; do
				disab=$(uci get $meshif.disabled)

				if [ "$disab" -eq 0 ]; then
					active_mesh_ifname=$(uci get $meshif.ifname)
					echo "active_mesh_ifname=\"$active_mesh_ifname\"" > "$tmpdir/active_mesh_ifname"
					break
				fi
			done
		fi

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

			if [ "$portal_detect" -eq 3 ]; then
				# Set the cpe gateway ipv4 address based in mac address
				. $tmpdir/devicemac

				seedvalue="$devicemac"
			else
				seedvalue="$auto_mesh_id"
			fi

			generate_ipv4_base "$seedvalue"
			echo "set network.$auto_mesh_network.ipaddr='$newipaddr'" | uci batch
		fi


		# Before restarting the network, check if CPE mode is requested
		if [ "$portal_detect" -eq 3 ] && [ "$commit_all" -eq 0 ]; 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

		br_tun=$(brctl show | grep br-tun | awk '{printf "%s", $1}')

		if [ ! -z "$br_tun" ]; then
			ip link delete dev "$br_tun"
		fi

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

		probe_interface_mac
	else
		restore_luci_cgi
	fi

	if [ -e "$tmpdir/brmac_la" ]; then
		rm "$tmpdir/brmac_la"
	fi

	if [ -f "$tmpdir/mesh_rssi_threshold" ]; then
		rm "$tmpdir/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
	transition_count=0
	vtunnel=""
	apmondloopcount=0
	apmondloopstart=6

	#loop counter for Mesh Reactive Stabilsation Threshold:
	mrstloopcount=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

	setup_apmon_cgi

	refresh_bridgemac

	# 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 ] || [ -e "$tmpdir/auto_config_test" ]; 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

						uciapconfig=$(uci get wireless.$ap.macaddr 2> /dev/null)

						if [ -z "$uciapconfig" ]; then
							index=$(($index + 1))
							make_indexed_mac "$mac_la" "$index"
							echo "set wireless.$ap.macaddr=$mac_indexed" | uci batch
						fi
					done

					macfixup=1
				fi
			else
				continue
			fi

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

				touch "$tmpdir/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

				set_iface_path_cost "$mesh_path_cost" "$device" "$iface"

				#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 ] || [ -e "$tmpdir/auto_config_test" ]; then

				if [ "$portal_detect" -ge 1 ] && [ "$portal_detect" -lt 4 ] && [ "$commit_all" -eq 0 ]; then
					check_portal

				elif [ "$portal_detect" -eq 0 ] || [ "$portal_detect" -eq 4 ] && [ "$commit_all" -eq 0 ]; then
					# portal_detect is not enabled - 0 force portal mode, 4 force portal bridge 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

						if [ "$portal_detect" -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

							echo "set dhcp.$auto_mesh_network.dhcpv4='server'" | uci batch
							echo "set dhcp.$auto_mesh_network.dhcpv6='server'" | uci batch
							echo "set dhcp.$auto_mesh_network.ignore='0'" | uci batch
							restore_ipv4

						elif [ "$portal_detect" -eq 4 ]; then
							debugtype="notice"
							syslogmessage="Portal detection is disabled, forcing portal bridge mode"
							write_to_syslog
							echo "set dhcp.$auto_mesh_network.dhcpv4='disabled'" | uci batch
							echo "set dhcp.$auto_mesh_network.dhcpv6='disabled'" | uci batch
							echo "set dhcp.$auto_mesh_network.ignore='1'" | uci batch
							echo "set network.$auto_mesh_network.proto='dhcp'" | uci batch
							set_ula_prefix "set"
							/sbin/service network reload
						fi

						uci set dhcp.@dnsmasq[0].authoritative='1'
						echo "set dhcp.$auto_mesh_network.ra_default='2'" | 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 [ "$vtunnel" = "configured" ]; then
							uci set dhcp.vtunlan.dhcpv4='server'
							uci set dhcp.vtunlan.dhcpv6='server'
							uci set dhcp.vtunlan.ra='server'
							uci set dhcp.vtunlan.ignore='0'
						fi

						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 ] && [ "$commit_all" -eq 0 ]; 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
						manage_opennds restart
						cpe_conf=1
					fi

				elif [ "$portal_detect" -eq 0 ]; then
					manage_opennds restart
				fi
			fi

			check_gate
			check_mesh_gate_only
			check_hwmp
			wait_for_mesh

			if [ "$mesh_mac_forced_forwarding" -eq 1 ] && [ -f "$tmpdir/active_mesh_ifname" ]; then
				. $tmpdir/active_mesh_ifname
				echo 1 > /proc/sys/net/ipv4/conf/$active_mesh_ifname/proxy_arp_pvlan
			fi

			if [ "$gateway_proxy_arp" -eq 0 ]; then
				. $tmpdir/devicemac
				echo 0 > /proc/sys/net/ipv4/conf/$device/proxy_arp
			fi

			block_bridge_loops
			check_path_changes

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

			check_vtunnel
			apmondloopcount=$((apmondloopcount + 1))

			if [ "$apmondloopcount" -ge "$apmondloopstart" ]; then
				send_ap_data
				apmondloopcount=0
				apmondloopstart=3
			fi
		fi

		if [ -e "$tmpdir/auto_config_test" ] && [ "$auto_config" -eq 0 ]; then
			debugtype="warn"
			syslogmessage="Auto Config is in TEST mode"
			write_to_syslog
		fi

		debugtype="debug"
		syslogmessage="checkinterval $checkinterval seconds"
		write_to_syslog
		check_mesh_active_led
		sleep $checkinterval
	done
	exit 0

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