# A collection of functions used in the ifupdown hook script for enhanced
# MadWifi (madwifi-ng) support in Debian and Debian-based distributions
#
# $Id: functions.inc.sh 27 2006-09-27 05:20:00Z mrenzmann $
#
# Copyright (c) 2006 Michael Renzmann <mrenzmann@otaku42.de>
# Portions Copyright (c) 2005 Matt Brown <matt@mattb.net.nz>
#
# For further information see:
# http://projects.otaku42.de/wiki/madwifi-ifupdown
#
# This is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License version 2 as published by the Free
# Software Foundation.
#
# This 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
# the madwifi-ifupdown package; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
function warning {
	echo "WARNING: $@" >&2
}

function error {
	echo "ERROR: $@" >&2
	exit 1
}

# found in "Advanced Bash Scripting Guide 4.0" from Mendel Cooper,
# example 10-28:
# http://tldp.org/LDP/abs/html/testbranch.html#ISALPHA
#
# returns 0 if input consists of decimal digits only, 1 otherwise
function isdigit() {
	[ "$#" -eq 1 ] || return 1
	
	case $1 in
	*[!0-9]*|"")
		return 1
	;;
	*)
		return 0
	;;
	esac
}

# returns 0 if input consists of hex digits only, 1 otherwise
function ishex() {
	[ "$#" -eq 1 ] || return 1
	
	case $1 in
	*[!0-9a-fA-F]*|"")
		return 1
	;;
	*)
		return 0
	;;
	esac
}

# parameter 1: name of parent device
# parameter 2: what VAP type to look for
#
# Will return 0 if the given parent device
# currently has VAPs of the given type
# attached, unless their name is identical
# to the one in $IFACE. Returns 1 otherwise.
function parent_has_vaptype {
	[ -n "$1" ] || return 1
	[ -n "$2" ] || return 1
	[ -d "/proc/sys/net" ] || return 1

	parent="$1"
	vaptype="$2"
	
	case "$vaptype" in
	ap)  mode="Master" ;;
	sta) mode="Managed" ;;
	any) mode="" ;;
	*) return 1 ;;
	esac
	
	for d in /proc/sys/net/*; do
		if [ -f $d/%parent ]; then
			parent=$(cat $d/%parent)
			if [ "$parent" != "$1" ]; then
				continue
			fi
			
			iface=${d##*/}
			if [ "$iface" = "$IFACE" ]; then
				continue
			fi
			
			res=$(iwconfig $iface | grep Mode:$mode)
			
			if [ -n "$res" ]; then
				return 0
			fi
		fi
	done
	
	return 1
}

# parameter 1: name of parent
#
# returns 0 if parent has any AP VAPs attached, 1 otherwise
function parent_has_ap {
	[ -n "$1" ] || return 1
	parent_has_vaptype $1 "ap" && return 0 || return 1
}

# parameter 1: name of parent
#
# returns 0 if parent has any STA VAPs attached, 1 otherwise
function parent_has_sta {
	[ -n "$1" ] || return 1
	parent_has_vaptype $1 "sta" && return 0 || return 1
}

# parameter 1: name of parent
#
# returns 0 if parent has any VAPs attached, 1 otherwise
function parent_has_vaps {
	[ -n "$1" ] || return 1
	parent_has_vaptype $1 "any" && return 0 || return 1
}

# make sure that the directory for our temporary hostapd
# configuration files is defined and exists; if the target
# configuration file exists, get rid of it
function prepare_hostapd_cfgdir {
	if [ -z "$HOSTAPD_CFGDIR" ]; then
		error "HOSTAPD_CFGDIR not defined"
	fi
	if [ ! -d "$HOSTAPD_CFGDIR" ]; then
		warning "creating $HOSTAPD_CFGDIR"
		mkdir -p "$HOSTAPD_CFGDIR" || \
			error "failed to create $HOSTAPD_CFGDIR"
	fi

	# determine this interface's hostapd configuration file name
	# and fill it with content
	if [ -f "$HOSTAPD_CFGFILE" ]; then
		rm -f "$HOSTAPD_CFGFILE" || \
			error "failed to remove old $HOSTAPD_CFGFILE"
	fi
}

# generates hostapd configuration file for $IFACE
function write_hostapd_conf {
	# some more preparation
	prepare_hostapd_cfgdir
	
	old_umask=$(umask)
	umask 177
	touch $HOSTAPD_CFGFILE
	umask $old_umask

	f=$HOSTAPD_CFGFILE
	echo "#
# automatically created, do not edit
# timestamp: $(date)
driver=madwifi
interface=$IFACE" >> $f

	if isbridged; then
		while read a b rest; do
			[ -n "$BRIDGEIF" ] && break

			a=$(echo $a | tr [A-Z] [a-z])
			case "$a" in
			iface)
				ifname=$b
			;;
			bridge_ports)
				for i in $b $rest; do
					if [ "$i" = "$IFACE" ]; then
						BRIDGEIF="$ifname"
					fi
				done
			;;
			esac
		done < /etc/network/interfaces

		echo "bridge=$BRIDGEIF" >> $f
	fi

	echo "
logger_syslog=-1
logger_syslog_level=2
logger_stdout=0
logger_stdout_level=2
debug=0

dump_file=/tmp/hostapd-$IFACE.dump
ctrl_interface=/var/run/hostapd-$IFACE
ctrl_interface_group=0

ssid=$IF_ATH_SSID
" >> $f	

	if [ "$ACL" -eq "1" ]; then
		echo "macaddr_acl=1" >> $f
		case "$ACLMODE" in
		"white")
			echo "accept_mac_file=$IF_ATH_ACL_FILE" >> $f
		;;
		"black")
			echo "deny_mac_file=$IF_ATH_ACL_FILE" >> $f
		;;
		esac
	else
		echo "macaddr_acl=0" >> $f
	fi
	
	echo "
auth_algs=1
wpa=$WPATYPE
wpa_key_mgmt=WPA-PSK
wpa_pairwise=$PAIRWISE" >> $f

	if [ -n "$IF_ATH_WPA_PSKFILE" ]; then
		echo "wpa_psk_file=$IF_ATH_WPA_PSKFILE" >> $f
	fi
	if [ -n "$IF_ATH_WPA_PSK" ]; then
		echo "wpa_psk=$IF_ATH_WPA_PSK" >> $f
	fi
	if [ -n "$IF_ATH_WPA_PASSPHRASE" ]; then
		echo "wpa_passphrase=$IF_ATH_WPA_PASSPHRASE" >> $f
	fi
}

# returns 0 is IFACE is part of a bridge, 1 otherwise
function isbridged {
	[ -n "$IFACE" ] || return 1
	
	if [ -n "$(sed -n -e "/bridge_ports.*$IFACE/p" /etc/network/interfaces)" ]; then
		return 0
	else
		return 1
	fi
}
