#!/bin/sh
lauch_time=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
echo "conn_dect($$): lauched at uptime:$lauch_time" >/dev/console

PID_FILE="/var/run/conn_dect.pid"
JSON_FILE="/var/cd_status"
JSON="json -f $JSON_FILE"
SLEEP_PERIOD=5
DEFAULT_RT_PRIO=39000
INVALID_DEFAULT_ROUTE=99999
DEBUG_LOG="logger"
CD_NONE_MAX_RETRY=1
USB_PORT_DECT=3

. $IPKG_INSTROOT/lib/network/config.sh
. $IPKG_INSTROOT/etc/functions.sh

model=`head -n 1 /etc/version`
case "$model" in
	Vigor2960)
		WAN_PORTS="WAN1 WAN2"
		;;
	Vigor2960F)
		WAN_PORTS="WAN1 WAN2"
		;;	
	Vigor300B)
		WAN_PORTS="WAN1 WAN2 WAN3 WAN4"
		;;	
	Vigor3900)
		WAN_PORTS="WAN1 WAN2 WAN3 WAN4 WAN5"
		;;
	*)
		WAN_PORTS=
		$DEBUG_LOG "Warnning: sciprt:conn_dect, no such a router model"
		;;
esac

## Pseudocode of modify_default_rt()
# We know there are 2 scripts may modify default route: network, conn_dect
# All passed judge_iface must be checked by follow rules to reduce non-necessary operations
#
# IF [judge_iface is not the default route] THEN return
#	IF [default route becomes 'down'] 
#		IF [original default route is in invlaid type:99999] THEN
#			return	//down-to-down case: don't care
#		ELSE
#			invalid defualt route	//other-to-down case: whatever original default route is another interface or current judge_iface, invalid it
#		ENDIF
#	ELSE	//default route becomes 'up'
#		IF [original default route is in invlaid type:99999] THEN
#			valid default route to judge_iface		//down-to-up case: original default route iface is down, now it is going up
#		ELSE
#			IF [original default route is the same with current judge_iface] THEN
#				return		//self up-to-up case: don't care
#			ELSE
#				valid default route to judge_iface	//up-to-up case: original default route is another 'up' interface, change to this judge_iface
#			ENDIF
#		ENDIF
#	ENDIF
# ENDIF
##
modify_default_rt() {
	judge_iface=$1
	suggest_action=$2
	if [ "$judge_iface" = "$default_table" ] ;then
		if [ "$suggest_action" = "invalid" ] ;then
			if [ "$old_rt_table_id" = "$INVALID_DEFAULT_ROUTE" ] ;then
				#echo "Oldid:$old_rt_table_id == $INVALID_DEFAULT_ROUTE $judge_iface is down already, skip" >/dev/console
				return
			else
				#echo "Oldid:$old_rt_table_id Newid:$iface_rt_table_id ; $judge_iface becomes down, invalid route" >/dev/console
				iface_rt_table_id=$INVALID_DEFAULT_ROUTE
			fi
		else	#up
			if [ "$old_rt_table_id" = "$INVALID_DEFAULT_ROUTE" ] ;then
				#echo "Oldid=$old_rt_table_id == $INVALID_DEFAULT_ROUTE ; $judge_iface becomes up, valid route" >/dev/console
				dummy=
			else
				if [ "$old_rt_table_id" = "$iface_rt_table_id" ] ;then
					#echo "Oldid:$old_rt_table_id == Newid:$iface_rt_table_id ; $judge_iface is up already, skip" >/dev/console
					return
				else
					#echo "Oldid:$old_rt_table_id != Newid:$iface_rt_table_id ; $judge_iface becomes up, valid route" >/dev/console
					dummy=
				fi
			fi
		fi
	else
		#echo "conn, type:regular, $judge_iface is not the default route =>return" >/dev/console
		return
	fi
	/usr/sbin/ip rule del pref $DEFAULT_RT_PRIO >/dev/null 2>/dev/null
	/usr/sbin/ip rule add pref $DEFAULT_RT_PRIO table $iface_rt_table_id
	/usr/sbin/flush_route_cache.sh "conn_dect"
	#/usr/sbin/ip route flush cache #Comment off by Vincent F. 2013/02/01
	#Following commands will clear route cache, not necessary to flush cache here.
	#1. ip route flush
	#2. ip route flush table
	#3. ip addr flush dev
	#4. ip link set device down

	/usr/sbin/ip -6 rule del pref $DEFAULT_RT_PRIO >/dev/null 2>/dev/null
	/usr/sbin/ip -6 rule add pref $DEFAULT_RT_PRIO table $iface_rt_table_id
	/usr/sbin/ip -6 route flush cache
	conntrack -F
}

load_network_cfg()
{
	scan_interfaces
	$JSON set global refresh_cfg=0 interfaces=
	$JSON delete switch.members

	for port in $WAN_PORTS; do
		$JSON set switch.members $port=
	done

	for ifs in $interfaces; do
		config_get status $ifs status
		config_get proto $ifs proto
		[ "$status" = "enable" ] || continue
		[ "$proto" = "none" -o "$proto" = "dmz" ] && continue
		
		config_get physical $ifs physical
		[ "$physical" = "eth2" -o "$physical" = "usb" ] || continue

		$JSON set global interfaces=,$ifs
		config_get port $ifs port
		$JSON set switch.members $port=,$ifs

		config_get cd_mode $ifs ${proto}_cd_mode
		config_get cd_hosts $ifs ${proto}_cd_host
		config_get cd_interval $ifs ${proto}_cd_interval
		config_get cd_retry $ifs ${proto}_cd_retry
		
		[ "$proto" = "pppoe" -o "$proto" = "pptp" ] && config_get ppp_always_on $ifs ${proto}_always_on
		[ -z "$ppp_always_on" ] && ppp_always_on=
		
		orig_port_down=`$JSON get interface.$ifs.port_down`
		[ -z "$orig_port_down" ] && orig_port_down=0
		
		$JSON delete inetface.$ifs
		
		$JSON set interface.$ifs proto=$proto cd_mode=$cd_mode cd_interval=$cd_interval \
			cd_retry=$cd_retry cd_hosts="$cd_hosts" port_down=$orig_port_down bak_down=0 primary= backup= \
			timer=0 retried=0 connection= if_rename_cnt=0 if_arpfail_cnt=0 ppp_always_on=$ppp_always_on \
			prev_port_status= pppd_start_time=0
	done
}

load_failover_cfg()
{
	config_load lb_pool
	config_foreach load_failover_cfg2
}

load_failover_cfg2()
{
	iface=$1
	config_get mode $iface mode
	[ "$mode" = "failover" ] || return
	config_get primary $iface primary
	config_get backup $iface backup
	$JSON set interface.$primary backup=,$backup
	$JSON set interface.$backup primary=$primary
}

get_online_status()
{
	for ifs in $interfaces; do
		eval `json load network.$ifs | eval sed 's/network_${ifs}_//g'` 2>/dev/null
		[ "$ifs" == "usb1" -o "$ifs" == "usb2" ] && ifname="wan-$ifs"
		$JSON set interface.$ifs ifname=$ifname ipaddr=$ipaddr gateway=$gateway online=$connection
	done
}

get_switch_status()
{
	if [ "$model" != "Vigor3900" ] ;then
		#Vigor 2960, Vigor300B
		#get old port status record
		#old_ports_status=`cat /tmp/wan_port_status | sed -e 's/0/Down/g' -e 's/1/Up/g'`
		#trigger switch to report new port status
		if [ "$model" = "Vigor2960" -o "$model" = "Vigor2960F" ];then
			/sbin/switch_queue_sender PCS WAN x x x Vigor2960
		fi
		if [ "$model" = "Vigor300B" ];then
			/sbin/switch_queue_sender PCS WAN x x x Vigor300B
		fi
		sleep 1
		new_ports_status=`cat /tmp/wan_port_status | sed -e 's/0/Down/g' -e 's/1/Up/g'`
		if_id=1
		for ps in $new_ports_status ;do
			[ "$ps" = "Up" ] && $JSON set interface.wan$if_id port_down=0
			[ "$ps" = "Down" ] && $JSON set interface.wan$if_id port_down=1
			if_id=$(($if_id+1))
		done
	else
		#Vigor 3900
		#check which switch model is using
		switch_model=$(cat /tmp/v39sw_model)
		if [ "$switch_model" = "rtk8366" ] ;then
			new_ports_status=$(cat /proc/rtk8366_status |sed -n '/Link/p' |awk -F": " '{print $2}')
			if_id=1
			for ps in $new_ports_status ;do
				#rtk8366 switch return status of (5 WANs + 1 LAN), skip LAN
				[ "$if_id" = 6 ] && continue
				[ "$ps" = "Up" ] && $JSON set interface.wan$if_id port_down=0
				[ "$ps" = "Down" ] && $JSON set interface.wan$if_id port_down=1
				if_id=$(($if_id+1))
			done
		elif [ "$switch_model" = "ar8327" ] ;then
			#trigger switch to report new port status
			/sbin/switch_queue_sender PCS WAN x x x Vigor3900
			sleep 1
			new_ports_status=`cat /tmp/wan_port_status | sed -e 's/0/Down/g' -e 's/1/Up/g'`
			#update basic/advance mode WAN interface port status
			if_id=1
			for ps in $new_ports_status ;do
				sw_members=`$JSON get switch.members.WAN$if_id`
				for member in $sw_members ;do
					[ "$ps" = "Up" ] && $JSON set interface.$member port_down=0
					[ "$ps" = "Down" ] && $JSON set interface.$member port_down=1
				done
				if_id=$(($if_id+1))
			done
		fi
	fi

	usbifs="usb1 usb2"
	for ps in $usbifs ;do
		usbif=$(uci -q -P /var/state/ get network.$ps.usbif)
		if [ -z "$usbif" ]; then
			$JSON set interface.$ps port_down=1
		else
			$JSON set interface.$ps port_down=0
		fi

		mode_sw=$(uci -q -P /var/state get network.$ps.modesw)
		usb_status=$(uci -q get network.$ps.status)
		if [ -n "$mode_sw" ] && [ "$usb_status" == "enable" ]; then
			mode_sw=`expr $mode_sw + 1`
			uci -q -P /var/state set network.$ps.modesw="$mode_sw"
			[ $mode_sw -ge $USB_PORT_DECT ] && {
				/etc/init.d/usb usb_pw $ps off
				sleep 10 && /etc/init.d/usb usb_pw $ps on &
			}
		fi

		[ -f /tmp/tty_restart_$ps ] && {
			tty=$(uci -q -P /var/state get network.$ps.usbif)
			tty_restart=$(cat /tmp/tty_restart_$ps)
			if [ "$tty" == "$tty_restart" ]; then
				ifdown $ps
				uci -q -P /var/state set network.$ps.ifup_running=0
				/etc/init.d/usb usb_pw $ps off
				sleep 10 && /etc/init.d/usb usb_pw $ps on &
			fi
			rm /tmp/tty_restart_$ps
		}
	done
}

#if arp/ping response time takes too long, we neglect the check result by assuming that the interface is too busy
check_traffic_rate()
{
	sent_time=$(cat /tmp/cd_senttime_$iface)
	sent_rx_byte=$(cat /tmp/cd_sent_rx_$iface)
	sent_tx_byte=$(cat /tmp/cd_sent_tx_$iface)
	
	now_time=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
	now_rx_byte=$(cmm -c show stat interface $ifname query |grep "Total Bytes Received" |awk -F": " '{print $2}')
	now_tx_byte=$(cmm -c show stat interface $ifname query |grep "Total Bytes Transmitted" |awk -F": " '{print $2}')
	
	if [ $now_time -ge $sent_time ]; then
		DUR=$(($now_time - $sent_time))
		[ "$DUR" = 0 ] && DUR=1
		TH=50000	#50 KBytes/s threshold
		if [ $now_rx_byte -ge $sent_rx_byte ] ;then
			RX_DIFF=$(($now_rx_byte - $sent_rx_byte))
			RX_RATE=$(eval "awk 'BEGIN{ print $RX_DIFF / $DUR}'")
			cmp_result=$(echo "$RX_RATE $TH" | awk '{if ($1 > $2) print "G"; else print "L"}')
			#logger "conn_dect:($ifname) DUR=$DUR, RX_DIFF=$RX_DIFF, RX_RATE=$RX_RATE"
			if [ "$cmp_result" = "G" ] ;then
				[ "$if_arpfail_cnt" -lt $cd_retry ] && logger "conn_dect: $ifname RX rate($RX_RATE), ignore arping result"
				return 0
			else
				[ "$if_arpfail_cnt" -lt $cd_retry ] && logger "conn_dect: $ifname RX rate($RX_RATE), admit arping result"
			fi
		fi
		if [ $now_tx_byte -ge $sent_tx_byte ] ;then
			TX_DIFF=$(($now_tx_byte - $sent_tx_byte))
			TX_RATE=$(eval "awk 'BEGIN{ print $TX_DIFF / $DUR}'")
			cmp_result=$(echo "$TX_RATE $TH" | awk '{if ($1 > $2) print "G"; else print "L"}')
			#logger "conn_dect:($ifname) DUR=$DUR, TX_DIFF=$TX_DIFF, TX_RATE=$TX_RATE"
			if [ "$cmp_result" = "G" ] ;then
				[ "$if_arpfail_cnt" -lt $cd_retry ] && logger "conn_dect: $ifname TX rate($TX_RATE), ignore arping result"
				return 0
			else
				[ "$if_arpfail_cnt" -lt $cd_retry ] && logger "conn_dect: $ifname TX rate($TX_RATE), admit arping result"
			fi
		fi
		[ "$if_arpfail_cnt" -lt $cd_retry ] && {
			if_arpfail_cnt=$(($if_arpfail_cnt+1))
			$JSON set interface.$iface if_arpfail_cnt=$if_arpfail_cnt
		}
	fi
	return 1
}

#save the time, rx/tx bytes before sending ARP
sent_time_save()
{
	sent_time=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
	sent_rx=$(cmm -c show stat interface $ifname query |grep "Total Bytes Received" |awk -F": " '{print $2}')
	sent_tx=$(cmm -c show stat interface $ifname query |grep "Total Bytes Transmitted" |awk -F": " '{print $2}')
	echo $sent_time >/tmp/cd_senttime_$iface
	echo $sent_rx >/tmp/cd_sent_rx_$iface
	echo $sent_tx >/tmp/cd_sent_tx_$iface
}

detect_connection()
{
	iface=$1
	ret=0
	eval `$JSON load interface.$iface | eval sed 's/interface_${iface}_//g'`
	#if port status is down, skip detection
	if [ "$port_down" = "1" ] ;then 
		#logger "conn_dect($$)CD: $iface($proto,$cd_mode,OS:$online,PD:$port_down): detect port down"
		ret="port_down"
	else
		#if port status is up, then do detection
		timer=$(($timer+$SLEEP_PERIOD))
		[ "$timer" -ge "$cd_interval" ] || {
			#not yet reach cd time interval, skip
			$JSON set interface.$iface connection= timer=$timer
			return
		}

		#if ifname was flushed, link should be already down => skip detection
		/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null || ret="no_ifname"
		[ "$ret" = "0" ] && case $cd_mode in
		none)
			ret=0
			;;
		arp)
			arping -f -c 2 -w 3 -i $ifname $gateway >/dev/null 2>/dev/null 
			if [ "$?" = "0" ] ;then
				ret=0
				if [ "$if_arpfail_cnt" -gt $cd_retry ] ;then
					$JSON set interface.$iface if_arpfail_cnt=0
				fi
			else
				[ "$if_arpfail_cnt" -lt $cd_retry ] && logger "conn_dect($$)CD: $iface($proto,$cd_mode,OS:$online,PD:$port_down): $ifname 1st ARPing fails, try again(max retry=$cd_retry, count=$if_arpfail_cnt)"
				sent_time_save
				arping -f -c 2 -w 2 -i $ifname $gateway >/dev/null 2>/dev/null 
				if [ "$?" = "0" ] ;then
					ret=0
					logger "conn_dect($$)CD: $iface($proto,$cd_mode,OS:$online,PD:$port_down): $ifname 2nd ARPing succeeded"
					$JSON set interface.$iface if_arpfail_cnt=0
				else
					[ "$if_arpfail_cnt" -lt $cd_retry ] && logger "conn_dect($$)CD: $iface($proto,$cd_mode,OS:$online,PD:$port_down): $ifname 2nd ARPing fails, do traffic rate checking"
					check_traffic_rate
					ret=$?
				fi
			fi
			;;
		ping)
			for host in $cd_hosts; do
				ping -c 1 -I $ipaddr -W 1 $host >/dev/null 2>/dev/null
				ret=$?
				[ "$ret" = "0" ] && break
			done
			;;
		http)
			for host in $cd_hosts; do
				port=${host#*:}
				[ "$port" = "$host" ] && port=
				host=${host%:*}
				httping -h $host ${port:+-p $port} -c 1 -t 3 -N 1 -y $ipaddr >/dev/null 2>/dev/null
				ret=$?
				[ "$ret" = "0" ] && break
			done
			;;
		esac
	fi
	
	if [ "$ret" = "0" ]; then
		#port is up, and detection result is success
		$JSON set interface.$iface connection=up timer=$(($timer%$SLEEP_PERIOD)) retried=0
	elif [ "$ret" = "port_down" ]; then
		$JSON set interface.$iface retried=0
	else
		#port is up, but detection result is failure: ifname is not existed or detection get no response
		if [ "$cd_mode" != "none" -a "$cd_mode" != "" ]; then
			[ "$retried" -le "$cd_retry" ] && {
				logger "conn_dect($$)CD: $iface($proto,$cd_mode,OS:$online,PD:$port_down): detection failed, code=$ret, retried=$retried"
				$JSON set interface.$iface connection=down timer=$(($timer%$SLEEP_PERIOD)) retried=$(($retried+1))
			}
		fi
	fi
}



#######Judge interface up or down
judge_status()
{
	iface=$1

	online=$(json get network.$iface.connection)
	$JSON set interface.$iface online=$online
	eval `$JSON load interface.$iface | eval sed 's/interface_${iface}_//g'`
	
	if [ "$port_down" = "0" ] ;then
		if [ "$bak_down" = "1" ] ;then
			#Failover case: backup is up but was told to down by primary
			/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null && {
				#if I can find my ifname, do ifdown myself
				logger "conn_dect($$)failover: $iface:I was told to be down by my primary"
				$JSON set interface.$iface timer=0 retried=0
				ifdown $iface &
				#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
				modify_default_rt $iface invalid
			}
			#Interface is determined by failover, no need to do further judgement
			return
		else
			#Failover: Although I was not told to down, but my "primary" is still UP => I should down myself
			#this case may happen when:
			#	1.conn_dect is restarted, because all bak_down are initialized to "0"
			if [ -n "$primary" ] ;then
				pri_online=`json get network.$primary.connection`
				if [ "$pri_online" = "up" ]; then
					/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null && {
						#if I can find my ifname, do ifdown myself
						logger "conn_dect($$)failover: $iface:my primary is still UP, ifdown myself"
						$JSON set interface.$iface timer=0 retried=0
						ifdown $iface &
						#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
						modify_default_rt $iface invalid
					}
					return
				elif [ "$pri_online" = "down" ]; then
					/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null || {
						#if I can not find my ifname, but primary is down, do ifup myself
						logger "conn_dect($$)failover: $iface:my primary is already down, ifup myself"
						if [ "$proto" = "pppoe" -o "$proto" = "pptp" -o "$proto" = "3g" ] ;then
							now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
							$JSON set interface.$iface pppd_start_time=$now
						fi
						$JSON set interface.$iface timer=0 retried=0
						ifup $iface &
						#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
						modify_default_rt $iface valid
						return
					}
				elif [ -z "$pri_online" ]; then 
					primary_status=`uci get network.$primary.status`
					[ "$primary_status" = "disable" ] && {
						#primary is disabled, do ifup myself
						/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null || {
							logger "conn_dect($$)failover: $iface:my primary is already disabled, ifup myself"
							if [ "$proto" = "pppoe" -o "$proto" = "pptp" -o "$proto" = "3g" ] ;then
								now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
								$JSON set interface.$iface pppd_start_time=$now
							fi
							$JSON set interface.$iface timer=0 retried=0
							ifup $iface &
							#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
							modify_default_rt $iface valid
							return
						}
					}
				fi
			fi
		fi
	fi
	
	####### Judge interface status according to connection detection result ####### 
	if [ "$port_down" = "1" ] ;then			## When port is down
		$JSON set interface.$iface prev_port_status=down
		if [ "$prev_port_status" = "up" -o "$prev_port_status" = "" ] ;then
			#whatever the cd_mode is, if new port status=down => do ifdown
			logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down):swport X->down => do ifdown"
			ifdown $iface &
			modify_default_rt $iface invalid
			#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
			#failover_tell_up
		else
			/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null
			if [ "$?" = "0" ] ;then 
				logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): interface found but port is down, do ifdown"
				ifdown $iface &
				modify_default_rt $iface invalid
				#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
				#failover_tell_up
			fi
		fi
	elif [ "$port_down" = "0" ] ;then		## When port is up
		$JSON set interface.$iface prev_port_status="up"
		##############   cd_mode=none or undefined, port is up   ##############
		if [ "$cd_mode" = "none" -o "$cd_mode" = "" ]; then
			if [ "$prev_port_status" = "down" ] ;then
				#if previous port status=down => do ifup
				logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): swport down->up, do ifup"
				if [ "$proto" = "pppoe" -o "$proto" = "pptp" -o "$proto" = "3g" ] ;then
					now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
					$JSON set interface.$iface pppd_start_time=$now
				fi
				$JSON set interface.$iface retried=0
				ifup $iface &
				modify_default_rt $iface valid
				#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
				#failover_tell_down
			else
				#whatever previous port status=up or unknown => check interface
				/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null
				if [ "$?" = "0" ] ;then 
					modify_default_rt $iface valid
					#failover_tell_down
				else
					#logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): interface is not found, prepare to redo ifup"
					if [ "$proto" = "pppoe" -o "$proto" = "pptp" -o "$proto" = "3g" ] ;then
						now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
						[ -z "$pppd_start_time" ] && pppd_start_time=0
						DIFF=$(($now - $pppd_start_time))
						PPPD_THRESHOLD=60
						if [ $DIFF -gt $PPPD_THRESHOLD ]; then
							logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): ppp interface is not found in 1 minute, redo ifup"
							$JSON set interface.$iface pppd_start_time=$now retried=0
							ifup $iface &
						fi
					else
						logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): interface not found, do ifup"
						$JSON set interface.$iface retried=0
						ifup $iface &
					fi
					modify_default_rt $iface valid
					#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
					#failover_tell_down
				fi
			fi
		##############   cd_mode =(arp,ping,httping), and port is up   ##############
		else
			if [ "$prev_port_status" = "down" ] ;then
				#if previous port was down, do ifup first, let detection can do work later
				logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): swport down->up => ifup first, let detection can work later"
				if [ "$proto" = "pppoe" -o "$proto" = "pptp" -o "$proto" = "3g" ] ;then
					now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
					$JSON set interface.$iface pppd_start_time=$now
				fi
				$JSON set interface.$iface retried=0
				ifup $iface &
				modify_default_rt $iface valid
				#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
				#failover_tell_down
			else
				#whatever previous port status=up or unknown => check interface
				/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null
				if [ "$?" = "0" ] ;then
					#Interface is existed. OK, we can apply detection result
					if [ "$connection" = "up" -a "$online" = "down" ]; then
						#when CD result is "up" and current online is "down" => chnage online status down->up
						logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): CD result=up => judge:status down->up"
						env -i ACTION="ifup" INTERFACE="$iface" DEVICE="$ifname" PROTO="$proto" /sbin/hotplug-call iface &
						modify_default_rt $iface valid
						#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
						#failover_tell_down
					elif [ "$connection" = "down" -a "$retried" = "$cd_retry" ]; then
						#when CD result is "down", wait until retry counter to reach maximum
						if [ "$online" = "up" ] ;then
							if [ "$proto" = "dhcp" ] ;then
								#In the case of riginal dhcp server goes down(gateway does not exist, arping is failed), we renew dhcp client to try
								logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): CD result=down, but this is dhcp WAN => redo ifup"
								ifup $iface &
								modify_default_rt $iface valid
							else
								logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): CD result=down and reach max retry=$cd_retry => judge:status up->down"
								env -i ACTION="ifdown" INTERFACE="$iface" DEVICE="$ifname" PROTO="$proto" /sbin/hotplug-call iface &
								modify_default_rt $iface invalid
							fi
							#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
							#failover_tell_up
						elif [ "$online" = "down" ] ;then
							logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): CD result=down but it's already down->down(stable)"
							modify_default_rt $iface invalid
							#failover_tell_up
						fi
					elif [ "$connection" = "up" -a "$online" = "up" ]; then
						modify_default_rt $iface valid
						#failover_tell_down
					fi
					#rest case:(connection=down, retried!=cd_retry) => do nothing
				else
					#logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): interface is not found, prepare to redo ifup"
					if [ "$proto" = "pppoe" -o "$proto" = "pptp" -o "$proto" = "3g" ] ;then
						now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
						[ -z "$pppd_start_time" ] && pppd_start_time=0
						DIFF=$(($now - $pppd_start_time))
						PPPD_THRESHOLD=60
						if [ $DIFF -gt $PPPD_THRESHOLD ]; then
							logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): ppp interface is not found in 1 minute, redo ifup"
							$JSON set interface.$iface pppd_start_time=$now retried=0
							ifup $iface &
						fi
					else
						logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): interface not found, redo ifup"
						$JSON set interface.$iface retried=0
						ifup $iface &
					fi
					modify_default_rt $iface valid
					#/etc/init.d/igmpproxy_script restart & >/dev/null 2>/dev/null
					#failover_tell_down
				fi
			fi
		fi
	fi
}

#Need a loop check to ifdown all WANs iface if HA mode=HS and currecnt HA status=backup
HS_status_backup_do_ifdown()
{
	iface=$1
	online=$(json get network.$iface.connection)
	$JSON set interface.$iface online=$online
	eval `$JSON load interface.$iface | eval sed 's/interface_${iface}_//g'`
	
	/usr/sbin/ip -4 addr show dev $ifname >/dev/null 2>/dev/null
	if [ "$?" = "0" ] ;then 
		logger "conn_dect($$): $iface($proto,$cd_mode,OS:$online,PD:$port_down): Current HS_status=backup, ifdown $iface"
		ifdown $iface &
		modify_default_rt $iface invalid
	fi
}


echo $$ > $PID_FILE
trap "$JSON set global refresh_cfg=1" SIGUSR1
trap "rm -f $PID_FILE $JSON_FILE $JSON_FILE.lock 2> /dev/null; exit 255" SIGTERM SIGKILL

$JSON set global refresh_cfg=1

while true; do
	loop_start=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
	refresh_cfg=`$JSON get global.refresh_cfg`
	[ "$refresh_cfg" = "1" ] && {
		$(load_network_cfg)
		$(load_failover_cfg)
		##### all interfaces should do detect, includes "cd_mode=none"
		interfaces="$($JSON get global.interfaces)"
	}
	sleep $SLEEP_PERIOD

	$(get_online_status)
	$(get_switch_status)

	##G40733: When HA master goes into WANs-ifdown state, skip conn_dect action
	default_table=`uci -q get network.default_route.default`
	old_rt_table_id=`ip rule list |grep "^$DEFAULT_RT_PRIO" |cut -d' ' -f 4`
	iface_rt_table_id=`json get policy_rt.table_map.$default_table`
	
	ucarp_status=`uci get ucarp_mode.general.status`
	HA_method=`uci get ucarp_mode.general.method`
	ucarp_state=`json get ucarp.state`
	if [ "$HA_method" = "HS" -a "$ucarp_status" = "enable" -a "$ucarp_state" = "master" ] ;then
		ps | grep master-polling_HS | grep -v grep >/dev/null 2>/dev/null
		if [ "$?" = "0" ] ;then
			if [ ! -f "/tmp/HA_ifdown_lock" ] ;then
				for ifs in $interfaces; do
					$(detect_connection $ifs)
				done

				for ifs in $interfaces; do
					$(judge_status $ifs)
				done
			#else
			#	logger "conn_dect($$): HA master_polling is in LAN port DOWN state, skip my actions"
			fi
		else
			if [ -f "/tmp/HA_ifdown_lock" ] ;then
				rm -f "/tmp/HA_ifdown_lock" >/dev/null 2>/dev/null
				logger "conn_dect($$): Special case: break lock and help to restart HA master ucarp"
				/etc/init.d/ucarp_mode restart &
			fi
		fi
	elif [ "$HA_method" = "HS" -a "$ucarp_status" = "enable" -a "$ucarp_state" = "backup" ] ;then
		for ifs in $interfaces; do
			$(HS_status_backup_do_ifdown $ifs)
		done
	else
		for ifs in $interfaces; do
			$(detect_connection $ifs)
		done

		for ifs in $interfaces; do
			$(judge_status $ifs)
		done
	fi
	
	loop_end=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
	echo "dur=$(($loop_end - $loop_start))"  >/tmp/exec_time_measure/conn_dect_loop
done
