# Copyright (c) 2004-2005 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header$

# Contributed by Roy Marples (uberlord@gentoo.org)

# Fix any potential localisation problems
# Note that LC_ALL trumps LC_anything_else according to locale(7)
brctl() {
	LC_ALL=C /sbin/brctl "$@"
}

# char* bridge_provides(void)
#
# Returns a string to change module definition for starting up
bridge_provides() {
	echo "bridge"
}

# void bridge_depend(void)
#
# Sets up the dependancies for the module
bridge_depend() {
	after interface tuntap
	before dhcp
}

# bool bridge_check_installed(void)
#
# Returns 1 if bridge is installed, otherwise 0
bridge_check_installed() {
	[[ -x /sbin/brctl ]] && return 0
	${1:-false} && eerror "For bridge support, emerge net-misc/bridge-utils"
	return 1
}

# bool bridge_check_depends(void)
#
# Checks to see if we have the needed functions
bridge_check_depends() {
	local f

	for f in interface_variable interface_down interface_del_addresses interface_set_flag; do
		[[ $( type -t ${f} ) == function ]] && continue
		eerror "bridge: missing required function ${f}\n"
		return 1
	done

	return 0
}

# char* bridge_get_vars(char *interface)
#
# Returns a string spaced with possible user set
# configuration variables
bridge_get_vars() {
	echo "bridge_${1} brctl_${1}"
}

# char* bridge_get_ports(char *interface)
#
# Returns a string spaced with interfaces added to the given bridge
# The awk statement kinda makes sense - would be much easier if the
# brctl program exported the bridge name on each line :/
bridge_get_ports() {
	brctl show | awk -v iface=${1} -v got=0 \
		'$1 == iface || got == 1 { \
			if ( got == 0 ) \
				{ print $4; got=1; } \
			else if ( NF == 1 ) \
				{ print $1; } \
			else \
				{ got = 0; } }' \
		| xargs
}

# bool bridge_start(char *iface)
#
# #set up bridge
bridge_pre_start() {
	local iface=${1} ports i e x ifvar=$( interface_variable ${1} )
	local -a opts
	eval ports=\"\$\{bridge_${ifvar}\[@\]\}\"

	[[ -z ${ports} ]] && return 0

	# Destroy the bridge if it exists
	bridge_stop ${iface}

	ebegin "Creating bridge ${iface}"
	e=$( brctl addbr ${iface} 2>&1 )
	if [[ -n ${e} ]]; then
		if [[ ${e} == "br_add_bridge: Package not installed" ]]; then
			eend 1 "Bridging (802.1d) support is not present in this kernel"
		else
			eend 1 "${e}"
		fi
		return 1
	fi

	eval opts=( \"\$\{brctl_${ifvar}\[@\]\}\" )
	for (( i=0; i<${#opts[@]}; i++ )); do
		x=${opts[i]/ / ${iface} }
		[[ ${x} == ${opts[i]} ]] && x="${x} ${iface}"
		e=$( brctl ${x} 2>&1 1>/dev/null )
		[[ -n ${e} ]] && ewarn "${e}"
	done
	eend 0

	einfo "Adding ports to ${iface}"
	eindent

	for i in ${ports}; do
		interface_exists ${i} && continue 
		eerror "interface ${i} does not exist"
		return 1
	done

	for i in ${ports}; do
		ebegin "${i}"
		interface_set_flag ${i} promisc true
		interface_up ${i}
		e=$( brctl addif ${iface} ${i} 2>&1 )
		if [[ -n ${e} ]]; then
			eend 1 "${e}"
			interface_set_flag ${i} promisc false
			return 1
		fi
		eend 0
	done
	eoutdent

	return 0
}

# bool bridge_stop(char *iface)
#
# Removes the device
# returns 0
bridge_stop() {
	local iface=${1} is_bridge=$( brctl show | awk -v iface=${1} '$1 == iface {print $1}' )
	
	bridge_check_installed || return 1
	[[ -z ${is_bridge} ]] && return 1

	ebegin "Destroying bridge ${iface}"
	interface_down ${iface}
	
 	local ports=$( bridge_get_ports ${1} ) i
	eindent
	for i in ${ports}; do
		ebegin "Removing port ${i}"
		interface_set_flag ${i} promisc false
		brctl delif ${iface} ${i} &>${devnull}
		eend $?
	done
	eoutdent
	
	brctl delbr ${iface} &>${devnull}
	eend 0
	return 0
}
