#!/bin/bash
###############################################################################
#                                                                             #
# IPFire.org - A linux based firewall                                         #
# Copyright (C) 2010  Michael Tremer & Christian Schmidt                      #
#                                                                             #
# 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 3 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/>.       #
#                                                                             #
###############################################################################

. /usr/lib/network/header-zone

HOOK_MANPAGE="network-zone-bridge"

HOOK_SETTINGS="HOOK STP STP_FORWARD_DELAY STP_HELLO STP_MAXAGE STP_MODE"
HOOK_SETTINGS="${HOOK_SETTINGS} STP_PRIORITY MAC MTU"

# Default values
MAC=$(mac_generate)
MTU=1500
STP="on"
STP_MODE="rstp"
STP_FORWARD_DELAY=0
STP_HELLO=2
STP_MAXAGE=20
STP_PRIORITY=512

function _check() {
	assert ismac MAC
	assert isbool STP
	assert isoneof STP_MODE stp rstp
	assert isinteger STP_HELLO
	assert isinteger STP_FORWARD_DELAY
	assert isinteger STP_PRIORITY
	assert isinteger MTU
}

function _parse_cmdline() {
	while [ $# -gt 0 ]; do
		case "${1}" in
			--stp=*)
				STP=${1#--stp=}
				;;
			--stp-mode=*)
				STP_MODE=${1#--stp-mode=}
				;;
			--stp-hello=*)
				STP_HELLO=${1#--stp-hello=}
				;;
			--stp-forward-delay=*)
				STP_FORWARD_DELAY=${1#--stp-forward-delay=}
				;;
			--stp-priority=*)
				STP_PRIORITY=${1#--stp-priority=}
				;;
			--mtu=*)
				MTU=${1#--mtu=}
				;;
			--mac=*)
				MAC=${1#--mac=}
				;;
			*)
				warning "Ignoring unknown option '${1}'"
				;;
		esac
		shift
	done
}

function _up() {
	local zone=${1}
	assert isset zone

	zone_config_read ${zone}

	# Create the bridge if it does not already exist.
	if ! device_exists ${zone}; then
		bridge_create ${zone} \
			--address=${MAC} --mtu=${MTU}

	# Adjust MAC address and MTU if needed.
	else
		device_set_address ${zone} ${MAC}
		device_set_mtu ${zone} ${MTU}
	fi

	# Enable STP
	if enabled STP; then
		stp_enable ${zone}

		if [ -n "${STP_FORWARD_DELAY}" ]; then
			stp_bridge_set_forward_delay ${zone} ${STP_FORWARD_DELAY}
		fi

		if [ -n "${STP_HELLO}" ]; then
			stp_bridge_set_hello_time ${zone} ${STP_HELLO}
		fi

		if [ -n "${STP_MAXAGE}" ]; then
			stp_bridge_set_max_age ${zone} ${STP_MAXAGE}
		fi

		if [ -n "${STP_PRIORITY}" ]; then
			stp_bridge_set_priority ${zone} ${STP_PRIORITY}
		fi
	else
		stp_disable ${zone}
	fi

	device_set_up ${zone}

	# XXX Currently, there is a bug (in the linux kernel?) that we need to
	# set our bridges to promisc mode.
	device_set_promisc ${zone} on

	# Bring all ports up
	zone_ports_up ${zone}
	zone_configs_up ${zone}

	exit ${EXIT_OK}
}

function _down() {
	local zone=${1}
	assert isset zone

	if ! device_is_up ${zone}; then
		warning "Zone '${zone}' is not up"
		exit ${EXIT_OK}
	fi

	zone_configs_down ${zone}
	zone_ports_down ${zone}

	# XXX See remark in _up().
	device_set_promisc ${zone} off

	device_set_down ${zone}
	bridge_delete ${zone}

	exit ${EXIT_OK}
}

function _status() {
	local zone=${1}
	assert isset zone

	# Print the default header.
	cli_device_headline ${zone}

	# Exit if zone is down
	if ! zone_is_up ${zone}; then
		echo # Empty line
		exit ${EXIT_ERROR}
	fi

	cli_headline 2 "Spanning Tree Protocol information"
	if stp_is_enabled ${zone}; then
		local proto=$(stp_bridge_get_protocol ${zone})

		cli_print_fmt1 2 "Version"	"$(stp_get_name ${proto})"
		cli_print_fmt1 2 "ID"		"$(stp_bridge_get_id ${zone})"
		cli_print_fmt1 2 "Priority"	"$(stp_bridge_get_priority ${zone})"

		if stp_bridge_is_root ${zone}; then
			cli_print 2 "This bridge is root."
		else
			cli_print_fmt1 2 "Designated root" \
				"$(stp_bridge_get_designated_root ${zone})"
			cli_print_fmt1 2 "Root path cost" \
				"$(stp_bridge_get_root_path_cost ${zone})"
		fi
		cli_space

		# Topology information
		cli_print_fmt1 2 "Topology changing" \
			"$(stp_bridge_get_topology_change_detected ${zone})"
		cli_print_fmt1 2 "Topology change time" \
			"$(beautify_time $(stp_bridge_get_topology_change_timer ${zone}))"
		cli_print_fmt1 2 "Topology change count" \
			"$(stp_bridge_get_topology_change_count ${zone})"
		cli_space
	else
		cli_print 2 "Disabled"
		cli_space
	fi

	cli_headline 2 "Ports"
	zone_ports_status ${zone}
	cli_space

	cli_headline 2 "Configurations"
	zone_configs_cmd status ${zone}
	cli_space

	exit ${EXIT_OK}
}
