#! /bin/bash
# Copyright (c) 2002, 2007 SUSE Linux products GmbH
#
# Author: Karsten Keil <kkeil@suse.de>
# 
# setup/shutdown a ISDN network interface
#

usage () {
	echo $@
	echo "usage: if{up,down,status}-isdn interface [ -o <some options>]"
	echo "   options:"
	echo "      -o prov=<provider short name>"
	echo "      -o changeprov=<provider short name>"
	echo ""
	exit $R_USAGE
}
######################################################################
#
# vars
#
# items for isdnctrl VARNAME COMMAND DEFAULT
SETUP_ITEMS="\
    LAYER2	l2_prot		hdlc
    LAYER3	l3_prot		trans
    ENCAP	encap		syncppp
    MSN		eaz		0
    CHARGEHUP	chargehup	off
    IHUP	ihup		off
    IDLETIME	huptimeout	60
    DIALMAX	dialmax		1
    CALLBACK	callback	off
    CBDELAY	cbdelay		2
    CBHUP	cbhup		on
    DIALMODE	dialmode	manual
    SECURE	secure		on
"	
# items for slave isdnctrl VARNAME COMMAND DEFAULT
SLAVE_ITEMS="\
    LAYER2	l2_prot		hdlc
    LAYER3	l3_prot		trans
    ENCAP	encap		syncppp
    SLAVEMSN	eaz		0
    CHARGEHUP	chargehup	off
    IHUP	ihup		off
    IDLETIME	huptimeout	60
    DIALMAX	dialmax		1
    CALLBACK	callback	off
    CBDELAY	cbdelay		2
    CBHUP	cbhup		on
    SECURE	secure		on
    SLAVE_DM	dialmode	auto
"	

######################################################################
# local functions
#

######################################################################
#
# check presence of a ISDN hardware driver
#

is_isdn_available() {
    idmap=`head -n 1 /dev/isdninfo 2>/dev/null`
    case "$idmap" in
	"") return 1 ;;
	"idmap:  - - - - - - - -"*) return 2 ;;
	idmap:*) return 0 ;;
	*) return 3 ;;
    esac 
}
######################################################################
# make a isdnctrl call
# $1 var_name
# $2 cmd_name
# $3 device
# $4 default value
# $5 optional sub_cmd
setup_item() {
    eval val=\$$1
    test -n "$val" || val=$4
#    debug "setup_item($*)"
    if [ -n "$val" ]; then
	cmd="$ISDNCTRL $2 $3 $5 $val"
	debug "setup_item run $cmd"
	$cmd >& /dev/null
	if test $? -ne 0; then
	    echo "error on $cmd"
	    exit $R_ERROR
	fi
    fi
}

# start ipppd
#
start_ipppd() {
    PIDFILE=/var/run/ipppd.$DEVICE.pid
    PROVIDERLOCK=/var/run/ipppd.$DEVICE.provider
    AUTH_OPTIONS="user $USERNAME name $USERNAME"
    rm -f ${PROVIDERLOCK}
    if [ "$ASKPASSWORD" = "yes" ]; then
	AUTH_OPTIONS="$AUTH_OPTIONS askpassword"
    else
	if [ -n "$PASSWORDFD" ]; then
	    AUTH_OPTIONS="$AUTH_OPTIONS passwordfd $PASSWORDFD" 
	fi
    fi
    test -n "$NETMASK" || NETMASK="255.255.255.255"
    CMDLINE_OPT="noipdefault netmask $NETMASK"
    test "$DEFAULTROUTE" = "yes" && CMDLINE_OPT="$CMDLINE_OPT defaultroute"
    test "$MODIFYDNS" = "yes" -a "$AUTODNS" = "yes" \
	&& CMDLINE_OPT="$CMDLINE_OPT ms-get-dns"
    if [ "$DYNAMICIP" = "yes" ]; then
	CMDLINE_OPT="$CMDLINE_OPT ipcp-accept-local ipcp-accept-remote"
    else
	CMDLINE_OPT="$CMDLINE_OPT useifip"
    fi
    test -n "$MTU" && CMDLINE_OPT="$CMDLINE_OPT mtu $MTU"
    test -n "$MRU" && CMDLINE_OPT="$CMDLINE_OPT mru $MRU"

    DEVICE_OPT="/dev/$DEVICE"
    if [ "$MULTILINK" = "yes" ]; then
	CMDLINE_OPT="$CMDLINE_OPT +mp"
	for slave in $SLAVES; do
	    DEVICE_OPT="$DEVICE_OPT /dev/$slave"
	done
    fi
    debug "$IPPPD pidfile $PIDFILE $DEVICE_OPT $AUTH_OPTIONS $CMDLINE_OPT $IPPPD_OPTIONS"
    $IPPPD pidfile $PIDFILE $DEVICE_OPT $AUTH_OPTIONS $CMDLINE_OPT $IPPPD_OPTIONS
    echo ${PROVIDERNAME} > ${PROVIDERLOCK}
}

######################################################################
# change the working directory and source some common files
#
R_INTERNAL=12      # internal error, e.g. no config or missing scripts
cd /etc/sysconfig/network || exit $R_INTERNAL
test -f scripts/functions && . scripts/functions || exit $R_INTERNAL
test -f /etc/rc.status && . /etc/rc.status || exit $R_INTERNAL
test -f config && . config

######################################################################
# check arguments and how we are called (in case of links)
#
SCRIPTNAME=`basename $0`
debug $*
case "${SCRIPTNAME}" in
	ifup-*)
	    ACTION=up
	    ;;
	ifdown-*)
	    ACTION=down
	    ;;
	ifstatus-*)
	    ACTION=status
	    ;;
	*) usage
esac
CONFIG=$1
test -z "$CONFIG" && usage
shift
test "$1" != "-o" && DEVICE=$1
shift
test "$1" = "-o" && shift
OPTIONS=$@
MODE=manual
FORCE_PROVIDER=""
while [ $# -gt 0 ]; do
	case $1 in
	    onboot|boot|hotplug|manual)
		MODE=$1 ;;
	    rc)		
		FROM_RC=yes ;;
	    doalias)	;;
	    check)	;;
	    type)	;;
	    quiet)
		BE_QUIET=yes ;;
	    debug)
		DEBUG=yes ;;
	    prov=*)
		FORCE_PROVIDER=${1##*=}
		;;
	    changeprov=*)
		FORCE_PROVIDER=${1##*=}
		ACTION=change
		;;
	    *)
		message "unknown option $1 ignored" ;;
	esac
	shift
done
test -z "$DEVICE" && DEVICE=$CONFIG

######################################################################
#
# check presence of a ISDN hardware driver
#

if ! is_isdn_available ; then
    if [ "$ACTION" = "up" ]; then
	logerror "no ISDN device available"
	exit $R_NODEV
    elif [ "$ACTION" = "status" ]; then
	message "no hardware device for $DEVICE"
	exit $R_NODEV	
    fi
fi
######################################################################
# check presence of configuration file and source it
#
test -f ifcfg-$CONFIG || exit $R_NOCONFIG
test -f ifcfg-$CONFIG && . ifcfg-$CONFIG

#echo "DEVICE=$DEVICE"
case $DEVICE in
  ippp*) ;;
  isdn*) ;;
  *) usage ;;
esac

SBIN=/usr/sbin
IPPPD=/usr/sbin/ipppd
ISDNCTRL=/sbin/isdnctrl
test -x $IPPPD || exit $R_ERROR
test -x $ISDNCTRL  || exit $R_ERROR

if [ -n "$FORCE_PROVIDER" ]; then
    if [ -r providers/${FORCE_PROVIDER} ]; then
	PROVIDER=$FORCE_PROVIDER
    else
	message "provider $FORCE_PROVIDER don't exist in /etc/sysconfig/network/providers"
	exit $R_ERROR
    fi
fi
PROVIDERNAME=$PROVIDER
if [ $ACTION = up -o $ACTION = change ]; then
    if [ -z "${PROVIDER}" ]; then
	message "internal error no PROVIDER set"
	exit $R_INTERNAL
    fi
    if [ -r providers/${PROVIDER} ]; then
	. providers/${PROVIDER}
        $ISDNCTRL status $DEVICE >& /dev/null
	ret=$?
        if [ $ret -eq 0 -o $ret -eq 1 ]; then
	    if [ $ACTION = up ]; then
		message "interface $DEVICE is already up"
		exit $R_SUCCESS
	    else
		ACTION = up
	    fi
	fi
	if [ "$ASKPASSWORD" = "yes" -a "$MODE" != "manual" ]; then
		message " askpassword=yes: manual start is needed"
		exit $R_NOTCONFIGURED
	fi
	if [ "$ASKPASSWORD" = "yes" -a "$FROM_RC" = "yes" ]; then
		message " askpassword=yes: rc network cannot start this interface"
		exit $R_NOTCONFIGURED
	fi
    else
	message "provider $PROVIDER don't exist in /etc/sysconfig/network/providers"
	exit $R_ERROR
    fi
fi

case $ACTION in
    up)
        $ISDNCTRL addif $DEVICE >& /dev/null
        if test $? -ne 0; then
            echo "error in $ISDNCTRL addif $DEVICE"
            exit $R_ERROR
        fi
	test "$DEMAND" = "yes" && DIALMODE="auto"
	test -n "$PHONE" && REMOTE_OUT=$PHONE
        if [ -n "$REMOTE_OUT" ]; then
            for RNO in $REMOTE_OUT ; do
		RNR=${DIALPREFIX}${RNO}
                setup_item RNR addphone $DEVICE 0 out
            done
        fi
        if [ -n "$REMOTE_IN" ]; then
            for RNI in $REMOTE_IN ; do
                setup_item RNI addphone $DEVICE 0 in
            done
        fi
        set -- $SETUP_ITEMS
        while [ $# -gt 0 ]; do
            setup_item $1 $2 $DEVICE $3
            shift
            shift
            shift
        done
	if [ -n "$VERBOSE_LEVEL" ]; then
	    test $VERBOSE_LEVEL -gt 0 && \
		$ISDNCTRL verbose $VERBOSE_LEVEL >& /dev/null
	fi
        if [ "$ENCAP" = "syncppp" ] ; then
            test -z "$PPPBIND" && PPPBIND=${DEVICE#ippp}
            setup_item PPPBIND pppbind $DEVICE
        fi
        if [ "$MULTILINK" = "yes" -a -n "$SLAVES" ]; then
            for slave in $SLAVES; do
                setup_item slave addslave $DEVICE $slave
                if [ -z "$SLAVE_OUT" ]; then
                   SLAVE_OUT=$REMOTE_OUT
                fi
                if [ -n "$SLAVE_OUT" ]; then
                    for SNO in $SLAVE_OUT ; do
			SNR=${DIALPREFIX}${SNO}
                        setup_item SNR addphone $slave 0 out
                    done
                fi
                if [ -z "$SLAVE_IN" ]; then
                    SLAVE_IN=$REMOTE_IN
                fi
                if [ -n "$SLAVE_IN" ]; then
                    for SNI in $SLAVE_IN ; do
                        setup_item SNI addphone $slave 0 in
                    done
                fi
                test -z "$SLAVEMSN" && SLAVEMSN=$MSN
                SLAVE_DM="auto"
                set -- $SLAVE_ITEMS
                while [ $# -gt 0 ]; do
                    setup_item $1 $2 $slave $3
                    shift
                    shift
                    shift
                done
                if [ "$ENCAP" = "syncppp" ] ; then
                    PPPBIND=${slave#ippp}
                    setup_item PPPBIND pppbind $slave 
                fi
            done
        fi
	if [ "$DEMAND" = "yes" -a "$DEFAULTROUTE" = "yes" ]; then
	    if [ -n "$DNS1" ]; then
		test -n "$DNS2" || DNS2=$DNS1
		/sbin/modify_resolvconf modify -s ifup -e "$DEVICE" \
		    -p $SCRIPTNAME -f /etc/sysconfig/network/scripts/$SCRIPTNAME \
		    -n "$DNS1 $DNS2" -t - << EOT
		    If you do not like that ifup change your nameserver
		    settings remove the option DNS1 from 
		    /etc/sysconfig/network/providers/$PROVIDERNAME.
EOT
	    fi
	fi
        if [ "$ENCAP" = "syncppp" ] ; then
	    start_ipppd
        fi
        retcode=$R_SUCCESS
	debug "ip link set up dev $DEVICE $LINK_OPTIONS"
        if ! ip link set up dev $DEVICE $LINK_OPTIONS; then
            logerror "Cannot enable interface $DEVICE."
            retcode=$R_NOTRUNNING
        else
	    if [ "$DYNAMICIP" = "yes" ]; then
		echo "7" > /proc/sys/net/ipv4/ip_dynaddr
		ip link set $DEVICE dynamic on
	    fi
	    IPADDR=${IPADDR:-0.0.0.0}
	    PTPADDR=${PTPADDR:-0.0.0.0}
	    debug "ip addr add dev $DEVICE local $IPADDR peer $PTPADDR"
            ip addr add dev $DEVICE local $IPADDR \
                peer $PTPADDR \
                || retcode=$R_NOTRUNNING
	    debug "ifup-route $CONFIG $DEVICE ${OPTIONS:+-o $OPTIONS}"
            ifup-route $CONFIG $DEVICE ${OPTIONS:+-o $OPTIONS}
        fi
	test "$IP_RESEND" = "yes" -a -x $SBIN/ip_resend && \
	    $SBIN/ip_resend -o $DEVICE $IP_RESEND_PARAMETER >& /dev/null
	test "$ENCAP" = "syncppp" -a -x /etc/init.d/smpppd \
		&& /etc/init.d/smpppd start > /dev/null
        ;;
    down)
        $ISDNCTRL status $DEVICE >& /dev/null
	ret=$?
        if [ $ret -eq 0 -o $ret -eq 1 ]; then
	    $ISDNCTRL dialmode $DEVICE off  >& /dev/null
	else
	    message "interface $DEVICE is not up"
# do not exit here, at least hotplug need to continue
#	    exit $R_SUCCESS
	fi
        ifdown-route $CONFIG $DEVICE ${OPTIONS:+-o $OPTIONS}
	$ISDNCTRL status $DEVICE >& /dev/null
	if [ "$?" = "0" ] ; then
	    $ISDNCTRL hangup $DEVICE >& /dev/null
	fi
	#
	test "$IP_RESEND" = "yes" -a -x $SBIN/ip_resend_wakeup && \
	    $SBIN/ip_resend_wakeup -m stop -o $DEVICE  >& /dev/null
	#
	if [ "$ENCAP" = "syncppp" ] ; then
	    PIDFILE=/var/run/ipppd.${DEVICE}.pid
	    if [ -s $PIDFILE ] ; then
		read -t 1 PID < $PIDFILE
		kill -15 $PID 2>/dev/null
	    fi
	    for ((count=0; count<120; count++)) ; do
		[ -s $PIDFILE ] || break;
		usleep 25000
	    done
	    if [ -s $PIDFILE ] ; then
	        # very stubborn :-(
	        kill -9 $PID
		rm -f $PIDFILE
	    fi
	    PROVIDERLOCK=/var/run/ipppd.${DEVICE}.provider
	    if [ -s $PROVIDERLOCK ]; then
		PROVIDERNAME=`cat $PROVIDERLOCK`
		PROVIDERFILE=/etc/sysconfig/network/providers/${PROVIDERNAME}
		rm -f $PROVIDERLOCK
		if [ -s $PROVIDERFILE ]; then
		    . $PROVIDERFILE
		    if [ "$DEMAND" = "yes" -a "$DEFAULTROUTE" = "yes" -a -n "$DNS1" ]; then
			/sbin/modify_resolvconf restore -s ifup -e "$DEVICE" >& /dev/null
		    fi
		fi
	    fi
	fi
	ip addr flush dev $DEVICE >& /dev/null
	ip link set dev $DEVICE down 
	$ISDNCTRL delif $DEVICE >& /dev/null
	retcode=$?
        ;;
    status)
        $ISDNCTRL status $DEVICE >& /dev/null
	ret=$?
	case $ret in
	    0)	# running and connected
		retcode=$R_BUSY
		message "interface $DEVICE is up and connected"
		;; 
	    1)	# running and not connected
		retcode=$R_SUCCESS
		message "interface $DEVICE is up and not connected"
		;;
	    255)# no such device
		retcode=$R_NODEV
		message "interface $DEVICE is not up"
		;;
	    *)  # unknown status
		retcode=$R_ERROR
		message "interface $DEVICE unknown status $ret"
		;;
	esac
        ;;
    *)
        echo "unknown scriptname of $SCRIPTNAME"
        ;;
esac
exit $retcode
