#!/bin/sh -e

local NAME=wpa_supplicant bindir=/usr/sbin
local DAEMON=$bindir/$NAME CLIUTIL=$bindir/wpa_cli
local desc="wpa supplicant" IFCONF_TOOL=/sbin/ip cli_cmd
local ACTION=$1

[ -x $IFCONF_TOOL ] || IFCONF_TOOL=/sbin/ifconfig

. /etc/init.d/functions.sh

show_err () {
	[ $? -eq 0 ] || error "$0: action '$ACTION' failed"
}
trap show_err EXIT

if_show () {
	case "$IFCONF_TOOL" in
		/sbin/ip)
			echo "$($IFCONF_TOOL address list" \
			     "dev $WPA_SUPPLICANT_IFACE 2>/dev/null)" || :
			;;
		/sbin/ifconfig)
			echo "$($IFCONF_TOOL $WPA_SUPPLICANT_IFACE" \
			     "2>/dev/null)" || :
			;;
	esac
}

if_up () {
	case "$IFCONF_TOOL" in
		/sbin/ip)
			echo "$($IFCONF_TOOL link set $WPA_SUPPLICANT_IFACE" \
			     "up 2>/dev/null)"
			;;
		/sbin/ifconfig)
			echo "$($IFCONF_TOOL $WPA_SUPPLICANT_IFACE" \
			     "up 2>/dev/null)"
			;;
	esac
}

# Some sane variable default values?
WPA_SUPPLICANT_ENABLED=no
WPA_SUPPLICANT_IFACE=${0##*.}

# Generate a WPA_SUPPLICANT_CONF.
/usr/sbin/mangle-wpa_supplicant-conf.sh $WPA_SUPPLICANT_IFACE

local rcfile=/etc/conf.d/$NAME.$WPA_SUPPLICANT_IFACE
[ ! -f $rcfile ] || . $rcfile
WPA_SUPPLICANT_OPTIONS="-i$WPA_SUPPLICANT_IFACE $WPA_SUPPLICANT_OPTIONS"

[ -f $WPA_SUPPLICANT_CONF ] && [ -f $DAEMON ] && [ -f $CLIUTIL ] ||
	error "$NAME: $WPA_SUPPLICANT_CONF and/or $DAEMON and/or " \
	      "$CLIUTIL files not found, not starting."
CLIUTIL="$CLIUTIL -i$WPA_SUPPLICANT_IFACE"

run_ethtool () {
	[ $WPA_SUPPLICANT_DEBOPTIONS -lt 2 ] || {
		ethtool $WPA_SUPPLICANT_IFACE
	}
}

halt_on_failure () {
	# Halt the system if that's the policy.
	[ $WPA_SUPPLICANT_HALT_IF_FAIL -ne 1 ] || {
		# This can be a quite interesting situation :)
		# While 'init 3' (Full multiuser mode) is in progress,
		# system halt is requested.
		init 0 || :
		#exit 0
	}
}

wait4auth () {
	local wait=0 fail=0 str more cliutil_status status

	while [ $wait -lt $WPA_SUPPLICANT_MAX_WAIT ]; do
		# This will give the the daemon enough time to start.
		# Also, there's no point checking the authentication status
		# right away, as the authentication process will usually
		# take some 15-45 seconds to complete.
		str=
		more=
		[ $wait -eq 0 ] || {
			str="waited $wait s; "
			more="more "
		}
		[ $WPA_SUPPLICANT_DEBOPTIONS -lt 2 ] ||
			information "$NAME: ${str}waiting" \
				    "$WPA_SUPPLICANT_WAIT_INTERVAL ${more}s..."
		sleep $WPA_SUPPLICANT_WAIT_INTERVAL
		wait=$(($wait + $WPA_SUPPLICANT_WAIT_INTERVAL))

		cliutil_status="$($CLIUTIL status)" ||
			warning "$NAME: $CLIUTIL exit status $?"

		status=$(echo "$cliutil_status" | \
			 sed -n -e 's/^EAP[[:space:]]\+state=\(.*\)/\1/p')

		[ $WPA_SUPPLICANT_DEBOPTIONS -lt 2 ] || {
			information "$NAME: status >>>>> $status <<<<<"
			information "$NAME: "if_show
		}

		[ -z "$status" ] || {
			case "$status" in
				SUCCESS)
					logger -p daemon.info -t "$0" \
						"status $status"
					return 0
					;;

				FAILURE)
					fail=$(($fail + 1))
					[ $fail -lt $WPA_SUPPLICANT_MAX_FAIL ] || {
						logger -p daemon.err -t "$0" \
							"status $status"
						halt_on_failure
						break
					}
					;;

				IDLE)
					# Working on it.
					;;

				*)
					# Occasionally, $CLIUTIL says:
					# "'STATUS' command timed out."
					warning "$NAME: Unknown status " \
						">>>>> $status <<<<<"
					warning "$NAME: " \
						">>>>> $cliutil_status <<<<<"
					;;
			esac
		}
	done

	return 1
}

start_d () {
	local msg

	[ "$WPA_SUPPLICANT_ENABLED" = yes ] || {
		warning "$NAME: disabled, see $rcfile."
		return 0
	}

	# Makes no sense starting the daemon, unless at least these
	# certificate files exist.
	[ ! -f /etc/dot1x/$WPA_SUPPLICANT_IFACE/global ] ||
		. /etc/dot1x/$WPA_SUPPLICANT_IFACE/global
	[ -f "$WPA_SUPPLICANT_CA_CERT" ] &&
	[ -f "$WPA_SUPPLICANT_PRIVATE_KEY" ] || {
		msg="$NAME: certificate files missing"
		logger -p daemon.warning -t "$0" $msg
		warning "$msg"
		exit 0
	}

	# Reasonable system date is required, else certificate validation
	# will _fail_ when the certificate creation/expiration dates are
	# matched against current time stamp.
	[ $WPA_SUPPLICANT_DEBOPTIONS -lt 2 ] ||
		information "$NAME: initial time $(date +%F:%T) ($(date +%s))"

	# Check current date against a sensible date (2004-11-09:12:33:20).
	# Lame way to verify time synchronization.
	[ $(date +%s) -gt 1100000000 ] || {
		msg="$NAME: time synchronization problem $(date +%F:%T)"
		logger -p daemon.err -t "$0" $msg
		error "$msg"
		#halt_on_failure
	}

	# Make sure the interface is up.
	if_show | grep -q 'UP' || if_up

	run_ethtool

	start_daemon $DAEMON $WPA_SUPPLICANT_OPTIONS || return 1

	wait4auth || {
		run_ethtool
		return 1
	}

	return 0
}

stop_d () {
	stop_daemon $DAEMON $WPA_SUPPLICANT_OPTIONS || return 1
	run_ethtool
}

case "$ACTION" in
	start)
		begin "Starting $desc"
		start_d
		end $?
		;;

	stop)
		begin "Stopping $desc"
		stop_d
		end $?
		;;

	restart)
		begin "Restarting $desc"
		stop_d && start_d
		end $?
		;;

	reload)
		# Changes to configuration file can be reloaded by sending
		# a SIGHUP signal ('killall -HUP wpa_supplicant'), or:
		begin "Reconfiguring $desc"
		if [ "$(pidof $DAEMON)" ]; then
			if [ "$WPA_SUPPLICANT_ENABLED" = yes ]; then
				cli_cmd=reconfigure
			else
				cli_cmd=terminate
			fi
			logger -t ${0##*/} "Kicking '$CLIUTIL $cli_cmd'"
			$CLIUTIL $cli_cmd || {
				logger -t ${0##*/} \
					"'$CLIUTIL $cli_cmd' failed with $?"
			}
		else
			start_d
		fi
		end $?
		;;

	*)
		echo "Usage: $0 {start|stop|restart|reload}" >&2
		exit 1
		;;
esac

exit 0
