#!/bin/sh

CFG=/etc/board.json

. /usr/share/libubox/jshn.sh
. /lib/functions.sh
. /lib/functions/system.sh

[ -s $CFG ] || /bin/board_detect || exit 1
[ -s /etc/config/network ] && \
[ -s /etc/config/system ] && \
[ -s /etc/config/poe] && \
[ -f /usr/share/vuci/menu.d/menu.json ] && \
exit 0

get_port_names() {
	local ports name
	json_select network
		json_select static

			json_get_keys keys ports
			json_select ports
			for i in $keys; do
				json_select "$i"
				json_get_var name "name"
				[ -z "$ports" ] && ports="$name" || ports="$ports $name"
				json_select ..
			done
			json_select ..
		json_select ..
	json_select ..

	echo "$ports"

	return 0
}

generate_bridge() {
	local name=bridge
	local ports=$1
	local macaddr=$2

	uci -q batch <<-EOF
		set network.$name=device
		set network.$name.name="br0"
		set network.$name.type=bridge
		set network.$name.stp='1'
	EOF

	if [ -n "$macaddr" ]; then
		uci -q batch <<-EOF
			set network.$name.macaddr=$macaddr
		EOF
	fi

	for port in $ports; do
		uci_add_list network $name ports $port
	done
}

generate_bridge_vlan() {
	local ports=$1

	uci -q batch <<-EOF
		set network.vlan1=bridge-vlan
		set network.vlan1.device='br0'
		set network.vlan1.vlan='1'
	EOF

	for port in $ports; do
		uci_add_list network "vlan1" ports "${port}:u"
	done
}

generate_static_network() {
	uci -q batch <<-EOF
		delete network.loopback
		set network.loopback='interface'
		set network.loopback.device='lo'
		set network.loopback.proto='static'
		set network.loopback.ipaddr='127.0.0.1'
		set network.loopback.netmask='255.0.0.0'
	EOF

	if json_is_a dsl object; then
		json_select dsl
			if json_is_a atmbridge object; then
				json_select atmbridge
					local vpi vci encaps payload nameprefix
					json_get_vars vpi vci encaps payload nameprefix
					uci -q batch <<-EOF
						delete network.atm
						set network.atm='atm-bridge'
						set network.atm.vpi='$vpi'
						set network.atm.vci='$vci'
						set network.atm.encaps='$encaps'
						set network.atm.payload='$payload'
						set network.atm.nameprefix='$nameprefix'
					EOF
				json_select ..
			fi

			if json_is_a modem object; then
				json_select modem
					local type annex firmware tone xfer_mode
					json_get_vars type annex firmware tone xfer_mode
					uci -q batch <<-EOF
						delete network.dsl
						set network.dsl='dsl'
						set network.dsl.annex='$annex'
						set network.dsl.firmware='$firmware'
						set network.dsl.tone='$tone'
						set network.dsl.xfer_mode='$xfer_mode'
					EOF
				json_select ..
			fi
		json_select ..
	fi
}

generate_network() {
	local ports device protocol type default_ip netmask vlan macaddr
	local bridge=$2

	json_select network
		json_select "$1"
			json_get_vars device protocol default_ip netmask vlan macaddr
		json_select ..
	json_select ..

	ports="$(get_port_names)"

	[ -n "$device" -o -n "$ports" ] || return
	# Force bridge for "lan" as it may have other devices (e.g. wireless)
	# bridged
	[ "$1" = "static" -a -z "$ports" ] && {
		ports="$device"
	}

	generate_bridge "$ports" "$macaddr"
	generate_bridge_vlan "$ports"

	case "$1" in
		static)
			uci -q batch <<-EOF
				delete network.$1
				set network.$1='interface'
				set network.$1.device='br0.1'
				set network.$1.proto='static'
				set network.$1.ipaddr=$default_ip
				set network.$1.netmask='255.255.255.0'
				set network.$1.metric='2'

				delete network.dhcp
				set network.dhcp='interface'
				set network.dhcp.device='br0.1'
				set network.dhcp.proto='dhcp'
				set network.dhcp.metric='1'

			EOF

			[ -e /proc/sys/net/ipv6 ] && {
				uci -q batch <<-EOF
					delete network.dhcp6
					set network.dhcp6='interface'
					set network.dhcp6.device='br0.1'
					set network.dhcp6.proto='dhcpv6'
					set network.dhcp6.metric='3'
				EOF
			}
		;;

	esac
}

generate_multicast_groups() {

	local max_multicast_groups

	json_select network
		json_select "static"
			json_get_var max_multicast_groups max_multicast_groups
		json_select ..
	json_select ..

	[ -n "$max_multicast_groups" ] || return

	uci set network.bridge.max_multicast_groups=$max_multicast_groups
}

generate_static_system() {
	param="$(/sbin/mnf_info --name)"
	hostname="${param:0:6}"
	uci -q batch <<-EOF
		delete system.@system[0]
		set system.system='system'
		set system.@system[-1].hostname='$hostname'
		set system.@system[-1].timezone='UTC'
		set system.@system[-1].ttylogin='0'
		set system.@system[-1].log_size_limit='128'
		set system.@system[-1].urandom_seed='0'

		delete system.ntp
		set system.ntp='timeserver'
		set system.ntp.enabled='1'
		set system.ntp.enable_server='0'
		add_list system.ntp.server='0.pool.ntp.org'
		add_list system.ntp.server='1.pool.ntp.org'
		add_list system.ntp.server='2.pool.ntp.org'
		add_list system.ntp.server='3.pool.ntp.org'

		delete system.banner
		set system.banner=banner
		set system.banner.enabled='0'

		set system.ledman='ledman'
		set system.ledman.enabled='1'
	EOF

	if json_is_a system object; then
		json_select system
			local hostname
			if json_get_var hostname hostname; then
				uci -q set "system.@system[-1].hostname=$hostname"
			fi

			local compat_version
			if json_get_var compat_version compat_version; then
				uci -q set "system.@system[-1].compat_version=$compat_version"
			else
				uci -q set "system.@system[-1].compat_version=1.0"
			fi

			if json_is_a ntpserver array; then
				local keys key
				json_get_keys keys ntpserver
				json_select ntpserver
					uci -q delete "system.ntp.server"

					for key in $keys; do
						local server
						if json_get_var server "$key"; then
							uci -q add_list "system.ntp.server=$server"
						fi
					done
				json_select ..
			fi
		json_select ..
	fi
}

set_poe_ports() {
	json_select "$1"
		json_get_vars name class budget
		poe_enable=$(uci get tswconfig.port$1.poe_enable 2>/dev/null)
		uci -q batch <<-EOF
			set poe.port$1='port'
			set poe.port$1.name='$name'
			set poe.port$1.poe_enable="${poe_enable:-1}"
			set poe.port$1.class='$class'
			set poe.port$1.budget='$budget'
		EOF
	json_select ..
}

set_poe_chips(){
	local keys key
	uci -q set poe.chip$1='chip'
	json_get_keys keys "$1"
	json_select "$1"
		for key in $keys; do
			json_get_var var "$key"
			uci -q set poe.chip$1.$key="$var"
		done
	json_select ..
}

generate_poe_config(){
	if json_is_a poe object; then
		json_select poe
			json_get_vars bus chip_count budget poe_ports high_load_lo_thresh high_load_hi_thresh
			uci -q batch <<-EOF
				set poe.poe='poe'
				set poe.poe.enable='1'
				set poe.poe.bus='$bus'
				set poe.poe.chip_count='$chip_count'
				set poe.poe.budget='$budget'
				set poe.poe.poe_ports='$poe_ports'
				set poe.poe.high_load_lo_thresh='$high_load_lo_thresh'
				set poe.poe.high_load_hi_thresh='$high_load_hi_thresh'
			EOF
			if json_is_a ports array; then
				#json_for_each_item "set_poe_ports" ports
				json_select ports
					idx=1
					while json_is_a ${idx} object
					do
						"set_poe_ports" $idx
						idx=$(( idx + 1 ))
					done
				json_select ..
			fi
			if json_is_a poe_chips array; then
				json_select poe_chips
					idx=1
					while json_is_a ${idx} object
					do
						"set_poe_chips" $idx
						idx=$(( idx + 1 ))
					done
				json_select ..
			fi
		json_select ..
	fi
}

generate_tswconfig() {
	local port keys cfg bridge name

	json_select network
	json_select static
	json_get_keys keys ports
	json_select ports

	for i in $keys; do
		json_select "$i"
		json_get_var port "name"
		macaddr=$(macaddr_add $macaddr 1)
		uci -q batch <<-EOF
			set tswconfig.$port='switch_port'
			set tswconfig.$port.enable="1"
			set tswconfig.$port.advert='0x3F'
			set tswconfig.$port.autoneg='1'
			set tswconfig.$port.mirror="0"
			set tswconfig.$port.eee_enable='1'
			set tswconfig.$port.ingr_bw='0'
			set tswconfig.$port.ingr_rate='62500'
			set tswconfig.$port.egr_bw='0'
			set tswconfig.$port.egr_rate='62500'
			set tswconfig.$port.storm_mult='0'
			set tswconfig.$port.storm_mult_rate='62500'
			set tswconfig.$port.storm_broad='0'
			set tswconfig.$port.storm_broad_rate='62500'
			set tswconfig.$port.storm_uni='0'
			set tswconfig.$port.storm_uni_rate='62500'
			set tswconfig.$port.storm_uni_type='unknown'
			set tswconfig.$port.storm_multi_type='unknown'
			set tswconfig.$port.qos_pri_group='0'
			set tswconfig.$port.qos_pri_inner='0'
			set tswconfig.$port.qos_pri_outer='0'
		EOF
		json_select ..
	done
	json_select ..
	json_select ..
	json_select ..

	json_get_vars bridge
	[ -n "$bridge" ] && {
		json_select bridge
		json_get_vars name
		json_select ..
		uci -q batch <<-EOF
			set tswconfig.$name='bridge'
			set tswconfig.$name.force_vers='rstp'
			set tswconfig.$name.max_age='20'
			set tswconfig.$name.fwd_delay='15'
			set tswconfig.$name.max_hops='20'
			set tswconfig.$name.hello_time='2'
			set tswconfig.$name.ageing_time='300'
			set tswconfig.$name.hold_count='6'
			set tswconfig.$name.priority='32768'
		EOF
	}

	uci -q batch <<-EOF
		set tswconfig.common='switch_bw'
		set tswconfig.common.bw_ifg='0'
		set tswconfig.common.storm_ifg='0'
		set tswconfig.common.storm_mult_burst='5'
		set tswconfig.common.storm_broad_burst='5'
		set tswconfig.common.storm_uni_burst='5'
		set tswconfig.common._storm_mult_burst='5'
		set tswconfig.common._storm_broad_burst='5'
		set tswconfig.common._storm_uni_burst='5'
		set tswconfig.common.storm_mode='bytes'
		set tswconfig.common.max_pkt_len='10000'
		set tswconfig.common.lldp_filter='0'
	EOF

	for i in `seq 0 63`
	do
		uci set tswconfig.common.dscp_priority_$i='0'
	done

	uci -q batch <<-EOF
		set tswconfig.common.quid_map_0="1"
		set tswconfig.common.quid_map_1="0"
		set tswconfig.common.quid_map_2="2"
		set tswconfig.common.quid_map_3="3"
		set tswconfig.common.quid_map_4="4"
		set tswconfig.common.quid_map_5="5"
		set tswconfig.common.quid_map_6="6"
		set tswconfig.common.quid_map_7="7"
	EOF

	uci set tswconfig.common.sheduling_algo='WRR'

	uci -q batch <<-EOF
		set tswconfig.common.queue_weight_0="1"
		set tswconfig.common.queue_weight_1="2"
		set tswconfig.common.queue_weight_2="4"
		set tswconfig.common.queue_weight_3="8"
		set tswconfig.common.queue_weight_4="16"
		set tswconfig.common.queue_weight_5="32"
		set tswconfig.common.queue_weight_6="64"
		set tswconfig.common.queue_weight_7="127"
	EOF

	uci -q batch <<-EOF
		set tswconfig.qos_group_weight='qos_group_weigths'
		set tswconfig.qos_group_weight.dscp_0='3'
		set tswconfig.qos_group_weight.dscp_1='7'
		set tswconfig.qos_group_weight.dscp_2='7'
		set tswconfig.qos_group_weight.dscp_3='3'
		set tswconfig.qos_group_weight.inner_tag_0='3'
		set tswconfig.qos_group_weight.inner_tag_1='3'
		set tswconfig.qos_group_weight.inner_tag_2='3'
		set tswconfig.qos_group_weight.inner_tag_3='3'
		set tswconfig.qos_group_weight.outer_tag_0='3'
		set tswconfig.qos_group_weight.outer_tag_1='3'
		set tswconfig.qos_group_weight.outer_tag_2='3'
		set tswconfig.qos_group_weight.outer_tag_3='3'
		set tswconfig.qos_group_weight.port_in_pri_0='7'
		set tswconfig.qos_group_weight.port_in_pri_1='3'
		set tswconfig.qos_group_weight.port_in_pri_2='7'
		set tswconfig.qos_group_weight.port_in_pri_3='3'
		set tswconfig.qos_group_weight.port_out_pri_0='3'
		set tswconfig.qos_group_weight.port_out_pri_1='3'
		set tswconfig.qos_group_weight.port_out_pri_2='3'
		set tswconfig.qos_group_weight.port_out_pri_3='3'
	EOF
}

generate_lbdconfig() {
	local ports

	ports="$(get_port_names)"

	[ -n "$ports" ] || return

	uci set loopbackd.globals="loopbackd"
	uci set loopbackd.globals.enabled="0"

	for port in $ports; do
		uci -q batch <<-EOF
			set loopbackd.$port="port"
			set loopbackd.$port.enabled="1"
			set loopbackd.$port.ifname="$port"
			set loopbackd.$port.recovery_mode="auto"
		EOF
	done
}

generate_lldpconfig() {
	local ports

	ports="$(get_port_names)"

	[ -n "$ports" ] || return

	uci set lldp.lldp="lldp"
	uci set lldp.lldp.enabled="0"
	uci set lldp.lldp.interval="5"

	for port in $ports; do
		uci_add_list lldp lldp tx_enabled "$port"
	done
}

generate_macfilter() {
	local port keys
	json_select network
	json_select static
	json_get_keys keys ports
	json_select ports

	for i in $keys; do
		json_select "$i"
		json_get_var port "name"
		uci -q batch <<-EOF
			set macfilter.$port='port'
			set macfilter.$port.rule_prio='$i'
			set macfilter.$port.enabled='0'
			set macfilter.$port.intruder_action='ignore'
		EOF
		json_select ..
	done
	json_select ..
	json_select ..
	json_select ..
	uci commit macfilter
}

json_init
json_load "$(cat ${CFG})"

umask 077

if [ ! -s /etc/config/network ]; then
	bridge_name=""
	touch /etc/config/network
	generate_static_network
	json_get_vars bridge
	[ -n "$bridge" ] && {
		json_select bridge
		json_get_vars name macaddr
		json_select ..
		bridge_name=$name
	}

	json_get_keys keys network
	for key in $keys; do generate_network $key $bridge_name; done

	json_get_keys keys switch
	for key in $keys; do generate_switch $key; done
fi

if [ -z "$(uci get network.bridge.max_multicast_groups)" ]; then
	generate_multicast_groups
fi

if [ ! -s /etc/config/system ]; then
	touch /etc/config/system
	generate_static_system
fi

if [ ! -s /etc/config/poe ]; then
	poe=""
	json_select hwinfo
	json_get_vars poe
	json_select ..
	[ "$poe" -eq 1 ] && {
		touch /etc/config/poe
		generate_poe_config
	}
fi

if [ ! -s /etc/config/tswconfig ]; then
	touch /etc/config/tswconfig
	generate_tswconfig
fi

if [ ! -s /etc/config/loopbackd ]; then
	touch /etc/config/loopbackd
	generate_lbdconfig
fi

if [ ! -s /etc/config/lldp ]; then
	touch /etc/config/lldp
	generate_lldpconfig
fi

if [ ! -s /etc/config/macfilter ]; then
	touch /etc/config/macfilter
	generate_macfilter
fi

if [ ! -f /usr/share/vuci/menu.d/menu.json ]; then
	/usr/bin/lua -e 'require("vuci.menu_generate"):regenerate_menu()'
fi

uci commit
