#!/bin/sh
#source /lib/network/ppp.sh
#source /lib/network/pppoe.sh

#input parameters
pppX="$1"         #ppp0
phy_if="$2"       #eth2.10
iface="$6"        #wan1
ifname=wan-$iface #wan-wan1
sla_lans="$7"     #lan1,lan2,lan3,... which sla_wan=$iface
speed="$3"
loc_addr6="$4"
rem_addr6="$5"

#define macro
LOCK=/tmp/lock_ipv6-up_$iface
RETRY_CNT_FILE=/tmp/pppd_retry_$iface
MAX_RETRY_CNT=3
UPTIME=`cat /proc/uptime |cut -d. -f1`

#Purpose of this script:
# 1) set default gateway6
# 2) if PPP mode -> start FSM and write json

# Debug functions----------------------------------------------------------------
DBG_LOG() {
	logger "[$0][`date +%Y/%m/%d-%H:%M:%S`] $1"
	#echo "[`date +%Y/%m/%d-%H:%M:%S`][UP] $1" > /dev/console
	#echo "[`date +%Y/%m/%d-%H:%M:%S`][UP] $1" >> /tmp/dbg_log/ipv6-$iface.log
	return
}

DBG_PRINT() {
	#echo "[`date +%Y/%m/%d-%H:%M:%S`][UP] $1" > /dev/console
	#echo "[`date +%Y/%m/%d-%H:%M:%S`][UP] $1" >> /tmp/dbg_log/ipv6-$iface.log
	return
}
#--------------------------------------------------------------------------------

# FUNCTIONS --------------------
dhcp6c_start() {
	rm -f /var/run/dhcp6c-$iface.pid
	cat > /var/dhcp6c_$iface.conf << EOF
interface $ifname {
    send ia-pd 0;
    script "/etc/dhcp6/dhcp6c.script";
    request domain-name-servers, domain-name;
};

id-assoc pd 0 {
    prefix-interface lo {
        sla-id 0;
    };
};

EOF
	DBG_PRINT "dhcp6c -c /var/dhcp6c_$iface.conf -D -p /var/run/dhcp6c-$iface.pid $ifname"
	/usr/sbin/dhcp6c -c /var/dhcp6c_$iface.conf -D -p /var/run/dhcp6c-$iface.pid $ifname
}

dhcp6c_stop() {
	DBG_PRINT "dhcp6c_stop()"
	if [ -e /var/run/dhcp6c-$iface.pid ]; then
		dhcp6c_pid=$(cat /var/run/dhcp6c-$iface.pid)
		DBG_PRINT "kill dhcp6c $dhcp6c_pid"
		kill -9 $dhcp6c_pid 2>/dev/null
	else
		DBG_PRINT "no dhcp6c-$iface.pid to kill"
	fi
	rm -f /var/dhcp6c_$iface.conf
}

waiting_for_dhcp6_prefix() {
	timeout=15 #wait dhcp6c start
	while [ $timeout -gt 0 ]; do
		[ -e /var/run/dhcp6c-$iface.pid ] && break
		DBG_PRINT "wait dhcp6c-$iface, cnt down $timeout..."
		sleep 1
		timeout=$(($timeout - 1))
	done

	timeout=45 #seconds
	while [ $timeout -gt 0 ]; do
		sleep 2
		timeout=$(($timeout - 2))
		[ "`ifconfig $ifname |grep Scope:Global`" ] || continue
		prefix=`json get network.$iface.iapd`
		[ "$prefix" ] && {
			ip6link=`/usr/sbin/ip -6 addr show $ifname |grep link |sed -e "s/^.*inet6 //" -e "s/ scope.*\$//"`
			DBG_PRINT "timeout=$timeout. json set network.$iface proto6=ppp connectio6=up ip6linkip=$ip6link"
			json set network.$iface proto6=ppp connectio6=up ip6linkip=$ip6link
			break
		}
	done
}

send_out_rs() {
	DBG_PRINT "send_out_rs() from $ifname"
	/usr/sbin/pktgen -s $ifname
	return
}

waiting_kernel_parse_ra() {
	DBG_PRINT "Start waiting_kernel_parse_ra()"
	timeout=30 #seconds
	while [ $timeout -gt 0 ]; do
		sleep 2
		prefix=`/usr/sbin/ip -6 route show |grep $ifname |grep -vE "fe80::|default" |sed -e "s/ dev.*\$//"`
		[ "$prefix" ] && {
			/usr/sbin/ip -6 route del $prefix dev $ifname
			ip6link=`/usr/sbin/ip -6 addr show $ifname |grep link |sed -e "s/^.*inet6 //" -e "s/ scope.*\$//"`
			ip6addr=`/usr/sbin/ip -6 addr show $ifname |grep global |sed -e "s/^.*inet6 //" -e "s/ scope.*\$//"`
			DBG_PRINT "Get prefix:$prefix. timeout=$timeout"
			DBG_PRINT "json set network.$iface proto6=icmp_ra connectio6=up ip6linkip=$ip6link ip6addr=$ip6addr gateway6=$rem_addr6 dns6= iapd=$prefix"
			json set network.$iface proto6=icmp_ra connectio6=up ip6linkip=$ip6link ip6addr=$ip6addr gateway6=$rem_addr6 dns6= iapd=$prefix iapd_vltime=86400 iapd_pltime=86400
			/etc/init.d/lb_pool reset v6 $iface

			#ICMP : set src routing to ip rule
			ITF_BASE_ID=`/usr/sbin/iprule_idx.sh iface`
			ipr_id=$(($ITF_BASE_ID + $tid))
			while [ "`/usr/sbin/ip -6 rule |grep $ipr_id`" ]; do
				/usr/sbin/ip -6 rule del pref $ipr_id
			done
			/usr/sbin/ip -6 rule add pref $ipr_id from `echo $ip6addr |sed 's/\/.*//g'` table $tid
			break
		}
		timeout=$(($timeout - 2))
	done
}

#ifup_related_lan() {
#	config_get status $1 status
#	[ "$status" == "enable" ] || return
#
#	config_get proto6 $1 proto6
#	[ "$proto6" == "dhcp-sla" ] || return
#
#	config_get sla_wan $1 dhcp6_sla_wan
#	[ "$sla_wan" == $iface ] || return
#
#	#echo "[$0] re-ifup $1" > /dev/console
#	/sbin/ifup $1
#}

get_retry_cnt() {
	retry_cnt=`cat $RETRY_CNT_FILE 2>/dev/null` || retry_cnt=0
	retry_cnt=`expr $retry_cnt + 1`
	echo $retry_cnt > $RETRY_CNT_FILE
}

do_exit() {
	rm -f $RETRY_CNT_FILE
	DBG_PRINT "END-- $LOCK"
	rm -f $LOCK
	exit 0
}
#-------------------------------

#For debug: show basic info.
DBG_PRINT "@  pppX:$pppX phy_if:$phy_if iface:$iface ifname:$ifname"
DBG_PRINT "@  loc_addr6:$loc_addr6 rem_addr6:$rem_addr6"
DBG_PRINT "@  speed:$speed uptime:$UPTIME sla_lans:$sla_lans"

# FSM
# ipv6-up               +-(got prefix)-->-------->-------->---+-(gotRA)-----> end (success)
#   |                   |                                     |
#   +-> A)start dhcp6c -+-(45s)-> B)stop dhcp6c -> C)sendRS -+-(30s)------|---------+-> end (failed)
#   |                                                                     |         |
#   +----<--------<--------<--------<--------<--------<--(loop*3)---------+---------+-> D)restart pppd (up to 2 times)

#Set default gateway6
if [ -f $LOCK ]; then
	/bin/ps |grep ipv6-up |grep $phy_if > ${LOCK}_$UPTIME
	num=`cat ${LOCK}_$UPTIME |wc |awk '{print $1}'`
	rm -f ${LOCK}_$UPTIME
	if [ $num -gt 1 ]; then
		DBG_PRINT "!! $LOCK -> exit (num=$num)"
		exit 0
	fi
fi
touch $LOCK
DBG_PRINT "----- $LOCK"
sleep 10 #other script run previously
tid=`get_route_table_id $iface`
/usr/sbin/ip -6 route flush table $tid

#if PPP mode -> start FSM
proto4=`uci get network.$iface.proto`
proto6=`uci get network.$iface.proto6`
DBG_PRINT "proto4:$proto4 proto6:$proto6"
[ "$proto6" -a "$proto6" != "link-local" ] && {
	DBG_PRINT "ip -6 route add table $tid default via $rem_addr6 dev $ifname"
	/usr/sbin/ip -6 route add table $tid default via $rem_addr6 dev $ifname
	DBG_PRINT "json set network.$iface gateway6=$rem_addr6"
	json set network.$iface gateway6=$rem_addr6
}

[ "$proto4" == "pppoe" -a "$proto6" == "ppp" ] && {
	#A) try dhcp iapd (15s)
	dhcp6c_start
	waiting_for_dhcp6_prefix
	DBG_LOG "$iface DHCP6C get prefix: $prefix"
	[ "$prefix" ] && do_exit
	dhcp6c_stop #B)

	#C) try icmp ra
	/usr/sbin/ip6tables -A ACC6_CTRL -i wan+ -p icmpv6 --icmpv6-type 134 -j ACCEPT
	echo 0 > /proc/sys/net/ipv6/conf/$ifname/forwarding
	send_out_rs
	waiting_kernel_parse_ra
	echo 1 > /proc/sys/net/ipv6/conf/$ifname/forwarding
	/usr/sbin/ip6tables -D ACC6_CTRL -i wan+ -p icmpv6 --icmpv6-type 134 -j ACCEPT
	DBG_LOG "$iface icmpv6 RS get prefix: $prefix"
	[ "$prefix" ] && {
		#. /etc/functions.sh
		#config_load network
		#config_foreach ifup_related_lan
		/usr/sbin/restart_lan_ipv6.sh ipv6-up $iface $prefix
		do_exit
	}

	#Set connection down
	ip6link=`/usr/sbin/ip -6 addr show $ifname |grep link |sed -e "s/^.*inet6 //" -e "s/ scope.*\$//"`
	DBG_PRINT "json set network.$iface proto6=ppp connectio6=down ip6linkip=$ip6link ip6addr= gateway6= dns6="
	json set network.$iface proto6=ppp connectio6=down ip6linkip=$ip6link ip6addr= gateway6= dns6=
	for lan in $sla_lans ; do
		ip6addr=`/usr/sbin/ip -6 addr show lan-$lan |grep global |sed -e "s/^.*inet6 //" -e "s/ scope.*\$//"`
		if [ "$ip6addr" ]; then
			for ipa in $ip6addr ; do
				DBG_PRINT "ip -6 addr del $ipa dev lan-$lan"
				/usr/sbin/ip -6 addr del $ipa dev lan-$lan
			done
			/sbin/ifup $lan
		fi
	done	

	#D) dhcp and icmp both failed, try restart pppd
	get_retry_cnt
	DBG_LOG "$iface fails to get prefix, retry_cnt:$retry_cnt"
	[ $retry_cnt -ge $MAX_RETRY_CNT ] && do_exit
	wtime=$(($retry_cnt * 30))
	DBG_PRINT "sleep for $wtime ..."
	sleep $wtime
	pppd_pid=$(cat /var/run/$pppX.pid)
	DBG_PRINT "kill $pppX : pppd($pppd_pid)"
	kill -9 $pppd_pid 2>/dev/null
	#setup_interface_pppoe $phy_if $iface pppoe wcd
	#reconnect seq cannot be execute because up seq is not done yet
	#kill pppd and wait 30s to auto reconnect
}
DBG_PRINT "END-- $LOCK"
rm -f $LOCK
