#!/bin/bash
###############################################################################
#                                                                             #
# IPFire.org - A linux based firewall                                         #
# Copyright (C) 2012  IPFire Network Development Team                         #
#                                                                             #
# 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_SETTINGS="HOOK ACCESS_CONCENTRATOR AUTH USERNAME PASSWORD"
HOOK_SETTINGS="${HOOK_SETTINGS} SERVICE_NAME MTU PORT"

# User credentials for the dialin.
USERNAME=""
PASSWORD=""

# Set the authentication mechanism.
AUTH=

# The physical ethernet port the modem is connected to.
PORT=""

# Access Concentrator.
ACCESS_CONCENTRATOR=""

# Service name.
SERVICE_NAME=""

# Maximum Transmission Unit.
# 1492 is a very common value for that.
MTU=1492

# This hook can work with all authentication methods supported by pppd.
PPPOE_SUPPORTED_AUTH_METHODS="${PPP_SUPPORTED_AUTH_METHODS}"
PPPOE_PLUGIN="rp-pppoe.so"

function _check() {
	assert isset USERNAME
	assert isset PASSWORD

	isset AUTH && assert isoneof AUTH ${PPPOE_SUPPORTED_AUTH_METHODS}

	# Check for a valid port setting.
	assert isset PORT
	assert port_exists ${PORT}
}

function _parse_cmdline() {
	while [ $# -gt 0 ]; do
		case "${1}" in
			--access-concentrator=*)
				ACCESS_CONCENTRATOR=$(cli_get_val ${1})
				;;
			--auth=*)
				AUTH=$(cli_get_val ${1})
				;;
			--mtu=*)
				MTU=$(cli_get_val ${1})
				;;
			--password=*)
				PASSWORD=$(cli_get_val ${1})
				;;
			--port=*)
				PORT=$(cli_get_val ${1})
				;;
			--service-name=*)
				SERVICE_NAME=$(cli_get_val ${1})
				;;
			--username=*)
				USERNAME=$(cli_get_val ${1})
				;;
			*)
				warning "Unknown argument: ${1}" >&2
				;;
		esac
		shift
	done
}

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

	zone_config_read ${zone}

	# Bring up the port.
	log DEBUG "Bringing up port '${PORT}'."
	port_up ${PORT}

	# Start the ppp daemon.
	pppd_start ${zone}

	exit ${EXIT_OK}
}

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

	zone_config_read ${zone}

	# Stop the ppp daemon.
	pppd_stop ${zone}

	# Bring down the port.
	log DEBUG "Bringing down port '${PORT}'."
	port_down ${PORT}

	exit ${EXIT_OK}
}

function _discover() {
	local device=${1}

	if [ "$(device_get_type ${device})" != "real" ]; then
		exit ${EXIT_ERROR}
	fi

	local output
	output=$(pppoe-discovery -I ${device} -U $(uuid) 2>&1)

	# Exit if there was not output
	[ -z "${output}" ] && exit ${DISCOVER_ERROR}

	# Exit if PADI timed out
	grep -q "Timeout" <<<${output} && exit ${DISCOVER_ERROR}

	local ac
	while read line; do
		case "${line}" in
			Access-Concentrator:*)
				ac="${line#Access-Concentrator: }"
				;;
		esac
	done <<<"${output}"

	echo "ACCESS_CONCENTRATOR=\"$ac\""

	exit ${DISCOVER_OK}
}

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

	cli_device_headline ${zone}

	zone_config_read ${zone}

	cli_headline 2 "Configuration"
	cli_print_fmt1 2 "Username" "${USERNAME}"
	cli_print_fmt1 2 "Password" "<hidden>"
	cli_print_fmt1 2 "Port" "${PORT}"
	cli_space

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

	# XXX display time since connection started

	cli_headline 2 "Point-to-Point-over-Ethernet protocol"
	local proto
	for proto in ${IP_SUPPORTED_PROTOCOLS}; do
		routing_db_exists ${zone} ${proto} || continue

		local headline
		case "${proto}" in
			ipv6)
				headline="Internet Protocol Version 6"
				;;
			ipv4)
				headline="Internet Protocol Version 4"
				;;
			*)
				headline="Unkown protocol"
				;;
		esac
		cli_headline 3 "${headline}"

		cli_print_fmt1 3 "IP address"  "$(routing_db_get ${zone} ${proto} local-ip-address)"
		cli_print_fmt1 3 "Gateway"     "$(routing_db_get ${zone} ${proto} remote-ip-address)"
		cli_print_fmt1 3 "DNS servers" "$(routing_db_get ${zone} ${proto} dns)"
		cli_space
		cli_print_fmt1 3 "MAC-Remote"  "$(routing_db_get ${zone} ${proto} remote-address)"
		cli_space
	done

	exit ${EXIT_OK}
}

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

	local file=${2}
	assert isset file

	# Read in the configuration files.
	zone_config_read ${zone}

	# Prepare the command line options for the pppoe plugin.
	local plugin_options

	# Add the access concentrator (if any).
	if isset ACCESS_CONCENTRATOR; then
		plugin_options="${plugin_options} rp_pppoe_ac '${ACCESS_CONCENTRATOR}'"
	fi

	# Add the service name (if any).
	if isset SERVICE_NAME; then
		plugin_options="${plugin_options} rp_pppoe_service '${SERVICE_NAME}'"
	fi

	# The last argument must be the interface.
	plugin_options="${plugin_options} ${PORT}"

	pppd_write_config ${file} \
		--interface="${zone}" \
		--username="${USERNAME}" \
		--password="${PASSWORD}" \
		--mtu="${MTU}" \
		--auth="${AUTH}" \
		\
		--plugin="${PPPOE_PLUGIN}" \
		--plugin-options="${plugin_options}"

	exit ${EXIT_OK}
}
