#!/bin/sh

. /etc/net6conf/6data.conf
TunnelName="6rd"

#For some project cannot use bc tool , so add dni_bc function 
dni_hex2bin()
{
	hex="0x$1"
	ten=`$ECHO $(($hex))`
	bin=""
	for i in `seq 4`
	do
		bin="$(($ten%2))$bin"
		ten=$(($ten/2))
	done
	$ECHO "$bin"

}

dni_hex2bin_transfer()
{
	local hex_num=$1
	i=1
	result=""
	while true
	do
		
		single_char=`$ECHO "$hex_num" |cut -c $i`
		if [ "x$single_char" = "x" ]; then
			$ECHO "hex2bin transfer finished!!!!!!" > /dev/console
			break
		else
		temp=`dni_hex2bin $single_char`
		result="$result$temp"
		i=$(($i+1))
		fi
	done
	final_result=`$ECHO "$result" |sed 's/^0*//g'`
	$ECHO "$final_result"
}

dni_bin2hex()
{
	bin=$1
	val=16
	for i in `seq 4`
	do
		val=$(($val/2))
		bit=`$ECHO "$bin" |cut -c $i`
		ten=$(($ten+$bit*$val))
	done
	if [ $ten -gt 9 ]; then
		case $ten in
			"10")hex="A"
				;;
			"11")hex="B"
				;;
			"12")hex="C"
				;;
			"13")hex="D"
				;;
			"14")hex="E"
				;;
			"15")hex="F"
				;;
		esac
	else
		hex=$ten
	fi
	$ECHO "$hex"
}
dni_bin2hex_transfer()
{
	bin=$1
	length=${#bin}
	len=$(($length%4))
	num=$(($length/4))
	if [ ! $len -eq 0 ]; then
		for i in `seq $len`
		do
			temp=`$ECHO "$bin" |cut -c $i`
			result="$result$temp"
		done
		for i in `seq $((4-$len))`
		do
			result="0$result"
		done
		final_result=`dni_bin2hex $result`
	fi
	bin=`$ECHO "$bin" |cut -c $(($len+1))-`
	if [ $num -gt 0 ]; then
		for i in `seq $num`
		do
			temp=`$ECHO "$bin" | cut -c 1-4`
			temp=`dni_bin2hex $temp`
			final_result="$final_result$temp"
			bin=`$ECHO "$bin" |cut -c 5-`
		done
	fi
	$ECHO "$final_result"
}


check_6rd_is_running() {
	if ifconfig $TunnelName >&- 2>&- ; then
		return 0
	else
		 return 1
	fi
}

# make ipv6 address to uppercase && rm :
to_upper()
{
	local prefix=$1
	local part1=`$ECHO $prefix|cut -f1 -d:`
	local part2=`$ECHO $prefix|cut -f2 -d:`
	local part3=`$ECHO $prefix|cut -f3 -d:`
	local part4=`$ECHO $prefix|cut -f4 -d:`

	[ "x$part2" = "x" ] && part2=0
	[ "x$part3" = "x" ] && part3=0
	[ "x$part4" = "x" ] && part4=0

	printf "%04X%04X%04X%04X" 0x$part1 0x$part2 0x$part3 0x$part4
}

# generate 64 bits hex digital from bin
bin2hex()
{
	local bin=`dni_bin2hex_transfer $1`
	local part1=`$ECHO $bin|cut -c 1-4`
	local part2=`$ECHO $bin|cut -c 5-8`
	local part3=`$ECHO $bin|cut -c 9-12`
	local part4=`$ECHO $bin|cut -c 13-16`

	printf $part1:$part2:$part3:$part4::
}

# the first digital by use bc to change from hex to bin needs to supply.
supply()
{
	local new_prefix=$1
	local ch=$2

	if [ "$ch" = "0" ] ;then
		new_prefix="0000$new_prefix"
	elif [ "$ch" = "1" ] ;then
		new_prefix="000$new_prefix"
	elif [ "$ch" = "2" ] || [ "$ch" = "3" ] ;then
		new_prefix="00$new_prefix"
	elif [ "$ch" = 4 ] || [ "$ch" = 5 ] || [ "$ch" = 6 ] || [ "$ch" = 7 ] ;then
		new_prefix="0$new_prefix"
	fi
	printf $new_prefix
}

#printf '%x' $num2
generate_6rd_prefix()
{
	local prefix=$1
	local plen=$2
	local zero=0

	prefix=`$ECHO $prefix|cut -c -$plen`
	local i=$((64 - $plen))
	while [ $i -gt 0 ]; do
		prefix="$prefix$zero"
		i=$(($i - 1))
	done
	prefix=$(bin2hex $prefix)
	new_6rd_prefix="$prefix"
	$ECHO "generate_6rd_prefix:$new_6rd_prefix"
}

# to gererate 6rd prefix according to rfc5969.
# use 6rd.prefix:ipv4address
generate_6rd_v4_prefix()
{
	local prefix=$1
	local plen=$2
	local ip4=$3
	local len4=$((32 - $4))

	local ch=`$ECHO $prefix|cut -c -1`
	prefix=$(to_upper $prefix)
	$ECHO "after upper:$prefix"
	local new_prefix=`dni_hex2bin_transfer $prefix`
	$ECHO "after to 16:$new_prefix"
	new_prefix=$(supply $new_prefix $ch)

	generate_6rd_prefix $new_prefix $plen

	new_prefix=`$ECHO $new_prefix|cut -c -$plen`
	$ECHO "get new_prefix:$new_prefix"

	local new_ip=`printf '%02X%02X%02X%02X' $($ECHO $ip4| sed 's/\./ /g')`
	$ECHO "ip hex:$new_ip"
	ch=`$ECHO $new_ip|cut -c -1`
	new_ip=`dni_hex2bin_transfer $new_ip`
	new_ip=$(supply $new_ip $ch)
	$ECHO "new ip:$new_ip"
	new_ip=`$ECHO $new_ip|cut -c $(($4 + 1))-`

	local new_prefix2="$new_prefix$new_ip"
	local total_len=$(($len4 + $plen))
	local zero=0
	if [ $total_len -le 64 ] ;then
		local i=$((64 - $total_len))
		while [ $i -gt 0 ]; do
			new_prefix2="$new_prefix2$zero"
			i=$(($i - 1))
		done
	else
		new_prefix2=`$ECHO $new_prefix2|cut -c -64`
	fi
	$ECHO "to gen64:$new_prefix2"
	new_6rd_v4_prefix=$(bin2hex $new_prefix2)
	$ECHO "get final:$new_6rd_v4_prefix"
}

# $1: 2001
#     2001:1
#     2001:1:2
#     2001:1:2:3
# $2: cafe:1234
# $3: 1:2:3:4
# count: ":" number of $1
generate_6rd_ip()
{
	local eui=$1
	local new_6rd_ip=`$ECHO $new_6rd_v4_prefix|sed 's/:://g'`

	new_6rd_ip="$new_6rd_ip:$eui"
	printf $new_6rd_ip
}

start() {
	if check_6rd_is_running; then
		$ECHO "6rd function is already running"
		return 0
	fi
	[ "$wan6_type" != "6rd" ] && [ "$wan6_type" != "autoDetect" ] && return

	[ "x$Mask" = "x" ] && Mask=0
	if [ "$wan6_type" = "autoDetect" ]; then
		Ipv66rdPrefix=`$CONFIG get Ipv6rdPrefixDynamic`
		Ipv66rdPrefixlen=`$CONFIG get Ipv6rdPlenDynamic`
		gw=`$CONFIG get Ipv6rdRelayDynamic`
		Mask=`$CONFIG get Ipv6rdv4MaskDynamic`
	fi

	$ECHO "Enabling IPv6RD Tunneling.." > /dev/console
	LocalIp=`ifconfig $WAN4 | grep 'inet addr' | cut -d':' -f 2|cut -d' ' -f 1`
	[ "x${LocalIp}" = "x" ]	&& return
	ValidIp=`$ECHO "$LocalIp" | grep '^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$'`
	if [ ! "${ValidIp}" ]; then
		$ECHO "Local IP=$LocalIp is invalid"
		exit 
	fi

	localip_t1=`printf '%02x%02x:%02x%02x' $($ECHO $LocalIp | sed 's/\./ /g')`
	generate_6rd_v4_prefix $Ipv66rdPrefix $Ipv66rdPrefixlen $LocalIp $Mask

	wanlinkip=$(ifconfig $bridge | grep "fe80" | awk '{print $3}' | awk -F/ '{print $1}')
	eui64=$(geteui64 $wanlinkip)
	localip=$(generate_6rd_ip $eui64)
	$ECHO "got localip: $localip" > /dev/console

	$IP addr add $localip/64 dev $bridge
	$IP tunnel add $TunnelName mode sit local $LocalIp ttl 64
	$IP tunnel 6rd dev $TunnelName 6rd-prefix $new_6rd_prefix/$Ipv66rdPrefixlen
	$IP tunnel 6rd dev $TunnelName 6rd-relay_prefix $gw/$Mask
	$IP addr add $localip/$Ipv66rdPrefixlen dev $TunnelName
	$IP link set $TunnelName up
	$IP -6 route add ::/0 via ::$gw dev $TunnelName

	# turn off the "Do Not Fragment" flag
	$ECHO 1 > /proc/sys/net/ipv6/ipv6_6to4_force_ip4fragoff_zero

	$CONFIG set ipv6_6rd_prefix=$new_6rd_v4_prefix
	$CONFIG set ipv6_6rd_prelen=64
}

stop_6rd() {
	$ECHO "Disabling IPv6RD Tunneling.." > /dev/console
	ifconfig $TunnelName down
	$IP tunnel del $TunnelName 2>/dev/null
	$CONFIG set ipv6_6rd_prefix=
	$CONFIG set ipv6_6rd_prelen=
}

stop() {
	check_6rd_is_running && stop_6rd
}

restart() {
	stop
	start
}

case "$1" in
	start)
	start
	;;
	stop)
	stop
	;;
	restart)
	restart
	;;
esac

