# Configure radvd

set_eui64_prefix() {
	IFACE=${1}
	ORIG_IFS=${IFS}
	IFS=:
	m=($(cat /sys/class/net/${IFACE}/address))
	IFS=${ORIG_IFS}

	/sbin/ip -6 addr change $(printf "%s%x:%x:%x:%x" ${2} $((((0x${m[0]} ^ 2) << 8) + 0x${m[1]}))  0x${m[2]}ff 0xfe${m[3]} 0x${m[4]}${m[5]})/64 dev ${1} valid_lft ${3} preferred_lft ${4} mngtmpaddr 2>/dev/null || :
}

route_config() {
	vlanid=${interface:5}
	if  [ "$interface" == "eth0" ];then
		metric=12
		table=100
	elif [ "$interface" == "wlan0" ];then
		metric=52
		table=200
	elif [ "$interface" == "usb0" ];then
		metric=992
		table=400
	elif [ "$interface" == "bnep0" ];then
		metric=245
		table=50
	elif [ "${interface:0:4}" == "eth0" ] && [ ${vlanid} -gt 0 ] && [ ${vlanid} -lt 4097 ];then
		if [ -e /etc/default/vlan_${vlanid} ];then
			source /etc/default/vlan_${vlanid}
		else
			echo "No VLAN config found for ${interface}" && exit 0
		fi
		table=$(($vlanid + 10000))
		metric=$((101 + (2 * ${METRIC})))
	fi;

	if [[ -n "${1}" && "${1}" == "0" ]];then
		while /sbin/ip -6 rule del prio ${table} >/dev/null 2>&1;do :;done
		/sbin/ip -6 rule add prio ${table} oif ${interface} table ${table}
		/sbin/ip -6 route flush proto ra  table ${table} >/dev/null 2>&1 | :
		return 0;
	fi;
}

fixup_pre() {
	ORIG_IFS=${IFS}
	IFS=:;
	pre_a=(${1})
	IFS=${ORIG_IFS}

	if [ ! "${pre_a[3]}" ];then
		pre_a[3]=0
	fi

	if [ ! "${pre_a[2]}" ];then
		pre_a[2]=0
	fi

	if [ ! "${pre_a[1]}" ];then
		pre_a[1]=0
	fi

	printf "%x:%x:%x:%x::/64" 0x${pre_a[0]} 0x${pre_a[1]} 0x${pre_a[2]} $((0x${pre_a[3]} + ${2}))
}

setup_interface() {
	ORIG_IFS=${IFS}
	IFS=/
	sn=(${2})
	IFS=${ORIG_IFS}

	eval $(ipcalc -p -n ${2})
	eval $(dhcpcd -U ${dhcpcd_iface} 2>/dev/null)

	case ${1} in
		eth0.*)
			if [ -e /etc/default/vlan_${interface:5} ];then
				source /etc/default/vlan_${interface:5}
			fi;
		;;
		wlan[01])
			if [ -e /etc/default/wifi ];then
				source /etc/default/wifi
			fi;
		;;
		eth0)
			if [ -e /etc/default/static ];then
				source /etc/default/static
			fi;
		;;
	esac

	if [[ -n "${IPV6PDSUF}" && "${IPV6PDSUF}" != "0" && "${IPV6PDSUF}" != "-1" && "${NETWORK:0:-2}${IPV6PDSUF}" =~ .*:.*:.*:.* ]]; then
		/sbin/ip -6 addr change ${NETWORK:0:-2}${IPV6PDSUF}/128 dev ${1} valid_lft ${dhcp6_ia_pd1_prefix1_vltime} preferred_lft ${dhcp6_ia_pd1_prefix1_pltime} >/dev/null 2>&1 || :
	fi;

	set_eui64_prefix ${1} ${NETWORK:0:-1} ${dhcp6_ia_pd1_prefix1_vltime} ${dhcp6_ia_pd1_prefix1_pltime}
	if [[ -e /run/dhcpcd-${1}.pid && /var/db/dhcpcd/${1}.lease6 && -e /run/netconf/dhcpcd_eth0.conf ]];then
		(/usr/sbin/dhcpcd -x ${1}
		rm /var/db/dhcpcd/${1}.lease6
		/usr/sbin/dhcpcd -b -f /run/netconf/dhcpcd_eth0.conf ${1}) >/dev/null 2>&1 || :
	fi
}

remove_snet_ip() {
	ORIG_IFS=${IFS}
	IFS=:
	sn=(${1})
	IFS=${ORIG_IFS}

	if [ "${sn[3]}" ];then
		sn[3]=$((0x${sn[3]} + ${2}))
	else
		sn[3]=${2}
	fi
	PREFIX=$(printf "%s:%s:%s:%x:" ${sn[0]} ${sn[1]} ${sn[2]} ${sn[3]})

	/sbin/ip -6 -s -o addr show scope global |grep ${PREFIX} |awk '{printf "ip addr del %s dev %s\n", $4, $2}'  |sh
	/sbin/ip -6 rule del from ${1}/$((${3}+${2})) >/dev/null 2>&1
}

cleanup_subnet() {
	SUBNETS=$((( 2 << (64 - ${2} -1))))

	route_config 1

	SNET=0
	while [ "${SNET}" -lt "${SUBNETS}" ];do
		remove_snet_ip ${1} ${SNET} ${2}
		SNET=$((${SNET} + 1))
	done;
}

foreach_ia_na() {
	route_config 1

	cnt=1

	while true;do
		ia_na=dhcp6_ia_na1_ia_addr${cnt}
		old_ia_na=old_${ia_na}
		new_ia_na=new_${ia_na}
		vltime=new_${ia_na}_vltime
		pltime=new_${ia_na}_pltime


		if [[ -z "${!new_ia_na}" && -z "${!old_ia_na}" ]];then
			break;
		fi;

		if [ "${1}" == "0" ];then
			if [ -n "${!old_ia_na}" ];then
				/sbin/ip -6 addr del ${!old_ia_na}/128 dev ${interface} > /dev/null 2>&1 || :
			fi;
		elif [[ -n "${!new_ia_na}" || -n ${!old_ia_na} ]];then
			rt_info="${!new_ia_na} dev ${interface} proto dhcp metric ${metric} table ${table}"
			if [[ -n "${!old_ia_na}" && "${!old_ia_na}" != "${!new_ia_na}" ]];then
				/sbin/ip -6 addr del ${!old_ia_na}/128 dev ${interface} > /dev/null 2>&1 || :
				/sbin/ip -6 rule del prio ${table} from ${!new_ia_na}/128 table ${table} >/dev/null 2>&1 || :
				/sbin/ip -6 route del ${rt_info} >/dev/null 2>&1 || :
			fi;
			if [ -n "${!new_ia_na}" ];then
				if [[ "${!vltime}" == "0" || "${!pltime}" == "0" ]];then
					/sbin/ip -6 addr change ${!new_ia_na}/128 dev ${interface} valid_lft ${new_dhcp6_ia_pd1_prefix1_vltime} preferred_lft ${new_dhcp6_ia_pd1_prefix1_pltime}
					/sbin/ip -6 route replace ${rt_info} expires ${new_dhcp6_ia_pd1_prefix1_vltime} >/dev/null 2>&1 || :
				else
					/sbin/ip -6 addr change ${!new_ia_na}/128 dev ${interface} valid_lft ${!vltime} preferred_lft ${!pltime}
					/sbin/ip -6 route replace ${rt_info} expires ${!vltime} >/dev/null 2>&1 || :
				fi
				if [ -z "$(/sbin/ip -6 rule show prio ${table} from ${!new_ia_na}/128 table ${table})" ];then
					/sbin/ip -6 rule add prio ${table} from ${!new_ia_na}/128 table ${table}
				fi

			fi
		fi;

		cnt=$(($cnt+1))
	done

}

handle_routeradvert() {
	route_config 1

	cnt=1
	while true;do
		pref=nd1_prefix_information${cnt}

		cpref=${pref}_prefix
		clen=${pref}_length
		flag=${pref}_flags

		cnt=$(($cnt+1))

		if [[ -z "${!cpref}" || -z "${!flag}" || "${!flag}" != "LA" ]];then
			break;
		fi;

		expire=${pref}_vltime
		prefer=${pref}_pltime

		rt_info="${!cpref}/${!clen} dev ${interface} proto ra metric ${metric} table ${table}"

		if [ "${!expire}" == "0" ];then
			/sbin/ip -6 rule del prio ${table} from ${!cpref}/${!clen} table ${table}
			/sbin/ip -6 route del ${rt_info}
			continue;
		elif [ -z "$(/sbin/ip -6 rule show prio ${table} from ${!cpref}/${!clen} table ${table})" ];then
			/sbin/ip -6 rule add prio ${table} from ${!cpref}/${!clen} table ${table}
		fi;
		/sbin/ip -6 route replace ${rt_info} expires ${!expire} >/dev/null 2>&1 || :

		set_eui64_prefix ${interface} ${!cpref:0:-1} ${!expire} ${!prefer}
	done;
	/sbin/ip -6 route add default via ${nd1_from} dev ${interface} proto ra metric ${metric} table ${table} >/dev/null 2>&1 || :
	/sbin/ip -6 route add fe80::/64 dev ${interface} proto kernel metric ${metric} table ${table} >/dev/null 2>&1 || :
	if [ -z "$(/sbin/ip -6 rule show prio ${table} oif ${interface} table ${table})" ];then
		/sbin/ip -6 rule add prio ${table} oif ${interface} table ${table}
	fi
}

case "$reason" in
REBIND6|BOUND6|REBOOT6)
		foreach_ia_na 1
		if [ -z "${old_dhcp6_ia_pd1_prefix1}" ] ||  [ "${old_dhcp6_ia_pd1_prefix1}" != "${new_dhcp6_ia_pd1_prefix1}" ];then
			echo "Restart radvd ($reason}"
			/etc/init.d/netconf radvd
		fi;
	;;
RECONFIGURE|EXPIRE6)
		echo "${reason} OLD PRE ${old_dhcp6_ia_pd1_prefix1} NEW ${new_dhcp6_ia_pd1_prefix1}"
#		if [ -z "${old_dhcp6_ia_pd1_prefix1}" ] ||  [ "${old_dhcp6_ia_pd1_prefix1}" != "${new_dhcp6_ia_pd1_prefix1}" ];then
#			echo "Restart radvd ($reason}"
#			/etc/init.d/netconf radvd
#		fi;
	;;
RELEASE6)
		if [[ -n "${old_dhcp6_ia_pd1_prefix1}" && -n "${old_dhcp6_ia_pd1_prefix1_length}" ]];then
			cleanup_subnet ${old_dhcp6_ia_pd1_prefix1} ${old_dhcp6_ia_pd1_prefix1_length}
			echo "Restart radvd ($reason}"
			/etc/init.d/netconf radvd
		fi;
	;;
STOP6|TIMEOUT|STOPPED)
		foreach_ia_na 0
		/etc/init.d/netconf radvd
	;;
DELEGATED6)
		setup_interface ${interface} ${new_delegated_dhcp6_prefix}
	;;
DEPARTED)
		echo "${reason} OLD PRE ${old_dhcp6_ia_pd1_prefix1} NEW ${new_dhcp6_ia_pd1_prefix1}"
		foreach_ia_na 0
		echo "Restart radvd ($reason}"
		/etc/init.d/netconf radvd
	;;
ROUTERADVERT)
#		printenv
		handle_routeradvert 1
	;;
esac
