#!/bin/sh
# Argument Description:
# cfg: wan#
# mode: NAT/ROUTING
# ifanme: wan-wan#

ITF_BASE_ID=`/usr/sbin/iprule_idx.sh iface`
. /etc/functions.sh

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


[ "$#" = "0" ] && { echo "  $0 <group>"; exit; }
[ "x$1" = "x-a" ] && {
	config_cb() {
		[ interface != "$1" -o -z "$2" ] || eval "$0 $2"
	}
	config_load network
	exit
}

iface=$1
caller=$2
cfg=$1
include /lib/network
scan_interfaces
##### Abort if ifdown of the iface is running
now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
runtime=$(uci -q -P /var/state get network.$iface.ifdown_running)
if [ $now -ge 100 -a -n "$runtime" ]; then
	DIFF=$(($now - $runtime))
	INTERVAL=30
	if [ $DIFF -le $INTERVAL ]; then
		logger -p 160.5 "$iface ifdown($$): another ifdown is running.......abort"
		return
	else
		uci revert -P /var/state/ network.$iface.ifdown_running
	fi
fi

##### prevent race event:A process calls ifdown directly(ex:conn_dect) when another process is running ifup(ex:network)
if [ "$caller" != "ifup" ] ;then
	runtime=$(uci -q -P /var/state get network.$iface.ifup_running)
	nowtime=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
	while [ $nowtime -ge 100 -a -n "$runtime" ]
	do
		DIFF=$(($nowtime - $runtime))
		INTERVAL=30
		[ "$iface" == "usb1" -o "$iface" == "usb2" ] && INTERVAL=60
		if [ $DIFF -le $INTERVAL ]; then
			logger -p 160.5 "$iface ifdown($$):another ifup is running, abort"
			return
		else
			#logger -p 160.5 "$iface ifdown($$):ifup has exceeded $INTERVAL secs, unlock"
			uci revert -P /var/state/ network.$iface.ifup_running
			break
		fi
	done
	##### update ifdown running lock
	now=$(cat /proc/uptime | awk 'FS="[.]+" {print $1}')
	uci -q -P /var/state set network.$iface.ifdown_running=$now
	logger -p 160.5 "$iface ifdown($$):set ifdown_running lock"
fi

logger -p 160.5 "========== [$$] START ifdown $iface (called by $caller)"

proto1=`json get network.$cfg.proto`
proto=${proto1%(*}
mode=${proto1#*(}
mode=${mode%)}
ifname=`json get network.$cfg.ifname`
current_intf=$(json get network.$cfg.physical)
rt_table_id=`json get policy_rt.table_map.$cfg`

##### if the interface is not up, it doesn't need to be shutdown
[ -z "$ifname" ] && return
#Fix that related iptables rules do not be deleted when pptp WAN in the dial-fial loop
	#in this case, $ifname here brings eth2.xx, not wan-wanx
if [ "$proto" = "pptp" ] ;then
	ifname=wan-$cfg
fi

[ "$proto" = "static" -o "$proto" = "dmz" ] && {
	[ -n "$rt_table_id" -a "$current_intf" = "wan" ] && {
		#logger -p 160.5 "$cfg ifdown($$)($proto): flush route table $rt_table_id"
		ip route flush table $rt_table_id
		#logger -p 160.5 "$cfg ifdown($$)($proto): del route rule pref $(($ITF_BASE_ID+$rt_table_id))"
		until [ -z `ip rule |grep $(($ITF_BASE_ID+$rt_table_id))` ]
		do
			ip rule del pref $(($ITF_BASE_ID+$rt_table_id)) 2>/dev/null
		done
	}
	connection=`json get network.$cfg.connection`
	[ "$connection" = "up" ] && {
		if [ "$proto" = "static" ];then
			#logger -p 160.5 "$cfg ifdown($$)($proto): call hotplug-call iface"
			env -i ACTION="ifdown" INTERFACE="$cfg" DEVICE="$ifname" PROTO="$proto" /sbin/hotplug-call "iface" &
		fi
	}
}

# call interface stop handler
( type "stop_interface_$proto" ) >/dev/null 2>/dev/null && {
	#logger -p 160.5 "$cfg ifdown: call stop_interface_$proto"
	eval "stop_interface_$proto '$cfg'"
}

# make sure all locks are removed
for lock in "/var/lock/dhcp-$cfg" "/var/lock/ppp-$cfg"; do
	[ -f "$lock" ] && {
		lock -u "$lock"
		sleep 1
	}
done

check_kill() {
	sleep 10
	[ -d "/proc/$1" ] && {
		kill -9 $1 2>/dev/null >/dev/null
	}
}

# kill active ppp daemon and other processes of this cfg 
pids="$(head -n1 -q /var/run/dhcp-${cfg}.pid /var/run/ppp-${cfg}.pid /var/run/dhcp6c-${cfg}.pid 2>/dev/null)"
[ -n "$pids" ] && {
	#logger -p 160.5 "ifdown($$)($proto): kill $cfg active ppp/dhcp/dhcp6c daemon:$pids"
	for pid in $pids; do
		[ -d "/proc/$pid" ] && {
			kill $pid
			check_kill $pid &
		}
	done
	rm -f /var/run/dhcp-${cfg}.pid /var/run/ppp-${cfg}.pid /var/run/dhcp6c-${cfg}.pid
}
##### remove block direct nat from wan
ipaddr=$(json get network.$cfg.ipaddr)
netmask=$(json get network.$cfg.netmask)
vlan_id=`uci get network.$cfg.vlan_id`
if [ "lan" = "$current_intf" ];then
    ## For Inter-LAN routing
    iptables -D LANROUTE -i ${ifname} -m mset --set lan_${cfg}_subnet src --set lan_${cfg}_subnet dst -j RETURN 2>/dev/null
	iptables -D LANROUTE -i ${ifname} -m mset --set lan_routing_subnet src --set lan_routing_subnet dst -j RETURN 2>/dev/null
    ipset -F lan_${cfg}_subnet 2>/dev/null
    ipset -X lan_${cfg}_subnet 2>/dev/null

	##### ian.20110331 remove lan_nat_subnet
	if   [ "$mode" = "NAT" ]; then
		ipset -D lan_nat_subnet $ipaddr/$netmask
	elif [ "$mode" = "ROUTING" ]; then
		ipset -D lan_routing_subnet $ipaddr/$netmask
	fi
	second_subnet=`json get network.$cfg.2nd_subnet`
	for net in $second_subnet; do
		set -- `echo $net | sed -e 's/[\/\(\)]/ /g'`
		if   [ "$3" = "NAT" ]; then
			ipset -D lan_nat_subnet $1/$2
		elif [ "$3" = "ROUTING" ]; then
			ipset -D lan_routing_subnet $1/$2
		fi
	done
fi
#####
vlan_id=`uci get network.$cfg.vlan_id`
port=`uci get network.$cfg.port`
untag=`uci get network.$cfg.untag`
# shutdown interface: static/dhcp/dmz
[ "$proto" = "static" -o "$proto" = "dhcp" -o "$proto" = "dmz" ] && {
	#/usr/sbin/ip addr show dev $ifname > /dev/null 2> /dev/null && vconfig rem $ifname
	
	 ip addr flush dev $ifname 2> /dev/null	
	 ip link set $ifname down 2> /dev/null	 
	#echo "ifdown($$): shutdown interface(static/dhcp): $ifname, done" > /dev/console	
		#logger -p 160.5 "$cfg ifdown($$):($proto) shutdown interface:name eth2.$vlan_id "
	if [ "wan" = "$current_intf" ]; then
		#logger -p 160.5 "$cfg ifdown($$):($proto) shutdown interface:name eth2.$vlan_id "
		if [ "$untag" = "enable" ]; then	  
		  for double_tag_port in $WAN_PORTS; do
		     double_tag_num=$(echo $double_tag_port | cut -c 4)
		     if [ "$port" = "$double_tag_port" ]; then
	           vlan_id=$double_tag_num
			   ip link set $ifname name eth2.$vlan_id 2> /dev/null
			 fi 
		  done
		   echo ifdown1 $ifname $vlan_id > /dev/console 
		   #ip link set $ifname down 2> /dev/null		  
		    #ip link set $ifname name eth2.$vlan_id 2> /dev/null
		    #ip link set eth2.$vlan_id up 2> /dev/null
			ip link delete eth2.1 
			ip link delete eth2.2 
			ip link delete eth2.3 
			ip link delete eth2.4 
			ip link delete eth2.5 
		 
		   		   		        
		else		  
		  for double_tag_port in $WAN_PORTS; do
		     double_tag_num=$(echo $double_tag_port | cut -c 4)
		     if [ "$port" = "$double_tag_port" ]; then
	           echo ifdown1 $ifname $vlan_id > /dev/console 
		       ip link set $ifname name eth2.$double_tag_num.$vlan_id 2> /dev/null
			 fi 
		  done
		  
        fi	  		
          #echo ifdown1 $ifname $vlan_id > /dev/console 
		#ip link set $ifname name eth2.$vlan_id 2> /dev/null
		ip_alias=`json get network.$cfg.ip_alias`
		[ -z "$ipaddr" ] || iptables -t mangle -D OUTPUT_WAN -s $ipaddr/$netmask -j MARK --set-mark $rt_table_id 2>/dev/null
		for ip2 in $ip_alias; do
			iptables -t mangle -D OUTPUT_WAN -s $ip2 -j MARK --set-mark $rt_table_id 2>/dev/null
		done
	elif [ "lan" = "$current_intf" ]; then	    
		ip link set $ifname name eth0.$vlan_id 2> /dev/null
		[ -z "$ipaddr" ] || iptables -t mangle -D OUTPUT_WAN -s $ipaddr/$netmask -j MARK --set-mark $rt_table_id 2>/dev/null
	fi
}

##### ian.20100521 remove iptables TCPMSS rule
tcpmss=`json get network.$cfg.tcpmss`
[ -n "$tcpmss" ] && {
	#/usr/sbin/iptables -t mangle -D WAN_TCPMSS -p tcp --tcp-flags SYN,RST SYN -o $ifname -j TCPMSS --set-mss $tcpmss 2> /dev/null > /dev/null
	/usr/sbin/iptables -t mangle -D WAN_TCPMSS -p tcp --tcp-flags SYN,RST SYN -o $ifname -m mset ! --set exception_subnet_set dst -m mset ! --set exception_subnet_gre_set dst  -j TCPMSS --set-mss $tcpmss 2> /dev/null > /dev/null
	/usr/sbin/iptables -t mangle -D TCPMSS_FORWARD -p tcp --tcp-flags SYN,RST SYN -i $ifname -m mset ! --set exception_subnet_set src -m mset ! --set exception_subnet_gre_set src -j TCPMSS --set-mss $tcpmss 2> /dev/null > /dev/null
	[ "$proto" = "pptp" ] && {
		/usr/sbin/iptables -t mangle -D WAN_TCPMSS -p tcp --tcp-flags SYN,RST SYN -o eth2.$vlan_id -m mset ! --set exception_subnet_set dst -m mset ! --set exception_subnet_gre_set dst  -j TCPMSS --set-mss $tcpmss 2> /dev/null > /dev/null
		/usr/sbin/iptables -t mangle -D TCPMSS_FORWARD -p tcp --tcp-flags SYN,RST SYN -i eth2.$vlan_id -m mset ! --set exception_subnet_set src -m mset ! --set exception_subnet_gre_set src -j TCPMSS --set-mss $tcpmss 2> /dev/null > /dev/null
		
	}
}

##### shutdown interface: ppp
if [ "$proto" = "pptp" -o "$proto" = "pppoe" ]; then
	over_dns=`json get network.$cfg.over_dns`
	server_gw=`json get network.$cfg.server_gw`
	#/usr/sbin/ip addr show eth2.$vlan_id >/dev/null 2>/dev/null && vconfig rem eth2.$vlan_id	  
	  for double_tag_port in $WAN_PORTS; do
		     double_tag_num=$(echo $double_tag_port | cut -c 4)
		     if [ "$port" = "$double_tag_port" ]; then
	           ip link set eth2.$double_tag_num.$vlan_id down 2> /dev/null
			 fi 
	  done	
	#logger -p 160.5 "$cfg  ifdown($$):($proto) shutdown interface eth2.$vlan_id"
	for ns in $over_dns; do
		ip route del $ns via $server_gw 2> /dev/null
	done
fi

##### remove nat iptables,20100331
local current_intf
current_intf=$(json get network.$cfg.physical)
if [ "wan" = "$current_intf" ];then
    if [ "$mode" = "ROUTING" ]; then
        iptables -t mangle -D BLOCKDIRECTNAT -i $ifname -j ACCEPT 2>/dev/null
    else
        iptables -t nat -D nat_post_route -o $ifname -m mset2 --set2 lan_nat_subnet src --set2 exception_subnet_set src -j MASQUERADE 2>/dev/null
        [ "$proto" = "pptp" ] && iptables -t nat -D nat_post_route -o eth2.$vlan_id -m mset2 --set2 lan_nat_subnet src --set2 exception_subnet_set src -j MASQUERADE 2>/dev/null
    fi
fi
#####


##### ian.20101117 remove ipset
##jimmy_c.2013-2-19: only do flush but do not destroy them. Some functions, ex:port redirection, require these set to be refered
if [ "wan" = "$current_intf" ];then
	/usr/sbin/ipset -D all_interface ipalias_$cfg 2>/dev/null
	/usr/sbin/ipset -F ipalias_$cfg 2>/dev/null
	#/usr/sbin/ipset -X ipalias_$cfg 2>/dev/null
	/usr/sbin/ipset -F ip_$cfg 2>/dev/null
	#/usr/sbin/ipset -X ip_$cfg 2>/dev/null
fi
if [ "lan" = "$current_intf" ];then
	/usr/sbin/ipset -D all_interface_lan ip_$cfg 2>/dev/null
	/usr/sbin/ipset -F ip_$cfg 2>/dev/null
	#/usr/sbin/ipset -X ip_$cfg 2>/dev/null
fi

##### ian.20091211 remove dns record
sed -i "/#$cfg$/d" /var/resolv.conf.auto 2> /dev/null
sed -i "/#ipv6-$cfg$/d" /var/resolv.conf.auto 2> /dev/null

##### ian.20091126 marked script is for wifi and bridge only
#config_get iftype "$cfg" type
#config_get int "$cfg" int
##[ "$iftype" = "bridge" ] && brctl delbr "$ifname" >/dev/null 2>/dev/null
#[ "$iftype" = "bridge" ] && {
# brctl delbr "$ifname" >/dev/null 2>/dev/null
# deletedbr="$ifname"
# }
#for i in $int; do
#ifup $i >/dev/null 2>/dev/null
#[ "$i" = "wifi" ] && /sbin/wifi up >/dev/null 2>/dev/null
#done

#if [ -n "$deletedbr" ] ; then
##  echo "deletedbr=$deletedbr"
#  uci del bridge.general."del$deletedbr"
#  uci commit bridge
#fi
##### ian.20091126 end
[ "$caller" != "ifup" ] && {
	uci revert -P /var/state/ network.$1.ifdown_running
}
logger -p 160.5 "========== [$$] END ifdown $iface (called by $caller)"
