#!/bin/sh
#
#	@author Forrest Lin
#

TMPFILE=/tmp/dhcp6s.conf.$$
CONFILE=/tmp/dhcp6s.conf
PIDFILE=/var/run/dhcp6s.pid
KEYFILE=/sbin/dhcp6ctlkey
LOCKFILE=/var/run/dhcp6s.lock

# Primitives
usage() {
	echo "Usage: $0 {start|stop|reload|ipup|ipchg|ipdown|trans}"
}

lock() {
	set -o noclobber
	while ! echo PID $$ @ $(date) > ${LOCKFILE} ; do
		sleep 1
	done
	set +o noclobber        
}

unlock() {
	rm -f ${LOCKFILE} > /dev/null 2>&1
}

trans() {
	#
	# Configuration
	#
	eval `sncfg mget LanIf6 WanIf6 \
DHCP6S_DNS_MODE DHCP6S_DNS_NUM DHCP6S_DNS DHCP6S_DOMAIN_NUM DHCP6S_DOMAIN \
DHCP6S_NTP_NUM DHCP6S_NTP \
DHCP6S_SIP_NUM DHCP6S_SIP DHCP6S_SIP_DOMAIN_NUM DHCP6S_SIP_DOMAIN \
DHCP6S_NIS_NUM DHCP6S_NIS DHCP6S_NIS_DOMAIN_NUM DHCP6S_NIS_DOMAIN \
DHCP6S_NISP_NUM DHCP6S_NISP DHCP6S_NISP_DOMAIN_NUM DHCP6S_NISP_DOMAIN \
DHCP6S_REFRESH_TIME DHCP6S_RAPID_COMMIT DHCP6S_PREFERENCE \
DHCP6S_ADDRESS_POOL_NUM DHCP6S_ADDRESS_POOL \
DHCP6S_HOST_NUM DHCP6S_HOST \
DHCP6S_ASSIGNED_ADDRESS_NUM DHCP6S_ASSIGNED_ADDRESS \
DHCP6S_DELIGATED_PREFIX_NUM DHCP6S_DELIGATED_PREFIX`
	#
	# RFC6204 : L-12
	#
	delim=""
	for LanIf in ${LanIf6//,/ } ; do
		ip6=$(sncfg get ${LanIf}.Ip6 | awk -F "=" '{ print $2 }' | sed -n 's/"//gp');
		if [ -n "${ip6}" ] ; then
			LanIp6="${LanIp6}${delim}${ip6}"
			delim=","
		fi
	done
	delim=""
	for WanIf in ${WanIf6//,/ } ; do
		dns6=$(sncfg get ${WanIf}.DNS6 | awk -F "=" '{ print $2 }' | sed -n 's/"//gp');
		if [ -n "${dns6}" ] ; then
			WanDns6="${WanDns6}${delim}${dns6}"
			delim=","
		fi
	done
	delim=""
	for WanIf in ${WanIf6//,/ } ; do
		domain6=$(sncfg get ${WanIf}.Domain6 | awk -F "=" '{ print $2 }' | sed -n 's/"//gp');
		if [ -n "${domain6}" ] ; then
			WanDomain6="${WanDomain6}${delim}${domain6}"
			delim=","
		fi
	done
	delim=""
	for WanIf in ${WanIf6//,/ } ; do
		sip6=$(sncfg get ${WanIf}.SIP6 | awk -F "=" '{ print $2 }' | sed -n 's/"//gp');
		if [ -n "${sip6}" ] ; then
			WanSIP6="${WanSIP6}${delim}${sip6}"
			delim=","
		fi
	done
	delim=""
	for WanIf in ${WanIf6//,/ } ; do
		sipDomain6=$(sncfg get ${WanIf}.SIPDomain6 | awk -F "=" '{ print $2 }' | sed -n 's/"//gp');
		if [ -n "${sipDomain6}" ] ; then
			WanSIPDomain6="${WanSIPDomain6}${delim}${sipDomain6}"
			delim=","
		fi
	done
	#
	# Reset
	#
	echo -n "" > ${TMPFILE}
	#
	# Configuration
	#	
	echo "" | awk -v file=${TMPFILE} -v LanIf6=${LanIf6} -v LanIp6=${LanIp6} \
-v dnsMode=${DHCP6S_DNS_MODE} -v dnsNum=${DHCP6S_DNS_NUM} -v dns=${DHCP6S_DNS} -v WanDns6=${WanDns6} \
-v domainNum=${DHCP6S_DOMAIN_NUM} -v domain=${DHCP6S_DOMAIN} -v WanDomain6=${WanDomain6} \
-v ntpNum=${DHCP6S_NTP_NUM} -v ntp=${DHCP6S_NTP} \
-v sipNum=${DHCP6S_SIP_NUM} -v sip=${DHCP6S_SIP} -v WanSIP6=${WanSIP6} \
-v sipDomainNum=${DHCP6S_SIP_DOMAIN_NUM} -v sipDomain=${DHCP6S_SIP_DOMAIN} -v WanSIPDomain6=${WanSIPDomain6} \
-v nisNum=${DHCP6S_NIS_NUM} -v nis=${DHCP6S_NIS} -v nisDomainNum=${DHCP6S_NIS_DOMAIN_NUM} -v nisDomain=${DHCP6S_NIS_DOMAIN} \
-v nispNum=${DHCP6S_NISP_NUM} -v nisp=${DHCP6S_NISP} -v nispDomainNum=${DHCP6S_NISP_DOMAIN_NUM} -v nispDomain=${DHCP6S_NISP_DOMAIN} \
-v refreshTime=${DHCP6S_REFRESH_TIME} -v rapidCommit=${DHCP6S_RAPID_COMMIT} -v preference=${DHCP6S_PREFERENCE} \
-v addressPoolNum=${DHCP6S_ADDRESS_POOL_NUM} -v addressPool=${DHCP6S_ADDRESS_POOL} \
-v hostNum=${DHCP6S_HOST_NUM} -v host=${DHCP6S_HOST} \
-v addressNum=${DHCP6S_ASSIGNED_ADDRESS_NUM} -v address=${DHCP6S_ASSIGNED_ADDRESS} \
-v prefixNum=${DHCP6S_DELIGATED_PREFIX_NUM} -v prefix=${DHCP6S_DELIGATED_PREFIX} '{
		# 
		# Global Options
		#
		if (dnsMode == "0") {
			num = split(LanIp6, elems, ",");
			for (i = 1; i <= num; i++) {
				printf("option domain-name-servers %s ;\n", elems[i]) >> file
			}
		}
		else {
			ispNum = split(WanDns6, fromisp, ",")
			num = split(dns, elems, ";")
			for (i = 1, j = 1; i <= dnsNum && i <= num; i++) {
				split(elems[i], fields, ",")
				if (fields[1] == "2") {
					printf("option domain-name-servers %s ;\n", fields[2]) >> file
				}
				if (fields[1] == "1") {
					if (j <= ispNum) {
						printf("option domain-name-servers %s ;\n", fromisp[j]) >> file
					}
				}
			}
		}
		num = split(WanDomain6, elems, ",")
		for (i = 1; i <= num; i++) {
			printf("option domain-name \"%s\" ;\n", elems[i]) >> file
		}
		num = split(domain, elems, ";")
		for (i = 1; i <= domainNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option domain-name \"%s\" ;\n", fields[2]) >> file
			}
		}
		num = split(ntp, elems, ";")
		for (i = 1; i <= ntpNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option ntp-servers %s ;\n", fields[2]) >> file
			}
		}
		num = split(WanSIP6, elems, ",")
		for (i = 1; i <= num; i++) {
			printf("option sip-server-address %s ;\n", elems[i]) >> file
		}
		num = split(sip, elems, ";")
		for (i = 1; i <= sipNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option sip-server-address %s ;\n", fields[2]) >> file
			}
		}
		num = split(WanSIPDomain6, elems, ",")
		for (i = 1; i <= num; i++) {
			printf("option sip-server-domain-name \"%s\" ;\n", elems[i]) >> file
		}
		num = split(sipDomain, elems, ";")
		for (i = 1; i <= sipDomainNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option sip-server-domain-name \"%s\" ;\n", fields[2]) >> file
			}
		}
		num = split(nis, elems, ";")
		for (i = 1; i <= nisNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option nis-server-address %s ;\n", fields[2]) >> file
			}
		}
		num = split(nisDomain, elems, ";")
		for (i = 1; i <= nisDomainNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option nis-domain-name \"%s\" ;\n", fields[2]) >> file
			}
		}
		num = split(nisp, elems, ";")
		for (i = 1; i <= nispNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option nisp-server-address %s ;\n", fields[2]) >> file
			}
		}
		num = split(nispDomain, elems, ";")
		for (i = 1; i <= nispDomainNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("option nisp-domain-name \"%s\" ;\n", fields[2]) >> file
			}
		}
		printf("option refreshtime %d ;\n", refreshTime) >> file
		#
		# Interface and Address Pool
		#
		ifnum = split(LanIf6, elems, ",")
		for (x = 1; x <= ifnum; x++) {
			printf("interface %s {\n", elems[x]) >> file
			if (rapidCommit == "1") {
				printf("  allow rapid-commit ;\n") >> file
			}
			printf("  preference %d ; \n", preference) >> file
			num = split(addressPool, elems, ";")
			for (i = 1; i <= addressPoolNum && i <= num; i++) {
				split(elems[i], fields, ",")
				if (fields[1] == "1") {
					printf("  address-pool IA-NA_%d ", i) >> file
					if (fields[4] == 0) {
						printf("infinity ") >> file
					}
					else {
						printf("%d ", fields[4]) >> file
					}
					if (fields[5] == 0) {
						printf("infinity ") >> file
					}
					else {
						printf("%d ", fields[5]) >> file
					}
					printf(";\n") >> file
				}
			}
			printf("} ;\n") >> file
		}
		num = split(addressPool, elems, ";")
		for (i = 1; i <= addressPoolNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] == "1") {
				printf("pool IA-NA_%d {\n", i) >> file
				printf("  range %s to %s ;\n", fields[2], fields[3]) >> file
				printf("} ;\n") >> file
			}
		}
		# 
		# Host, Keyinfo, and Delegated Prefix
		#
		num = split(host, elems, ";")
		for (i = 1; i <= hostNum && i <= num; i++) {
			split(elems[i], fields, ",")
			if (fields[1] != "1") {
				continue
			}
			if (fields[3] == "1") {
				printf("keyinfo key_%d {\n", i) >> file
				printf("  keyid %d ;\n", fields[4]) >> file
				printf("  realm \"%s\" ;\n", fields[5]) >> file
				printf("  secret \"%s\" ;\n", fields[6]) >> file
				printf("} ;\n") >> file
			}
			printf("host client_%d {\n", i) >> file
			printf("  duid %s ;\n", fields[2]) >> file
			if (fields[3] == "1") {
				printf("  delayedkey key_%d ;\n", i) >> file
			}
			aNum = split(address, aElems, ";")
			for (j = 1; j <= addressNum && j <= aNum; j++) {
				split(aElems[j], aFields, ",")
				if (aFields[1] != "1") {
					continue
				}
				if (aFields[2] != i) {
					continue
				}
				if (aFields[3] != "::") {
					printf("  address %s %d %d ;\n", aFields[3], aFields[4], aFields[5]) >> file
				}
			}
			pNum = split(prefix, pElems, ";")
			for (j = 1; j <= prefixNum && j <= pNum; j++) {
				split(pElems[j], pFields, ",")
				if (pFields[1] != "1") {
					continue
				}
				if (pFields[2] != i) {
					continue
				}
				split(pFields[3], atom, "/")
				if (atom[1] != "::") {
					printf("  prefix %s %d %d ;\n", pFields[3], pFields[4], pFields[5]) >> file
				}
			}
			printf("} ;\n") >> file
		}
	}'
	mv ${TMPFILE} ${CONFILE}
}

start() {
	ret=0
	eval `sncfg mget LanIf6 DHCP6S_DEBUG`
	trans
	for LanIf in ${LanIf6//,/ } ; do
		PIDFILE=/var/run/dhcp6s-${LanIf}.pid
		pid=`cat ${PIDFILE} 2> /dev/null`
		if grep dhcp6s /proc/${pid}/stat > /dev/null 2>&1 ; then
			echo -n "dhcp6s for interface ${LanIf} was already running ... "
			ret=0
			continue
		fi
		if [ "${DHCP6S_DEBUG}" == "1" ] ; then
			echo -n "dhcp6s -P ${PIDFILE} -c ${CONFILE} -dDf ${LanIf} & ... "
			dhcp6s -P ${PIDFILE} -c ${CONFILE} -dDf ${LanIf} &
		else
			echo -n "dhcp6s -P ${PIDFILE} -c ${CONFILE} ${LanIf} ... "
			dhcp6s -P ${PIDFILE} -c ${CONFILE} ${LanIf}
		fi
		if [ $? != 0 ] ; then
			ret=$?
		fi
	done
}

stop() {
	ret=0
	for PIDFILE in $(ls /var/run/dhcp6s-*.pid) ; do
		local pid=`cat ${PIDFILE} 2> /dev/null`
		if grep dhcp6s /proc/${pid}/stat > /dev/null 2>&1 ; then
			echo -n "kill ${pid} ... "
			kill ${pid} > /dev/null 2>&1
			rm -f ${PIDFILE} > /dev/null 2>&1
		else
			ret=1
		fi
	done
}

if echo "$0" | grep "trans" ; then
	lock
	trans
	unlock
	exit 0
fi
if [ $# != 1 ] ; then
	usage
	exit 1
fi
case "$1" in
	start)
		echo -n "[Starting] dhcp6s ... "
		eval `sncfg get DHCP6S_ENABLE`
		lock
		if [ "${DHCP6S_ENABLE}" != "1" ] ; then
			echo -n "dhcp6s was configured to be disabled ... "
			ret=1
		else 
			start
		fi
		unlock
	;;
	stop)
		echo -n "[Stopping] dhcp6s ... "
		lock
		stop
		unlock
	;;
	reload|ipup|ipchg|ipdown)
		echo -n "[Reloading] dhcp6s ... "
		lock
		stop
		eval `sncfg get DHCP6S_ENABLE`
		if [ "${DHCP6S_ENABLE}" != "1" ] ; then
			echo -n "dhcp6s was configured to be disabled ... "
			ret=1
		else 
			start
		fi
		unlock
	;;
	trans)
		echo -n "[Translating] dhcp6s configuration ... "
		lock
		trans
		unlock
		ret=0
	;;
	*)
		usage
		exit 1
	;;
esac
if [ $ret == 0 ] ; then
	echo "OK"
	exit 0
else
	echo "FAIL"
	exit 1
fi
