#!/bin/bash
#
# Network interface configuration
#
# Copyright (c) 2001-2002 SuSE Linux AG, Nuernberg, Germany.
# Copyright (c) 2003-2008 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Author: Michal Svec <msvec@suse.cz>
#         Christian Zoz <zoz@suse.de>
#         Mads Martin Jrgensen <mmj@suse.de>
#         Marius Tomaschewski <mt@suse.de>
#
# $Id$
#
# /etc/init.d/network
#
### BEGIN INIT INFO
# Provides:		network
# Required-Start:	$local_fs
# Should-Start:		earlysyslog isdn openibd SuSEfirewall2_init
# Required-Stop:	$local_fs
# Should-Stop:		isdn openibd SuSEfirewall2_init
# Default-Start:	3 5
# Default-Stop:		
# X-Systemd-RemainAfterExit: true
# Short-Description:	Configure network interfaces and set up routing
# Description:		Configure network interfaces and set up routing
### END INIT INFO

unset POSIXLY_CORRECT ; set +o posix # we're using non-posix bash features

SYSTEMD_NO_WRAP=1 . /etc/rc.status
rc_reset

cd /etc/sysconfig/network
test -f ./config && . ./config
if ! . scripts/functions 2>/dev/null; then
	echo -n "Network: file /etc/sysconfig/network/scripts/functions is missing."
	rc_failed
	rc_status -v
	rc_exit
fi

test "$DEBUG" = "EXTRA" && . scripts/extradebug

SCRIPTNAME=${0##*/}
debug $*
MODE=""
ACTION=$1 ; shift
SERVICE=`get_network_service_id`

# Only use ifup option 'onboot' if booting or changing runlevel
# Therefore we check if we were called from init or systemd is booting.
SD_RUNNING=no
SD_BOOTING=no
if systemd_running ; then
	# systemd never calls status action,
	# so always enable boot-wait mode ...
	MODE=onboot
	SD_RUNNING=yes
	systemd_booting && SD_BOOTING=yes
fi
if [ \( -n "$INIT_VERSION" -o "$SD_BOOTING" = yes \) -a \
	-z "$YAST_IS_RUNNING" ] ; then
	MODE=onboot
fi

######################################################################
# Commandline parsing
#
unset INTERFACE CONFIG
if test "$1" != "-o" ; then
	INTERFACE=$1; shift
fi
if test -n "$1" -a "$1" != "-o" ; then
	CONFIG=$INTERFACE; INTERFACE=$1; shift
fi
if test "$1" = "-o" ; then
	shift
fi
OPTIONS=$@
unset CHECK FAKE TYPE SKIP
while [ $# -gt 0 ]; do
	case $1 in
		boot|onboot) MODE=onboot ;;
		hotplug)     MODE=hotplug ;;
		manual)      MODE=manual ;;
		debug)       DEBUG=yes ;;
		check)       CHECK=check ;;
		fake)        FAKE=echo ;;
		type=*)      TYPE=${1#type=} ;;
		skip=*)      SKIP=${1#skip=} ;;
		quiet)       debug "Option '$1' is gone." ;;
		localfs)     debug "Option '$1' is gone." ;;
		remotefs)    debug "Option '$1' is gone." ;;
		*)           mesg "Unknown option '$1'"
		             mesg "options: {[on]boot,hotplug,manual,check,debug,type=<typelist>,fake}"
			     exit 1 ;;
	esac
	shift
done
# Source functions.common again, because values of DEBUG and BE_QUIET might
# have changed. These variable will be evaluated while sourcing the file.
test -f scripts/functions.common \
   && . scripts/functions.common \
   || exit $R_INTERNAL


kill_all_instances()
{
	local s l

	l=`systemctl show -p ConsistsOf network.service 2>/dev/null`
	for s in ${l#ConsistsOf=} ; do
		case $s in
		network@*.service)
			/bin/systemctl "$@" kill "$s"
		;;
		esac
	done
}

#
# Check if to redirect to systemd or not
#
if test $PPID -ne 1 -a -z "$RCNETWORK" ; then
	case $SERVICE in
	"")
		# no service enabled / installed network.service alias link,
		# even /etc/init.d/network seems disabled by insserv -r -f?
		mesg "/etc/init.d/network is disabled, can't find any\n"\
		     "another service enabled as the network.service."
		exit 1
	;;
	network.service)
		#
		# when /etc/init.d/network is enabled / not masked,
		# show it's status first as requested and map the
		# special rcnetwork actions.
		#
		case $ACTION in
		status)
			cd "$OLDPWD"
			RCNETWORK=1 \
			"$0" $ACTION $CONFIG $INTERFACE ${OPTIONS:+-o $OPTIONS}
			unset INTERFACE CONFIG OPTIONS
		;;
		stop-all-dhcp-clients)
			# suspend, but don't do anything when not running
			netcontrol_running || exit 0

			# set a kill flag
			rm -f            "${RUN_FILES_BASE}/killed"
			echo "$ACTION" > "${RUN_FILES_BASE}/killed"

			# kill hard to avoid deconfiguration
			opts=($SYSTEMCTL_OPTIONS "--signal=9")
			SYSTEMCTL_OPTIONS="${opts[*]}"
			kill_all_instances --signal=9

			# and map it to kill
			ACTION="kill"
			unset TYPE SKIP INTERFACE CONFIG OPTIONS
		;;
		restart-all-dhcp-clients)
			# resume, but don't do anything when not running
			netcontrol_running || exit 0

			# set a kill flag
			rm -f            "${RUN_FILES_BASE}/killed"
			echo "$ACTION" > "${RUN_FILES_BASE}/killed"

			# kill hard to avoid deconfiguration
			kill_all_instances --signal=9
			/bin/systemctl --signal=9 kill network.service

			# and map it to restart (start has no effect),
			# so systemd resets its state ...
			ACTION="restart"
			unset TYPE SKIP INTERFACE CONFIG OPTIONS
		;;
		esac
		alias_hint=""
	;;
	*)
		alias_hint=" ($SERVICE)"
		# ignore additional arguments for another service, redirect
		if test -n "$INTERFACE" -o -n "$TYPE" -o -n "$SKIP" ; then
			mesg "$0: Additional arguments not supported"\
			     "for $SERVICE: $INTERFACE ${OPTIONS:+-o $OPTIONS}"
		fi
		unset TYPE SKIP INTERFACE CONFIG OPTIONS
	;;
	esac

	#
	# redirect common actions to systemd
	#
	if test -z "$INTERFACE" -a -z "$TYPE" -a -z "$SKIP" ; then
		case $ACTION in
		kill|status|start|stop|reload|restart|try-restart|force-reload)
			mesg "redirecting to \"systemctl $SYSTEMCTL_OPTIONS $ACTION network.service\"$alias_hint"
			exec /bin/systemctl $SYSTEMCTL_OPTIONS "$ACTION" network.service
		;;
		*)
			# reject other (systemctl) actions, when we're inactive
			if test "x$SERVICE" != "xnetwork.service" ; then
				mesg "Network is managed by $SERVICE\n"\
				     "and rcnetwork does not support '$1' action."
				mesg "Use systemctl for systemd specific actions."
				exit 1
			fi
		;;
		esac
	fi
fi

# allow "rcnetwork <action> <interface>", as well as
# -o type=... skip=... options in started state only
# as the "cached" systemd state does not change here.
if ! netcontrol_running && \
   test -n "$INTERFACE" -o -n "$TYPE" -o -n "$SKIP" ; then
	case $ACTION in
		status)	            ;;	# OK, fall through
		stop)	rc_failed 0 ;;  # OK, not started
		*)	rc_failed 7 ;;	# reject / not running
	esac
fi

### We're inside of rcnetwork now...
export RCNETWORK=1

check_firewall() {
	test "$MODE" = onboot && return 1
	test "$FIREWALL" != yes && return 2
	test -x scripts/firewall || return 3
	return 0
}

lock_firewall() {
	check_firewall || return $?
	scripts/firewall net-reconfig-init
}

reload_firewall() {
	check_firewall || return $?
	scripts/firewall net-reconfig-done
}

cd "$OLDPWD"
case "$ACTION" in
	stop)
		# when we were killed, the stop is just to reset
		# the systemd state; remove the flag and exit
		if netcontrol_running && test -z "$INTERFACE" -a \
			   -f "${RUN_FILES_BASE}/killed" ;
		then
			rm -f "${RUN_FILES_BASE}/killed"
			rc_failed 0
			rc_exit
		fi

		netconfig update
		# fall through
		;;
	status|start|reload)
		# fall through
		;;
	try-restart)
		$0 status >/dev/null && \
			$0 restart $CONFIG $INTERFACE ${OPTIONS:+-o $OPTIONS}
		rc_status
		rc_exit
		;;
	restart|force-reload)
		if netcontrol_running && test -z "$INTERFACE" -a \
			   -f "${RUN_FILES_BASE}/killed" ;
		then
			rm -f "${RUN_FILES_BASE}/killed"
			lock_firewall
			for IFACE in `get_iface_config_names` ; do
				test -n "$IFACE" -a -d "/sys/class/net/$IFACE" -a \
				     -f "${RUN_FILES_BASE}/ifup-$IFACE" || continue

				$0 start $IFACE ${OPTIONS:+-o $OPTIONS}
			done
			rc_status
			reload_firewall
			rc_exit
		else
			$0 stop $CONFIG $INTERFACE ${OPTIONS:+-o $OPTIONS}
			$0 start $CONFIG $INTERFACE ${OPTIONS:+-o $OPTIONS}
			rc_status
			rc_exit
		fi
		;;
	*)
		echo "Usage: $0 <action> [<config>] [<interface>] [-o <options>]"
		echo "  actions: start|stop|status|reload|force-reload|try-restart"
		echo "           restart|stop-all-dhcp-clients|restart-all-dhcp-clients"
		echo "  options: [on]boot,hotplug,manual,check,debug,fake"
		echo "           type=<typelist>,skip=<skiplist>"
		echo "  typelist: space seperated list of interface types"
		echo "  skiplist: space seperated list of interfaces to skip for 'start'"
		exit 1
		;;
esac
cd /etc/sysconfig/network


######################################################################


if [ "$MODE" = onboot -a "$ACTION" = start -a -z "$INTERFACE$SKIP$TYPE" ] ; then
	rm -f  ${RUN_FILES_BASE}/if-*
	rm -f  ${RUN_FILES_BASE}/ifup-*
	rm -Rf ${RUN_FILES_BASE}/tmp
	rm -f  ${RUN_FILES_BASE}/route-stack-* 2>/dev/null
fi
mkdir -p ${RUN_FILES_BASE}/tmp

# This has to happen early; don't move that into start section below!!!
# (Writing NETWORK_RUNFILE means that service network is started. And only if
# service network was started interfaces will be set up via hotplug. And it must
# be started before checking which interfaces are already available and might
# still have to be set up because the were registered to early. Bug 39005)
case $ACTION in
start)
	IFS=. read a b < /proc/uptime
	echo "$a" > $NETWORK_RUNFILE
;;
esac

if [ -n "$TYPE" ] ; then
	type_filter() {
		for i in $*; do
			for t in $TYPE; do
				case $i in
					# $t*) echo -n "$i "; continue 2;;
					$t*) echo $i; continue 2;;
				esac
			done
		done
		echo
	}
else
	LO=lo
	type_filter() {
		echo $*
	}
fi


######################################################################
# Get interfaces to handle
#
# Seperate this interfaces into several sets, not all mutually exclisive;
# none of them may contain lo, because it will always handled separately
#
# PHYSICAL_IFACES       available interfaces to present physical devices
#                       (not in VIRTUAL_IFACES), that are already prepared
#                       by udev rules using an "ifup -o hotplug" call.
#
# NOT_PHYSICAL_IFACES   available interfaces that are in VIRTUAL_IFACES
#
# AVAILABLE_IFACES      are all interfaces available at /sys/class/net
#                       (that is PHYSICAL_IFACES + NOT_PHYSICAL_IFACES)
#
# VIRTUAL_IFACES        all configured interfaces (derived from ifcfg-*
#                       files), except of thoseinterfaces "known" as
#                       interfaces to physical devices
#
# subsets of VIRTUAL_IFACES:
#   BONDING_IFACES      are virtual bonding interfaces
#   BRIDGE_IFACES       are virtual bridge interfaces
#   DIALUP_IFACES       are virtual modemX, dslX, etc.
#   TUNNEL_IFACES       are virtual tunnel interfaces
#   VLAN_IFACES         are virtual vlan (802.1q) interfaces
#
# MANDATORY_DEVICES     interfaces specified in global network/config or
#                       interfaces (to physical devices) that are not in
#                       the VIRTUAL_IFACES set.
#                       in boot mode, the script waits up to the limit
#                       of $WAIT_FOR_INTERFACES seconds to become ready.
#                       
# MANDATORY_SLAVES      all interfaces that are slave/base interfaces for
#                       virtual interfaces and not virtual themself.
#
# The PHYSICAL and NOT_PHYSICAL interfaces sets are mutually exclusive.
# Their union contains AVAILABLE and MANDATORY and all of them have to
# be set up when starting.
#

# At first sort into VIRTUAL interface set and the subsets BONDING,
# BRIDGE, DIALUP, TUNNEL and VLAN.
for b in `get_iface_config_names` ; do
	b=`type_filter $b`
	t=`get_iface_type_from_config $b`
	case $t in
		lo|eth|ib|tr|wlan|irda|ip6tnl|mip6mnha)
			continue
		;;
		bond)
			BONDING_IFACES="$BONDING_IFACES $b"
			add_to_wordlist VIRTUAL_IFACES $b
		;;
		bridge)
			BRIDGE_IFACES="$BRIDGE_IFACES $b"
			add_to_wordlist VIRTUAL_IFACES $b
		;;
		*ppp|dsl|modem|isdn)
			DIALUP_IFACES="$DIALUP_IFACES $b"
			add_to_wordlist VIRTUAL_IFACES $b
		;;
		vlan|ibchild)
			VLAN_IFACES="$VLAN_IFACES $b"
			add_to_wordlist VIRTUAL_IFACES $b
		;;
		ipip|sit|gre|tun|tap)
			TUNNEL_IFACES="$TUNNEL_IFACES $b"
			add_to_wordlist VIRTUAL_IFACES $b
		;;
		dummy)
			add_to_wordlist VIRTUAL_IFACES $b
		;;
		*)
			add_to_wordlist VIRTUAL_IFACES $b

			err_mesg "$b has unknown interface type. Please file a bug report."
		;;
	esac
done

# Now get all available interfaces drop lo and separate them into physical and
# not physical. Then get AVAILABLE_IFACES sorted to shutdown the not physical
# first.
# Interfaces may be renamed by udev after they are registered. In some cases
# this may take some time. Therefore we check a 'renamed' flag if an interface
# is ready to be set up. If an it is not ready now, it will be set up via
# udev/ifup (because network is started now). We will just have to wait for it
# later in the start section if it is considered mandatory (see next section).
#
# When udev is not in use / started,  e.g. inside of LXC container, then the
# 'renamed' flag will be never set and we don't need to check it -- except
# when there is an explicit configuration telling how to behave here.
#
if /sbin/checkproc /sbin/udevd &>/dev/null ; then
	FORCE_PERSISTENT_NAMES=${FORCE_PERSISTENT_NAMES:-yes}
else
	FORCE_PERSISTENT_NAMES=${FORCE_PERSISTENT_NAMES:-no}
fi
for a in $(type_filter `ls -A /sys/class/net/`); do
	test -d /sys/class/net/$a || continue
	t=`get_iface_type $a`
	case "$t" in
		eth|tr|ib|wlan)
			STAMPFILE=$STAMPFILE_STUB`cat /sys/class/net/$a/ifindex`
			if [ "$MODE" = onboot -a "$ACTION" = start -a \
			     "${FORCE_PERSISTENT_NAMES}" = yes ] ; then
				# skip interfaces (with active drivers)
				# but not yet prepared by an
				#   ifup -o hotplug
				# call is triggered in udev rules.
				# (may need rename to their final name)
				if [ ! -e "$STAMPFILE" ] ; then
					continue
				fi
			fi
			;;
		lo|wlan_aux)
			continue
			;;
	esac
	for b in $VIRTUAL_IFACES ; do
		if [ "$a" = "$b" ] ; then
			NOT_PHYSICAL_IFACES="$NOT_PHYSICAL_IFACES $a"
			continue 2
		fi
	done
	PHYSICAL_IFACES="$PHYSICAL_IFACES $a"
done

# mandatory interfaces may be specified in /etc/sysconfig/network/config
# If $MANDATORY_DEVICES is empty we take all PHYSICAL_IFACES, which are
# configured with STARMODE=auto, as mandatory
if [ -z "$MANDATORY_DEVICES" ] ; then
	# take all configurations except these
	# -  which seem to be backup files
	# -  which have STARTMODE != onboot/auto
	# -  which are virtual, dialup or tunnel interfaces
	# -  which serve as slave interfaces for bonding, vlan
	#    or tunnels, except the slave interfaces are physical
	for b in `get_iface_config_names` ; do
		case "`get_startmode $b`" in
			on|boot|onboot|auto|ifplugd) : ;;
			*) continue ;;
		esac
		for d in $DIALUP_IFACES ; do
			if [ "$b" = "$d" ] ; then
				continue 2
			fi
		done
		for d in $VIRTUAL_IFACES ; do
			if [ "$b" = "$d" ] ; then
				#slaves="`get_slaves $b`"
				# resolve all slaves recursively
				slaves=""
				resolve_iface_startorder slaves "$b" "$b"
				test $? = 0 || continue 2
				for s in $slaves ; do
					for v in $SLAVE_IFACES $VIRTUAL_IFACES
					do
						[ "$v" = "$s" ] && continue 2
					done
					SLAVE_IFACES="$SLAVE_IFACES $s"
				done
				continue 2
			fi
		done
		MANDATORY_DEVICES="$MANDATORY_DEVICES $b"
	done
	if [    -n "$MANDATORY_DEVICES" \
	     -a "$MODE" != onboot \
	     -a "$ACTION" = start ] ; then
		echo "Hint: you may set mandatory devices in" \
		     "/etc/sysconfig/network/config"
	fi
	for s in $SLAVE_IFACES ; do
		for m in $MANDATORY_DEVICES ; do
			[ "$m" = "$s" ] && continue 2
		done
		MANDATORY_SLAVES="$MANDATORY_SLAVES $s"
	done
fi

#
# find out the start order of non-physical & non-mandatory
# interfaces resolving their slave interfaces recursively
#
filter_wordlist() {
	local fwv="${1}"
	local fwf="${2}"
	local fwl=""
	local fwi
	test "x$fwv" != x -a \
	     "x$fwf" != x || return 1
	for fwi in ${!fwv} ; do
		$fwf $fwi || continue
		add_to_wordlist fwl $fwi
	done
	eval "${fwv}='${fwl}'"
	return 0
}

bw_fs_filter()
{
	local filter=$1 ; shift
	local w_list=$1 ; shift
	local b_list=$1 ; shift
	local i
	test "x$filter" != x -a \
	     "x$w_list" != x -a \
	     "x$b_list" != x || return 1
	for i in $@ ; do
		$filter $i && \
		add_to_wordlist ${w_list} $i || \
		add_to_wordlist ${b_list} $i
	done
	return 0
}	

resolve_iface_startorder VIRTUAL_IFACES "$VIRTUAL_IFACES" \
	"$PHYSICAL_IFACES $MANDATORY_DEVICES $MANDATORY_SLAVES"

add_to_wordlist AVAILABLE_IFACES $NOT_PHYSICAL_IFACES $PHYSICAL_IFACES
add_to_wordlist MANDATORY_DEVICES __NSC__ $MANDATORY_SLAVES

# Check for mandatory devices only when booting
test "$MODE" = onboot || MANDATORY_DEVICES=""

debug "CONFIG            = $CONFIG"
debug "INTERFACE         = $INTERFACE"
debug "AVAILABLE_IFACES  = $AVAILABLE_IFACES"
debug "PHYSICAL_IFACES   = $PHYSICAL_IFACES"
debug "BONDING_IFACES    = $BONDING_IFACES"
debug "VLAN_IFACES       = $VLAN_IFACES"
debug "DIALUP_IFACES     = $DIALUP_IFACES"
debug "TUNNEL_IFACES     = $TUNNEL_IFACES"
debug "BRIDGE_IFACES     = $BRIDGE_IFACES"
debug "SLAVE_IFACES      = $SLAVE_IFACES"
debug "MANDATORY_DEVICES = $MANDATORY_DEVICES"
debug "VIRTUAL_IFACES    = $VIRTUAL_IFACES"
debug "SKIP              = $SKIP"
start_list="$PHYSICAL_IFACES ; $MANDATORY_DEVICES ; $VIRTUAL_IFACES"
debug "start order       : ${start_list//  / }"


status() {
	local M FIN IFACE
	# declare -i R=0 F=0
	declare -i F=0
	while test $# -gt 0 ; do
		case $1 in
		--final) FIN=yes ; shift ;;
		-m)        M=yes ; shift ;;
		*)  break ;;
		esac
	done
	for IFACE in $@; do
		$FAKE /sbin/ifstatus $CONFIG $IFACE -o rc $CHECK $MODE
		RET=$?
		debug && printf "    %-9s returned %s\n" $IFACE $RET
		case $RET in
			$R_SUCCESS|$R_BUSY)
				# : $((R++))
				rc_failed 0
				rc_status -v1
				;;
			$R_DHCP_BG)
				if [ -f "$NETWORK_RUNFILE" -a "$M" = yes ] ; then
					# do not report failure in --final check under
					# systemd when setup is still in progress ...
					if [ "$SD_RUNNING" != "yes" -o "$FIN" != "yes" ] ; then
						: $((F++))
					fi
				fi
	 			rc_startmode="${esc}[1A${stat}${attn}waiting${norm}"
	 			echo -e "$rc_startmode" 1>&2
				;;
			$R_INACTIVE|$R_NOTCONFIGURED)
				rc_failed 3
				rc_status -v1
				;;
			$R_NOCONFIG)
				if [ -f "$NETWORK_RUNFILE" -a "$M" = yes ] ; then
					: $((F++))
					rc_failed 1
				else
					rc_failed 3
				fi
				rc_status -v1
				;;
			*)
				if [ -f "$NETWORK_RUNFILE" ] ; then
					test "$M" = yes && : $((F++))
					rc_failed 1
				else
					rc_failed 3
				fi
				rc_status -v1
				;;
		esac
		rc_reset
	done
	test "$F" -gt 0 && return 1
	# test "$R" = 0 && return 3
	return 0
}

rc_reset
declare -i FAILED=0
case "$ACTION" in
	start)
		echo "Setting up network interfaces:"

		lock_firewall
		if test -n "$LO" && /sbin/ifstatus $LO &>/dev/null ; then
			# don't check if it is up only, but also if the
			# ifcfg-lo settings are applied by /sbin/ifup.
			if test -e "$RUN_FILES_BASE/if-$LO" -o \
				-e "$RUN_FILES_BASE/ifup-$LO" ; then
				unset LO
			fi
		fi

		for IFACE in ${INTERFACE:-$LO $PHYSICAL_IFACES}; do
			for SI in $SKIP; do
				test "$IFACE" = "$SI" && continue 2
			done
			$FAKE ifup $CONFIG $IFACE -o rc $MODE
			RET=$?
			debug && printf "    %-9s returned %s\n" $IFACE $RET
			case "$RET" in
	 			$R_SUCCESS)
	 				SUCCESS_IFACES="$SUCCESS_IFACES $IFACE"
	 				rc_status -v1
	 				;;
				$R_DHCP_BG)
	 				startmode=waiting
	 				rc_startmode="${esc}[1A${stat}${attn}$startmode${norm}"
	 				echo -en "$rc_startmode" 1>&2
	 				echo
					;;
				$R_NOCONFIG)
					rc_failed 6
					rc_status -v1
					;;
	 			$R_NOTCONFIGURED|$R_INACTIVE)
	 				SUCCESS_IFACES="$SUCCESS_IFACES $IFACE"
					rc_failed 5
					rc_status -v1
	 				;;
	 			*)
	 				rc_failed 7
	 				rc_status -v1
	 				;;
			esac
			rc_reset
		done

		# Wait $WAIT_FOR_INTERFACES seconds after interface setup
		# started for hotplug interfaces to become available
		NEWLINE=no
		while true; do

			debug ... still waiting for hotplug devices:
			debug SUCCESS_IFACES=$SUCCESS_IFACES
			debug MANDATORY_DEVICES=$MANDATORY_DEVICES
			TMP=$MANDATORY_DEVICES
			MANDATORY_DEVICES=
			STATUS_CHECK=yes
			for D in $TMP; do
				if [ "$D" = "__NSC__" ] ; then
					STATUS_CHECK=no
					MANDATORY_DEVICES="$MANDATORY_DEVICES $D"
					continue
				fi
				IFACE=$D
				if [ ! -d /sys/class/net/$IFACE ] ; then
					MANDATORY_DEVICES="$MANDATORY_DEVICES $D"
					continue	
				fi
				for S in $SUCCESS_IFACES; do
					test "$IFACE" = "$S" && continue 2
				done
				if [ "$STATUS_CHECK" = no ] ; then
					echo
					NEWLINE=no
					continue
				fi
				IFACE="`type_filter $IFACE`"
				test -z "$IFACE" && continue
				status -m $IFACE &>/dev/null
				RET=$?
				if [ $RET = 0 ] ; then
					SUCCESS_IFACES="$SUCCESS_IFACES $IFACE"
					if [ "$NEWLINE" = yes ] ; then
						echo
						NEWLINE=no
					fi
					status -m $IFACE
					continue
				fi	
				MANDATORY_DEVICES="$MANDATORY_DEVICES $D"
			done

			# If only the seperator remains we are done and thus remove it
			test "`echo $MANDATORY_DEVICES`" = __NSC__ && MANDATORY_DEVICES=

			IFS=. read a b < /proc/uptime
			TTWAIT=$(($a - `cat $NETWORK_RUNFILE`))
			test $TTWAIT -gt $((WAIT_FOR_INTERFACES)) \
			     -o -z "$MANDATORY_DEVICES" && break

			debug "Time to wait: $((WAIT_FOR_INTERFACES - TTWAIT))"
			if [ "$NEWLINE" != yes ] ; then
				echo "Waiting for mandatory devices: ${MANDATORY_DEVICES//__NSC__/}"
			fi
			echo -n "$((WAIT_FOR_INTERFACES - TTWAIT)) "
			NEWLINE=yes
			sleep 1
		done

		if [ "$NEWLINE" = yes ] ; then
			echo
		fi

		for D in $MANDATORY_DEVICES; do
			# Don't check the seperator
			test "$D" = __NSC__ && continue
			IFACE=$D
			if [ -d /sys/class/net/$IFACE ] ; then
				status --final -m $IFACE && continue
				printf "    %-9s interface could not be set up until now\n" $IFACE
			else
				printf "    %-35s No interface found\n" $D
			fi
			rc_failed
			rc_status -v1
			: $((FAILED++))
		done

		debug ... final
		debug FAILED_IFACES=''
		debug SUCCESS_IFACES=$SUCCESS_IFACES
		debug MANDATORY_DEVICES=$MANDATORY_DEVICES
		debug FAILED=$FAILED
		debug TTWAIT=$TTWAIT

		if [ -z "$INTERFACE" ] ; then
			for IFACE in $VIRTUAL_IFACES ; do
				for SI in $SKIP; do
					test "$IFACE" = "$SI" && continue 2
				done
				$FAKE ifup $CONFIG $IFACE -o rc $MODE
				RET=$?
				debug && printf "    %-9s returned %s\n" $IFACE $RET
				case "$RET" in
		 			$R_SUCCESS)
		 				SUCCESS_IFACES="$SUCCESS_IFACES $IFACE"
		 				rc_status -v1
		 				;;
					$R_DHCP_BG)
		 				startmode=waiting
		 				rc_startmode="${esc}[1A${stat}${attn}$startmode${norm}"
		 				echo -en "$rc_startmode" 1>&2
		 				echo
						;;
					$R_NOCONFIG)
						FAILED_IFACES="$FAILED_IFACES $IFACE"
						rc_failed 6
						rc_status -v1
						# : $((FAILED++))
						;;
		 			$R_NOTCONFIGURED|$R_INACTIVE)
		 				SUCCESS_IFACES="$SUCCESS_IFACES $IFACE"
						rc_failed 5
						rc_status -v1
		 				;;
		 			*)
						FAILED_IFACES="$FAILED_IFACES $IFACE"
		 				rc_failed 7
		 				rc_status -v1
						# : $((FAILED++))
		 				;;
				esac
				rc_reset
			done

			LINE=""
			NEWLINE=no
			while true; do
				debug ... still waiting for virtual devices:
				debug SUCCESS_IFACES=$SUCCESS_IFACES
				debug VIRTUAL_IFACES=$VIRTUAL_IFACES

				TMP=$VIRTUAL_IFACES
				VIRTUAL_IFACES=
				for IFACE in $TMP ; do
					for S in $SUCCESS_IFACES; do
						test "$IFACE" = "$S" && continue 2
					done
					for F in $FAILED_IFACES ; do
						test "$IFACE" = "$F" && continue 2
					done
					IFACE="`type_filter $IFACE`"
					test -z "$IFACE" && continue
					status -m $IFACE &>/dev/null
					RET=$?
					if [ $RET = 0 ] ; then
						SUCCESS_IFACES="$SUCCESS_IFACES $IFACE"
						if [ "$NEWLINE" = yes ] ; then
							echo
							NEWLINE=no
						fi
						status $IFACE
						continue
					fi
					VIRTUAL_IFACES="$VIRTUAL_IFACES $IFACE"
				done
	
				IFS=. read a b < /proc/uptime
				TTWAIT2=$((a - (TTWAIT + `cat $NETWORK_RUNFILE`)))
				test $TTWAIT2 -gt $((WAIT_FOR_INTERFACES)) \
					-o -z "$VIRTUAL_IFACES" && break

				debug "Time to wait: $((WAIT_FOR_INTERFACES - TTWAIT2))"
				if [ "$NEWLINE" != yes ] ; then
					echo "Waiting for virtual interfaces: $VIRTUAL_IFACES"
				fi
				echo -n "$((WAIT_FOR_INTERFACES - TTWAIT2)) "
				NEWLINE=yes
				sleep 1
			done

			if [ "$NEWLINE" = yes ] ; then
				echo
			fi

			for IFACE in $VIRTUAL_IFACES; do
				if [ -d /sys/class/net/$IFACE ] ; then
					status --final -m $IFACE && continue
					printf "    %-9s interface is not ready until now\n" $IFACE
				fi
				rc_failed
				rc_status -v1
				: $((FAILED++))
			done
		fi

		rc_reset
		if [ -z "$INTERFACE" ] ; then
			$FAKE ifup-route noiface -o rc $MODE
			rc_status
			test $FAILED -gt 0 && rc_failed 7
			echo -n "Setting up service network  .  .  .  .  .  .  .  .  .  .  .  .  ."
			rc_status -v
		fi

		reload_firewall

		;;

	stop)

		echo Shutting down network interfaces:

		if [ -z "$INTERFACE" ] ; then
			$FAKE ifdown-route noiface -o rc $MODE
		fi

		DONE_IFACES=""
		STOP_VIFACES=""
		for IFACE in ${VIRTUAL_IFACES} ; do
			STOP_VIFACES="$IFACE $STOP_VIFACES"
		done

		#for IFACE in ${INTERFACE:-$STOP_VIFACES $PHYSICAL_IFACES $BONDING_IFACES $AVAILABLE_IFACES} ; do
		for IFACE in ${INTERFACE:-$STOP_VIFACES $PHYSICAL_IFACES $AVAILABLE_IFACES} ; do
			test -d /sys/class/net/$IFACE || continue
			for I in $DONE_IFACES ; do
				test "x$I" = "x$IFACE" && continue 2
			done
			# printf "    %-9s " $IFACE
			$FAKE ifdown $CONFIG $IFACE -o rc $MODE
			RET=$?
			debug && printf "    %-9s returned %s\n" $IFACE $RET
			rc_failed $RET
			case "$RET" in
				$R_NODEV|$R_NOTCONFIGURED|$R_INACTIVE)
					rc_failed 5
					rc_status -v1 ;;
				*)
					rc_status -v1 ;;
			esac
			DONE_IFACES="$DONE_IFACES $IFACE"
			rc_reset
		done

		if [ -z "$INTERFACE" -a -z "$TYPE" ] ; then
			# At last stop any remaining dhcp client
			$FAKE ifdown-dhcp all -o rc
			rc_status
			rm -f $RUN_FILES_BASE/if-*
			rm -f $RUN_FILES_BASE/config-*
			rm -f ${NETWORK_RUNFILE}*
			echo -n "Shutting down service network  .  .  .  .  .  .  .  .  .  .  .  ."
			rc_status -v
		fi

		;;

	reload)
		if ! $0 status &>/dev/null; then
			echo -n service network not active
			rc_failed 7
			rc_status -v
			rc_exit
		fi
		if [ -z "$INTERFACE" -a routes -nt $NETWORK_RUNFILE ] ; then
			$FAKE ifdown-route noiface -o rc $MODE
		fi
		UP2DATE_IFACES=lo
		for IFACE in ${INTERFACE:-$AVAILABLE_IFACES} ; do
			# ifprobe checks if iface configuration changed
			if ifprobe $IFACE ; then
				UP2DATE_IFACES="$UP2DATE_IFACES $IFACE"
				continue
			fi
			$FAKE ifdown $CONFIG $IFACE -o rc $MODE
			RET=$?
			debug && printf "    %-9s returned %s\n" $IFACE $RET
			rc_failed $RET
			case "$RET" in
				$R_NODEV|$R_NOTCONFIGURED|$R_INACTIVE)
					rc_failed 5
					rc_status -v1 ;;
				*)
					rc_status -v1 ;;
			esac
			rc_reset
		done
		# And we we start all interfaces to catch also new virtual interfaces
		cd "$OLDPWD" # we went to /etc/sysconfig/network, so we have to go back.
		$0 start $CONFIG $INTERFACE -o $OPTIONS skip="$UP2DATE_IFACES"
		rc_status
		;;

	status)

		if [ -z "$INTERFACE" ] ; then
 	 		for D in $LO $MANDATORY_DEVICES; do
				test "$D" = __NSC__ && continue
 	 			IFACE=$D
				if [ ! -d /sys/class/net/$IFACE ] ; then
					printf "    %-35s No interface found\n" $D
 	 				: $((FAILED++))
 	 				continue
 	 			fi
 	 			MANDATORY_IFACES="$MANDATORY_IFACES `type_filter $IFACE`"
 	 		done
			debug getting MANDATORY_IFACES: FAILED=$FAILED
 	 
 	 		for IFACE in $AVAILABLE_IFACES $VIRTUAL_IFACES ; do
 	 			for MI in $MANDATORY_IFACES $TOCHECK_IFACES; do
 	 				test "$IFACE" = "$MI" && continue 2
 	 			done
 	 			TOCHECK_IFACES="$TOCHECK_IFACES $IFACE"
 	 		done
 	 
 			debug MANDATORY_DEVICES=$MANDATORY_DEVICES
 			debug MANDATORY_IFACES=$MANDATORY_IFACES
 			debug TOCHECK_IFACES=$TOCHECK_IFACES
 
			if [ -n "$TOCHECK_IFACES" ] ; then
				echo Checking optional network interfaces:
 	 			status $TOCHECK_IFACES
			fi
			if [ -n "$MANDATORY_IFACES" ] ; then
				echo Checking mandatory network interfaces:
 	 			status -m $MANDATORY_IFACES
 	 			test $? != 0 && : $((FAILED++))
				debug checking MANDATORY_IFACES: FAILED=$FAILED
			else
				echo No interfaces declared as mandatory
			fi

 			$FAKE ifstatus-route noiface -o rc $MODE
 			rc_status 
			test $FAILED -gt 0 && rc_failed 1
		else
			status $INTERFACE
			rc_status
		fi

		if [ ! -f $NETWORK_RUNFILE ] ; then
			rc_failed 3 # unused
		fi

		echo -n "Checking service network .  .  .  .  .  .  .  .  .  .  .  .  .  ."
		rc_status -v

		;;

esac

rc_exit

