#!/bin/bash

DH_CONF="/var/cache/dhclient.conf"
WATCH_CONF="/data/etc/watch.conf"

SYS_STATIC_CONF="/etc/static_ip.conf"
BOOT_STATIC_CONF="/boot/static_ip.conf"
STATIC_CONF="/data/etc/static_ip.conf"

SYS_INTERFACES_CONF="/etc/network/interfaces"
BOOT_INTERFACES_CONF="/boot/network/interfaces"
INTERFACES_CONF="/data/etc/network/interfaces"

LINK_NEGO_TIMEOUT=10


test -n "${OS_VERSION}" || source /etc/init.d/base

source ${WATCH_CONF}

prepare_conf ${STATIC_CONF} ${SYS_STATIC_CONF} ${BOOT_STATIC_CONF}
test -r ${STATIC_CONF} && source ${STATIC_CONF}

prepare_conf ${INTERFACES_CONF} ${SYS_INTERFACES_CONF} ${BOOT_INTERFACES_CONF}

mkdir -p /var/lib/dhcp


watch_eth() {
    count=0
    while true; do
        sleep 5
        if [[ "$(cat /sys/class/net/${OS_ETH}/operstate 2>/dev/null)" == "up" ]]; then
            count=0
        else
            if [[ ${count} -lt ${LINK_WATCH_TIMEOUT} ]]; then
                count=$((${count} + 5))
                logger -t ethernet "disconnected"
            else
                logger -t ethernet "disconnected for ${LINK_WATCH_TIMEOUT} seconds, calling panic action"
                panic_action network
            fi
        fi
    done
}

watch_ip() {
    iface=$1
    count=0
    while true; do
        sleep 5
        if ip addr show dev ${iface} | grep inet &>/dev/null; then
            count=0
        else
            if [[ ${count} -lt ${IP_WATCH_TIMEOUT} ]]; then
                count=$((${count} + 5))
                logger -t network "${iface} has no IP address"
            else
                logger -t network "${iface} had no IP address for ${IP_WATCH_TIMEOUT} seconds, calling panic action"
                panic_action network
            fi
        fi
    done
}

start_lo() {
    if [[ -r ${INTERFACES_CONF} ]] && grep -q "^iface lo" ${INTERFACES_CONF}; then
        ifup -i ${INTERFACES_CONF} lo 2>&1 | logger -t network
    else
        ifconfig lo up
    fi
}

start_wlan() {
    msg_begin "Configuring wireless network"
    if ! ifconfig ${OS_WLAN} &>/dev/null; then
        msg_fail "no device"
        return 1
    fi

    if [[ "$(cat /sys/class/net/${OS_WLAN}/carrier 2>/dev/null)" != "1" ]]; then
        msg_fail "no link"
        return 1
    fi

    if [[ -n "${mtu}" ]]; then
        ip link set mtu ${mtu} dev ${OS_WLAN}
    fi

    if [[ -r ${INTERFACES_CONF} ]] && grep -q "^iface ${OS_WLAN}" ${INTERFACES_CONF}; then
        ifup -i ${INTERFACES_CONF} ${OS_WLAN} 2>&1 | logger -t network
        test ${PIPESTATUS[0]} == 0 && msg_done || msg_fail
    else
        if [[ -n "${STATIC_IP}" ]]; then
            msg_done ${STATIC_IP}
            ifconfig ${OS_WLAN} ${STATIC_IP} up
            STATIC_IP="" # won't be used again
        else
            msg_done dhcp
            dhclient -cf "${DH_CONF}" ${OS_WLAN}
        fi
    fi

    if [[ "${IP_WATCH}" == "true" ]] && ip addr show dev ${OS_WLAN} | grep inet &>/dev/null; then
        watch_ip ${OS_WLAN} &
    fi
}

start_eth() {
    msg_begin "Configuring wired network"

    # wait for driver
    w=3
    count=0
    while ! ifconfig ${OS_ETH} >/dev/null 2>&1; do
        sleep 1
        count=$((${count} + 1))
        if [[ ${count} -ge ${w} ]]; then
            msg_done "no device"
            return 1
        fi
    done

    # bring it up
    ifconfig ${OS_ETH} up

    # wait for operstate
    w=3
    count=0
    while [[ "$(cat /sys/class/net/${OS_ETH}/operstate 2>&1)" == "unknown" ]]; do
        sleep 1
        count=$((${count} + 1))
        if [[ ${count} -ge ${w} ]]; then
            msg_done "no link"
            return 1
        fi
    done

    # wait for link
    test "${LINK_WATCH}" == "true" || LINK_NEGO_TIMEOUT=5
    count=0
    while [[ "$(cat /sys/class/net/${OS_ETH}/carrier 2>&1)" != "1" ]]; do
        sleep 1
        count=$((${count} + 1))
        if [[ ${count} -ge ${LINK_NEGO_TIMEOUT} ]]; then
            msg_done "no link"
            return 1
        fi
    done
    
    if [[ -n "${mtu}" ]]; then
        ip link set mtu ${mtu} dev ${OS_ETH}
    fi

    if [[ -r ${INTERFACES_CONF} ]] && grep -q "^iface ${OS_ETH}" ${INTERFACES_CONF}; then
        ifup -i ${INTERFACES_CONF} ${OS_ETH} 2>&1 | logger -t network
        test ${PIPESTATUS[0]} == 0 && msg_done || msg_fail
    else
        if [[ -n "${STATIC_IP}" ]]; then
            msg_done ${STATIC_IP}
            ifconfig ${OS_ETH} ${STATIC_IP} up
            STATIC_IP="" # won't be used again
        else
            msg_done dhcp
            dhclient -cf "${DH_CONF}" ${OS_ETH}
        fi
    fi

    if [[ "${LINK_WATCH}" == "true" ]]; then
        watch_eth &
    fi

    if [[ "${IP_WATCH}" == "true" ]] && ip addr show dev ${OS_ETH} | grep inet &>/dev/null; then
        watch_ip ${OS_ETH} &
    fi
}

start() {
    hostname=$(hostname)
    echo "send host-name = \"${hostname}\";" > /var/cache/dhclient.conf

    start_lo

    test "${OS_NETWORKLESS}" == "true" && return 0

    ssid=$(cat /data/etc/wpa_supplicant.conf 2>&1 | grep ssid | grep -v scan_ssid | cut -d '"' -f 2)
    test -n "${OS_WLAN}" -a -n "${ssid}" && start_wlan && wlan_ok="ok"
    test -n "${OS_PPP}" -a -r /data/etc/ppp/modem && ifconfig | grep ${OS_PPP} &>/dev/null && ppp_ok="ok"
    def_route_ok=$(ip route get 1.1.1.1 &>/dev/null && echo "ok")
    
    if [[ -n "${OS_ETH}" ]]; then
        # if wifi or ppp link ok, start eth in background
        if [[ "${wlan_ok}" == "ok" ]] || [[ "${ppp_ok}" == "ok" ]] && [[ "${def_route_ok}" == "ok" ]]; then
            start_eth &>/dev/null &
        else
            start_eth && eth_ok="ok"
        fi
    fi

    if [[ "${eth_ok}" != "ok" ]] && [[ "${wlan_ok}" != "ok" ]] && [[ "${ppp_ok}" != "ok" ]]; then
        if [[ "${LINK_WATCH}" == "true" ]]; then
            logger -t network "no network connection available, calling panic action"
            panic_action network
            return 1
        else
            logger -t network "no network connection available"
            return 0
        fi
    fi

    if [[ -r ${INTERFACES_CONF} ]]; then
        # ifup doesn't set the DNS server, so we have to set it manually
        STATIC_DNS=$(cat ${INTERFACES_CONF} | grep dns-nameserver | tr -s ' ' | cut -d ' ' -f 3 | head -n 11)
        if [[ -n "${STATIC_DNS}" ]]; then
            msg_begin "Setting static DNS server to ${STATIC_DNS}"
            echo "nameserver ${STATIC_DNS}" > /etc/resolv.conf
            test $? == 0 && msg_done || msg_fail
        fi
        
        # Make sure all auto interfaces are brought up
        ifup -i ${INTERFACES_CONF} -a >/dev/null
    else
        if [[ -n "${STATIC_GW}" ]]; then
            msg_begin "Setting static gateway to ${STATIC_GW}"
            ip route add default via ${STATIC_GW}
            test $? == 0 && msg_done || msg_fail
        fi

        if [[ -n "${STATIC_DNS}" ]]; then
            msg_begin "Setting static DNS server to ${STATIC_DNS}"
            echo "nameserver ${STATIC_DNS}" > /etc/resolv.conf
            test $? == 0 && msg_done || msg_fail
        fi
    fi

    # re-evalutate default route, as it might have changed with start_eth or static IP
    def_route_ok=$(ip route get 1.1.1.1 &>/dev/null && echo "ok")
    if [[ "${def_route_ok}" != "ok" ]]; then
        if [[ "${IP_WATCH}" == "true" ]]; then
            logger -t network "no default route, calling panic action"
            panic_action network
            return 1
        else
            logger -t network "no default route"
            return 0
        fi
    fi
}

stop() {
    msg_begin "Stopping network"
    if [[ -r ${INTERFACES_CONF} ]]; then
        ifdown -i ${INTERFACES_CONF} -a 2>&1 | logger -t network
    fi
    ps | grep S40network | grep -v $$ | grep -v grep | tr -s ' ' | sed -e 's/^\s//' | cut -d ' ' -f 1 | xargs -r kill
    killall dhclient &>/dev/null
    msg_done
}

case "$1" in
    start)
        start
        ;;

    stop)
        stop
        ;;

    restart)
        stop
        start
        ;;

    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
esac

exit $?

