#!/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/>.       #
#                                                                             #
###############################################################################

. /lib/network/header-zone

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 # XXX check out better value

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}
	shift

	zone_config_read ${zone}

	if ! device_exists ${zone}; then
		brctl addbr ${zone}
	fi

	[ -n "${MAC}" ] && device_set_address ${zone} ${MAC}
	[ -n "${MTU}" ] && device_set_mtu ${zone} ${MTU} 

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

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

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

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

		if [ -n "${STP_PRIORITY}" ]; then
			brctl setbridgeprio ${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}

	event_interface_up ${zone}

	exit ${EXIT_OK}
}

function _down() {
	local zone=${1}
	shift

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

	event_interface_down ${zone}

	zone_configs_down ${zone}
	zone_ports_down ${zone}

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

	device_set_down ${zone}
	brctl delbr ${zone}

	exit ${EXIT_OK}
}

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

	cli_status_headline ${zone}

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

	cli_headline "  Spanning Tree Protocol information:"
	if [ -n "$(stp_bridge_get_protocol ${zone})" ]; then
		printf "${DEVICE_PRINT_LINE1}" "Version:" $(stp_bridge_get_protocol ${zone})
		printf "${DEVICE_PRINT_LINE1}" "ID:" $(stp_bridge_get_id ${zone})
		printf "${DEVICE_PRINT_LINE1}" "Priority:" $(stp_bridge_get_priority ${zone})

		if stp_bridge_is_root ${zone}; then
			echo -e "    ${COLOUR_BOLD}This bridge is root.${COLOUR_NORMAL}"
		else
			printf "${DEVICE_PRINT_LINE1}" "Designated root:" $(stp_bridge_get_designated_root ${zone})
			printf "${DEVICE_PRINT_LINE1}" "Root path cost:" $(stp_bridge_get_root_path_cost ${zone})
		fi
		echo # Empty line

		# Topology information
		printf "${DEVICE_PRINT_LINE1}" "Topology changing:" $(stp_bridge_get_topology_change_detected ${zone})
		printf "${DEVICE_PRINT_LINE1}" "Topology change time:" $(beautify_time $(stp_bridge_get_topology_change_timer ${zone}))
		printf "${DEVICE_PRINT_LINE1}" "Topology change count:" $(stp_bridge_get_topology_change_count ${zone})
	else
		echo -e "    ${COLOUR_BOLD}STP is disabled.${COLOUR_NORMAL}"
	fi

	cli_headline "  Ports:"
	zone_ports_status ${zone}

	cli_headline "  Configurations:"
	zone_configs_cmd status ${zone}

	echo # Empty line
	exit ${EXIT_OK}
}

run $@
