#!/bin/sh
# Copyright (c) 2000-2011 Synology Inc. All rights reserved.

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/syno/bin:/usr/syno/sbin
GPIO=/sys/class/gpio
SYNOINFO=/etc.defaults/synoinfo.conf

BN_LOCK=/tmp/burnin.lock

BN_STATUS=/tmp/burnin.$$
BN_STATUS_UNKNOWN=0
BN_STATUS_INIT=1
BN_STATUS_STAGE1=2
BN_STATUS_STAGE2=3
BN_STATUS_COMPLETE=4
BN_STATUS_FAILED=5
BN_STAGE1_BOOTLOADER_MTEST_RET="Not Tested"

# link self test begins from eth2. all before eth2 will do wget
BN_STAGE2_SELF_TEST_BEGIN=2

TEST_NOTYET=0
TEST_PASSED=1
TEST_FAILED=2

is_us2="no"
is_us3="no"
is_alpine_2_10G="no"
is_alpine_4_1G="no"
is_RTL8111H="no"
is_vs960hd="no"
is_rtd129x_mem_factorymodel="no"
support_lcm="no"
bn_silent="no"
bn_stage1_skip="no"
bn_stage2_been_passed="no"
bn_stage2_duration=90
bn_stage2_do_selftest="yes"

enable_remote_command=0

# self loop test IPs
IP1="10.10.1.1"
IP2="20.20.1.1"
IP3="30.30.1.1"
IP4="40.40.1.1"

# Variables for copy log
burninlog_mnt="/logmnt"
burnin_server_ipaddr="169.254.1.1"
burnin_server_log_nfs="/volume1/log"
label="B1BurnIn"
server_name="B1Server_Ori"
model=`get_key_value /etc.defaults/synoinfo.conf unique | cut -d'_' -f3`
product_serial=`cat /proc/sys/kernel/syno_serial`
product_mac=`cat /proc/sys/kernel/syno_mac_address1`
burnin_log_path="/tmp/"
randomNum=0
FLAG_LIST_TMP="/tmp/flag_list"

get_spec_hw()
{
	local _isusbstation=`get_key_value $SYNOINFO usbstation`
	local _isus3=`cat /proc/sys/kernel/syno_hw_version| grep US3`
	local _isds2015xs=`cat /proc/sys/kernel/syno_hw_version | grep DS2015xs`
	local _isds1515=`cat /proc/sys/kernel/syno_hw_version | grep "DS1515-"`
	local _isds1517=`cat /proc/sys/kernel/syno_hw_version | grep "DS1517-"`
	local _isds1817=`cat /proc/sys/kernel/syno_hw_version | grep "DS1817-"`
	local _isvs960hd=`cat /proc/sys/kernel/syno_hw_version | grep "VS960HD-"`
	local _isds3619xs=`cat /proc/sys/kernel/syno_hw_version | grep "DS3619xs"`
	local _isrtd129x_mem_factorymodel="`get_key_value /etc.defaults/synoinfo.conf mem_factorymodel`"
	local _isrs1219=`cat /proc/sys/kernel/syno_hw_version | grep "RS1219-"`
	support_lcm=`get_key_value $SYNOINFO support_acm`

	if [ "x" != "x$_isds2015xs" ] || [ "x" != "x$_isds1817" ]; then
		is_alpine_2_10G="yes"
	fi
	if [ "x" != "x$_isds1515" ] || [ "x" != "x$_isds1517" ] || [ "x" != "x$_isrs1219" ]; then
		is_alpine_4_1G="yes"
	fi
	if [ "x" != "x$_isds3619xs" ]; then
		is_RTL8111H="yes"
	fi

	if [ "x" != "x$_isvs960hd" ]; then
		is_vs960hd="yes"
	fi

	if [ "xyes" = "x${_isrtd129x_mem_factorymodel}" ]; then
		is_rtd129x_mem_factorymodel="yes"
	fi

	if [ "yes" != "$_isusbstation" ]; then
		return
	fi

	if [ "x" = "x$_isus3" ]; then
		is_us2="yes"
	else
		is_us3="yes"
	fi
}

rtd129x_set_factory_memory()
{
	local ion_heaps_size="0x3200000"
	local cur_ion_heaps_size="`cat /sys/kernel/debug/ion/heaps/Media | grep GEN | head -1 | cut -c 41-51`"

	if [ "xflag" = "x${1}" -a $((cur_ion_heaps_size)) -gt $((ion_heaps_size)) ]; then
		/usr/lib/firmware/rtd1296/factory.bin flag FACTORY
		bn_log "change memory layout for factory mode and reboot"
		/sbin/reboot
	elif [ "xunflag" = "x${1}" -a $((cur_ion_heaps_size)) -le $((ion_heaps_size)) ]; then
		/usr/lib/firmware/rtd1296/factory.bin unflag FACTORY
		bn_log "change memory layout to normal mode, need reboot"
	fi
}

led_init()
{
	if [ "yes" = "$is_us3" ]; then
		echo 42 > $GPIO/export
		echo out > $GPIO/gpio42/direction
		echo 43 > $GPIO/export
		echo out > $GPIO/gpio43/direction
	elif [ "yes" = "$is_us2" ]; then
		echo 40 > $GPIO/export
		echo out > $GPIO/gpio40/direction
		echo 36 > $GPIO/export
		echo out > $GPIO/gpio36/direction
		echo 37 > $GPIO/export
		echo out > $GPIO/gpio37/direction
	fi
}

led_status_off()
{
	if [ "yes" = "$is_us2" ]; then
		echo 0 > $GPIO/gpio40/value
		echo 0 > $GPIO/gpio36/value
	elif [ "yes" = "$is_vs960hd" ]; then
		mantool -gpio_write 2 1 > /dev/null
		mantool -gpio_write 3 1 > /dev/null
	elif [ "yes" = "$support_lcm" ]; then
		echo 7 > /dev/ttyACM0
	else
		echo 7 > /dev/ttyS1
	fi
}

led_status_green()
{
	if [ "yes" = "$is_us3" ]; then
		echo 0 > $GPIO/gpio42/value
		echo 1 > $GPIO/gpio43/value
	elif [ "yes" = "$is_us2" ]; then
		echo 0 > $GPIO/gpio40/value
		echo 1 > $GPIO/gpio36/value
	elif [ "yes" = "$is_vs960hd" ]; then
		mantool -gpio_write 2 0 > /dev/null
		mantool -gpio_write 3 1 > /dev/null
	elif [ "yes" = "$support_lcm" ]; then
		echo 8 > /dev/ttyACM0
	else
		echo 8 > /dev/ttyS1
	fi
}

led_status_orange()
{
	if [ "yes" = "$is_us3" ]; then
		echo 1 > $GPIO/gpio42/value
		echo 0 > $GPIO/gpio43/value
	elif [ "yes" = "$is_us2" ]; then
		echo 1 > $GPIO/gpio40/value
		echo 0 > $GPIO/gpio36/value
	elif [ "yes" = "$is_vs960hd" ]; then
		mantool -gpio_write 2 1 > /dev/null
		mantool -gpio_write 3 0 > /dev/null
	elif [ "yes" = "$support_lcm" ]; then
		echo : > /dev/ttyACM0
	else
		echo : > /dev/ttyS1
	fi
}

led_stage_procesing()
{
	local _led_status=0
	local _stop_function=$1

	while ! $_stop_function; do
		if [ 0 -eq "$_led_status" ]; then
			led_status_green
		else
			led_status_orange
		fi

		_led_status=$((($_led_status + 1) % 2))
		sleep 1
	done
}

led_power_on()
{
	if [ "yes" = "$is_us2" ]; then
		echo 0 > $GPIO/gpio37/value
	elif [ "yes" = "$is_vs960hd" ]; then
		mantool -gpio_write 0 0 > /dev/null
		mantool -gpio_write 1 1 > /dev/null
	else
		echo 4 > /dev/ttyS1
	fi
}

led_power_off()
{
	if [ "yes" = "$is_us2" ]; then
		echo 1 > $GPIO/gpio37/value
	elif [ "yes" = "$is_vs960hd" ]; then
		mantool -gpio_write 0 1 > /dev/null
		mantool -gpio_write 1 1 > /dev/null
	else
		echo 6 > /dev/ttyS1
	fi
}

system_max_lan()
{
	local _num=-1

	if [ -f /proc/sys/kernel/syno_internal_netif_num ]; then
		_num=$(cat /proc/sys/kernel/syno_internal_netif_num)
	else
		_num=$(get_key_value $SYNOINFO maxlanport)
	fi

	[ "$_num" -ge 1 ] || _num=1
	echo $_num
}

test_flag_set()
{
	mantool -test_flag_set $1 $2
}

test_flag_get()
{
	mantool -test_flag_get $1
}

free_tmp()
{
	local tmp_free=$(df -m /tmp | tail -1 | xargs echo | cut -d' ' -f4)
	echo $(((${tmp_free:-50} - 2) * 95 / 100))
}

bn_msg()
{
	echo `date +'%b %e %T'` burnin: "$@"
}

bn_log()
{
	local _msg=$(bn_msg "$@")

	echo $_msg
	echo $_msg >> /var/log/messages
}

bn_status_set()
{
	echo "$1" >> $BN_STATUS
}

bn_status_get()
{
	if [ -f $BN_STATUS ]; then
		tail -1 $BN_STATUS 2>> /var/log/messages
	else
		echo "$BN_STATUS not found, status unknown" >> /var/log/messages
		echo $BN_STATUS_UNKNOWN
	fi
}

bn_status_show()
{
	local _pid=$(cat $BN_LOCK 2>> /var/log/messages)

	[ -f "/tmp/burnin.$_pid" ] || { echo "no burn-in is running..."; return; }

	case "$(tail -1 /tmp/burnin.$_pid 2>> /var/log/messages)" in
		$BN_STATUS_UNKNOWN)
			echo "unknown"
			;;
		$BN_STATUS_INIT)
			echo "initialize"
			;;
		$BN_STATUS_STAGE1)
			echo "memory test. progress: $(cat /tmp/memtester.progress 2> /dev/null)"
			;;
		$BN_STATUS_STAGE2)
			echo "dma test"
			;;
		$BN_STATUS_COMPLETE)
			echo "PCBA burn-in completed"
			;;
		$BN_STATUS_FAILED)
			echo "PCBA burn-in failed"
			;;
	esac
}

bn_lock()
{
	if [ ! -f $BN_LOCK ]; then
		echo $$ > $BN_LOCK
	else
		bn_log "PCBA burn-in test is already running..."
		exit 1
	fi
}

bn_unlock()
{
	rm -f $BN_LOCK
}

bn_completed()
{
	bn_log "Burn-in test main thread completed"
	bn_status_set $BN_STATUS_COMPLETE


	if [ "xyes" = "x${is_rtd129x_mem_factorymodel}" ]; then
		rtd129x_set_factory_memory unflag
	fi

	bn_copy_log_to_server
	exit 0
}

bn_error_exit()
{
	bn_unlock
	if [ "Fail" = "$(test_flag_get PTB_NETWORK_CRC)" ]; then
		bn_log "Restart rc.network"
		/etc/rc.network restart > /dev/null 2>&1
	fi
	bn_log "Burn-in exited with error or force terminate"
	bn_status_set $BN_STATUS_FAILED

	if [ "xyes" = "x${is_rtd129x_mem_factorymodel}" ]; then
		rtd129x_set_factory_memory unflag
	fi

	exit 1
}

bn_init()
{
	set -o nounset
	trap bn_error_exit HUP INT TERM

	get_spec_hw
	led_init
	bn_status_set $BN_STATUS_INIT

	#generate random session number for log
	let randomNum=${RANDOM}*${RANDOM}%99999999
	bn_copy_log_to_server
}

bn_seconds()
{
	date +%s | cut -d' ' -f3
}

bn_wget_max_lan()
{
	local _maxlan=$(system_max_lan)

	if [ "xyes" = "x${is_alpine_2_10G}" ]; then
		echo 4  # stress wget for lan: 2 <= n < 4
	elif [ "xyes" = "x${is_alpine_4_1G}" -o "xyes" = "x${is_RTL8111H}" ]; then
		echo 2  # only eth0 and eth1 do wget. eth2 and eth3 do self loop test
	elif [ $_maxlan -lt $BN_STAGE2_SELF_TEST_BEGIN ]; then
		echo $_maxlan
	else
		echo $BN_STAGE2_SELF_TEST_BEGIN
	fi
}

bn_link_detect()
{
	if [ -f /usr/bin/ethtool ]; then
		[ "yes" = "$(echo `ethtool $1 2>&1 | grep 'Link detected' | cut -d':' -f2`)" ]
	else
		true # usbstation2
	fi
}

bn_stage1_is_bootloader_support()
{
	local ret=`cat /proc/cmdline | grep "MTEST_BOOTLOADER=1"`
	[ ! -z "$ret" ]
}

bn_stage1_is_bootloader_mtest_tested()
{
	local ret=`/usr/syno/bin/mantool -get_mtest_ret | grep "Not tested"`
	[ -z "$ret" ]
}

bn_stage1_get_bootloader_mtest_ret()
{
	local ret=`/usr/syno/bin/mantool -get_mtest_ret | grep "Error"`
	if [ ! -z "$ret" ]; then
		BN_STAGE1_BOOTLOADER_MTEST_RET="ERROR"
	else
		BN_STAGE1_BOOTLOADER_MTEST_RET="PASS"
	fi
}

bn_stage1()
{
	local min_free_kbytes=`get_key_value $SYNOINFO min_free_kbytes`
	local memtester_min_free_kbytes=`get_key_value $SYNOINFO memtester_min_free_kbytes`

	[ "yes" = "$bn_stage1_skip" ] && return

	bn_log "Start memtester"
	bn_status_set $BN_STATUS_STAGE1
	bn_stage1_led_status &

	if [ -n "$memtester_min_free_kbytes" ]; then
		echo $memtester_min_free_kbytes > /proc/sys/vm/min_free_kbytes;
	fi

	if bn_stage1_is_bootloader_support; then
		bn_log "BN_STAGE1_BOOTLOADER_MTEST_RET = ${BN_STAGE1_BOOTLOADER_MTEST_RET}"
		if [ "Not Tested" = "$BN_STAGE1_BOOTLOADER_MTEST_RET" ]; then
			bn_log "Trigger bootloader to do memory test"
			/usr/syno/bin/mantool -set_mtest_on
			/sbin/reboot
		elif [ "ERROR" = "$BN_STAGE1_BOOTLOADER_MTEST_RET" ]; then
			bn_log "Failed to do memtester"
			led_status_orange
			test_flag_set PTB_MEMORY_TEST $TEST_FAILED
			bn_error_exit
		fi
	else
		if ! memtester -max 1; then
			bn_log "Failed to do memtester"
			test_flag_set PTB_MEMORY_TEST $TEST_FAILED
			bn_error_exit
		fi
	fi

	if [ -n "$min_free_kbytes" ]; then
		echo $min_free_kbytes > /proc/sys/vm/min_free_kbytes;
	fi

	bn_log "Complete memtester"
	test_flag_set PTB_MEMORY_TEST $TEST_PASSED
	sleep 2

	bn_copy_log_to_server
}

bn_stage1_led_status()
{
	local _led_active=""
	local _led_complete=""
	if [ "yes" = "$is_us3" ]; then
		_led_active="memtest_blinking"
	else
		_led_active="usbcopy_blinking"
	fi

	synohwctrl -set_led ${_led_active}
	sleep 1
	led_stage_procesing bn_stage1_should_stop
	if [ "yes" = "$is_us3" ]; then
		synohwctrl -set_led "memtest_off"
	fi
}

bn_stage1_should_stop()
{
	local _get=`ps | grep memtester | grep -v grep`
	[ "x" = "x$_get" ]
}

bn_stage2()
{
	local _lan=0
	local _begin_time=$(bn_seconds)

	bn_log "Check stage2 of this unit whether had been passed or not"
	bn_stage2_been_passed_check

	bn_log "Start RAM/NIC test"
	bn_status_set $BN_STATUS_STAGE2

	if [ "xyes" = "x${is_alpine_2_10G}" ]; then
		_lan=2  # DS2015xs 1G ports start from eth2
		bn_stage2_do_selftest="no"
		bn_stage2_self_loop_test 0 1 &
	elif [ "xyes" = "x${is_alpine_4_1G}" -o "xyes" = "x${is_RTL8111H}" ]; then
		bn_stage2_do_selftest="no"
		bn_stage2_self_loop_test 2 3 &
	fi

	while [ $_lan -lt $(bn_wget_max_lan) ]; do
		bn_stage2_wget $_lan &
		_lan=$(($_lan + 1))
	done

	if [ "xyes" = "x${bn_stage2_do_selftest}" ]; then
		bn_stage2_selftest &
	fi
	bn_stage2_links_detect &
	bn_stage2_led_status &

	while [ $(($(bn_seconds) - $_begin_time)) -lt $(($bn_stage2_duration * 60)) ]; do
		# only error would stop main loop before time is up
		[ "$BN_STATUS_STAGE2" -eq "$(bn_status_get)" ] || exit 1
		sleep 10
	done

	bn_log "Stage2 has been lasted for $bn_stage2_duration minutes and passed successfully."
	test_flag_set PTB_FILE_CHECKSUM $TEST_PASSED
	test_flag_set PTB_NETWORK_CRC $TEST_PASSED
	test_flag_set PTB_FILE_COPY $TEST_PASSED
	test_flag_set pt_dma_cnt $((($(bn_seconds) - $_begin_time) / 60))

	bn_copy_log_to_server
}

bn_stage2_duration_adjust()
{
	local _unique=$(get_key_value $SYNOINFO unique)
	local _maxdisks=$(get_key_value $SYNOINFO maxdisks)
	local _freemem=$(free | grep Mem| xargs echo| cut -d' ' -f2)
	_freemem=`expr ${_freemem} / 1024`

	if [ "$_freemem" -le 1024 ] && [ "$_maxdisks" -le 2 ]; then
		bn_stage2_duration=60
	fi
}

bn_stage2_been_passed_check()
{
	if [ "Pass" = "$(test_flag_get PTB_FILE_CHECKSUM)" ] && [ "Pass" = "$(test_flag_get PTB_NETWORK_CRC)" ] && [ "Pass" = "$(test_flag_get PTB_FILE_COPY)" ]; then
		bn_stage2_been_passed="yes"
	else
		bn_log "This unit is not passed yet."
	fi
}

bn_stage2_should_stop()
{
	[ "$BN_STATUS_FAILED" -eq "$(bn_status_get)" -o "$BN_STATUS_UNKNOWN" -eq "$(bn_status_get)" ]
}

bn_stage2_air_setup()
{
	local _bridge="lbr0"
	local _unique=$(get_key_value $SYNOINFO unique)
	local _airmodel=`echo ${_unique} | grep air | grep -v 213`
	local _airbridge=`brctl show | grep ${_bridge}`

	if [ "x" != "x${_airmodel}" -a "x" != "x${_airbridge}" ]; then
		`ifconfig ${_bridge} down`
		`brctl delbr ${_bridge}`
	fi
}

bn_stage2_self_loop_network_setup()
{
	# For some specific models, we physically connect eth$1 and eth$2 together, to form a self loop.
	# Here sets up the required network settings
	local _lan1=$1
	local _lan2=$2

	lsmod | grep iptable_nat > /dev/null
	if [ $? -ne 0 ]; then
		for m in nf_conntrack nf_defrag_ipv4 nf_conntrack_ipv4 nf_nat x_tables ip_tables nf_nat_ipv4 xt_nat iptable_nat; do
			insmod /lib/modules/$m.ko
		done
		sleep 1
	fi

	# avoid flushing kernel log "nf_conntrack: table full, dropping packet."
	echo 60 > /proc/sys/net/netfilter/nf_conntrack_generic_timeout  # was 600
	echo 131072 > /proc/sys/net/netfilter/nf_conntrack_max  # was 65536
	echo 20 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established  # was 432000

	if [ "xyes" = "x${is_alpine_2_10G}" ]; then
		# disable 10GbE RX equalization
		echo 0 > /sys/class/net/eth${_lan1}/device/rx_equal_enable
		echo 0 > /sys/class/net/eth${_lan2}/device/rx_equal_enable
		ifconfig | grep eth${_lan1} > /dev/null
		if [ $? -ne 0 ]; then
			ifconfig eth${_lan1} up
			ifconfig eth${_lan2} up
			sleep 25  # wait for udhcpc to take effect. We want to overwrite dhcp's result
		fi
	fi
	ifconfig eth${_lan1} ${IP1} netmask 255.255.0.0
	bn_log "Set IP address ${IP1} to eth${_lan1}"
	ifconfig eth${_lan2} ${IP2} netmask 255.255.0.0
	bn_log "Set IP address ${IP2} to eth${_lan2}"
	/sbin/iptables -t nat -A POSTROUTING -s ${IP1} -d ${IP4} -j SNAT --to-source ${IP3}
	/sbin/iptables -t nat -A PREROUTING -d ${IP3} -j DNAT --to-destination ${IP1}
	/sbin/iptables -t nat -A POSTROUTING -s ${IP2} -d ${IP3} -j SNAT --to-source ${IP4}
	/sbin/iptables -t nat -A PREROUTING -d ${IP4} -j DNAT --to-destination ${IP2}

	ip route add ${IP4} dev eth${_lan1} > /dev/null 2>&1
	arp -i eth${_lan1} -s ${IP4} `ifconfig eth${_lan2} | grep HWaddr | cut -c 39-55`
	ip route add ${IP3} dev eth${_lan2} > /dev/null 2>&1
	arp -i eth${_lan2} -s ${IP3} `ifconfig eth${_lan1} | grep HWaddr | cut -c 39-55`
}

bn_stage2_led_status()
{

	if [ "yes" == "$is_us3" ]; then
		synohwctrl -set_led memtest_on
	elif [ "yes" = "$is_us2" ] || [ "yes" == "$is_vs960hd" ]; then
		led_power_off
	else
		#usbcopy_off means green on, not off
		synohwctrl -set_led usbcopy_off
	fi

	led_stage_procesing bn_stage2_should_stop
}

bn_stage2_wget()
{
	local _nif=eth$1
	local _server=169.$((254 - $1)).1.1
	if [ "xyes" = "x${is_alpine_2_10G}" ]; then
		_server=169.$((254 - $1 + 2)).1.1
	fi
	local _localdir=/tmp/$_server
	local _freetmp=$(free_tmp)
	local _maxidx=$(( $_freetmp / $(bn_wget_max_lan) ))
	local _platform=$(get_key_value $SYNOINFO unique | cut -d"_" -f2)
	local _idx=0
	local _crcerr=0
	local _httpok="no"
	local _retrywget=5
	local _localfile=$_localdir/testing.$_idx

	mkdir -p $_localdir

	while ! bn_stage2_should_stop; do
		_idx=0
		_crcerr=0

		[ "yes" = "$bn_silent" ] || bn_msg "Remove files in $_localdir"
		rm -f $_localdir/*

		while [ $_idx -lt $_maxidx ]; do

			_httpok="no"
			_retrywget=5
			_localfile=$_localdir/testing.$_idx

			[ "yes" = "$bn_silent" ] || bn_msg "Fetching $_localfile from $_server"
			while [ "yes" != "$_httpok" -a $_retrywget -gt 0 ]; do
				if wget http://${_server}/testing -O$_localfile > /dev/null 2>&1; then
					_httpok="yes"
				fi
				_retrywget=$(($_retrywget - 1))
			done

			if [ "yes" != "$_httpok" ]; then
				bn_log "wget returned error ($?) when fetching $_localfile"
				test_flag_set PTB_FILE_COPY $TEST_FAILED
				bn_error_exit
			elif [ ! -f "$_localfile" ]; then
				bn_log "Failed to wget $_localfile"
				test_flag_set PTB_FILE_COPY $TEST_FAILED
				bn_error_exit
			elif [ "4193933615" != $(cksum $_localfile | cut -d' ' -f1) ]; then
				bn_log "Incorrect checksum of $_localfile"
				test_flag_set PTB_FILE_CHECKSUM $TEST_FAILED
				bn_error_exit
			fi

			_idx=$(($_idx + 1))
		done

		if [ "6281" = "$(get_key_value $SYNOINFO unique | cut -d'_' -f2)" ]; then
			[ "yes" = "$bn_silent" ] || bn_msg "Check network CRC errors for $_nif."
			_crcerr=$(ifconfig $_nif | grep 'RX' | grep errors | cut -d':' -f3 | cut -d' ' -f1)
			if [ "$_crcerr" -gt 2 ]; then
				led_power_off
			elif [ "$_crcerr" -gt 4 ]; then
				bn_log "Too many RX error packets for $_nif"
				test_flag_set PTB_NETWORK_CRC $TEST_FAILED
				bn_error_exit
			fi
		fi

	done
}

bn_stage2_selftest()
{
	local _lan=$BN_STAGE2_SELF_TEST_BEGIN
	local _maxlan=$(system_max_lan)

	[ $_lan -lt $_maxlan ] || return

	while ! bn_stage2_should_stop; do
		_lan=$BN_STAGE2_SELF_TEST_BEGIN
		while [ $_lan -lt $_maxlan ]; do

			[ "yes" = "$bn_silent" ] || bn_msg "Self test eth$_lan"
			if ! ethtool -t eth$_lan online 1>/dev/null 2>&1; then
				bn_log "Failed to self test eth$_lan"
				test_flag_set PTB_NETWORK_CRC $TEST_FAILED
				bn_error_exit
			fi

			_lan=$(($_lan + 1))
			sleep 10
		done
	done
}

bn_network_setup()
{
	local _lan=0
	local _maxlan=$(system_max_lan)
	local _backup_ip=""

	bn_stage2_air_setup
	ip route flush table main

	if [ "xyes" = "x${is_alpine_2_10G}" ]; then
		ifconfig eth0 down
		ifconfig eth1 down
		bn_stage2_self_loop_network_setup 0 1
		_lan=2  # 1G ports start from eth2
	elif [ "xyes" = "x${is_alpine_4_1G}" -o "xyes" = "x${is_RTL8111H}" ]; then
		_maxlan=$(bn_wget_max_lan)
		bn_stage2_self_loop_network_setup 2 3
	fi

	while [ $_lan -lt $_maxlan ]; do
		local _old=$(ifconfig eth$_lan | grep 'inet addr' | cut -d':' -f2 | cut -d' ' -f1 )
		if [ "x" = "x${_old}" ]; then
			_old=${_backup_ip}
		fi
		if [ "xyes" = "x${is_alpine_2_10G}" ]; then
			local _new=169.$((254 - $_lan + 2)).$(echo $_old | cut -d'.' -f3,4)
		else
			local _new=169.$((254 - $_lan)).$(echo $_old | cut -d'.' -f3,4)
		fi

		_backup_ip=${_old}
		bn_log "Set IP address $_new to eth$_lan"
		if [ "xyes" = "x${is_alpine_2_10G}" ]; then
			ip route add 169.$((254 - $_lan + 2)).0.0/16 dev eth$_lan
		else
			ip route add 169.$((254 - $_lan)).0.0/16 dev eth$_lan
		fi
		ifconfig eth$_lan $_new

		_lan=$(($_lan + 1))
	done

	sleep 3
}

bn_check_network_by_ping()
{
	local _lan=0
	local _maxlan=$(bn_wget_max_lan)

	if [ "xyes" = "x${is_alpine_2_10G}" ]; then
		_lan=2  # 1G ports start from eth2
	fi

	while [ $_lan -lt $_maxlan ]; do
		local _ping_IP="169.$((254 - $_lan)).1.1"
		if [ "xyes" = "x${is_alpine_2_10G}" ]; then
			_ping_IP="169.$((254 - $_lan + 2)).1.1"
		fi

		ping -w 5 -c 5 $_ping_IP
		if [ "x0" != "x$?" ]; then
			bn_log "Failed to ping $_ping_IP by eth$_lan"
			bn_log "Restart rc.network"
			/etc/rc.network restart > /dev/null 2>&1
			bn_error_exit
		fi

		_lan=$(($_lan + 1))
	done
}

bn_links_detect_common()
{
	local _lan=0
	local _maxlan=$(bn_wget_max_lan)
	local _sleep_time=$1
	local _stage=$2

	if [ "xyes" = "x${is_alpine_2_10G}" ]; then
		_lan=2
	fi
	while [ $_lan -lt $_maxlan ]; do
		[ "yes" = "$bn_silent" ] || bn_msg "Detect link of eth$_lan"
		if ! bn_link_detect "eth$_lan"; then
			bn_log "Failed to detect link of eth$_lan"
			[ "bn_precheck" = "$_stage" ] || test_flag_set PTB_NETWORK_CRC $TEST_FAILED
			bn_error_exit
		fi

		_lan=$(($_lan + 1))
		[ $_sleep_time -gt 0 ] && sleep $_sleep_time
	done
}

bn_stage2_links_detect()
{
	while ! bn_stage2_should_stop; do
		bn_links_detect_common 10 "bn_stage2"
	done
}

bn_stage2_self_loop_test()
{
	# do self loop socket transfer test between eth$1 and eth$2
	local _lan1=$1
	local _lan2=$2
	local _port=5566
	local _transfer_ok="yes"
	local _retry_connection=5

	/usr/sbin/socket_server ${IP1} ${_port} &
	/usr/sbin/socket_server ${IP2} ${_port} &

	while ! bn_stage2_should_stop; do
		_transfer_ok="yes"
		_retry_connection=5

		while [ $_retry_connection -gt 0 ]; do
			/usr/sbin/socket_client ${IP3} ${_port}
			if [ $? -ne 0 ]; then
				_transfer_ok="no"
			fi
			/usr/sbin/socket_client ${IP4} ${_port}
			if [ $? -ne 0 ]; then
				_transfer_ok="no"
			fi

			if [ "yes" = "$_transfer_ok" ]; then
				break
			else
				_retry_connection=$(($_retry_connection - 1))
				/usr/bin/killall socket_server > /dev/null 2>&1
				/usr/bin/killall socket_client > /dev/null 2>&1
				sleep 10
				bn_stage2_self_loop_network_setup ${_lan1} ${_lan2}
				/usr/sbin/socket_server ${IP1} ${_port} &
				/usr/sbin/socket_server ${IP2} ${_port} &
			fi
		done

		if [ "yes" != "$_transfer_ok" ]; then
			/usr/bin/killall socket_server > /dev/null 2>&1
			/usr/bin/killall socket_client > /dev/null 2>&1
			bn_log "Traffic transfer error between eth${_lan1} and eth${_lan2}"
			test_flag_set PTB_NETWORK_CRC $TEST_FAILED
			bn_error_exit
		fi
	done
}

bn_precheck_f401()
{
	local Model="`get_key_value /etc.defaults/synoinfo.conf unique`"

	if [ "$Model" != "synology_monaco_ds216play" -a \
		 "xyes" != "x${is_rtd129x_mem_factorymodel}" ]; then
		bn_log "This model doesn't need f401 check"
		return
	fi

	if [ "xyes" = "x${is_rtd129x_mem_factorymodel}" ]; then
		if [ "f401" = "`cat /sys/bus/usb/devices/usb*/*/idVendor`" ] && [ "f401" = "`cat /sys/bus/usb/devices/usb*/*/idProduct`" ]; then
			rtd129x_set_factory_memory flag
			return
		else
			bn_log "no f401 found ! skip B1\n"
			exit 1
		fi
	fi


	#whether something is plugged on USB3 port
	if [ ! -e "/sys/bus/usb/devices/usb3/3-1/idVendor" ] || [ ! -e "/sys/bus/usb/devices/usb3/3-1/idProduct" ]; then
		bn_log "f401 not found ! Skip B1"
		exit 1
	fi

	#whether f401 is plugged on USB3 port
	if [ "f401" = "`cat /sys/bus/usb/devices/usb3/3-1/idVendor`" ] && [ "f401" = "`cat /sys/bus/usb/devices/usb3/3-1/idProduct`" ]; then
		bn_log "f401 found ! Proceed B1"
	else
		bn_log "f401 not found ! Skip B1"
		exit 1
	fi

	bn_copy_log_to_server
}

bn_precheck_network()
{
	bn_log "Links detect"
	bn_links_detect_common 0 "bn_precheck"

	bn_log "Set up network interfaces"
	bn_network_setup

	bn_log "Check network by ping"
	bn_check_network_by_ping

	bn_copy_log_to_server
}

bn_remaining_force_stop()
{
	killall memtester >/dev/null 2>&1
	kill -TERM `cat ${BN_LOCK}`
	rm ${BN_LOCK}

	if [ "0" != `ls /tmp |grep -c burnin` ]; then
		bn_copy_log_to_server
	else
		bn_log "B1 not started"
		return 0
	fi

	for p in /tmp/burnin.*; do
		if [ -f "$p" ]; then
			kill -9 $(echo $p | cut -d'.' -f2) >/dev/null 2>&1
			rm -f $p
		fi
	done
}

bn_usage()
{
	cat <<USAGE
`basename $0`
	-k		skip memtester
	-s		show status
	-t MIN		assign duration of stage2
	-q		be more silent
	-f		force stop remaining sub-processes in background
USAGE
}

# remote command will get script from remote ip and run it.
# burnin_test will not be exec if remote command exec successfully
remote_command()
{
	local remote_exec_failed=1
	/usr/sbin/remote_command.sh
	remote_exec_failed=$?
	if [ "0" -eq "${remote_exec_failed}" ] ; then
		exit 0
	fi
}

bn_mount_log_dir()
{
	ping ${burnin_server_ipaddr} -c 1 -W 1
	if [ $? -ne 0 ]; then
		bn_log "ping server fail, do not copy log"
		return 1
	fi

	if [ ! -d ${burninlog_mnt} ]; then
		mkdir -p ${burninlog_mnt}
	fi

	if grep -qs ${burninlog_mnt} /proc/mounts; then
		umount ${burninlog_mnt}
	fi

	mount ${burnin_server_ipaddr}:${burnin_server_log_nfs} ${burninlog_mnt}
	if [ $? -ne 0 ]; then
		bn_log "Error, mount server fail!"
		return 1
	fi
}

bn_umount_log_dir()
{
	if grep -qs ${burninlog_mnt} /proc/mounts; then
		umount ${burninlog_mnt}
	fi
}

bn_copy_log_to_server()
{
	bn_mount_log_dir
	local res=$?
	if [ $res -gt 0 ]; then
		return 1
	fi

	#Format will be like "B1BurnIn-ServerName-1860R4R9W4PK7-00113293a3e5-72317654-xxx.txt"
	date_now=`date +"%Y%m"`
	log_dir=${burninlog_mnt}/${model}/${date_now}
	mkdir -p ${log_dir}
	cp /var/log/messages ${log_dir}/${label}-${server_name}-${product_serial}-${product_mac}-${randomNum}-messages.txt
	dmesg > ${log_dir}/${label}-${server_name}-${product_serial}-${product_mac}-${randomNum}-dmesg.txt
	[ -e /usr/syno/bin/mantool ] && mantool -test_flag_list > ${FLAG_LIST_TMP}
	cp ${FLAG_LIST_TMP} ${log_dir}/${label}-${server_name}-${product_serial}-${product_mac}-${randomNum}-flag.txt

	bn_umount_log_dir
}

bn_stage2_duration_adjust

while getopts ":rkst:qfh" opt; do
	case "$opt" in
		r)
			# run remote command
			enable_remote_command=1
			;;
		k)
			bn_stage1_skip="yes"
			;;
		s)
			bn_status_show
			exit 0
			;;
		t)
			bn_stage2_duration=$OPTARG
			;;
		q)
			bn_silent="yes"
			;;
		f)
			bn_remaining_force_stop
			exit 0
			;;
		h)
			bn_usage
			exit 0
			;;
		\?)
			echo "Invalid option: -$OPTARG" >&2
			exit 1
			;;
		:)
			echo "Option -$OPTARG requires an argument." >&2
			exit 1
			;;
	esac
done

bn_lock

if bn_stage1_is_bootloader_support && bn_stage1_is_bootloader_mtest_tested; then
	bn_stage1_get_bootloader_mtest_ret
	/usr/syno/bin/mantool -reset_mtest
fi

if [ 1 -eq $enable_remote_command ]; then
    remote_command
fi

bn_init
bn_precheck_f401
bn_precheck_network
bn_stage1
bn_stage2
bn_completed

