#!/bin/sh
#
# chkconfig: 2345 80 20
# description: Start and stop ISDN services
#
# Thomas Woerner <thomas.woerner@redhat.de>
# Than Ngo <than@redhat.de>
#
# changes for channel bundling
# Karl Fischer <karl.fischer@ficos.de>

# Source function library
if [ -f /etc/init.d/functions ]; then
  . /etc/init.d/functions
elif [ -f /etc/rc.d/init.d/functions ] ; then
  . /etc/rc.d/init.d/functions
else
  exit 0
fi

# Source configuration
. /etc/sysconfig/network

[ -s /etc/sysconfig/activeisdn ] || exit 0

test -f /etc/sysconfig/isdncard || exit 0
. /etc/sysconfig/isdncard

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

# disable debug as default
DEBUG=off

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 log_echo()
{
    if [ "$DEBUG" = "on" ] ; then
        echo $*
    fi
}

function log_isdnctrl()
{
    isdnctrl $* >>/var/log/isdn.log 2>&1
}

function addprovider() {
    # clear environment
    PROVIDER=; USER=; PASSWORD=; ENCAP=; DIALMODE=; SECURE=; MSN=; PHONE_IN=
    PREFIX=; AREACODE=; PHONE_OUT=; CITY=; BUNDLING=; LOCAL_IP=; REMOTE_IP=
    NETWORK=; BROADCAST=; HUPTIMEOUT=; DNS=; HOSTNAME=; DOMAIN=; L2_PROT=
    L3_PROT=; CALLBACK=; CHARGEHUP=; CHARGEINT=; CBHUP=; CBDELAY=; DIALMAX=
    AUTH=; IHUP=; IP_FORWARD=; SLAVE_DELAY=; SLAVE_TRIGGER=
    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=

    # 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
    if [ "$BUNDLING" = yes ]; then
        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

            # slave dialmode auto:
            # slave_delay and slave_trigger hast to be set
            if [ "$SLAVE_DIALMODE" = auto ]; then
                if [ -z "$SLAVE_DELAY" ]; then
                    log_echo " Error: Slave delay not set - slave interface disabled"
                    BUNDLING=
                fi
                if [ -z "$SLAVE_TRIGGER" ]; then
                    log_echo " Error: Slave triggering not set - slave interface disabled"
                    BUNDLING=
                fi
            fi
        else
            log_echo " Error: $1 channel bundling only supported with syncppp - slave interface disabled"
            BUNDLING=
        fi
    fi

    # 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
            # Fix me here!
            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 [ "$SECURE" = "out" ]; 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

        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
        fi

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

        # Disable Van Jacobson style TCP/IP header compression and
        # VJ connection-ID compression
        options="$options -vj -vjccomp"

        # Disable Address/Control compression, protocol field compression and
        # BSD-Compression scheme
        options="$options -ac -pc -bsdcomp"

        #	# Set max receive and max transmit units
        #	options="$options mru 1524 mtu 1500"
        #
        #	# set host name
        #	if [ -n "$HOSTNAME" ]; then
        #	    options="$options hostname $HOSTNAME"
        #	fi
        #
        # set domain name
        if [ -n "$DOMAIN" ]; then
            # options="$options domain $DOMAIN"
            echo "DOMAIN=\"$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]
            done
        fi

        # Add device
        options="$options /dev/$device"

        # Create slave device if bundling enabled
        if [ "$BUNDLING" = "yes" ]; 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 $slave $SLAVE_DELAY
            fi
            if [ -n "$SLAVE_TRIGGER" ]; then
                log_isdnctrl trigger $slave $SLAVE_TRIGGER
            fi
        fi

        # Use provider options file instead
        if [ -f "/etc/ppp/options-$1" ]; then
            options="file /etc/ppp/options-$1"
        fi

        # Start ipppd
        /usr/sbin/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
        #route add default gw $REMOTE_IP >/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

    if [ "$IP_FORWARD" = 1 ]; then
        echo 1 >/proc/sys/net/ipv4/ip_forward
    fi

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

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

function start()
{
    # load modules
    action "Loading ISDN modules" /sbin/modprobe $MODULE $RESOURCES

    # start logging
    if [ "$MODULE" = hisax ]; then
        hisaxctrl HiSax 1 0x3ff > /dev/null 2>&1
    fi

    echo -n "Starting isdnlog"
    daemon isdnlog /dev/isdnctrl0 -x0x3fff -M -w2 -S -D -s -O+/var/log/isdnctrl
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/isdnlog

    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 devive '$device'" $ACTION_STATUS
    done
}

function stop()
{
    # stopping isdnlog
    if [ -f /var/lock/subsys/isdnlog ] ; then
	echo -n "Shutting down isdnlog"
	killproc isdnlog
	RETVAL=$?
	echo
	[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/isdnlog
    fi

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

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

	rm -f /var/run/isdn /var/lock/subsys/isdn

	PID=`ps auxww | grep tail | grep isdnctrl | awk '{print $2}'`
	if [ -n "$PID" ]; then
	    kill $PID >/dev/null 2>&1
	fi
    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/subsys/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
