#!/bin/sh /etc/rc.common

. /etc/net6conf/6data.conf
. /usr/share/libubox/jshn.sh

export LEGACY=1
V6PLUS_PID=/var/run/v6plus.pid
V6PLUS_CONF_DIR=/tmp/v6plus
JP_NE_NETGEAR_TOKEN=$(echo $JP_NE_NETGEAR_TOKEN_ENC | openssl base64 -d)

generate_rand()
{
	local start_time=$1
	local end_time=$2
	local time_length=$((${end_time}-${start_time}))
	local randtime=$(awk 'BEGIN{srand(); print rand()*1000000}' | cut -d'.' -f1)
	local ret=$((${randtime}%${time_length}+$start_time))
	printf $ret
}

check_ntt_hgw()
{
	resolveip -6 -t 1 ntt.setup >/dev/null
	local have_ntt_hgw=$?
	if [ "$have_ntt_hgw" != "0" ]; then
		return 0
	fi
	killall udhcpc
	udhcpc -b -i $bridge_wan
	#waiting for lease
	sleep 6
	local ret=`curl -4 -X GET -w %{http_code} -o $V6PLUS_CONF_DIR/ntt_setup http://ntt.setup:8888/enabler.ipv4/check?callback=v6plus`
	if [ $ret -ne 200 ]; then
		return 0
	fi

	local status
	sed -i 's/^.*(\(.*\))$/\1/g' ${V6PLUS_CONF_DIR}/ntt_setup
	json_load "$(cat ${V6PLUS_CONF_DIR}/ntt_setup)"
	json_get_vars status
	json_cleanup
	if [ "$status" = "ON" ]; then
		return 1
	else
		return 0
	fi
}

setup_mape_tunnel()
{
	local RULE_DATA=$(cat $V6PLUS_CONF_DIR/map.rules)
	set $RULE_DATA
	RULE_DATA=$(mapcalc brwan $@)
	eval $RULE_DATA

	if [ -z "$RULE_BMR" ]; then
		echo "No Matching PD found"
		return 1
	fi

	local k=$RULE_BMR
	local ip4addr=$(eval "echo \$RULE_${k}_IPV4ADDR")
	local localip=$(eval "echo \$RULE_${k}_IPV6ADDR")
	local remote=$(eval "echo \$RULE_${k}_BR")
	local fmr=""

	for i in $(seq $RULE_COUNT); do
		[ "$(eval "echo \$RULE_${i}_FMR")" != 1 ] && continue
		if [ -z $fmr ]; then
			fmr="$(eval "echo \$RULE_${i}_IPV6PREFIX")/$(eval "echo \$RULE_${i}_PREFIX6LEN")"
		else
			fmr="$fmr|$(eval "echo \$RULE_${i}_IPV6PREFIX")/$(eval "echo \$RULE_${i}_PREFIX6LEN")"
		fi
		fmr="$fmr,$(eval "echo \$RULE_${i}_IPV4PREFIX")/$(eval "echo \$RULE_${i}_PREFIX4LEN")"
		fmr="$fmr,$(eval "echo \$RULE_${i}_EALEN"),$(eval "echo \$RULE_${i}_OFFSET")"
	done

	ip -6 tunnel addmape name map-e local $localip remote $remote fmrs "$fmr" dev $WAN draft03 1
	ip -6 addr add $localip dev map-e
	ip link set mtu 1460 dev map-e
	ip -4 addr add "$ip4addr/32" dev map-e
	ip link set map-e up
	ip -4 route del default
	ip route add default dev map-e

	#Handle the case that use same BMR with same ip but different port
	ip rule add table local prio 1
	ip rule del table local prio 0
	ip rule add to $ip4addr iif $bridge fwmark 0x100/0x100 table local prio 0
	ip rule add to $ip4addr iif $bridge table main prio 0

	/etc/scripts/firewall/v6plus.rule start

	/etc/init.d/ndppd.init stop
	/etc/init.d/ndppd.init start
	return 0
}

report_status()
{
	local reason=$1
	case $reason in
		"SUCCESS")
			curl -s -6 -k -i -X GET -o $V6PLUS_CONF_DIR/report "https://api.enabler.ne.jp/$JP_NE_NETGEAR_TOKEN/acct_report?callback=report10&action=1&reason=0&id=$(cat ${V6PLUS_CONF_DIR}/v6plus_id)" &
			;;
		"MISMATCH")
			curl -s -6 -k -i -X GET -o $V6PLUS_CONF_DIR/report "https://api.enabler.ne.jp/$JP_NE_NETGEAR_TOKEN/acct_report?callback=report23&action=2&reason=3&id=$(cat ${V6PLUS_CONF_DIR}/v6plus_id)" &
			;;
		"STOP")
			curl -s -6 -k -i -X GET -o $V6PLUS_CONF_DIR/report "https://api.enabler.ne.jp/$JP_NE_NETGEAR_TOKEN/acct_report?callback=report20&action=2&reason=0&id=$(cat ${V6PLUS_CONF_DIR}/v6plus_id)" &
			;;
	esac
}

tunnel_stop()
{
	local ip4addr=$(ifconfig map-e | awk '/inet addr/ {print $2}' | cut -f2 -d ":")
	ip -6 link set map-e down
	ip -6 tunnel del map-e

	#Handle the case that use same BMR with same ip but different port
	ip rule del table local prio 1
	if [ -z "$(ip rule list |grep "from all lookup local")" ]; then
		ip rule add table local prio 0
	fi
	if [ -n "$ip4addr" ]; then
		ip rule del to $ip4addr iif $bridge fwmark 0x100/0x100 table local
		ip rule del to $ip4addr iif $bridge table main
	fi
	/etc/scripts/firewall/v6plus.rule stop
	if [ "x$1" != "xSTOP_NO_REPORT" ]; then
		report_status STOP
	fi
}

stop()
{
	#if [ -f $V6PLUS_PID -a -n "$(cat $V6PLUS_PID)" ]; then
	#	kill -SIGTERM $(cat $V6PLUS_PID)
	#fi
	tunnel_stop
	pidof v6plus_client | sed -e "s/$$//g" | xargs kill
	rm -rf $V6PLUS_PID ${V6PLUS_CONF_DIR}/v6plus_id
}

parse_json_data()
{
	local wan_ip6addr=${1}
	local pd=$(6rdcalc "$wan_ip6addr" "0.0.0.0/32")
	pd=${pd%%/*}
	local BMR="type=map-e"
	local FMR=
	local dmr id ipv6_fixlen keys k ipv6 ipv4 psid_offset ea_length ip6prefix_calc

	json_load $(cat ${V6PLUS_CONF_DIR}/maprules)
	json_get_vars dmr id ipv6_fixlen
	[ -n "$dmr" ] && BMR="$BMR,br=$dmr"
	[ -n "$ipv6_fixlen" ] && BMR="$BMR,pdlen=$ipv6_fixlen"
	[ -n "$pd" ] && BMR="$BMR,pd=$pd"
	[ -n "$id" ] && echo "$id" > ${V6PLUS_CONF_DIR}/v6plus_id
	json_select fmr
	json_get_keys keys
	for k in $keys; do
		ip6prefix_calc=
		ipv6=
		ipv4=
		psid_offset=
		ea_length=
		json_select $k
		json_get_vars ipv6 ipv4 psid_offset ea_length
		ip6prefix_calc=$(6rdcalc "${wan_ip6addr%%/*}/${ipv6##*/}" "0.0.0.0/32")
		if [ "$ip6prefix_calc" = "$ipv6" ]; then
			BMR="$BMR,ipv6prefix=${ipv6%%/*},prefix6len=${ipv6##*/},ipv4prefix=${ipv4%%/*},prefix4len=${ipv4##*/},offset=$psid_offset,ealen=$ea_length,fmr=1"
		else
			FMR="type=map-e,ipv6prefix=${ipv6%%/*},prefix6len=${ipv6##*/},ipv4prefix=${ipv4%%/*},prefix4len=${ipv4##*/},offset=$psid_offset,ealen=$ea_length,fmr=1 "$FMR""
		fi
		json_select ..
	done
	json_select ..
	json_cleanup

	echo "$BMR $FMR" > $V6PLUS_CONF_DIR/map.rules
}

start()
{
	if [ "x`$CONFIG get ipv6_type`" != "xv6plus" ]; then
		echo "v6plus client: mape is not enabled"
		return
	fi

	[ ! -d $V6PLUS_CONF_DIR ] && mkdir -p $V6PLUS_CONF_DIR
	rm -rf $V6PLUS_CONF_DIR/*

	if [ -f $V6PLUS_PID ]; then
		echo "v6plus_client: v6plus client is running, kill it"
		#kill -SIGTERM $(cat $V6PLUS_PID)
		stop
	fi

	echo "$$" > $V6PLUS_PID
	echo "v6plus_client: v6client is going to start, save pid $$"

	local IPV6_ADDR=
	local ret
	local id
	local wait_time
	local HGW_status
	while [ 1 ]
	do
		wan_cable_type=`$CONFIG get wan_preference`
		if [ "x$wan_cable_type" = "x0" ]; then
			port_status=`cat /tmp/port_status | grep 0`
		else
			port_status=`cat /tmp/port_status | grep down`
		fi

		if [ -n "$port_status" ]; then
			echo "v6plus_client: WAN port is not up, sleep 10 and continue"
			sleep 10
			continue
		fi

		IPV6_ADDR=$(/sbin/ifconfig $WAN | awk '/Scope:Global/{print $3}');
		if [ -z $IPV6_ADDR ]; then
			#Continue if no get ipv6 address
			echo "v6plus_client: WAN has no ipv6 address, sleep 10s and continue"
			sleep 10 && rs_send -i $WAN && continue
		elif [ -z  $(/sbin/ifconfig $bridge | awk '/Scope:Global/{print $3}') ]; then
			#WAN has address obtained, need to call service reload for LAN, handle RA only topo
			/etc/net6conf/6service reload
		fi

		resolveip -6 api.enabler.ne.jp > /dev/null
		ret=$?
		if [ $ret -ne 0 ]; then
			echo "v6plus_client: Cannot access map rule server, sleep 10s and continue"
			sleep 10 && continue
		fi

		if [ -z "$HGW_status" ]; then
			check_ntt_hgw
			ret=$?
			if [ $ret -eq 1 ]; then
				#HGW has enabled v6plus
				exit
			else
				HGW_status=0
				killall udhcpc
			fi
		fi

		if [ "$($CONFIG get v6plus_qa)" = "1" ]; then
			ret=`curl -s -6 -k -X GET -w %{http_code} -o $V6PLUS_CONF_DIR/maprules "https://api.enabler.ne.jp/maprules"`
		else
			if [ -f ${V6PLUS_CONF_DIR}/v6plus_id ] && [ "x$(cat ${V6PLUS_CONF_DIR}/v6plus_id)" != "x" ]; then
				ret=`curl -s -6 -k -X GET -w %{http_code} -o $V6PLUS_CONF_DIR/maprules "https://api.enabler.ne.jp/$JP_NE_NETGEAR_TOKEN/get_rules?callback=v6plus&id=$(cat ${V6PLUS_CONF_DIR}/v6plus_id)"`
			else
				ret=`curl -s -6 -k -X GET -w %{http_code} -o $V6PLUS_CONF_DIR/maprules "https://api.enabler.ne.jp/$JP_NE_NETGEAR_TOKEN/get_rules?callback=v6plus"`
			fi
		fi

		#Sleep for 2s for wget finish
		sleep 2
		
		case $ret in
			403)
				#spec:403 Forbbiden, not JPNE, retry in 3-24h
				wait_time=$(generate_rand 10800 86400)
				[ -n "$(ifconfig map-e 2>&-)" ] && tunnel_stop
				sleep $wait_time
				continue
				;;
			200)
				id=
				#Extract json
				sed -i 's/^.*(\(.*\))$/\1/g' ${V6PLUS_CONF_DIR}/maprules
				json_load "$(cat ${V6PLUS_CONF_DIR}/maprules)"
				json_get_vars id
				json_cleanup
				if [ -z $id ]; then
					echo "v6plus_client: wget success with get_rules, but with invalid json data, sleep 10s and continue"
					wait_time=$(generate_rand 600 1800)
					[ -n "$(ifconfig map-e 2>&-)" ] && tunnel_stop
					sleep $wait_time
					continue
				else
					echo "v6plus_client: wget success with get_rules, with valid json, going to set up tunnel"
					parse_json_data $IPV6_ADDR
					[ -n "$(ifconfig map-e 2>&-)" ] && tunnel_stop STOP_NO_REPORT
					setup_mape_tunnel
					ret=$?
					if [ $ret = 1 ]; then
						echo "v6plus_client: setup tunnel failed with json, sleep 10-30 mins"
						report_status MISMATCH
						wait_time=$(generate_rand 600 1800)
						[ -n "$(ifconfig map-e 2>&-)" ] && tunnel_stop
						sleep $wait_time
						continue
					else
						echo "v6plus_client: Tunnel setup successfully, return OK to server"
						report_status SUCCESS
						wait_time=$(generate_rand 10800 86400)
						sleep $wait_time
					fi
				fi
				;;
			50*)
				wait_time=$(generate_rand 60 600)
				sleep $wait_time
				continue
				;;
			*)
				echo "v6plus_client: wget failed with get_rules, sleep 30s and try again"
				sleep 30
				continue
				;;
		esac

	done
}

