#!/bin/sh
#
### BEGIN INIT INFO
# Provides:       netconf
# Required-Start: $remote_fs $named $syslog
# Required-Stop:  $remote_fs $named $syslog
# Default-Start:  3 5
# Default-Stop:   0 1 2 6
# Description:    Comb NS Netconfig
### END INIT INFO

OPTIONS_DHCP="-b"
DAEMON_DHCP=/usr/sbin/dhcpcd

PIDFILE_RADVD=/var/run/radvd/radvd.pid
OPTIONS_RADVD="-m none -u radvd -p ${PIDFILE_RADVD}"
DAEMON_RADVD=/usr/sbin/radvd

FW_DEBUG=0

# Source function library.
. /etc/init.d/functions

HOSTNAME=$(/bin/hostname)

if [ -e /etc/default/wireguard0 ];then
        source /etc/default/wireguard0
else
	WG0_ROUTE="";
	WG0_ENABLE="0";
fi

if [ -e /etc/default/static ];then
        source /etc/default/static
	STAT_LAN_IP="${IP}"
	PREFIX_LAN=${IPV6PREFIX}
	ADDR_LAN=${IPV6ADDR}
	LAN_IDX=${IPV6ULANET-0}
	LAN_PDSUF=${IPV6PDSUF-0}
else
	STAT_LAN_IP="";
	PREFIX_WIFI=""
	ADDR_WIFI=""
	LAN_IDX="0";
	LAN_PDSUF="0"
fi

if [ -e /etc/default/wifi ];then
	unset IPV6ULANET IPV6PDSUF IPV6ADDR IPV6PREFIX IP IPV6
        source /etc/default/wifi
	STAT_WIFI_IP="${IP}"
	IPV6_DEF_WIFI=${IPV6_DEF-0}
	IPV6_PRIV_WIFI=${IPV6_PRIV-0}
	WIFI_PDSUF=${IPV6PDSUF-0}
	if [ "${WIFI_MODE}" == "STA" ];then
		WIFI_IFACE="wlan0"
		WIFI_SUBPRE=${IPV6ULANET-1}
		IPV6_WIFI=${IPV6-1}
		WIFI_DHCP6=${DHCP6-0};
	elif [ "${WIFI_MODE}" == "OFF" ] || [ "${WIFI_MODE}" == "DEF" ];then
		WIFI_IFACE="wlan0"
		WIFI_SUBPRE=${IPV6ULANET-1}
		IPV6_WIFI=0
		WIFI_DHCP6=0;
	else
		IPV6_WIFI=${IPV6-1}
		WIFI_IFACE="wlan1"
		WIFI_SUBPRE=${IPV6ULANET-2}
		WIFI_DHCP6=${DHCP6-0};
	fi
	IPV6RA_WIFI=${IPV6RA-0}
	if [ "${IPV6_WIFI}" == "1" ];then
		PREFIX_WIFI=${IPV6PREFIX}
		ADDR_WIFI=${IPV6ADDR}
	else
		PREFIX_WIFI=""
		ADDR_WIFI=""
		IPV64WIFI=0
	fi
else
	PREFIX_WIFI=""
	ADDR_WIFI=""
	IPV6_WIFI=0
	IPV6_DEF_WIFI=0
	IPV6_PRIV_WIFI=0
	STAT_WIFI_IP=""
	IPV64WIFI=0
	WIFI_PDSUF="0"
fi

if [ -e /etc/default/vlans ];then
	source /etc/default/vlans
else
	VLANS=""
fi;

if [ -e /etc/default/ppp ];then
        source /etc/default/ppp
	IPV6_EN=${IPV6-0}
	IPV6RA_EN=${IPV6RA-0}
	IPV6_DEF=${IPV6_DEF-0}
	IPV6_PRIV=${IPV6_PRIV-0}
	if [ "${IPV6_EN}" == "0" ];then
  		IPV64LAN="0";
		IPV64WAN="0";
	fi
	EXT_DHCP=${DHCP}
	EXT_DHCP6=${DHCP6_PD:-0}
	if [ "${VLAN}" == "1" ];then
		VLAN="";
	fi;
else
	IPV6_EN="0";
	IPV6RA_EN="0";
	IPV6_DEF="0";
	IPV6_PRIV="0";
	ENABLE="0";
	IPV64LAN="0";
	IPV64WAN="0";
	EXT_DHCP="0";
	EXT_DHCP6="0";
fi

if [ "${VLAN}" ] && [ -e /etc/default/vlan_${VLAN} ];then
	unset IPV6ULANET IPV6PDSUF IPV6ADDR IPV6PREFIX IP IPV6
	source /etc/default/vlan_${VLAN}
	WAN_IFACE="eth0.${VLAN}"
	STAT_WAN_IP="${IP}"
	DEF_ULANET=$(printf "%x" $((${VLAN} << 4)))
	WAN_IDX=${IPV6ULANET-${DEF_ULANET}}
	EIFACE=${WAN_IFACE}
	EXT_PDSUF=${IPV6PDSUF-0}
elif [ "${VLAN}" ];then
	WAN_IFACE="eth0.${VLAN}"
	STAT_WAN_IP="";
	WAN_IDX=$(printf "%x" $((${VLAN} << 4)))
	EIFACE=${WAN_IFACE}
	EXT_PDSUF="0";
elif [ "${IPV64LAN}" != "1" ];then
	WAN_IFACE="eth0"
	STAT_WAN_IP="${STAT_WAN_LAN}"
	WAN_IDX=${LAN_IDX}
	EIFACE=${WAN_IFACE}
	EXT_PDSUF="0";
else
	EXT_PDSUF="${LAN_PDSUF}";
	EIFACE="eth0"
	WAN_IFACE=""
fi

pidstatus() {
  local pid

  if [ -e "${2}" ];then
    pid=$(cat ${2})
  fi;
  if [ -n "$pid" ] && kill -s 0 ${pid}; then
    echo "$1 (pid $pid) is running..."
    return 0
   elif [ -n "${pid}" ];then
    echo "$1 (pid $pid) is not running..."
    return 1
   else
    echo "$1 is stopped"
  fi
  return 3
}

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

  printf "%s:%s:%x:%x:%x:%x\n" ${2} ${3} $((((0x${m[0]} ^ 2) << 8) + 0x${m[1]}))  0x${m[2]}ff 0xfe${m[3]} 0x${m[4]}${m[5]}
}

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

  printf "fe80::%x:%x:%x:%x\n" $((((0x${m[0]} ^ 2) << 8) + 0x${m[1]}))  0x${m[2]}ff 0xfe${m[3]} 0x${m[4]}${m[5]}
}

conf_radvd_64_int() {
  if [ "${2}" != "" ];then
    iface="${1}:${2}"
   else
    iface="${1}"
  fi;
  presub=${3}

  cat <<__EOF__
	prefix 0:0:0:${presub}::/64 {
		Base6to4Interface ${iface};
		AdvAutonomous on;
		DeprecatePrefix on;
		DecrementLifetimes on;
		AdvValidLifetime ${IPV6ND_DYN_VLIM};
		AdvPreferredLifetime ${IPV6ND_DYN_PLIM};
	};

__EOF__

#  if [[ -n "${4}" &&  -z "$(/sbin/ip -6 rule show lookup ${4} from  prio ${4})" ]];then
#    /sbin/ip -6 rule add table ${5} from ${IPV6ULA}:${subnet6[0]}::/64 prio ${5} >/dev/null 2>&1 || :
#  fi
#  /sbin/ip -6 route replace ${IPV6ULA}:${subnet6[0]}::/64 dev ${1} proto kernel table ${5} metric ${6} >/dev/null 2>&1 || :
}


fixup_pre_pd0() {
  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:" 0x${pre_a[0]} 0x${pre_a[1]} 0x${pre_a[2]} $((0x${pre_a[3]} + ${2}))
}

prefix_pd0() {
  if [ ! -e /var/db/dhcpcd/${1}.lease6 ] || ! pidstatus ${DAEMON_DHCP} /run/dhcpcd-${1}.pid > /dev/null 2>&1;then
    return 1;
  fi;

  eval $(${DAEMON_DHCP} -f /run/netconf/dhcpcd_${1}.conf -U ${1} 2>/dev/null)
  if [ ! "${dhcp6_ia_pd1_prefix1}" ];then
    return 1
  fi

  printf "${dhcp6_ia_pd1_prefix1}/${dhcp6_ia_pd1_prefix1_length}"
}

add_dhcp_pd_pre() {
  ORIG_IFS=${IFS}
  IFS=/
  WG0=(${2})
  IFS=${ORIG_IFS}

  /sbin/ip -6 route flush cache
  for sub in $(ip -6 route show dev ${1} proto dhcp |grep -E "metric ${3:0:1}[0-9]{2}" |cut -d' ' -f1) ;do
    IFS=/
    dpre=(${sub})
    IFS=${ORIG_IFS}

    eval $(ipcalc -n ${dpre[0]}/${WG0[1]} 2>/dev/null)
    if [ -x "${NETWORK}" ];then
      continue;
    fi;

    rt_info="${sub} dev ${1} proto dhcp  metric ${5} table ${4} expires ${IPV6ND_DYN_VLIM}"

    if [ "${NETWORK}" == "${WG0[0]}" ];then
      printf "\tprefix %s {\n\t\tAdvOnLink on;\n\t\tAdvAutonomous on;\n\t\tDeprecatePrefix on;\n\t\tDecrementLifetimes on;\n\t\tAdvPreferredLifetime ${IPV6ND_DYN_PLIM};\n\t\tAdvValidLifetime ${IPV6ND_DYN_VLIM};\n\t};\n\n" ${sub}
      if [[ -n "${4}" &&  -z "$(/sbin/ip -6 rule show lookup ${4} from ${sub} prio ${4})" ]];then
        /sbin/ip -6 rule add table ${4} from ${sub} prio ${4} >/dev/null 2>&1 || :
      fi
      /sbin/ip -6 route replace ${rt_info} >/dev/null 2>&1 || :
    else
      printf "\tprefix %s {\n\t\tAdvOnLink on;\n\t\tAdvAutonomous on;\n\t\tDeprecatePrefix on;\n\t\tDecrementLifetimes off;\n\t\tAdvPreferredLifetime 0;\n\t\tAdvValidLifetime 0;\n\t};\n\n" ${sub}
      if [[ -n "${4}" &&  -n "$(/sbin/ip -6 rule show lookup ${4} from ${sub} prio ${4})" ]];then
        /sbin/ip -6 rule del table ${4} from ${sub} prio ${4} >/dev/null 2>&1 || :
      fi
      /sbin/ip -6 route change ${sub} dev ${1} metric ${6} proto static expires 0 >/dev/null 2>&1 || :
      /sbin/ip -6 route change ${sub} dev ${1} metric ${3} proto dhcp expires 0 >/dev/null 2>&1 || :
    fi;
  done
  return 1;
}

conf_radvd_int() {
  ORIG_IFS=${IFS}
  IFS=:
  subnet6=(${2})
  IFS=${ORIG_IFS}

  if [ "${subnet6[0]}" == "" ];then
	subnet6[0]="0"
  fi

  if [ -e /etc/default/ipv6nd ];then
    source /etc/default/ipv6nd
  fi;

  IPV6ND_RTR_MAX="${IPV6ND_RTR_MAX-600}";
  IPV6ND_RTR_MIN="${IPV6ND_RTR_MIN-$((${IPV6ND_RTR_MAX}/3))}";
  IPV6ND_DEFADV="${IPV6ND_DEFADV-$((${IPV6ND_RTR_MAX} * 3))}";
  IPV6ND_DEFDNS="${IPV6ND_DEFDNS-$((${IPV6ND_RTR_MAX} * 2))}";
  IPV6ND_STATIC_VLIM="${IPV6ND_STATIC_VLIM-2592000}";
  IPV6ND_STATIC_PLIM="${IPV6ND_STATIC_PLIM-604800}";
  IPV6ND_DYN_VLIM="${IPV6ND_DYN_VLIM-7200}";
  IPV6ND_DYN_PLIM="${IPV6ND_DYN_PLIM-$((${IPV6ND_DYN_VLIM}/4))}";
  IPV6ND_RA_DELAY="${IPV6ND_RA_DELAY-3}";
  IPV6ND_HOP_LIM="${IPV6ND_HOP_LIM-64}";
  IPV6ND_SEND_MAC="${IPV6ND_SEND_MAC-on}";
  IPV6ND_DHCP="${IPV6ND_DHCP-on}";
  IPV6ND_OTHER="${IPV6ND_OTHER-on}";
  IPV6ND_REACHABLE="${IPV6ND_REACHABLE-0}";
  IPV6ND_RETRANS="${IPV6ND_RETRANS-0}";
  IPV6ND_MTU="${IPV6ND_MTU-0}";

  if [ "${3}" == "1" ];then
	DEFADV=${IPV6ND_DEFADV}
  else
	DEFADV=0
  fi;

  if [ "${1}" == "${EIFACE}" ];then
    PREF="high";
   elif [ "${1}" == "${WIFI_IFACE}" ];then
    PREF="low";
   else
    PREF="medium";
  fi  

  if [[ -n "${5}" &&  -z "$(/sbin/ip -6 rule show lookup ${5} oif ${1} prio ${5})" ]];then
    /sbin/ip -6 rule add table ${5} oif ${1} prio ${5} >/dev/null 2>&1 || :
  fi
  /sbin/ip -6 route replace fe80::/64 dev ${1} proto kernel table ${5} metric ${6} >/dev/null 2>&1 || :

  cat <<__EOF__
interface ${1} {
	AdvSendAdvert on;
	MinRtrAdvInterval ${IPV6ND_RTR_MIN};
	MaxRtrAdvInterval ${IPV6ND_RTR_MAX};
	AdvDefaultLifetime ${DEFADV};
	MinDelayBetweenRAs ${IPV6ND_RA_DELAY};
	AdvCurHopLimit ${IPV6ND_HOP_LIM};
	AdvSourceLLAddress ${IPV6ND_SEND_MAC};
	AdvManagedFlag ${IPV6ND_DHCP};
	AdvOtherConfigFlag ${IPV6ND_OTHER};
	AdvReachableTime ${IPV6ND_REACHABLE};
	AdvRetransTimer ${IPV6ND_RETRANS};
	AdvLinkMTU ${IPV6ND_MTU};
	IgnoreIfMissing on;
	AdvDefaultPreference ${PREF};

__EOF__

  printf "\tRDNSS %s {\n\t\tAdvRDNSSLifetime %i;\n\t};\n\n" $(get_eui64_link ${1}) ${IPV6ND_DEFDNS}

  if [ "${4}" == "1" ];then
	for rt6 in 2002:ac10::/28 2002:a00::/24 2002:c0a8::/32 fc00::/7;do
		printf "\troute %s {\n\t\tAdvRouteLifetime ${DEFADV};\n\t\tAdvRoutePreference ${PREF};\n\t};\n\n" ${rt6}
	done;
  fi;

  if [ "${WG0_ENABLE-0}" == "1" ];then
	for rt6 in ${WG0_ROUTE};do
		if ipcalc -c -s -6 ${rt6};then
			printf "\troute %s {\n\t\tAdvRouteLifetime ${DEFADV};\n\t\tAdvRoutePreference ${PREF};\n\t};\n\n" ${rt6}
		fi;
	done;
  fi;

  if [ "${IPV6ULA}" ];then
    printf "\tprefix %s:%s::/64 {\n\t\tAdvOnLink on;\n\t\tAdvAutonomous on;\n\t\tDecrementLifetimes on;\n\t\tAdvPreferredLifetime ${IPV6ND_STATIC_PLIM};\n\t\tAdvValidLifetime ${IPV6ND_STATIC_VLIM};\n\t};\n\n" ${IPV6ULA} ${subnet6[0]}
    if [[ -n "${5}" &&  -z "$(/sbin/ip -6 rule show lookup ${5} from ${IPV6ULA}:${subnet6[0]}::/64 prio ${5})" ]];then
      /sbin/ip -6 rule add table ${5} from ${IPV6ULA}:${subnet6[0]}::/64 prio ${5} >/dev/null 2>&1 || :
    fi
    /sbin/ip -6 route replace ${IPV6ULA}:${subnet6[0]}::/64 dev ${1} proto kernel table ${5} metric ${6} expires ${IPV6ND_STATIC_VLIM} >/dev/null 2>&1 || :
  fi;

  if [[ "${1}" == "${EIFACE}" && "${EXT_DHCP6}" == "1" && -n "${PREFIX_EXT}" ]];then
    add_dhcp_pd_pre ${1} ${PREFIX_EXT} 100 ${5} ${6}
  fi

  if [ -n "${PREFIX_WG0}" ];then
    add_dhcp_pd_pre ${1} ${PREFIX_WG0} 300 ${5} ${6}
  fi;

  if [ -n "${PREFIX_PPP0}" ];then
    add_dhcp_pd_pre ${1} ${PREFIX_PPP0} 200 ${5} ${6}
  fi;

  if [ "${IPV64PPP}" == "1" ];then
    conf_radvd_64_int ppp0 "" ${subnet6[0]} ${5} ${6}
  fi;

  if [ "${IPV64LAN}" == "1" ];then
    if [ "${STAT_LAN_IP}" ];then
      conf_radvd_64_int eth0 static ${subnet6[0]} ${5} ${6}
     else
      conf_radvd_64_int eth0 dhcp ${subnet6[0]} ${5} ${6}
    fi
  fi;

  if [ "${IPV64WAN}" == "1" ] && [ "${WAN_IFACE}" ];then
    if [ "${STAT_WAN_IP}" ];then
      conf_radvd_64_int ${WAN_IFACE} static ${subnet6[0]} ${5} ${6}
     else
      conf_radvd_64_int ${WAN_IFACE} dhcp ${subnet6[0]} ${5} ${6}
    fi
  fi;

  if [ "${IPV64WIFI}" == "1" ];then
    if [ "${WIFI_MODE}" == "STA" ];then
      if [ "${STAT_WIFI_IP}" ];then
        conf_radvd_64_int ${WIFI_IFACE} static ${subnet6[0]} ${5} ${6}
       else
        conf_radvd_64_int ${WIFI_IFACE} dhcp ${subnet6[0]} ${5} ${6}
      fi
     else
      conf_radvd_64_int ${WIFI_IFACE} "" ${subnet6[0]} ${5} ${6}
    fi
  fi
}

fixup_prefix(){
  PREFIX=""
  eval $(ipcalc -p --minaddr ${ipaddr} 2>/dev/null);
  if [ "${PREFIX}" ] && [ ${PREFIX} -lt 65 ];then
    echo ${MINADDR}/${PREFIX}
  fi
}

conf_prefixes() {
  iface=${1}
  table=${2}
  metric=${3}
  shift 3

  if [ -z "${1}" ];then
    return 0;
  fi;

  TMPPRE=$(mktemp -q /tmp/tmppr_${iface}-XXXXXXXXX)
  if [[ -z "${TMPPRE}" || ! -e "${TMPPRE}" ]];then
    return 0
  fi;
 
  export table metric iface IPV6ND_STATIC_PLIM IPV6ND_STATIC_VLIM

  (for ipaddr in $@;do
    fixup_prefix ${ipaddr}
  done) |sort |uniq > ${TMPPRE}

  awk '{printf "\tprefix %s {\n\t\tAdvOnLink on;\n\t\tAdvAutonomous on;\n\t\tDecrementLifetimes on;\n\t\tAdvPreferredLifetime ${IPV6ND_STATIC_PLIM};\n\t\tAdvValidLifetime ${IPV6ND_STATIC_VLIM};\n\t};\n\n",$1}' ${TMPPRE}
  awk '{printf "/sbin/ip -6 route replace %s dev ${iface} proto kernel table ${table} metric ${metric} expires ${IPV6ND_STATIC_VLIM} >/dev/null 2>&1 || :\n",$1}' ${TMPPRE} |sh
  awk '{printf "#/sbin/ip -6 rule add prio ${table} table ${table} from %s >/dev/null 2>&1 || :\n",$1}' ${TMPPRE} |sh

  rm ${TMPPRE}
}

conf_ipv6addr() {
  iface=${1}
  table=${2}
  metric=${3}
  shift 3

  if [ -z "${1}" ];then
    return 0;
  fi;

  if [ -z "${1}" ];then
    return 0;
  fi;

  for ipaddr in $@;do
    /sbin/ip -6 route replace ${ipaddr} dev ${iface} proto static table ${table} metric ${metric} >/dev/null 2>&1 || :
    /sbin/ip -6 rule add prio ${table} table ${table} from ${ipaddr}  >/dev/null 2>&1 || :
  done
}

conf_radvd_vlan() {
  if [ ! -e /etc/default/vlan_${1} ] || [ ! -d /sys/class/net/eth0.${1} ];then
    return 0;
  fi

  unset IPV6ULANET IPV6PDSUF IPV6ADDR IPV6PREFIX IP IPV6 IPV6_DEF IPV6_PRIV
  IPV6ULANET=$(printf "%x" $((${1} << 4)))

  IPV6="0"
  if [ -e /etc/default/vlan_${1} ];then
    source /etc/default/vlan_${1}
  fi;

  if [ "${IPV6}" != "1" ] && [ "${VLAN}" != "${1}" ];then
    return
  fi;

#  if [ "${VLAN}" == "${1}" ]  && [ "${EXT_DHCP6}" == "1" ];then
#    return
#  fi



  conf_radvd_int eth0.${1} ${IPV6ULANET} ${IPV6_DEF-0} ${IPV6_PRIV-0} $((${1} + 10000)) $((101 + (2 * ${METRIC})))
  conf_prefixes eth0.${1} $((${1} + 10000)) $((101 + (2 * ${METRIC}))) ${IPV6PREFIX}
  conf_ipv6addr eth0.${1} $((${1} + 10000)) $((101 + (2 * ${METRIC}))) ${IPV6ADDR}
  printf "};\n\n";
}

build_radvd_conf() {
  if [ -d /sys/class/net/wg0 ];then
    PREFIX_WG0=$(prefix_pd0 wg0)
  fi;

  if [ -d /sys/class/net/ppp0 ];then
    PREFIX_PPP0=$(prefix_pd0 ppp0)
  fi;

  if [ -d /sys/class/net/${EIFACE} ];then
    PREFIX_EXT=$(prefix_pd0 ${EIFACE})
  fi;

  if [ "${IPV6_EN}" == "1" ] && [ -d /sys/class/net/eth0 ];then
    conf_radvd_int eth0 ${LAN_IDX} ${IPV6_DEF} ${IPV6_PRIV} 100 12
    conf_prefixes eth0 100 12 ${PREFIX_LAN}
    conf_ipv6addr eth0 100 12 ${ADDR_LAN}
    printf "};\n\n";
  fi;

  if [ "${IPV6_WIFI}" == "1" ] && [ -d /sys/class/net/${WIFI_IFACE} ];then
    conf_radvd_int ${WIFI_IFACE} ${WIFI_SUBPRE} ${IPV6_DEF_WIFI} ${IPV6_PRIV_WIFI} 200 52
    conf_prefixes ${WIFI_IFACE} 200 52 ${PREFIX_WIFI}
    conf_ipv6addr ${WIFI_IFACE} 200 52 ${ADDR_WIFI}
    printf "};\n\n";
  fi

  for vlanid in ${VLANS};do
    if [ "${vlanid}" == "${VLAN}" ];then
      continue;
    fi;
    (conf_radvd_vlan ${vlanid})
  done

  if [ "${VLAN}" ] && [ "${IPV6_EN}" == "1" ];then
    (conf_radvd_vlan ${VLAN})
  fi;
}

conf_dhcpcd_vlan() {
  if [ ! -e /etc/default/vlan_${1} ] || [ ! -d /sys/class/net/eth0.${1} ];then
    return 6;
  fi

  unset IPV6ULANET IPV6PDSUF IPV6ADDR IPV6PREFIX IP IPV6
  source /etc/default/vlan_${1}

  if [[ "${DHCP6-0}" == "1" || "${DHCP6-0}" == "3" ]] && [[ "${IPV6}" == "1" && "${IPV6RA}" == "1" && "${IPV6PDSUF}" != "-1" ]];then
    return 7
  elif [[ "${DHCP6-0}" == "1" || "${DHCP6-0}" == "3" ]] && [[ "${IPV6}" == "1" && "${IPV6PDSUF}" != "-1" ]];then
    return 5
  elif [[ "${DHCP6-0}" == "1" || "${DHCP6-0}" == "3" ]] && [[ "${IPV6}" == "1" && "${IPV6RA}" == "0" ]];then
    return 4
  elif [[ "${IPV6}" == "1"  && "${IPV6RA}" == "1" && "${IPV6PDSUF}" != "-1" ]];then
    return 6
  elif [[ "${IPV6}" == "1"  && "${IPV6PDSUF}" != "-1" ]];then
    return 3
  elif [[ "${IPV6}" == "1"  && "${IPV6RA}" == "0" ]];then
    return 2
  elif [[ "${DHCP6-0}" == "1"  || "${DHCP6-0}" == "3" ]];then
    return 1
  else
    return 0
  fi
}

run_dhcpcd() {
  if [[ -e /var/run/dhcpcd-${2}.pid && "${3}" == "0" ]];then
    ${DAEMON_DHCP} -x ${2}
    if [ -e /var/run/dhcpcd-${2}.pid ];then
      /bin/kill $(cat /var/run/dhcpcd-${2}.pid)
      sleep 2
      if [ -e /var/run/dhcpcd-${2}.pid ];then
        /bin/kill -9 $(cat /var/run/dhcpcd-${2}.pid)
        sleep 2
      fi;
    fi
  fi;

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

  if [ ! -e /var/run/dhcpcd-${2}.pid ];then
    start-stop-daemon --start -p /run/dhcpcd-${2}.pid ${DAEMON_DHCP} -- ${OPTIONS_DHCP} -f /run/netconf/dhcpcd_${1}.conf ${2}
  else
    ${DAEMON_DHCP} -f /run/netconf/dhcpcd_${1}.conf -n ${2}
  fi;
}

build_dhcpcd_conf() {
  PRE=0;
  VLIST="";
  RLIST="";
  KLIST="";

  if [ -n "${1}" ] && [ "${1}" != "eth0" ];then
    ALLOWI="${1}"
    IAID=${1}
    IFACE=${1}
    ILIST="${IFACE} "
   else
    IFACE=${EIFACE}
    IAID=${EIFACE}
    if [[ "${DHCP6-0}" == "1"  || "${DHCP6-0}" == "3" || "${IPV6_EN}" == "0" || "${IPV6RA_EN}" == "1" ]];then
      ILIST="${IFACE} "
    fi;
  fi;

  if [ "${IPV6_EN}" == "1" ] && [ -d /sys/class/net/eth0 ] && [ "${LAN_PDSUF}" != "-1" ] && [[ "${IFACE}" != "eth0" ||  "${VLAN}" != "" ]];then
    PDLIST=" eth0/${PRE}/64/0";
    PRE=$((${PRE} + 1));
  fi;

  for vlanid in ${VLANS};do
    if [ "${vlanid}" == "${VLAN}" ];then
      VLIST="${VLIST} ${vlanid}"
      ILIST="${ILIST}eth0.${vlanid} "
      continue;
    fi;
    SUFFIX=$(conf_dhcpcd_vlan ${vlanid})
    VRET=$?
    VROUTE[${vlanid}]=${VRET}
    if [[ "${VRET}" == "1" || "${VRET}" == "4" || "${VRET}" == "5" || "${VRET}" == "7" ]];then
      ILIST="${ILIST}eth0.${vlanid} "
      VLIST="${VLIST} ${vlanid}"
    elif [[ "${VRET}" == "0" ]];then
      ILIST="${ILIST}eth0.${vlanid} "
      RLIST="${RLIST} ${vlanid}"
    else
      KLIST="${KLIST} ${vlanid}"
    fi
    if [[ "${VRET}" -gt "5" ||  "${VRET}" == "3" ]];then
      PDLIST="${PDLIST} eth0.${vlanid}/${PRE}/64/0";
      PRE=$((${PRE} + 1));
    fi;
  done

  if [[ "${IPV6_WIFI}" == "1"  && "${WIFI_PDSUF}" != "-1" && -d /sys/class/net/${WIFI_IFACE} ]];then
    PDLIST="${PDLIST} ${WIFI_IFACE}/${PRE}/64/0";
    PRE=$((${PRE} + 1));
  fi;

  if [[ -n ${WIFI_IFACE} &&  -d /sys/class/net/${WIFI_IFACE} ]] && [[ "${IPV6_WIFI}" != "1" || "${WIFI_DHCP6}" == "1" || "${WIFI_DHCP6}" == "3" ]];then
    ILIST="${ILIST}${WIFI_IFACE} "
  fi

  case ${IFACE} in
    wg0)METRIC="300";;
    ppp0)METRIC="200";;
    *)METRIC="100";;
  esac

  (cat <<__EOF__
duid
noipv6rs
ipv6only
noipv4
hostname
slaac private
logfile /dev/null
ipv6ra_noautoconf
persistent
metric ${METRIC}
#nogateway

nohook hostname, ntp.conf

env dhcpcd_iface=${IFACE}

background
#debug

allowinterfaces ${ALLOWI:-${ILIST:0:-1}}
__EOF__
  if  [ "${IFACE}" != "eth0" ] || [[ "${VLAN}" == "" && "${EXT_DHCP6}" == "1" ]];then
	printf "\ninterface ${IFACE}\n\tmetric ${METRIC}\n\tiaid ${IAID}\n\tia_na\n\tia_ta\n\toption dhcp6_name_servers\n"
	if [ -n "${PDLIST}" ];then
		printf "\tia_pd ${IAID}${PDLIST}\n"
	fi;
	METRIC=$((${METRIC} + 1))
  fi;

  if [ "${IFACE}" != "eth0" ];then
    return 0;
  elif [[ "${DHCP6-0}" == "1"  || "${DHCP6-0}" == "3" ]];then
    printf "\ninterface ${IFACE}\n\tmetric ${METRIC}\n\tiaid ${IAID}\n\tia_na\n\tia_ta\n\toption dhcp6_name_servers\n"
    if [[ "${IPV6_EN}" == "0" ]];then
      printf "\tipv6rs\n"
    fi;
  elif [ "${IPV6_EN}" == "0" ];then
    printf "\ninterface ${IFACE}\n\tipv6rs\n"
  fi;
  METRIC=$((${METRIC} + 1))

  for vlanid in ${VLIST};do
    printf "\ninterface %s\n\tmetric %i\n\tiaid ff:00:00:%02X\n\tia_na\n\tia_ta\n\toption dhcp6_name_servers\n" ${IFACE}.${vlanid} ${METRIC} ${vlanid}
    if [[ -n "${PDLIST}" && "${VLAN}" == "${vlanid}" && "${EXT_DHCP6}" == "1" ]];then
	printf "\tia_pd ${IAID}${PDLIST}\n"
    elif [[ "${VROUTE[${vlanid}]}" == "1" ]];then
        printf "\tipv6rs\n";
    fi;
    METRIC=$((${METRIC} + 1))
  done;

  for vlanid in ${RLIST};do
    printf "\ninterface %s\n\tmetric %i\n\tipv6rs\n" ${IFACE}.${vlanid} ${METRIC}
    METRIC=$((${METRIC} + 1))
  done

  if [[ -n ${WIFI_IFACE} &&  -d /sys/class/net/${WIFI_IFACE} ]];then
    if [[ "${WIFI_DHCP6}" == "1" || "${WIFI_DHCP6}" == "3" ]];then
      printf "\ninterface %s\n\tmetric %i\n\tiaid %s\n\tia_na\n\tia_ta\n\toption dhcp6_name_servers\n" ${WIFI_IFACE} ${METRIC} ${WIFI_IFACE}
      if [ "${IPV6_WIFI}" != "1" ];then
        printf "\tipv6rs\n"
      fi;
    elif [ "${IPV6_WIFI}" != "1" ];then
      printf "\ninterface %s\n\tmetric %i\n\tipv6rs\n" ${WIFI_IFACE} ${METRIC}
    fi
  fi;) > /run/netconf/dhcpcd_${IFACE}.conf

  if [ "${IFACE}" != "eth0" ];then
    run_dhcpcd ${IFACE} ${IFACE} 1
    return 0;
  fi;
  if [[ "${DHCP6-0}" == "1" || "${DHCP6-0}" == "3" || "${IPV6_EN}" == "0" ]];then
    run_dhcpcd ${IFACE} ${IFACE} 1
  else
    run_dhcpcd ${IFACE} ${IFACE} 0
  fi;

  for vlanid in ${VLIST} ${RLIST};do
    run_dhcpcd eth0 eth0.${vlanid} 1
  done;

  for vlanid in ${KLIST};do
    run_dhcpcd eth0 eth0.${vlanid} 0
  done;

  if [[ -n ${WIFI_IFACE} &&  -d /sys/class/net/${WIFI_IFACE} ]] && [[ "${IPV6_WIFI}" != "1" || "${WIFI_DHCP6}" == "1" || "${WIFI_DHCP6}" == "3" ]];then
    run_dhcpcd eth0 ${WIFI_IFACE} 1
  else
    run_dhcpcd eth0 ${WIFI_IFACE} 0
  fi;
}

update_secret() {
  if [ ! -e ${1} ];then
    printf "%s\t*\t%s\n" ${2} ${3} > ${1}
   elif ! grep -q -s -E "^${2}\s" ${1};then
    printf "%s\t*\t%s\n" ${2} ${3} >> ${1}
   elif ! grep -q -s -E "^${2}\s\*\s${3}$" ${1};then
    sed -e 's|'${2}'\s.*|'${2}'\t*\t'${3}'|' -i ${1}
 fi;
}

ppp_call_conf() {
  PPP_OPTS="noipdefault\nusepeerdns\npersist\nlcp-echo-failure 2\nlcp-echo-interval 60\nnoauth\nholdoff 30\nmaxfail 0\nplugin rp-pppoe.so\n";

  if [ "${USER}" ];then
    PPP_OPTS="${PPP_OPTS}user ${USER}\n"
  fi;

  if [ "${MRU}" ];then
    PPP_OPTS="${PPP_OPTS}mru ${MRU}\n"
   else
    PPP_OPTS="${PPP_OPTS}mru 1492\n"
  fi;

  if [ "${SERVICE}" ];then
    PPP_OPTS="${PPP_OPTS}rp_pppoe_service ${SERVICE}\n"
  fi;

  PPP_OPTS="${PPP_OPTS}nic-${EIFACE}\n"

  if [ "${IPV6PPP}" == "1" ];then
    PPP_OPTS="${PPP_OPTS}+ipv6\nipv6cp-use-persistent\n"
  fi;

  printf "${PPP_OPTS}"  > /run/netconf/ns_default

  if [ ! -L /etc/ppp/peers/ns_default ];then
     if [ -e /etc/ppp/peers/ns_default ];then
       rm /etc/ppp/peers/ns_default
     fi;
     ln -rs /run/netconf/ns_default /etc/ppp/peers/ns_default
  fi;
}

ppp_conf() {
  ppp_call_conf

  update_secret /etc/ppp/pap-secrets ${USER} ${PASS}
  update_secret /etc/ppp/chap-secrets ${USER} ${PASS}
  chown root.root /etc/ppp/pap-secrets /etc/ppp/chap-secrets
  chmod 400 /etc/ppp/pap-secrets /etc/ppp/chap-secrets
}

enable_forwarding_vlan() {
  if [ ! -e /etc/default/vlan_${1} ] || [ ! -d /sys/class/net/eth0.${1} ];then
    return 0;
  fi

  unset IPV6ULANET IPV6PDSUF IPV6ADDR IPV6PREFIX IP IPV6 IPV6_DEF IPV6_PRIV
  if [ -e /etc/default/vlan_${1} ];then
    source /etc/default/vlan_${1}
  fi;

  if [ "${IPV6-0}" != "1" ] && [ "${VLAN}" != "${1}" ];then
    echo 0 > /proc/sys/net/ipv6/conf/eth0.${1}/forwarding
  fi;
}

enable_forwarding() {
  echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
  if [ "${IPV6_EN}" != "1" ];then
    echo 0 > /proc/sys/net/ipv6/conf/eth0/forwarding
 fi;

  for vlanid in ${VLANS};do
    if [ "${vlanid}" == "${VLAN}" ];then
      continue;
    fi;
    (enable_forwarding_vlan ${vlanid})
  done
}

start_radvd() {
  build_radvd_conf > /tmp/radvd.conf

  if [ ! -e /run/netconf/radvd.conf ];then
    cp /tmp/radvd.conf /run/netconf/radvd.conf
  elif ! diff -q /tmp/radvd.conf /run/netconf/radvd.conf >/dev/null 2>&1;then
    mv /tmp/radvd.conf /run/netconf/radvd.conf
  elif [ -L /etc/radvd.conf ];then
    rm /tmp/radvd.conf
    if [ "${1-0}" != "1" ];then
	return 0;
     fi;
  fi; 

  if [[ ! -L /etc/radvd.conf || ! -e /etc/radvd.conf ]];then
    if [ -e /etc/radvd.conf ];then
      rm /etc/radvd.conf
    fi;
    ln -rs /run/netconf/radvd.conf /etc/radvd.conf
  fi;

  if pidstatus ${DAEMON_RADVD} /var/run/radvd/radvd.pid;then
    if ! start-stop-daemon --stop --signal HUP --quiet --pidfile ${PIDFILE_RADVD} --exec ${DAEMON_RADVD};then
      rm ${PIDFILE_RADVD}
    else
      return 0
    fi;
  fi;

  if [ -s /run/netconf/radvd.conf ];then
    echo 0 > /proc/sys/net/ipv6/conf/all/forwarding
    start-stop-daemon --start -p ${PIDFILE_RADVD} --oknodo --exec ${DAEMON_RADVD} -- ${OPTIONS_RADVD}
    enable_forwarding
  fi;
}

start_ipv6_firewall() {
  if [ "${WWW}" == "1" ];then
    /usr/sbin/ip6tables -A PPP -j ACCEPT -p tcp --dport 80
  elif [[ -n "${IPV6ULA}" && "${FWLOCAL}" != "0" ]];then
    /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --dport 80
  fi;

  if [ "${FWLOCAL}" == "0" ];then
    if [ -n "${IPV6ULA}" ];then
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48
    fi;
    for lip64 in 2002:ac10::/28 2002:a00::/24 2002:c0a8::/32 fc00::/7;do
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${lip64}
    done
   else
    if [ -n "${IPV6ULA}" ];then
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p icmpv6
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --sport 0:1023 --dport 2049:2052
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p udp --sport 0:1023 --dport 2049:2052
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --sport 0:1023 --dport 111
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p udp --sport 0:1023 --dport 111
    fi;
    for lip64 in 2002:ac10::/28 2002:a00::/24 2002:c0a8::/32 fc00::/7;do
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${lip64} -p icmpv6
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${lip64} -p tcp --sport 0:1023 --dport 2049:2052
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${lip64} -p udp --sport 0:1023 --dport 2049:2052
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${lip64} -p tcp --sport 0:1023 --dport 111
      /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${lip64} -p udp --sport 0:1023 --dport 111
    done
  fi;
  if [ "${FW_DEBUG}" == "1" ];then
    /usr/sbin/ip6tables -A PPP -j LOG
    /usr/sbin/ip6tables -A PPP -j ACCEPT
  fi
}

start_ipv4_firewall() {
  if [ "${EXT_DHCP}" == "0" ];then
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -p udp -d 255.255.255.255 --dport 67:68
   else
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p udp -d 255.255.255.255 --dport 67:68
  fi;

  if [ "${FWLOCAL}" == "1" ] || [ "${WWW}" == "0" ];then
    /sbin/ip route show dev ${1} scope link proto kernel |sort |uniq |\
	awk -v DEV=${1} \
		'{printf "/usr/sbin/iptables -A PPP -j ACCEPT -p tcp -i %s -d %s -s %s --dport 80\n", DEV, $3, $1, DEV, $3, $1}' |sh
   elif [ "${WWW}" == "1" ];then
    /usr/sbin/iptables -A PPP -j ACCEPT -p tcp --dport 80
  fi

  if [ "${FWLOCAL}" == "0" ];then
    /sbin/ip route show dev ${1} scope link proto kernel |sort |uniq |\
	awk -v DEV=${1} '{printf "/usr/sbin/iptables -A PPP -j ACCEPT -i %s -s %s -d %s\n\
		/usr/sbin/iptables -A PPP -j ACCEPT -p igmp -i %s -s %s -d 224.0.0.0/4\n", DEV, $1, $1, DEV, $1}' |sh
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p udp -d 255.255.255.255
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p udp -d 224.0.0.251
    /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -d 224.0.0.1
   else
    /sbin/ip route show dev ${1} scope link proto kernel |sort |uniq |awk -v DEV=${1} '{printf "\
	/usr/sbin/iptables -A PPP -j ACCEPT -p tcp --sport 0:1023 --dport 2049:2052 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j ACCEPT -p udp --sport 0:1023 --dport 2049:2052 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j ACCEPT -p tcp --sport 0:1023 --dport 111 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j ACCEPT -p udp --sport 0:1023 --dport 111 -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j DROP -i %s -s %s -d %s\n\
	/usr/sbin/iptables -A PPP -j DROP -p igmp -i %s -s %s -d 224.0.0.0/4\n", \
		DEV, $1, $1, DEV, $1, $1, DEV, $1, $1, DEV, $1, $1, DEV, $1, $1, DEV, $1}' |sh
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -p udp -d 255.255.255.255
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -p udp -d 224.0.0.251
    /usr/sbin/iptables -A PPP -j DROP -i ${1} -d 224.0.0.1
  fi;

  /usr/sbin/iptables -A PPP -j ACCEPT -i ${1} -p tcp --tcp-flags SYN,ACK,FIN,RST FIN,ACK
#  /usr/sbin/iptables -A PPP -j LOG -i ${1}
  /usr/sbin/iptables -A PPP -j DROP -i ${1}
}

setup_firewall() {
  /usr/sbin/iptables -F SIP
  /usr/sbin/iptables -F PPP
  /usr/sbin/ip6tables -F PPP

  /usr/sbin/ip6tables -F IPv6LOCAL
  if [ "${IPV6ULA}" ];then
    /usr/sbin/ip6tables -A IPv6LOCAL -j ACCEPT -s ${IPV6ULA}::/48
  fi;
  for lip64 in 2002:ac10::/28 2002:a00::/24 2002:c0a8::/32 fc00::/7;do
    /usr/sbin/ip6tables -A IPv6LOCAL -j ACCEPT -s ${lip64}
  done

  if [ "${ENABLE-0}" == "1" ] || [ "${FWALL}" == "1" ];then
    start_ipv4_firewall ${EIFACE}
    start_ipv6_firewall
    if [[ "${WWW}" == "1" && "${ENABLE-0}" == "1" ]];then
      /usr/sbin/iptables -A PPP -j ACCEPT -i ppp0 -p tcp --dport 80
      /usr/sbin/iptables -A PPP -j ACCEPT -i wg0 -p tcp --dport 80
    fi
    echo 1 > /proc/sys/net/ipv4/conf/${EIFACE}/rp_filter
   else
    if [ "${WWW}" == "0" ] && [ "${WIFI_MODE}" != "DEF" ];then
      if [ "${IPV6ULA}" ];then
        /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d ${IPV6ULA}::/48 -p tcp --dport 80
       else
        /usr/sbin/ip6tables -A PPP -j IPv6LOCAL -d fc00::/7 -p tcp --dport 80
      fi
      /usr/sbin/ip6tables -A PPP -j REJECT --reject-with icmp6-adm-prohibited -p tcp --dport 80
    fi;
    /usr/sbin/ip6tables -A PPP -j ACCEPT
    echo 0 > /proc/sys/net/ipv4/conf/${EIFACE}/rp_filter
  fi;
  if [ "${SIP-0}" == "0" ];then
    /usr/sbin/iptables -A SIP -j DROP
  fi;
}

if [ ! -d /run/netconf ];then
  mkdir -p /run/netconf
fi;

case "$1" in
	start)
		setup_firewall

		if [ "${HOSTNAME}" ];then
			/usr/bin/avahi-set-host-name ${HOSTNAME} >/dev/null 2>&1 || :
		fi;

		if [ "${ENABLE-0}" == "1" ] && [ "${USER}" ] && [ "${PASS}" ];then
			build_dhcpcd_conf || start_radvd
			ppp_conf
		else
			build_dhcpcd_conf || :
			start_radvd || :
		fi;
	;;
	stop)
		start-stop-daemon --oknodo --stop --pidfile ${PIDFILE_RADVD}  --exec ${DAEMON_RADVD}
		for dint in /run/dhcpcd-*.pid;do
			${DAEMON_DHCP} -k $(echo /run/dhcpcd-eth0.10.pid |sed 's|/run/dhcpcd-\(.*\).pid|\1|')
#			start-stop-daemon --oknodo --stop --pidfile ${dint}  --exec ${DAEMON_DHCP}
		done

	;;
	status)
		pidstatus ${DAEMON_DHCP} /run/dhcpcd-${EIFACE}.pid && pidstatus ${DAEMON_RADVD} ${PIDFILE_RADVD}
		exit $?
        ;;
	radvd)
		start_radvd ${2} || :
	;;
	firewall)
		setup_firewall
	;;
	dhcpcd)
		shift
		build_dhcpcd_conf ${1}
	;;
	ppp)
		ppp_conf
	;;
	*)
		N=/etc/init.d/$NAME
		echo "Usage: $N {start|stop|status|dhcpcd|firewall|ppp|radvd}" >&2
		exit 1
	;;
esac
