# VLAN module for net-scripts
# Version 1.0.2
# Copyright (c) 2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License V2
# Contributed by Roy Marples (uberlord@gentoo.org)

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

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

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

# bool vlan_check_installed(void)
#
# Returns 1 if vconfig is installed, otherwise 0
vlan_check_installed() {
	[[ -x /sbin/vconfig ]] && return 0
	${1:-false} && eerror "For VLAN (802.1q) support, emerge net-misc/vconfig"
	return 1
}

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

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

	return 0
}

# char* vlan_get_vars(char *interface)
#
# Returns a string spaced with possible user set
# configuration variables
vlan_get_vars() {
	echo "vlans_${1} iface_${1}_vlans"
}

# char* vlan_get_vlans(char *interface)
#
# Fetch the configured vlans for an interface.  Outputs a space
# separated list on stdout.  For example "eth0.1 eth0.2 eth0.3"
vlan_get_vlans() {
	awk -v iface=${1} 'BEGIN { ORS = " "; } $5==iface { print $1 }' /proc/net/vlan/config 2>/dev/null
}

# bool vlan_check_kernel(void)
#
# Checks to see if the 802.1q module is present - if not try and load it
# Returns 1 if there is a problem
vlan_check_kernel() {
	[[ -d /proc/net/vlan ]] && return 0
	/sbin/modprobe 8021q &>/dev/null
	[[ -d /proc/net/vlan ]] && return 0
	eerror "VLAN (802.1q) support is not present in this kernel"
	return 1
}

#bool vlan_pre_start(char *iface)
#
# Setup vconfig
vlan_pre_start() {
	local iface=${1} opts i x e
	local ifvar=$( interface_variable ${iface} )

	eval opts=( \"\$\{vconfig_${ifvar}\[@\]\}\" )
	[[ -z ${opts} ]] && return 0

	vlan_check_kernel || return 1

	for (( i=0; i<${#opts[@]}; i++ )); do
		if [[ ${opts[i]} == set_name_type* ]]; then
			x=${opts[i]}
		else
			x=${opts[i]/ / ${iface} }
			[[ ${x} == ${opts[i]} ]] && x="${x} ${iface}"
		fi
		e=$( vconfig ${x} 2>&1 1>/dev/null )
		[[ -z ${e} ]] && continue
		eerror "vconfig ${x}"
		eerror "${e}"
		return 1
	done

	return 0
}

# bool vlan_post_start(char *iface)
#
# Starts VLANs for a given interface
#
# Always returns 0 (true) 
vlan_post_start() {
	local iface=${1} vlan vlans vlans_old e ifname ifvar=$( interface_variable ${1} )

	eval vlans=\"\$\{vlans_${ifvar}\}\"

	# BACKWARD COMPATIBILITY: check for old vlan variable name
	eval vlans_old=\"\$\{iface_${ifvar}_vlans\}\"
	[[ -n ${vlans_old} && -z ${vlans} ]] && vlans=${vlans_old}

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

	vlan_check_kernel || return 1

	# Start vlans for this interface
	for vlan in ${vlans}; do
		einfo "Adding VLAN ${vlan} to ${iface}"
		e=$( vconfig add ${iface} ${vlan} 2>&1 1>/dev/null )
		if [[ -n ${e} ]] ; then
			eend 1 ${e}
			continue
		fi
		eend 0

		# We need to work out the interface name of our new vlan id
		ifname=$( cat /proc/net/vlan/config \
			| awk -v iface=${iface} -v id=${vlan} '$5==iface && $3==id { print $1 }' )
		iface_start ${ifname}
	done

	return 0
}

# bool vlan_pre_stop(char *iface)
#
# Stops VLANs for a given interface
#
# Always returns 0 (true) 
vlan_pre_stop() {
	local iface=${1} vlan

	vlan_check_installed || return 0

	for vlan in $( vlan_get_vlans ${iface} ); do
		einfo "Removing VLAN ${vlan##*.} from ${iface}"
		iface_stop ${vlan}
		vconfig rem ${vlan} >${devnull}
	done

	return 0
}
