#!/bin/bash

# dhclient-script for Linux. Dan Halbert, March, 1997.
# Updated for Linux 2.[12] by Brian J. Murrell, January 1999.
# Modified for Debian.  Matt Zimmerman and Eloy Paris, December 2003

# Modified for Endian Firewall. Peter Warasin, September 2005

. /etc/rc.d/efw_lib.sh
. ${UPLINK_SCRIPTS}/generic/static.sh
. ${UPLINK_SCRIPTS}/generic/hookery.sh

# Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
exit_with_hooks() {
    exit_status=$1

    # Source the documented exit-hook script, if it exists
    if ! run_hook /etc/dhclient/dhclient-exit-hooks; then
        exit_status=$?
    fi

    # Now run scripts in the Debian-specific directory.
    if ! run_hookdir /etc/dhclient/dhclient-exit-hooks.d; then
        exit_status=$?
    fi

    exit $exit_status
}

function search_uplink() {
    local iface="$1"
    ls -1 ${UPLINK_ETC} | while read uplink; do
	RED_DEV=""
	ENABLED=""
	if [ ! -f "${UPLINK_ETC}/${uplink}/settings" ]; then
	    continue
	fi
	loadSettings "${UPLINK_ETC}/${uplink}/settings"
	if [ "${ENABLED}" != "on" ]; then
	    continue
	fi
	if [ -z "${RED_DEV}" ]; then
	    continue
	fi
	if [ "${RED_DEV}" == "$iface" ]; then
	    echo $uplink
	    return
	fi
    done
}

function ip_changed() {
    [ -z "$old_ip_address" ] && return 1
    [ "$old_ip_address" == "$new_ip_address" ] && return 1
    return 0
}

uplink=$(search_uplink $interface)

logger_tag="uplink[$uplink]"
if [ -z $uplink ] || [ ! -f "$UPLINK_ETC/$uplink/settings" ]; then
    logger_tag="uplink[unknown]"
    # uplink not found. make dhclient harmless
    log_failed "DHCP client runs with no uplink configuration. Stop it."
    kill $PPID
fi

loadSettings "$UPLINK_ETC/$uplink/settings"
red_type=$RED_TYPE
if [ -n "${DNS1}" -o -n "${DNS2}" ]; then
    new_domain_name_servers="${DNS1} ${DNS2}"
fi

if [ -n "${MTU}" ]; then
    new_interface_mtu="${MTU}"
fi

if [ -n "${MAC}" ]; then
    new_interface_mac="${MAC}"
fi

test -n $new_subnet_mask && export new_cidr=$(nm2cidr "$new_subnet_mask")
test -n $old_subnet_mask && export old_cidr=$(nm2cidr "$old_subnet_mask")

export new_ips="$new_ip_address/$new_cidr"
export old_ips="$old_ip_address/$old_cidr"

if [ "$new_ips" == "/" ]; then
    export new_ips=""
fi
if [ "$old_ips" == "/" ]; then
    export old_ips="$new_ips"
fi

new_gateway=$(echo "${new_routers}" | cut -d ' ' -f 1)
if [ -z "${new_gateway}" ]; then
    new_gateway=${new_routers}
fi

old_gateway=$(echo "${old_routers}" | cut -d ' ' -f 1)
if [ -z "${old_gateway}" ]; then
    old_gateway=${old_routers}
fi

# The action starts here

# Invoke the local dhcp client enter hooks, if they exist.
run_hook /etc/dhclient/dhclient-enter-hooks
run_hookdir /etc/dhclient/dhclient-enter-hooks.d

# XXX: what happens if static_start will be triggered which recreates all the
# ip link/ip addr, but does not reset default gateway, which will be removed
# on ip link set down. ip addresses will not change so the uplinkdaemon
# will not recognize the change!

# Execute the operation
case "$reason" in
    MEDIUM|ARPCHECK|ARPSEND)
        # Do nothing
        ;;
    PREINIT)
	static_up
        sleep 1
        ;;
    BOUND|RENEW|REBIND|REBOOT)
	log_done "Request acknowledged with reason $reason."
        if ip_changed; then
	    log_done "DHCP changed the ip address from $old_ips to $new_ips"

            # IP address changed. Bringing down the interface will delete all routes,
            # and clear the ARP cache.
	    static_stop
        fi

        if ip_changed || [ "$reason" == "BOUND" -o "$reason" == "REBOOT" ]; then
	    static_start
        fi
        ;;
    EXPIRE|FAIL|RELEASE|STOP)
	static_stop
        if [ "$reason" == "FAIL" ]; then
	    log_failed "DHCP request FAILED."
            set_failure "$uplink"
        else
	    log_failed "DHCP set to inactive due to $reason from DHCP server."
            set_inactive "$uplink"
        fi
        ;;
    TIMEOUT)
	static_up
	static_addr
	if [ $? -ne 0 ]; then
	    log_failed "FAILED configuring ip addresses"
            set_failure "$uplink"
	fi

        set -- $new_routers
        first_router="$1"
        if ping -I $interface -q -c 1 $first_router; then
	    if ip_changed; then
		log_done "DHCP sent TIMEOUT, but continues to work. Ip address changed from $old_ips to $new_ips."
		static_start
	    fi
	else
	    static_stop
	    log_failed "DHCP sent TIMEOUT. Connection failure."
	    set_failure "$uplink"
            exit_with_hooks 2
        fi
        ;;
esac

exit_with_hooks 0
