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

#input parameters
script="$0"       #/etc/ppp/ipv6-up
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

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

# FUNCTIONS --------------------
dhcp6c_start() {
	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
	#echo "[$0] /usr/sbin/dhcp6c -c /var/dhcp6c_$iface.conf -D -p /var/run/dhcp6c-$iface.pid $ifname" > /dev/console
	/usr/sbin/dhcp6c -c /var/dhcp6c_$iface.conf -D -p /var/run/dhcp6c-$iface.pid $ifname
}

dhcp6c_stop() {
	#echo "[$0] dhcp6c_stop()" > /dev/console
	[ -e "/var/run/dhcp6c-$iface.pid" ] && {
		dhcp6c_pid=$(cat /var/run/dhcp6c-$iface.pid)
		#echo "kill $pppX : dhcp6c($dhcp6c_pid)" >/dev/console
		kill -9 $dhcp6c_pid 2>/dev/null
	} || {
		dummy_line=
		#echo "no dhcp6c-$iface.pid" >/dev/console
	}
	#killall dhcp6c 2>/dev/null
	[ -e "/var/dhcp6c_$iface.conf" ] && {
		rm /var/dhcp6c_$iface.conf 
	} || {
		dummy_line=
		#echo "no dhcp6c_$iface.conf" >/dev/console
	}
}

waiting_for_dhcp6_prefix() {
	timeout=15 #seconds
	while [ $timeout -ge 0 ]; do
		sleep 1
		timeout=`expr $timeout - 1`
		[ "`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.*\$//"`
			json set network.$iface proto6=ppp ip6linkip=$ip6link
			break
		}
	done
}

send_out_rs() {
	#echo "[$0] send_out_rs() from $ifname" > /dev/console
	/usr/sbin/pktgen -s $ifname
	return
}

waiting_kernel_parse_ra() {
	timeout=15 #seconds
	while [ $timeout -ge 0 ]; do
		sleep 1
		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.*\$//"`
			#echo "[$0] json set network.$iface proto6=icmp_ra ip6linkip=$ip6link ip6addr=$ip6addr gateway6=$rem_addr6 dns6= iapd=$prefix iapd_vltime=86400 iapd_pltime=86400" > /dev/console
			json set network.$iface proto6=icmp_ra ip6linkip=$ip6link ip6addr=$ip6addr gateway6=$rem_addr6 dns6= iapd=$prefix iapd_vltime=86400 iapd_pltime=86400
			break
		}
		timeout=`expr $timeout - 1`
	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
	rm -f $LOCK
	exit 0
}
#-------------------------------

#For debug: show basic info.
#echo "!!-> EXECUTE $script" > /dev/console
#echo "pppX: $pppX, phy_if: $phy_if, iface: $iface, ifname: $ifname" > /dev/console
#echo "loc_addr6: $loc_addr6, rem_addr6: $rem_addr6, speed: $speed" > /dev/console
#echo "sla_lans: $sla_lans" > /dev/console

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

#Set default gateway6
[ -f $LOCK ] && exit 0
touch $LOCK
sleep 10 #other script run previously
tid=`get_route_table_id $iface`
/usr/sbin/ip -6 route flush table $tid

#For debug: check gateway6
#kt1=`/usr/sbin/ip -6 route show table 1`
#echo "[$0] check d-route: $kt1" > /dev/console

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

[ "$proto4" == "pppoe" -a "$proto6" == "ppp" ] && {
	#echo "start dhcp6c($iface)" > /dev/console
	#A) try dhcp iapd (15s)
	dhcp6c_start
	waiting_for_dhcp6_prefix
	logger "[$0] 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
	logger "[$0] 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
	}

	#D) dhcp and icmp both failed, try restart pppd
	get_retry_cnt
	logger "[$0] fails to get prefix, retry_cnt: $retry_cnt"
	[ $retry_cnt -ge $MAX_RETRY_CNT ] && do_exit
	wtime=$(($retry_cnt * 30))
	sleep $wtime
	pppd_pid=$(cat /var/run/$pppX.pid)
	#echo "kill $pppX : pppd($pppd_pid)" >/dev/console
	kill -9 $pppd_pid 2>/dev/null
	#killall pppd 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
}
rm -f $LOCK
