# Copyright (c) 2005-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# shellcheck shell=sh disable=SC1008

clip_depend()
{
    program atmsigd
    before interface
}

_config_vars="$_config_vars clip"

# This starts a service. Albeit atmsigd, ilmid and atmarpd do allow for back-
# grounding through the -b option, its usage causes them to be sensible to
# SIGHUP, which is sent to all daemons when console detaches right after
# startup. This is probably due to the fact that these programs don't detach
# themself from the controlling terminal when backgrounding... The only way I
# see to overcame this is to use the --background option in start-stop-daemon,
# which is reported as a "last resort" method, but it acts correctly about this.
atmclip_svc_start()
{
    ebegin "Starting $2 Daemon ($1)"
    start-stop-daemon --start \
		--background \
		--make-pidfile --pidfile "/run/$1.pid" \
		--exec "$1" -- -l syslog
    eend $?
}

atmclip_svcs_start()
{
    einfo "First CLIP instance: starting ATM CLIP daemons"
    eindent

	if yesno ${clip_full:-yes}; then
		atmclip_svc_start atmsigd "Signaling" && \
		atmclip_svc_start ilmid	  "Integrated Local Management Interface" && \
		atmclip_svc_start atmarpd "Address Resolution Protocol"
    else
		atmclip_svc_start atmarpd "Address Resolution Protocol"
    fi

    local r=$?

    eoutdent
    return ${r}
}

atmclip_svc_stop()
{
    ebegin "Stopping $2 Daemon ($1)"
    start-stop-daemon --stop --quiet \
		--pidfile "/run/$1.pid" \
		--exec "$1"
    eend $?
}

atmclip_svcs_stop()
{
    einfo "Last CLIP instance: stopping ATM CLIP daemons"
    eindent

    # Heartake operation!
    sync

    atmclip_svc_stop atmarpd "Address Resolution Protocol"
	if yesno ${clip_full:-yes}; then
		atmclip_svc_stop ilmid "Integrated Local Management Interface"
		atmclip_svc_stop atmsigd "Signaling"
    fi

    eoutdent
}

are_atmclip_svcs_running()
{
	[ -f /run/atmarpd.pid ] || return 1
	start-stop-daemon --quiet --test --stop --pidfile /run/atmarpd.pid || return 1

	if yesno ${clip_full:-yes}; then
		[ -f /run/ilmid.pid -a -f /run/atmsigd.pid ] || return 1
		start-stop-daemon --quiet --test --stop --pidfile /run/ilmid.pid || return 1
		start-stop-daemon --quiet --test --stop --pidfile /run/atmsigd.pid || return 1
	fi

    return 0
}

clip_pre_start()
{
	local clip=
	eval clip=\$clip_${IFVAR}
	[ -z "${clip}" ] && return 0

    if [ ! -r /proc/net/atm/arp ]; then
		modprobe clip && sleep 2
		if [ ! -r /proc/net/atm/arp ]; then
	    	eerror "You need first to enable kernel support for ATM CLIP"
	    	return 1
		fi
    fi

    local started_here=
    if ! are_atmclip_svcs_running; then
		atmclip_svcs_start || return 1
		started_here=1
    fi

    if ! _exists; then
		ebegin "Creating CLIP interface ${IFACE}"
		atmarp -c "${IFACE}"
		if ! eend $?; then
			[ -z "${started_here}" ] && atmclip_svcs_stop
	    	return 1
		fi
    fi

    return 0
}

clip_post_start()
{
	local clip="$(_get_array "clip_${IFVAR}")"
	[ -z "${clip}" ] && return 0

	are_atmclip_svcs_running || return 1

    # The atm tools (atmarpd?) are silly enough that they would not work with
    # iproute2 interface setup as opposed to the ifconfig one.
    # The workaround is to temporarily toggle the interface state from up
    # to down and then up again, without touching its address. This (should)
    # work with both iproute2 and ifconfig.
    _down
    _up

    # Now the real thing: create a PVC with our peer(s).
    # There are cases in which the ATM interface is not yet
    # ready to establish new VCCs. In that cases, atmarp would
    # fail. Here we allow 10 retries to happen every 2 seconds before
    # reporting problems. Also, when no defined VC can be established,
    # we stop the ATM daemons.
    local has_failures= i=
	for i in ${clip}; do
		local IFS=","
		set -- ${i}
		unset IFS
		local peerip="$1"; shift
		local ifvpivci="$1"; shift
		ebegin "Creating PVC ${ifvpivci} for peer ${peerip}"

		local nleftretries=10 emsg= ecode=
		while [ ${nleftretries} -gt 0 ]; do
			: $(( nleftretries -= 1 ))
	    	emsg="$(atmarp -s "${peerip}" "${ifvpivci}" "$@" 2>&1)"
	    	ecode=$? && break
	    	sleep 2
		done

		if ! eend ${ecode}; then
	    	eerror "Creation failed for PVC ${ifvpivci}: ${emsg}"
	    	has_failures=1
		fi
    done

    if [ -n "${has_failures}" ]; then
		clip_pre_stop "${iface}"
		clip_post_stop "${iface}"
		return 1
    else
		return 0
    fi
}

clip_pre_stop()
{
    are_atmclip_svcs_running || return 0

	# We remove all the PVCs which may have been created by
	# clip_post_start for this interface. This shouldn't be
	# needed by the ATM stack, but sometimes I got a panic
	# killing CLIP daemons without previously vacuuming
	# every active CLIP PVCs.
	# The linux 2.6's ATM stack is really a mess...
	local itf= t= encp= idle= ipaddr= left=
	einfo "Removing PVCs on this interface"
	eindent
	{
		read left && \
		while read itf t encp idle ipaddr left; do
			if [ "${itf}" = "${IFACE}" ]; then
				ebegin "Removing PVC to ${ipaddr}"
				atmarp -d "${ipaddr}"
				eend $?
			fi
		done
	} < /proc/net/atm/arp
	eoutdent
}

# Here we should teorically delete the interface previously created in the
# clip_pre_start function, but there is no way to "undo" an interface creation.
# We can just leave the interface down. "ifconfig -a" will still list it...
# Also, here we can stop the ATM CLIP daemons if there is no other CLIP PVC
# outstanding. We check this condition by inspecting the /proc/net/atm/arp file.
clip_post_stop()
{
    are_atmclip_svcs_running || return 0

    local itf= left= hasothers=
    {
		read left && \
		while read itf left; do
	    	if [ "${itf}" != "${IFACE}" ]; then
				hasothers=1
				break
	    	fi
		done
    } < /proc/net/atm/arp

    if [ -z "${hasothers}" ]; then
		atmclip_svcs_stop || return 1
    fi
}
