#!/bin/sh

cachedir="/var/cache/alterator/net-eth"
precommit_hooks_dir=/usr/lib/alterator/hooks/net-eth-precommit.d
postcommit_hooks_dir=/usr/lib/alterator/hooks/net-eth.d
ALTERATOR_DOMAIN=/usr/lib/alterator/backend3/net-domain
ALTERATOR_BOND=/usr/lib/alterator/backend3/net-bond
ALTERATOR_WIFI=/usr/lib/alterator/backend3/net-wifi
ALTERATOR_VLAN=/usr/lib/alterator/backend3/net-vlan
ALTERATOR_BRIDGE=/usr/lib/alterator/backend3/net-bridge

NETWORKMANAGER=/usr/sbin/NetworkManager
NMCLI=/usr/bin/nmcli
IPA_CONFIGURED=/usr/sbin/ipa_configured

SYSTEMD_NETWORKD=/lib/systemd/systemd-networkd
NETWORKCTL=/bin/networkctl

HOSTNAMECTL=/usr/bin/hostnamectl

max_hostname_length=64

alterator_api_version=1

. alterator-sh-functions
. alterator-net-functions
. alterator-hw-functions
. shell-config

# determine that the installer is running
if [ -f /_NEW_SYSTEM_ ] || [ -d /mnt/destination ]; then
	DURING_INSTALL=1
fi

###
is_defined()
{
    set|grep -qs "^$(quote_sed_regexp "$1")="
}

is_bridge()
{
	local name="$1"; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"
	local iftype="$(read_iface_option "$ifacedir" TYPE)"

	if [ -n "$iftype" ] && list_bridge_types | grep -qF "$iftype"; then
		true
	else
		if netdev_is_up "$name"; then
			netdev_is_bridge "$name"
		else
			false
		fi
	fi
}

is_bond()
{
    local name="$1"; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"

	[ "$(read_iface_option "$ifacedir" TYPE)" = bond ]
}

is_vlan()
{
    local name="$1"; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"

	[ "$(read_iface_option "$ifacedir" TYPE)" = vlan ]
}

check_bond()
{
    local iface="$1"; shift

	if [ -n "$in_configuration" -a "$in_configuration" != "static" ]; then
		write_error "`_ "$iface: Only 'static' configuration allowed for bond interface"`"
		return 1
	fi

	return 0
}

check_bridge()
{
	return 0
}

check_altdomain()
{
    local domain=

    [ -f "$ALTERATOR_DOMAIN" ] || return 1

    # Check for configured FreeIPA domain
    if [ -x "$IPA_CONFIGURED" ] && $IPA_CONFIGURED; then
        return 0
    fi

    [ "$(shell_config_get /etc/sysconfig/system SERVER_ROLE)" = "master" ] ||
        return 1

    domain="$(read_computer_domain)"
    if [ -n "$domain" -a -f "/etc/openldap/slapd-$domain.conf" ]; then
        return 0
    else
        return 1
    fi
}

### cache
init_cache()
{
    local name="$1"; shift
    local ifacedir="/etc/net/ifaces/$name"
    local dstdir="$cachedir/$name"

    if [ ! -d "$dstdir" ] ;then
		[ -d "$ifacedir" ] && cp -a "$ifacedir" "$cachedir"
        mkdir -p -- "$dstdir"
        init_systemd_networkd_cache "$dstdir" "$name"
    fi

    [ ! -f /etc/sysconfig/network -o -f "$cachedir/network" ] || cp -p /etc/sysconfig/network "$cachedir/network"

    if [ ! -f "$cachedir/hostname" ]; then
        local hname=
        [ -f "$HOSTNAMECTL" ] && hname="$($HOSTNAMECTL hostname --static)"
        [ -n "$hname" ] && \
            echo "$hname" > "$cachedir/hostname" || \
            cp -p /etc/hostname "$cachedir/hostname" 2>/dev/null
    fi
}

clear_cache()
{
    rm -rf "$cachedir"
    mkdir -p "$cachedir"
}

commit_hostname()
{
    [ -f "$cachedir/network" ] || return
    ! cmp -s /etc/sysconfig/network "$cachedir/network" || return

    local old_value="$(shell_config_get /etc/sysconfig/network HOSTNAME)"
    local new_value="$(shell_config_get "$cachedir/network"    HOSTNAME)"

    mv -f "$cachedir/network" /etc/sysconfig/network

    "$HOSTNAMECTL" set-hostname "$new_value" --static || \
        (mv -f "$cachedir/hostname" /etc/hostname 2>/dev/null && hostname "$new_value")

    run-parts /etc/hooks/hostname.d "$old_value" "$new_value"
}

list_ifaces_for_restart()
{
	local ifacedir= ifname=
	local eth_list= vlan_list= other_list=
	local nl='
'

	for ifacedir in $(find "$cachedir" -maxdepth 1 -mindepth 1 -type d); do
		ifname="${ifacedir##*/}"
		case "$(read_iface_option "$ifacedir" TYPE)" in
			eth)
				eth_list="$eth_list${eth_list:+$nl}$ifname"
				# VLAN ifaces from /etc/net/ifaces
				# No need to add VLAN interfaces from cachedir:
				# they will be added in the proceeding of this cycle itself.
				vlan_list="$vlan_list${vlan_list:+$nl}$(list_vlans_for_iface "$ifname" /etc/net/ifaces)"
				;;
			vlan)
				vlan_list="$vlan_list${vlan_list:+$nl}$ifname"
				;;
			*)
				other_list="$other_list${other_list:+$nl}$ifname"
				;;
		esac
	done

	# First restart eth ifaces, then VLANs and others
	echo "$eth_list" | sort -u
	echo "$vlan_list" | sort -u
	echo "$other_list" | sort -u
}

commit_cache()
{
	local need_reload_nm=
	local need_reload_networkctl=
	local ifaces_restart=

    #little run-parts: check configuration before apply it
    set_locale
    local answer=
    for f in "$precommit_hooks_dir"/*; do
	[ -f "$f" -a -x "$f" ] || continue
	[ "${f%.rpm*}" = "$f" -a "${f%\~}" = "$f" ] || continue

	if ! answer="$("$f")";then
	    [ -n "$answer" ] || answer="$f failed"
	    write_error "$answer"
	    return 1
	fi
    done

    commit_hostname

	ifaces_restart="$(list_ifaces_for_restart)"
	for ifname in $ifaces_restart; do
	    local new_ifacedir="$cachedir/$ifname"
	    local old_ifacedir="/etc/net/ifaces/$ifname"
	    local new_controlled="$(read_controlled "$new_ifacedir")"
	    local old_controlled="$(read_controlled "$old_ifacedir")"
		local restart_only=

		[ -n "$ifname" ] || continue

	    [ -n "$DURING_INSTALL" ] || iface_down "$ifname"

		[ -d "$new_ifacedir" ] || restart_only=1

		if [ -f "$NMCLI" -a -z "$DURING_INSTALL" ] && \
			[ "$new_controlled" = "NetworkManager" -o \
			  "$old_controlled" = "NetworkManager" -o \
			  "$new_controlled" = "NetworkManagerNative" -o \
			  "$old_controlled" = "NetworkManagerNative" ]; then
			need_reload_nm=1
		fi

		if [ -f "$NETWORKCTL" -a -z "$DURING_INSTALL" ]; then
			if [ "$new_controlled" = "systemd-networkd" -o \
			  "$old_controlled" = "systemd-networkd" ]; then
				need_reload_networkctl=1
				"$NETWORKCTL" down "$ifname" 2>/dev/null ||:
			fi
		fi

		if [ -z "$restart_only" ]; then
			# IPv4 configuration
			local old_config_ipv4="$(read_config_ipv "$old_ifacedir" 4)"
			local new_config_ipv4="$(read_config_ipv "$new_ifacedir" 4)"

			local old_ipv4addresses="$(read_iface_addresses "$old_ifacedir" 4)"
			local new_ipv4addresses="$(read_iface_addresses "$new_ifacedir" 4)"

			local old_ipv4configuration="$(read_configuration "$old_ifacedir" 4)"
			local new_ipv4configuration="$(read_configuration "$new_ifacedir" 4)"

			# IPv6 configuration
			local old_config_ipv6="$(read_config_ipv "$old_ifacedir" 6)"
			local new_config_ipv6="$(read_config_ipv "$new_ifacedir" 6)"

			local old_ipv6addresses="$(read_iface_addresses "$old_ifacedir" 6)"
			local new_ipv6addresses="$(read_iface_addresses "$new_ifacedir" 6)"

			local old_ipv6configuration="$(read_configuration "$old_ifacedir" 6)"
			local new_ipv6configuration="$(read_configuration "$new_ifacedir" 6)"

		    #update configs
		    rm -rf -- "$old_ifacedir"
			if iface_will_removed "$cachedir" "$ifname"; then
				continue
			fi

			mv -f -- "$new_ifacedir" "$old_ifacedir"
			commit_systemd_networkd "$old_ifacedir" "$ifname"
		fi

	    #try to restart
	    [ -n "$DURING_INSTALL" ] && netdev_is_up "$ifname" || iface_up "$ifname"

		if [ "$new_controlled" = "NetworkManagerNative" -a "$old_controlled" != "NetworkManagerNative" ]; then
			"$NMCLI" connection add type ethernet ifname "$ifname" con-name "Native $ifname" 2>/dev/null ||:
		elif [ "$new_controlled" != "NetworkManagerNative" -a "$old_controlled" = "NetworkManagerNative" ]; then
			"$NMCLI" connection delete "Native $ifname" 2>/dev/null ||:
		fi

		if [ -z "$restart_only" ]; then
			if [ "$old_config_ipv4" != "$new_config_ipv4" -o \
				 "$old_ipv4addresses" != "$new_ipv4addresses" -o \
				 "$old_ipv4configuration" != "$new_ipv4configuration" -o \
				 "$old_config_ipv6" != "$new_config_ipv6" -o \
				 "$old_ipv6addresses" != "$new_ipv6addresses" -o \
				 "$old_ipv6configuration" != "$new_ipv6configuration" ];then
				# Deprecated. For backward compatibility only.
				local old_addresses="$old_ipv4addresses"
				local new_addresses="$new_ipv4addresses"
				local old_configuration="$old_ipv4configuration"
				local new_configuration="$new_ipv4configuration"
				export old_addresses new_addresses old_configuration new_configuration
				###
				export old_config_ipv4 new_config_ipv4 old_ipv4addresses new_ipv4addresses \
					old_ipv4configuration new_ipv4configuration \
					old_config_ipv6 new_config_ipv6 old_ipv6addresses new_ipv6addresses \
					old_ipv6configuration new_ipv6configuration

				run-parts  "$postcommit_hooks_dir"  "$ifname"
			fi
		fi
	done

	if [ -n "$need_reload_nm" ]; then
		"$NMCLI" connection reload 2>/dev/null ||:
		for ifname in $ifaces_restart; do
			"$NMCLI" device reapply "$ifname" 2>/dev/null ||:
		done
	fi

	if [ -n "$need_reload_networkctl" ]; then
		"$NETWORKCTL" reload 2>/dev/null ||:
	fi

    clear_cache
    /sbin/update_chrooted conf >&2 || :
}

### hostname
check_hostname()
{
    local hn="$1"
    local length=

    length=${#hn}
    if [ $length -gt $max_hostname_length ]; then
        write_error "`_ "Host name is too long"`"
        return 1
    fi
    return 0
}

read_hostname()
{
	local netconfig="/etc/sysconfig/network"
	local hostname_file="/etc/hostname"
	local value=

	[ -f "$cachedir/network" ] && netconfig="$cachedir/network"
	[ -f "$cachedir/hostname" ] && hostname_file="$cachedir/hostname"

	[ -f "$HOSTNAMECTL" ] && value="$($HOSTNAMECTL hostname --static)"

	if [ -z "$value" ]; then
		if [ -f "$hostname_file" ]; then
			value="$(cat "$hostname_file" | head -1)"
		else
			value="$(shell_config_get "$netconfig" HOSTNAME)"
		fi
	fi

	[ -n "$value" ] || value="localhost.localdomain"
	echo "$value"
}

write_hostname()
{
	local netconfig="$cachedir/network"

	check_hostname "$1" || return
	shell_config_set "$netconfig" HOSTNAME "$1"
	shell_config_del "$netconfig" DOMAINNAME

	# Write hostname to /etc/hostname
	echo "$1" >"/etc/hostname"

	if [ -f "$cachedir/hostname" ]; then
		echo "$1" >"$cachedir/hostname"
	fi
}

### computer name

read_computer_name()
{
	local value="$(read_hostname)"
	echo "$value"
}

read_computer_domain()
{
	local host=$1
	[ $(expr index "$host" .) -eq 0 ] && unset host
	local value="${host:-$(read_hostname)}"
	local domain="${value#*.}"
	echo "$domain"
}

write_computer_name()
{
    write_hostname "$1"
}

### interface work
list_ipv()
{
	write_enum_item "4" "`_ "IPv4"`"
	if is_ipv6_enabled; then
		write_enum_item "6" "`_ "IPv6"`"
	fi
}

read_iface_host_var_cached()
{
	if [ -f "$cachedir/$1/options" ]; then
		read_iface_host_var "$cachedir/$1"
	else
		read_iface_host_var "/etc/net/ifaces/$1"
	fi | sort -u
}

list_eth_cached()
{
  local filter=cat filter_list= b= s=
  for b in $(list_bond_with_cache "$cachedir") $(list_bridge_with_cache "$cachedir"); do
	  echo "$b" 2>/dev/null
	  for s in $(read_iface_host_var_cached "$b"); do
		  filter_list="$filter_list${filter_list:+|}$s"
	  done
  done

  [ -z "$filter_list" ] || filter="egrep -v ($filter_list)"

  list_eth | $filter | while read name; do
        echo "$name" 2>/dev/null
    done
}

list_ifaces()
{
	list_eth_cached
	list_vlan_with_cache "$cachedir"
}

list_mask()
{
	local ipv="${1:-4}"
	if [ "$ipv" = 4 ]; then
		for i in `seq 32 -1 0`; do
			write_enum_item "$i" "/$i ($(ipv4_prefix2mask "$i"))"
		done
	else
		for i in `seq 128 -1 0`; do
			write_enum_item "$i" "/$i"
		done
	fi
}

list_controlled()
{
    local name="$1"; shift

    write_enum_item "etcnet" "Etcnet"
    if [ -f "$NETWORKMANAGER" ] && ! is_bond "$name" && ! is_bridge "$name" && ! is_vlan "$name"; then
	write_enum_item "NetworkManager" "NetworkManager (etcnet)"
	write_enum_item "NetworkManagerNative" "NetworkManager (native)"
    fi
    if [ -f "$SYSTEMD_NETWORKD" ] && ! is_bond "$name" && ! is_bridge "$name" && ! is_vlan "$name"; then
	write_enum_item "systemd-networkd" "systemd-networkd"
    fi
    write_enum_item "nothing" "`_ "not under control"`"
}

list_configuration()
{
	local ipv="${1:-4}"
	[ "$ipv" = 6 ] && write_enum_item "ra" "`_ "Use RA only"`"
    write_enum_item "dhcp" "`_ "Use DHCP"`"
	[ "$ipv" = 4 ] && write_enum_item "ipv4ll" "`_ "Use Zeroconf"`"
    write_enum_item "static" "`_ "Manually"`"
}

read_info()
{
	local name="$1";shift
	local iftype="${1:-eth}"
	local info=
	local tmp=
	local nl='
'

    [ -n "$name" ] || return 0

	case "$iftype" in
		eth)
			info="`_ "Network adaptor:"`"
			info="$info $(netdev_read_info "$name")"

			if ! netdev_is_wireless "$name"; then
				netdev_is_plugged "$name" && tmp="`_ "plugged"`" || tmp="`_ "unplugged"`"
				info="$info$nl$tmp"
		    fi
			;;
		vlan)
			info="`_ "VLAN: "`$(read_iface_host_var_cached "$name") VID $(read_iface_option "$ifacedir" "VID")"
			;;
		bond)
			info="`_ "Bonding: "`$(read_iface_host_var_cached "$name")"
			;;
		bri)
			info="`_ "Bridge: "`$(read_iface_host_var_cached "$name")"
			;;
	esac

	# MAC
	tmp="$(netdev_read_mac "$name")"
	if [ -n "$tmp" ]; then
		info="$info$nl`_ "MAC:"` $tmp"
	fi

	# Status
	netdev_is_up "$name" && tmp="`_ "UP"`" || tmp="`_ "DOWN"`"
	if [ -n "$tmp" ]; then
		info="$info$nl`_ "Interface is "`$tmp"
	fi

	echo "$info"
}

read_controlled()
{
	local nm_controlled="$(read_iface_option "$1" NM_CONTROLLED)"
	local systemd_controlled="$(read_iface_option "$1" SYSTEMD_CONTROLLED)"
	local disabled="$(read_iface_option "$1" DISABLED)"
	local bootproto="$(read_iface_option "$1" BOOTPROTO)"

	# Set NetworkManager Native as default if NetworkManager exists
	if [ -f "$NETWORKMANAGER" -a ! -d "$1" ]; then
		nm_controlled="yes"
		bootproto="static"
	# Set systemd-networkd as default if NetworkManager not exists
	elif [ -f "$SYSTEMD_NETWORKD" -a ! -d "$1" ]; then
		systemd_controlled="yes"
		nm_controlled="no"
	fi

	if [ $(write_bool "$nm_controlled") = "#t" ];then
		if [ "$bootproto" = "static" -a ! -e "$1/ipv4address" ];then
			echo 'NetworkManagerNative'
		else
			echo 'NetworkManager'
		fi
	elif [ $(write_bool "$systemd_controlled") = "#t" ];then
		echo 'systemd-networkd'
	elif [ $(write_bool "$disabled") = "#f" ];then
		echo 'etcnet'
	else
		echo "nothing"
	fi
}

read_configuration()
{
	local bootproto="$(read_iface_option "$1" BOOTPROTO)"
	local ipv="${2:-4}"
	local config=

	case "$bootproto" in
		static)
			# If there is no IPv6 static configuration
			# then it is RA really.
			if [ "$ipv" = 6 ] &&
				[ ! -s "$1/ipv6address" ] &&
				[ ! -s "$1/ipv6route" ]; then
				config='ra'
			else
				config='static'
			fi
			;;
		ipv4ll)
			if [ "$ipv" = 6 ]; then
				config='ra'
			else
				config='ipv4ll'
			fi
			;;
		dhcp|dhcp[-,\ ]*)
			if [ "$ipv" = 4 ]; then
				config='dhcp'
			else
				# Very strange logic in etcnet
				config='ra'
			fi
			;;
		dhcp6|dhcp6[-,\ ]*)
			if [ "$ipv" = 4 ]; then
				# Very strange logic in etcnet
				config='static'
			else
				config='dhcp'
			fi
			;;
		*)
			if [ "$ipv" = 4 ]; then
				config='dhcp'
			else
				config='ra'
			fi
			;;
	esac

	echo "$config"
}

read_config_ipv()
{
	local ifacedir="$1"; shift
	local v="$1"; shift
	local enabled="$(read_iface_option "$ifacedir" CONFIG_IPV$v)"

	case "$enabled" in
		[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|[Yy]|1) echo yes ;;
		*) echo no ;;
	esac
}

read_iface()
{
	local name="$1"; shift
	local ipv="${1:-4}"; shift
	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"
	local conf=
	local iface_type=

	#collect general information
  # We just need to know is it a bridge of any type
  if is_bridge "$name"; then
    iface_type="bri"
  else
    iface_type="$(read_iface_option "$ifacedir" "TYPE")"
  fi
  write_string_param "iface_type" "$iface_type"

  local vlan_vid=
  local iface_host=
  if [ "$iface_type" == "vlan" ]; then
    vlan_vid="$(read_iface_option "$ifacedir" "VID")"
    iface_host="$(read_iface_option "$ifacedir" "HOST")"
    write_string_param "label_vlan_host" "$iface_host"
    write_string_param "label_vlan_vid" "$vlan_vid"
  fi

	write_bool_param ipv_enabled "$(read_config_ipv "$ifacedir" "$ipv")"
	write_string_param iface_info "$(read_info "$name" "$iface_type")"
	conf="$(read_configuration "$ifacedir" "$ipv")"
	write_string_param configuration "$conf"
	write_string_param controlled "$(read_controlled "$ifacedir")"
	write_bool_param onboot "$(read_iface_option "$ifacedir" ONBOOT)"
	write_bool_param wireless "$(netdev_is_wireless "$name" && echo "yes" || echo "no")"

	if [ "$conf" = static ]; then
		write_string_param dns "$(read_iface_dns "$ifacedir")"
		write_string_param search "$(read_iface_search "$ifacedir")"

		write_string_param default "$(read_iface_default_gw "$ifacedir" "$ipv")"
	else
		write_string_param dns "$(read_current_dns)"
		write_string_param search "$(read_current_search)"

		write_string_param default "$(read_iface_current_default_gw "$name" "$ipv")"
	fi
}

write_controlled()
{
	local ifacedir="$1";shift
	local controlled="$1";shift

	case "$controlled" in
	    systemd-networkd)
		write_iface_option "$ifacedir" DISABLED yes
		write_iface_option "$ifacedir" NM_CONTROLLED no
		write_iface_option "$ifacedir" SYSTEMD_CONTROLLED yes
		;;
	    NetworkManagerNative)
		write_iface_option "$ifacedir" DISABLED yes
		write_iface_option "$ifacedir" NM_CONTROLLED yes
		write_iface_option "$ifacedir" SYSTEMD_CONTROLLED no
		write_iface_option "$ifacedir" BOOTPROTO "static"
		rm -f -- "$ifacedir/ipv4address"
		;;
	    NetworkManager)
		write_iface_option "$ifacedir" DISABLED yes
		write_iface_option "$ifacedir" NM_CONTROLLED yes
		write_iface_option "$ifacedir" SYSTEMD_CONTROLLED no
		touch "$ifacedir/ipv4address"
		;;
	    etcnet)
		write_iface_option "$ifacedir" DISABLED no
		write_iface_option "$ifacedir" NM_CONTROLLED no
		write_iface_option "$ifacedir" SYSTEMD_CONTROLLED no
		;;
	    nothing)
		write_iface_option "$ifacedir" DISABLED yes
		write_iface_option "$ifacedir" NM_CONTROLLED no
		write_iface_option "$ifacedir" SYSTEMD_CONTROLLED no
		;;
	esac
}

# Try to determine BOOTPROTO according with
# that brain-damaged logic in etcnet
get_etcnet_bootproto()
{
	local ipv4config="$1"; shift
	local ipv6config="$1"; shift
	local bootproto=

	if [ -z "$ipv4config" ]; then
		case "$ipv6config" in
			dhcp) bootproto=dhcp6 ;;
			*) bootproto=static ;;  # static | ra
		esac
	elif [ -z "$ipv6config" ]; then
		bootproto="$ipv4config"
	else
		case "$ipv4config" in
			static)
				if [ "$ipv6config" = dhcp ]; then
					bootproto=dhcp6
				else # static | ra
					bootproto=static
				fi
				;;
			ipv4ll)
				if [ "$ipv6config" = ra ]; then
					bootproto=ipv4ll
				else # static | dhcp
					# Cannot be defined
					bootproto=
				fi
				;;
			dhcp)
				if [ "$ipv6config" = ra ]; then
					bootproto=dhcp
				else # static | dhcp
					# Cannot be defined
					bootproto=
				fi
				;;
		esac
	fi

	echo "$bootproto"
}

# Try to determine BOOTPROTO according with
# that brain-damaged logic in etcnet for systemd-networkd
get_systemd_networkd_bootproto()
{
	local ipv4config="$1"; shift
	local ipv6config="$1"; shift
	local bootproto="$ipv4config"

	if [ -z "$ipv4config" ]; then
		case "$ipv6config" in
			dhcp) bootproto=dhcp6 ;;
			ra) bootproto=ipv6ll ;;
			*) bootproto=static ;;
		esac
	elif [ -z "$ipv6config" ]; then
		bootproto="$ipv4config"
	fi

	case "$bootproto" in
		static)
			if [ "$ipv6config" = dhcp ]; then
				bootproto=dhcp6
			elif [ "$ipv6config" = ra ]; then
				bootproto=static
			else
				bootproto=static
			fi
			;;
		ipv4ll)
			if [ "$ipv6config" = static ]; then
				bootproto=ipll
			elif [ "$ipv6config" = ra ]; then
				bootproto=ipll
			else
				bootproto=ipv4ll
			fi
			;;
		dhcp)
			if [ "$ipv6config" = dhcp ]; then
				bootproto=dhcp
			elif [ "$ipv6config" = ra ]; then
				bootproto=dhcp
			else
				bootproto=dhcp4
			fi
			;;
		dhcp6|ipv6ll)
			bootproto="$bootproto"
			;;
		*dhcp)
			if [ "$ipv6config" = dhcp ]; then
				bootproto=dhcp
			elif [ "$ipv6config" = ra ]; then
				bootproto=dhcp
			else
				bootproto=dhcp4
			fi
			;;
		*)
			if [ "$ipv6config" = dhcp ]; then
				bootproto=dhcp6
			elif [ "$ipv6config" = ra ]; then
				bootproto=dhcp6
			else
				bootproto=static
			fi
			;;
	esac

	echo "$bootproto"
}

write_configuration()
{
	local ifacedir="$1";shift
	local configuration="$1";shift
	local ipv="$1"; shift
	local bootproto=
	local systemd_bootproto=
	local ipv4config= ipv6config=

	if [ "$ipv" = 4 ]; then
		ipv4config="$configuration"
		[ "$(read_config_ipv "$ifacedir" 6)" = yes ] &&
			ipv6config="$(read_configuration "$ifacedir" 6)"
	else
		ipv6config="$configuration"
		[ "$(read_config_ipv "$ifacedir" 4)" = yes ] &&
			ipv4config="$(read_configuration "$ifacedir" 4)"
	fi

	bootproto="$(get_etcnet_bootproto "$ipv4config" "$ipv6config")"
	systemd_bootproto="$(get_systemd_networkd_bootproto "$ipv4config" "$ipv6config")"

	if [ -n "$bootproto" ]; then
		write_iface_option "$ifacedir" BOOTPROTO "$bootproto"
		write_iface_option "$ifacedir" SYSTEMD_BOOTPROTO "$systemd_bootproto"
		if [ "$ipv" = 6 -a "$ipv6config" = ra ]; then
			# Actually RA-only it is static without configuration.
			# So remove ipv6* config files.
			rm -f -- "$ifacedir/ipv6address" "$ifacedir/ipv6route"
		fi
		if [ "$bootproto" != "static" ]; then
			rm -f -- "$ifacedir/ipv${ipv}address" "$ifacedir/ipv${ipv}route" "$ifacedir/resolv.conf"
		fi
	else
		write_error "`_ "IPv4 and IPv6 configurations are incompatible:"` $ipv4config and $ipv6config"
		return 1
	fi

	return 0
}

write_config_ipv()
{
	local ifacedir="$1"; shift
	local v="$1"; shift
	local enabled="$1"; shift
	local config_ipv=

	test_bool "$enabled" && config_ipv=yes || config_ipv=no
	write_iface_option "$ifacedir" CONFIG_IPV$v "$config_ipv"
}

check_dns()
{
	local ifacedir="$1"; shift
	local ns_list="$1"; shift
	local config_ipv4="$(read_config_ipv "$ifacedir" 4)"
	local config_ipv6="$(read_config_ipv "$ifacedir" 6)"

	for ns in $ns_list; do
		if [ "$config_ipv4" = yes ] && check_ip "$ns" 4; then
			continue
		fi
		if [ "$config_ipv6" = yes ] && check_ip "$ns" 6; then
			continue
		fi
		# ns is not IPv4 and not IPv6 address
		return 1
	done

	return 0
}

write_iface()
{
	local name="$1"; shift
	local ifacedir="$cachedir/$name"
	local is_wireless=
	local systemd_bootproto=

	# check bond settings
	if is_bond "$name" && ! check_bond "$name"; then
		return
	fi

	if is_bridge "$name" && ! check_bridge "$name"; then
		return
	fi

	if [ -z "$(read_iface_option "$ifacedir" TYPE)" ]; then
		write_iface_option "$ifacedir" TYPE eth
	fi

	netdev_is_wireless "$name" && is_wireless=yes || is_wireless=no
	write_iface_option "$ifacedir" CONFIG_WIRELESS "$is_wireless"

	if [ -n "$in_onboot" ]; then
		local onboot=

		test_bool "$in_onboot" && onboot=yes || onboot=no
		write_iface_option "$ifacedir" ONBOOT "$onboot"
	fi

	[ -n "$in_configuration" ] &&
		test_bool "$in_ipv_enabled" &&
	    write_configuration "$ifacedir" "$in_configuration" "$in_ipv"

	[ -n "$in_ipv_enabled" ] &&
		write_config_ipv "$ifacedir" "$in_ipv" "$in_ipv_enabled"

	if [ "$in_configuration" = "static" ]; then
		if is_defined "in_default" && [ -n "$in_default" ] && test_bool "$in_ipv_enabled"; then
			check_ip "$in_default" "$in_ipv" &&
				write_iface_default_gw "$ifacedir" "$in_default" "$in_ipv" ||
				write_error "`_ "Invalid default gateway"`"
		fi

		if is_defined "in_dns"; then
			check_dns "$ifacedir" "$in_dns" &&
				write_iface_dns "$ifacedir" "$in_dns" ||
				write_error "`_ "Invalid DNS list"`"
		fi

		is_defined "in_search" &&
			write_iface_search "$ifacedir" "$in_search"
	fi

	if [ -n "$in_controlled" ]; then
		write_controlled "$ifacedir" "$in_controlled"
		systemd_bootproto="$(read_iface_option "$ifacedir" SYSTEMD_BOOTPROTO)"
		if [ "$in_controlled" = "systemd-networkd" -a -n "$systemd_bootproto" ]; then
			write_systemd_networkd "$ifacedir" "$name" "$systemd_bootproto"
		else
			del_systemd_networkd "$ifacedir" "$name"
		fi
	fi
}

check_ip()
{
	local ip="$1"
	local ipv="${2:-4}"

	if [ "$ipv" = 4 ]; then
		valid_ipv4addr "$ip"
	else
		valid_ipv6addr "$ip"
	fi
}

check_prefix()
{
	local prefix="$1"
	local ipv="${2:-4}"
	local max=

	[ "$ipv" = 4 ] &&
		max=32 ||
		max=128

	[ -n "$prefix" -a $prefix -ge 0 -a $prefix -le $max ]
}

add_iface_address()
{
	local iface="$1"
	local addr="$2"
	local mask="$3"
	local v="$4"


	if ! check_ip "$addr" "$v" || ! check_prefix "$mask" "$v"; then
		write_error "`_ "Invalid IP address:"` $addr/$mask"
		return 1
	fi
	if [ -n "$iface" -a -n "$addr" -a -n "$mask" ] ; then
		echo "$addr/$mask" >> "$cachedir/$iface/ipv${v}address"
	fi
}

del_iface_address()
{
    local iface="$1"
    local addr="$2"
	local v="$3"
    if [ -n "$iface" -a -n "$addr" ] ; then
	sed -i -e "s|^${addr}$||" -e '/^$/d' "$cachedir/$iface/ipv${v}address"
    fi
}

list_iface_addresses()
{
    local name="$1"; shift
	local v="$1"; shift
    [ -n "$name" ] || name="$(list_ifaces|head -n1)"

	local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"

    [ -s "$ifacedir/ipv${v}address" ] && cat "$ifacedir/ipv${v}address" | write_enum
}

list_current_iface_addresses()
{
    local name="$1"; shift
	local v="${1:-4}"

    [ -n "$name" ] || return

	read_iface_current_addresses "$name" "$v" | write_enum
}

#initial actions
iface_up lo
clear_cache

alterator_export_var \
    computer_name	hostname \
    search		hostname-list \
    dns			ip-address-list
#    default		ipv4-address \
#    addresses 		ipv4-addrwmask-list \


oem_wifi_first_start()
{
	[ -n "$in_name" ] || return
	name="$in_name"
	if [[ "$name" == wlan* && -f /usr/lib/alterator/backend3/setup-kworkstation ]]; then
		local ifacedir="$(ifacedir_with_cache "$cachedir" "$name")"
		[ -f "$ifacedir/options" ] && return
		[ -d "$ifacedir" ] || mkdir -p "$ifacedir"
		touch "$ifacedir/options"
		write_iface_option "$ifacedir" DISABLED yes
		write_iface_option "$ifacedir" NM_CONTROLLED yes
		write_iface_option "$ifacedir" BOOTPROTO "static"
		write_iface_option "$ifacedir" CONFIG_WIRELESS yes
	fi
}


on_message()
{
	oem_wifi_first_start

	case "$in_action" in
		add_iface_address)
			init_cache "$in_name"
		    add_iface_address "$in_name" "${in_addip}" "${in_addmask}" "$in_ipv"
			;;
		del_iface_address)
			init_cache "$in_name"
		    del_iface_address "$in_name" "$in_addresses" "$in_ipv"
			;;
		list)
			case "${in__objects##*/}" in
				avail_ipv) list_ipv;;
			    avail_masks) list_mask "$in_ipv";;
			    avail_configurations) list_configuration "$in_ipv";;
			    avail_controlled) list_controlled "$in_name";;
			    avail_iface_address) list_iface_addresses "$in_name" "$in_ipv";;
			    list_current_iface_address) list_current_iface_addresses "$in_name" "$in_ipv";;
          # avail_ifaces
			    *) list_ifaces|write_enum;;
			esac
			;;
		read)
			local name="${in_name}"
			[ -n "$name" ] || name="$(list_ifaces|head -n1)"
			case "$in__objects" in
			    /)
				[ -n "$name" ] && read_iface "$name" "$in_ipv"

				write_string_param name		"$name"

                if [ -z "$DURING_INSTALL" ] && check_altdomain; then
                    write_bool_param altdomain yes
                else
                    write_bool_param altdomain no
                fi

				write_string_param computer_name "$(read_computer_name)"
				write_string_param computer_domain "$(read_computer_domain)"


				if [ -f "$ALTERATOR_BOND" ]; then
					write_bool_param bond_module_installed yes
				else
					write_bool_param bond_module_installed no
				fi

				if [ -f "$ALTERATOR_WIFI" ]; then
					write_bool_param wifi_module_installed yes
				else
					write_bool_param wifi_module_installed no
				fi

				if [ -f "$ALTERATOR_VLAN" ]; then
					write_bool_param vlan_module_installed yes
				else
					write_bool_param vlan_module_installed no
				fi

				if [ -f "$ALTERATOR_BRIDGE" ]; then
					write_bool_param bridge_module_installed yes
				else
					write_bool_param bridge_module_installed no
				fi
				;;
			    controlled)
				local controlled="$(read_controlled "$(ifacedir_with_cache "$cachedir" "$name")")"
				write_string_param controlled "$controlled"
				;;
			esac
			;;
		write)
			if  [ -n "$in_reset" ]; then
			    clear_cache
			    return
			fi
			local name="${in_name}"
			[ -n "$name" ] || name="$(list_ifaces|head -n1)"
			init_cache "$name"

			[ -n "$name" ] && write_iface "$name"

			[ -n "$in_computer_name" ] && write_computer_name "$in_computer_name"

			if [ -n "$in_commit" ]; then
			    commit_cache || return
			fi
			;;
	esac
}

message_loop
# vim: autoindent tabstop=2 shiftwidth=2 expandtab softtabstop=2 filetype=sh
