# (C) Copyright 2005-2007, Axis Communications AB, LUND, SWEDEN
# This file is released under the GPL v2.

RC_GOT_IPv4=y

[ -r $RCLIB/sh/rc-dhcp.sh ] && . $RCLIB/sh/rc-dhcp.sh
[ -r $RCLIB/sh/rc-zeroconf.sh ] && . $RCLIB/sh/rc-zeroconf.sh

#---------------------------------------------------------------------
# IPv4 configuration functions
#     net4_config
#     net4_stop
#     net4_need_restart
#     net4_get_enabled
#     net4_set_enabled
#---------------------------------------------------------------------

# Configure the interface for IPv4 using parameters from global env.
# variables.
# The interface is brought up before calling this function.
net4_config() {
	local _iface

	[ $# -gt 0 ] || {
		echo "net4_config: invalid number of arguments: $#" >&2
		return 1
	}

	_iface=$1

	if [ "$INET_ENABLED" = no ]; then
		information "no IPv4 on $_iface"

		[ "$RC_GOT_ZEROCONF" ] && zeroconf_stop $_iface
		if check_dhcp $_iface; then
			stop_dhcp $_iface
		fi
		ip -f inet address flush scope nowhere dev $_iface 2>/dev/null
		ip -f inet address flush scope global dev $_iface 2>/dev/null
		return 0
	fi
	information "IPv4 on $_iface"

	# Automatic IP configuration.
	information "boot protocol: $BOOTPROTO"
	if [ "$BOOTPROTO" = dhcp ]; then
		if ! check_dhcp $_iface; then
			manual_ipv4_configuration $_iface nowhere
			start_dhcp $_iface
		else
			! check_dhcp_lease $_iface &&
			manual_ipv4_configuration $_iface nowhere
		fi
	else
		check_dhcp $_iface && stop_dhcp $_iface
		manual_ipv4_configuration $_iface global
	fi

	# Make it possible to talk to link-local addresses.
	ip -f inet route add 169.254.0.0/16 dev eth0 metric 99

	# Zeroconf
	if [ "$RC_GOT_ZEROCONF" ]; then
		zeroconf_config $_iface
	fi
}

# Remove all IPv4 configuration.
net4_stop() {
	local _iface

	[ $# -gt 0 ] || {
		echo "net4_stop: invalid number of arguments: $#" >&2
		return 1
	}

	_iface=$1

	[ "$RC_GOT_ZEROCONF" ] && zeroconf_stop $_iface
	check_dhcp $_iface && stop_dhcp $_iface
	ip -f inet address flush scope nowhere dev $_iface 2>/dev/null
	ip -f inet address flush scope global dev $_iface 2>/dev/null
	return 0
}

# Check if the IPv4 configuration require a restart of the interface.
net4_need_restart() {
	return 1
}

net4_get_enabled() {
	[ "$INET_ENABLED" != no ] && return 0
	return 1
}

net4_set_enabled() {
	INET_ENABLED=yes
}

#---------------------------------------------------------------------
# Help functions
#---------------------------------------------------------------------

# Convert dotted decimal netmask to prefix length.
netmask2plen() {
	local _plen _done _old_ifs _quad _m

	if [ $# -ne 1 ]; then
		echo "netmask2plen: invalid number of arguments: $#" >&2
		return 1
	fi

	_plen=0
	_done=
	_old_IFS="$IFS"
	IFS=.
	for _quad in $1; do
		[ "$_done" ] && break;
		for _m in 128 64 32 16 8 4 2 1; do
			if [ $(($_quad & $_m)) = $_m ]; then
				_plen=$(($_plen + 1))
			else
				_done=1
				break
			fi
		done
	done
	IFS="$_old_IFS"
	echo -n $_plen
	return 0
}

# Convert prefix length to dotted decimal netmask.
plen2netmask() {
	local _plen _quad _numquads _i

	if [ $# -ne 1 ]; then
		echo "plen2netmask: invalid number of arguments: $#" >&2
		return 1
	fi
	[ \( $1 -ge 0 \) -a \( $1 -le 32 \) ] 2>/dev/null || {
		echo "plen2netmask: invalid prefix length: \"$1\"" >&2
		return 1
	}

	_plen=$1
	_quad=0
	_numquads=0
	while [ $_plen -gt 0 ]; do
		for _i in 128 64 32 16 8 4 2 1; do
			if [ $_plen -gt 0 ]; then
				_quad=$(($_quad + $_i))
				_plen=$(($_plen - 1))
			else
				break
			fi
		done
		echo -n $_quad
		_numquads=$(($_numquads + 1))
		[ $_numquads -lt 4 ] && echo -n .
		_quad=0
	done
	while [ $_numquads -lt 4 ]; do
		echo -n 0
		_numquads=$(($_numquads + 1))
		[ $_numquads -lt 4 ] && echo -n .
	done
	return 0
}

# Manual IPv4 configuration
manual_ipv4_configuration() {
	local _iface _scope

	[ $# -gt 1 ] || {
		echo "manual_ipv4_configuration: invalid number of arguments: $#" >&2
		return 1
	}

	_iface=$1
	_scope=$2

	if [ -z "$IP" ] || [ "$IP" = none ]; then
		information "no manual IPv4 address configured"
	else
		[ "$NETMASK" ] || end 1 "$0: NETMASK is missing!"
		[ "$BROADCAST" ] || end 1 "$0: BROADCAST is missing!"

		ip -f inet address flush scope nowhere dev $_iface 2>/dev/null
		ip -f inet address flush scope global dev $_iface 2>/dev/null

		if ip -f inet address add $IP/$(netmask2plen $NETMASK) \
			   broadcast $BROADCAST scope $_scope dev $_iface
		then
			information "IP address: $IP"
			information "netmask: $NETMASK"
			information "broadcast address: $BROADCAST"
		else
			return 1
		fi
	fi

	# Default route
	if [ "$GATEWAY" ]; then
		information "default IPv4 gateway: $GATEWAY"
		if ! net_route_exists default $GATEWAY $_iface; then
			ip -f inet route del 0.0.0.0/0 metric 0 2>/dev/null
			ip -f inet route add default via $GATEWAY dev $_iface ||
				return 1
		fi
	else
		information "no manual IPv4 default routers configured"
	fi
}
