#! /bin/sh
#
# chkconfig: 2345 80 20
# description: start and stop ISDN services
#
# Debian/KNOPIPX changes Aug 2002 -KK

PATH="/bin:/sbin:/usr/bin:/usr/sbin"
export PATH

# Source configuration
[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
[ -d /etc/sysconfig/network-scripts ] || mkdir -p /etc/sysconfig/network-scripts

test -f /etc/sysconfig/isdncard || { echo "Error: no /etc/sysconfig/isdncard description file found." >&2 ; exit 0; }
. /etc/sysconfig/isdncard

if [ -z "$MODULE" ]; then
    exit 0
fi        

# disable debug as default
DEBUG=off
IBOD=no
RETVAL=0
sync_devices=0
raw_devices=0

if [ -f /var/log/isdn.log ] ; then
    touch /var/log/isdn.log
    chmod 644 /var/log/isdn.log
fi

function action()
{
echo "[1m$1[0m" ; shift
[ -n "$1" ] && "$@"
return "$?"
}

function log_echo()
{
    if [ "$DEBUG" = "on" ] ; then
        echo $*
    fi
}

function log_isdnctrl()
{
    if [ "$DEBUG" = "on" ]; then
        echo "isdnctrl $*" >>/var/log/isdn.log 2>&1
    fi
    isdnctrl $* >>/var/log/isdn.log 2>&1
}

function clear_env() {
    PROVIDER=; USER=; PASSWORD=; ENCAP=; DIALMODE=; SECURE=; MSN=; PHONE_IN=
    PREFIX=; AREACODE=; PHONE_OUT=; CITY=; BUNDLING=; LOCAL_IP=; REMOTE_IP=
    NETWORK=; BROADCAST=; HUPTIMEOUT=; DNS=; ISDN_HOSTNAME=; ISDN_DOMAIN=; L2_PROT=
    L3_PROT=; CALLBACK=; CHARGEHUP=; CHARGEINT=; CBHUP=; CBDELAY=; DIALMAX=
    AUTH=; IHUP=; IP_FORWARD=; SLAVE_DELAY=; SLAVE_TRIGGER=; FIRMWARE=
    VJ=; VJCCOMP=; AC=; PC=; BSDCOMP=; MTU=; MRU=; IPPPOPTION=; DRIVERTYPE=
    SLAVE_DIALMODE=; SLAVE_MSN=; SLAVE_PHONE_IN=; SLAVE_PHONE_OUT=
    SLAVE_HUPTIMEOUT=; SLAVE_CALLBACK=; SLAVE_CHARGEHUP=; SLAVE_CHARGEINT=
    SLAVE_CBHUP=; SLAVE_CBDELAY=; SLAVE_DIALMAX=; SLAVE_IHUP=; DELDEFAULTROUTE=
    OPTIONS_FILE=;
}

function set_channel_bundling() {
    if [ "$BUNDLING" = "yes" -o "$BUNDLING" = "on" ]; then
        IBOD="yes"
        if [ "$ENCAP" = "syncppp" ]; then
            if [ -z "$SLAVE_MSN" ]; then
                SLAVE_MSN="$MSN"
            fi
            if [ -z "$SLAVE_PHONE_OUT" ]; then
                SLAVE_PHONE_OUT="$PHONE_OUT"
            fi
            if [ -z "$SLAVE_PHONE_IN" ]; then
                SLAVE_PHONE_IN="$PHONE_IN"
            fi
            if [ -z "$SLAVE_HUPTIMEOUT" ]; then
                SLAVE_HUPTIMEOUT="$HUPTIMEOUT"
            fi
            if [ -z "$SLAVE_CHARGEHUP" ]; then
                SLAVE_CHARGEHUP="$CHARGEHUP"
            fi
            if [ -z "$SLAVE_CHARGEINT" ]; then
                SLAVE_CHARGEINT="$CHARGEINT"
            fi
            if [ -z "$SLAVE_CBHUP" ]; then
                SLAVE_CBHUP="$CBHUP"
            fi
            if [ -z "$SLAVE_IHUP" ]; then
                SLAVE_IHUP="$IHUP"
            fi
            if [ -z "$SLAVE_DIALMAX" ]; then
                SLAVE_DIALMAX="$DIALMAX"
            fi
           if [ -z "$SLAVE_CALLBACK" ]; then
                SLAVE_CALLBACK="$CALLBACK"
            fi
            if [ -z "$SLAVE_CBDELAY" ]; then
                SLAVE_CBDELAY="$CBDELAY"
            fi
            if [ -z "$SLAVE_DIALMODE" ]; then
                SLAVE_DIALMODE="auto"
            fi
        else
            log_echo " Error: $1 channel bundling only supported with syncppp - slave interface disabled"
            BUNDLING=
        fi
    fi
}

function addprovider() {
    clear_env

    # load provider config
    . /etc/sysconfig/provider/conf-$1

    options=

    # Do some checks
    if [ -z "$MSN" ]; then
        log_echo "Error: $1: MSN not set"
        return 1
    fi
    if [ -z "$PHONE_OUT" ]; then
        log_echo "Error: $1: no outgoing phone number set"
        return 1
    fi
    if [ -z "$ENCAP" ]; then
        log_echo "Error: $1: Encapsulation not set"
        return 1
    fi
    if [ -z "$DIALMODE" ]; then
        log_echo "Error: $1: Dialmode not set"
        return 1
    fi
    if [ -z "$AUTH" ]; then
        AUTH="+pap -chap"
    fi

    # Check for channel bundling
    set_channel_bundling

    # some settings
    if [ -z "$L2_PROT" ]; then
        L2_PROT="hdlc"
    fi
    if [ -z "$L3_PROT" ]; then
        L3_PROT="trans"
    fi

    # checks for syncppp
    if [ "$ENCAP" = "syncppp" ]; then
        device=ippp$sync_devices
        sync_devices=$[$sync_devices+1]

        # 1=delete default route, if exists
        if [ "$DELDEFAULTROUTE" = "enabled" -o -z "$DELDEFAULTROUTE" ]; then
            options="$options deldefaultroute"
        fi
	
        # we use authentication with pap and/or chap
        _auth=`echo "$AUTH" | sed 's/[a-z -]*//g'`
        if [ -n "$_auth" ]; then
            if [ -z "$USER" ]; then
                log_echo " Error: $1 (syncppp) user is not set"
                return 1
            fi
            if [ "$AUTH" = "-pap +chap" ]; then
                options="$options name $USER"
            else
                options="$options user $USER"
            fi
	    
            # authentication options:
            # +pap and/or +chap does not work with ipppd correctly - removing
            # them
            AUTH=`echo "$AUTH" | sed 's/+[a-z]*//g'`
        fi
    fi

    # checks for rawip
    if [ "$ENCAP" = "rawip" ]; then
        device=isdn$raw_devices
        raw_devices=$[$raw_devices+1]
        if [ -z "$LOCAL_IP" -o -z "$REMOTE_IP" ]; then
            log_echo " Error: $1 (rawip) local or remote ip not set"
            return 1
        fi
    fi

    # did we got a device
    if [ -z "$device" ]; then
        log_echo " Error: $1: cannot determine device"
        return 1
    fi

    log_isdnctrl addif $device
    log_isdnctrl eaz $device $MSN

    for i in $PHONE_OUT; do
        log_isdnctrl addphone $device out $AREACODE$i
    done

    for i in $PHONE_IN; do
        log_isdnctrl addphone $device in $i
    done

    log_isdnctrl l2_prot $device $L2_PROT
    log_isdnctrl l3_prot $device $L3_PROT
    log_isdnctrl encap $device $ENCAP
    log_isdnctrl dialmode $device $DIALMODE

    if [ -n "$SECURE" ]; then
        log_isdnctrl secure $device $SECURE
    fi
    if [ -n "$HUPTIMEOUT" ]; then
        log_isdnctrl huptimeout $device $HUPTIMEOUT
    fi
    if [ -n "$CHARGEHUP" ]; then
        log_isdnctrl chargehup $device $CHARGEHUP
    fi
    if [ -n "$CHARGEINT" ]; then
        log_isdnctrl chargeint $device $CHARGEINT
    fi
    if [ -n "$CBHUP" ]; then
        log_isdnctrl cbhup $device $CBHUP
    fi
    if [ -n "$IHUP" ]; then
        log_isdnctrl ihup $device $IHUP
    fi
    if [ -n "$DIALMAX" ]; then
        log_isdnctrl dialmax $device $DIALMAX
    fi
    if [ "$CALLBACK" = "out" ]; then
        log_isdnctrl callback $device $CALLBACK
    else
        log_isdnctrl callback $device off
    fi
    if [ -n "$CBDELAY" ]; then
        log_isdnctrl cbdelay $device $CBDELAY
    fi

    if [ "$ENCAP" = "syncppp" ]; then
        # set config options for /etc/sysconfig/network-scripts/ifcfg-$device
        ifcfg_file="/etc/sysconfig/network-scripts/ifcfg-$device"
        echo "DEVICE=$device" > $ifcfg_file
        options="$options ipparam $device"
        dyn_local=
        log_isdnctrl pppbind $device
        if [ -z "$LOCAL_IP" ]; then
            dyn_local=1
            LOCAL_IP="0.0.0.0"
            options="$options ipcp-accept-local"
        else
            options="$options noipdefault"
        fi
        # Add device
        options="$options /dev/$device"

        # Create slave device if bundling enabled
        if [ "$BUNDLING" = "yes" -o "$BUNDLING" = "on" ]; then
            slave=ippp$sync_devices
            sync_devices=$[$sync_devices+1]

            options="$options /dev/$slave +mp"

            # Create slave and set options
            log_isdnctrl addslave $device $slave
            log_isdnctrl eaz $slave $SLAVE_MSN
            for i in $SLAVE_PHONE_OUT; do
                log_isdnctrl addphone $slave out $AREACODE$i
            done
            for i in $SLAVE_PHONE_IN; do
                log_isdnctrl addphone $slave in $i
            done
            log_isdnctrl l2_prot $slave $L2_PROT
            log_isdnctrl l3_prot $slave $L3_PROT
            log_isdnctrl encap $slave $ENCAP
            log_isdnctrl dialmode $slave $SLAVE_DIALMODE
            if [ -n "$SECURE" ]; then
                log_isdnctrl secure $slave $SECURE
            fi
            if [ -n "$SLAVE_HUPTIMEOUT" ]; then
                log_isdnctrl huptimeout $slave $SLAVE_HUPTIMEOUT
            fi
            if [ -n "$SLAVE_CHARGEHUP" ]; then
                log_isdnctrl chargehup $slave $SLAVE_CHARGEHUP
            fi
            if [ -n "$SLAVE_CHARGEINT" ]; then
                log_isdnctrl chargeint $slave $SLAVE_CHARGEINT
            fi
            if [ -n "$SLAVE_CBHUP" ]; then
                log_isdnctrl cbhup $slave $SLAVE_CBHUP
            fi
            if [ -n "$SLAVE_IHUP" ]; then
                log_isdnctrl ihup $slave $SLAVE_IHUP
            fi
            if [ -n "$SLAVE_DIALMAX" ]; then
                log_isdnctrl dialmax $slave $SLAVE_DIALMAX
            fi
            if [ -n "$SLAVE_CALLBACK" ]; then
                log_isdnctrl callback $slave $SLAVE_CALLBACK
            else
                log_isdnctrl callback $slave off
            fi
            if [ -n "$SLAVE_CBDELAY" ]; then
                log_isdnctrl cbdelay $device $SLAVE_CBDELAY
            fi

            # Options for master device
            if [ -n "$SLAVE_DELAY" ]; then
                log_isdnctrl sdelay $device $SLAVE_DELAY
            fi
            if [ -n "$SLAVE_TRIGGER" ]; then
                log_isdnctrl trigger $device $SLAVE_TRIGGER
            fi
        fi

        if [ -z "$REMOTE_IP" ]; then
            options="$options ipcp-accept-remote"
            # Activate network interface
            ifconfig $device $LOCAL_IP up >/dev/null 2>&1
        else
            # Activate network interface
            ifconfig $device $LOCAL_IP pointopoint $REMOTE_IP up >/dev/null 2>&1
        fi

        # do we have all dynamically?
        if [ -n "$dyn_local" ]; then 
            if [ -z "$REMOTE_IP" ]; then
       	        # Set the local and/or remote interface IP addresses
                options="$LOCAL_IP:0.0.0.0 $options"
            else
                # Set the local and/or remote interface IP addresses
                options="$LOCAL_IP:$REMOTE_IP $options"
            fi
        else
            options="$options $LOCAL_IP:$REMOTE_IP"
        fi

        # Add default route while connection
        options="$options defaultroute"

        # configure Van Jacobson style TCP/IP header compression and
        # VJ connection-ID compression
        [ -z "$VJ" ] && VJ="-vj"
        [ -z "$VJCCOMP" ] && VJCCOMP="-vjccomp"
        options="$options $VJ $VJCCOMP"

        # configure Address/Control compression, protocol field compression and
        # BSD-Compression scheme
        [ -z "$AC" ] && AC="-ac"
        [ -z "$PC" ] && PC="-pc"
        [ -z "$BSDCOMP" ] && BSDCOMP="-bsdcomp"
        options="$options $AC $PC $BSDCOMP"

        # Set max receive and max transmit units
        if [ -n "$MRU" -a -n "$MTU" ] ; then
            options="$options mru $MRU mtu $MTU"
        fi

        # set host name
        if [ -n "$ISDN_HOSTNAME" ]; then
            options="$options hostname $ISDN_HOSTNAME"
        fi

        # set domain name
        if [ -n "$ISDN_DOMAIN" ]; then
            options="$options domain $ISDN_DOMAIN"
            echo "DOMAIN=\"$ISDN_DOMAIN\"" >> $ifcfg_file
        fi

        # Set authentication options
        for i in $AUTH; do
            options="$options $i"
        done

        # check dns entry
        if [ -z "$DNS" ]; then
            options="$options ms-get-dns"
            if [ "$RESOLV_MODS" != "no" ]; then
                echo "RESOLV_MODS=\"yes\"" >> $ifcfg_file
            fi
        else
            k=1
            for i in $DNS; do
                options="$options ms-dns $i"
                echo "DNS$k=$i" >> $ifcfg_file
                k=$[$k+1]
		grep -q -i "$i" /etc/resolv.conf || echo "nameserver $i" >> /etc/resolv.conf
            done
        fi

        # Use provider options file instead
        # set overwrite as default if OPTIONS_FILE is empty
        [ -z "$OPTIONS_FILE" ] && OPTIONS_FILE="append"
        if [ -f "/etc/ppp/options-$1" ]; then
            if [ "$OPTIONS_FILE" = "overwrite" ]; then
                options="file /etc/ppp/options-$1"
            elif [ "$OPTIONS_FILE" = "append" ]; then
                options="$options `cat /etc/ppp/options-$1`"
            fi
        fi

        # Start ipppd
        if [ "$DEBUG" = "on" ]; then
            options="-d $options"
        fi
        ipppd $options

        if [ -n "$dyn_local" ]; then
            echo 1 > /proc/sys/net/ipv4/ip_dynaddr
        fi
    fi

    if [ "$ENCAP" = "rawip" ]; then
        ifconfig $device $LOCAL_IP pointopoint $REMOTE_IP up >/dev/null 2>&1
    fi

    if [ "$DIALMODE" = "auto" ]; then
        route del default >/dev/null 2>&1
        if [ -z "$REMOTE_IP" ]; then
            route add default $device >/dev/null 2>&1
        else
            route add default gw $REMOTE_IP >/dev/null 2>&1
	fi
    fi

    ip_forwarding

    echo "$device $1" >> /var/run/isdn
    touch /var/lock/isdn
}

function removeprovider() {
    action "Removing provider '$1' on device '$2'" /sbin/ifconfig $2 down >& /dev/null
    log_isdnctrl delif $2 >/dev/null 2>&1
}

function load_modules() {
    /sbin/modprobe -r $MODULE 2>/dev/null && sleep 1 || true
    action "Loading ISDN modules" /sbin/modprobe $MODULE $RESOURCES
}

function load_firmware() {
    # loading firmware
    $FIRMWARE >/dev/null 2>&1

    # setup isdn device, only work with hisax
    [ "$MODULE" = "hisax" ] && hisaxctrl HiSax 1 0x3ff >/dev/null 2>&1
}

function start_isdnlog() {
    # don't start isdnlog, if the ISDN card requires the firmware
    if [ -z "$FIRMWARE" ] ; then
        echo -n "Starting isdnlog"
        ( exec isdnlog /dev/isdnctrl0 -x0x3fff -M -w2 -S -D -s -O+/var/log/isdnctrl )
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch /var/lock/isdnlog
    fi
}

function ip_forwarding()
{
    if [ "$IP_FORWARD" = 1 ]; then
        echo 1 >/proc/sys/net/ipv4/ip_forward
    fi
}

function start()
{
    # don't start again if it's already started
    [ ! -f /var/lock/isdn ] || exit 0

    # load modules
    load_modules

    # load firmware and setup isdn device driver
    load_firmware

    # start isdn logging
    start_isdnlog

    # don't add provider if /etc/sysconfig/activeisdn does not exist
    [ -s /etc/sysconfig/activeisdn ] || exit 0

    ACTION_STATUS=/bin/true

    # start provider configurations
    for prov in `cat /etc/sysconfig/activeisdn`; do
        if [ -f "/etc/sysconfig/provider/conf-$prov" ]; then
            # execute function in sub-shell to have clear environment
            addprovider $prov || ACTION_STATUS=/bin/false
        fi
        action "Adding provider '$prov' on device '$device'" $ACTION_STATUS
    done

    # start ibod daemon for channel bundling
    if [ "$IBOD" = "yes" -a -f /etc/isdn/ibod.cf -a -x ibod ] ; then
        ibod &
        pid=`pidofproc ibod`
        if [ -n "$pid" ] ; then
            action "Starting ibod" /bin/true
            touch /var/lock/ibod
        else
            action "Starting ibod" /bin/false
        fi
    fi
}

function stop()
{
    # stopping ibod daemon for channel bundling
    if  [ -f /var/lock/ibod ] ; then
        echo -n "Shutting down ibod"
        killall ibod
        RETVAL=$?
        [ $RETVAL -eq 0 ] && /bin/rm -f /var/lock/ibod
        echo
    fi

    # stopping isdnlog
    if [ -f /var/lock/isdnlog ] ; then
        echo -n "Shutting down isdnlog"
        killall isdnlog
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && /bin/rm -f /var/lock/isdnlog
    fi

    # removing provider
    if [ -f /var/run/isdn ]; then
        # kill ipppd if running
        echo -n "Shutting down ipppd"
        killall ipppd
        echo

        while read device provider ; do
            removeprovider $provider $device
            /bin/rm -f /etc/sysconfig/network-scripts/ifcfg-$device
        done < /var/run/isdn

        /bin/rm -f /var/run/isdn /var/lock/isdn
    fi

    # Unload hisax modules
    if /sbin/lsmod | grep "^hisax" >/dev/null 2>&1 ; then
        action "Unloading ISDN modules" /sbin/modprobe -r $MODULE
    fi
}

function restart()
{
    stop
    start
}

function condrestart() {
    if [ -f /var/lock/isdn ] ; then
        restart
    fi
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    condrestart)
       condrestart
       ;;
    *)
        echo "Usage: isdn {start|stop|restart|condrestart}"
        exit 1
    esac

exit 0
