#!/bin/dash
# Description: This is the Network Tool found at the bottom of your screen in the system tray.
# 20170626 step: overhaul
#   Don't use iwconfig, which sometimes can hang really hard (can't shutdown).
#   Improve detecting when wpa_supplicant isn't running.
#   Fix restart action (eth0 was left stopped in some cases).
#   Fix status action (reported "running" if no wpa_gui process existed).
# 20180104 step: ensure that start_wireless won't start the interface supplicant twice
# 20200717 step: support preferred wireless interface - see also fatdog-wireless-antenna.sh
# NOTE users should never start wpa_supplicant and wpa_cli from a terminal, that is, without using fatdog network scripts. Starting wpa_gui -t from the terminal is OK.
# NOTE This script doesn't support multiple simultaneous wireless connections.

#exec >>/tmp/${0##*/}.log 2>&1
#echo ========================
#date +%Y%m%d-%H%M%S
#echo "$0 $*"
#echo ========================
#set -x

set +f

#
enum_interfaces() {
	local p iface
	unset OTHER WIRED WIRELESS
	for p in /sys/class/net/*; do
		case $p in *\* ) return 1 ;; esac # no interfaces
		iface=${p##*/}
		case $iface in
			lo|teredo)
				OTHER="$OTHER $iface" ;;
			*)
				if [ -e $p/wireless ]; then
					WIRELESS="$WIRELESS $iface"
				else
					WIRED="$WIRED $iface"
				fi
				;;
		esac
	done
}

### configuration
. $BOOTSTATE_PATH
# initrd::/sbin/system-init sets CONFIGURED_NET iff the Fatdog-specific kernel boot options include a network location.
[ "$CONFIGURED_NET" ] && exit # leave if network already configured at boot
# /etc/rc.d/rc.network -> /usr/sbin/network-setup.sh configures wifi before us unless $WPAGUI_ACTIVE_FLAG exist
WPAGUI_ACTIVE_FLAG=/etc/wpagui
UP_FLAG=/tmp/50-wpagui-up
APPTITLE=${0##*/}
MAX_RETRY=15 # 15 seconds
# must match ctrl_interface=DIR= in /etc/wpa_supplicant.conf
CONTROL_SOCKET_PATH=/var/run/wpa_supplicant
PREF_WIFI_IFACE_PATH=/etc/wpa_gui/wifi-preferred

### start/stop routines
start_loopback() {
	ifconfig lo up > /dev/null
	ifconfig lo 127.0.0.1
	route add -net 127.0.0.0 netmask 255.0.0.0 lo 2> /dev/null
}

start_wired_autodhcp() {
	local TIMEOUT=$MAX_RETRY IFACE ADDR

	while [ $TIMEOUT -ge 0 ]; do
		#echo auto_dhcp $TIMEOUT
		enum_interfaces
		#! [ "$WIRED" ] && break 2 # no wired interfaces
		for IFACE in $WIRED; do
			# start dhcp, but only if not configured by network wizard/network-setup
			read ADDR < /sys/class/net/$IFACE/address
			if ! [ -f /etc/network-setup/ip/$IFACE ] &&
			! [ -f /etc/network-wizard/network/interfaces/$ADDR.conf ]; then
				ifconfig $IFACE up >/dev/null; ifconfig $IFACE | grep -q UP || continue
				#echo $APPTITLE - auto dhcp for $IFACE
				#dhcpcd -q -L -h $(hostname) $IFACE &
				echo $APPTITLE - calling wpa_gui-wired for $IFACE
				wpa_gui-wired $IFACE &
			else
				echo $APPTITLE - $IFACE will be configured by network-wizard
			fi
			break 2
		done
		TIMEOUT=$((TIMEOUT-1))
		sleep 1
	done
}

# Start the first wireless interface that can be started.
# The preferred interface, if configured, is tried first and, if successful, all other radios are disabled.
# To restart an interface you must call stop_wireless first.
start_wireless() {
	local TIMEOUT=$MAX_RETRY IFACE socket pidf pid pref started

	[ -r "$PREF_WIFI_IFACE_PATH" ] && read pref < "$PREF_WIFI_IFACE_PATH"
	while [ $TIMEOUT -ge 0 ]; do
		enum_interfaces
		for IFACE in $pref $WIRELESS; do
			ifconfig $IFACE up >/dev/null; ifconfig $IFACE | grep -q UP || continue
			# don't stop an existing supplicant for $IFACE
			if pid=$(pidof wpa_supplicant) && ps $pid 2>/dev/null | grep -Fq -- "-i$IFACE"; then
				echo >&2 "$APPTITLE - warning: wpa_supplicant is already running for $IFACE; restart the connection"
				continue
			fi
			echo >&2 "$APPTITLE - loading wpa_supplicant for $IFACE"
			socket=$CONTROL_SOCKET_PATH/$IFACE pidf=/var/run/wpa_cli-$IFACE.pid
			rm -f "$socket" "$pidf"
			if ! wpa_supplicant -i$IFACE -c/etc/wpa_supplicant.conf -B; then
				wpa_supplicant -i$IFACE -c/etc/wpa_supplicant.conf -B -Dwext
			fi &&
			if ! [ -e "$pidf" ]; then
				sleep 1 # give wpa_supplicant enough time to start and open its $socket
				dhcpcd-wpagui $IFACE CONNECTED # pretend we're connected
				wpa_cli -a /usr/sbin/dhcpcd-wpagui -i$IFACE -B -P "$pidf"
			fi
			# finished if the $socket exists
			# (early on wpa_supplicant could have quit on events it considers errors)
			if [ -S "$socket" ]; then
				started=true
				break 2
			fi
		done
		TIMEOUT=$((TIMEOUT-1))
		sleep 1
	done
	if [ "$started" -a "$pref" ]; then
		disable_all_radios_except $pref
	fi
}

stop_wired() {
	local IFACE ADDR pid
	enum_interfaces
	for IFACE in $WIRED; do
		# only do it for interfaces not configured by network wizard/network-setup
		read ADDR < /sys/class/net/$IFACE/address
		if ! [ -f /etc/network-setup/ip/$IFACE ] &&
			! [ -f /etc/network-wizard/network/interfaces/$ADDR.conf ]; then
			echo $APPTITLE - turning off $IFACE
			if [ -f /var/run/dhcpcd-$IFACE.pid ] &&
				read pid < /var/run/dhcpcd-$IFACE.pid
			then
				kill $pid 2>/dev/null
			fi
			ifconfig $IFACE down > /dev/null
		else
			echo $APPTITLE - $IFACE will be turned off by network-wizard
		fi
	done
}

stop_wireless() {
	local IFACE pid
	enum_interfaces
	killall wpa_cli; rm -f /var/run/wpa_cli-*.pid
	killall dhcpcd-wpagui
	killall wpa_supplicant
	for IFACE in $WIRELESS; do
		echo $APPTITLE - turning off $IFACE
		if [ -f /var/run/dhcpcd-$IFACE.pid ] &&
			read pid < /var/run/dhcpcd-$IFACE.pid
		then
			kill $pid 2>/dev/null
		fi
		ifconfig $IFACE down > /dev/null
	done
}

# Turn $1-pref, the preferred antenna ON, and all other antennas off.
disable_all_radios_except() {
	local pref="${1:?}" iface x

	enum_interfaces
	for iface in $WIRELESS; do
		[ "$iface" = "$pref" ] && continue
		set /sys/class/net/$iface/phy80211/rfkill*/index
		if [ -r "$1" ] && read x < "$1"; then
			rfkill block $x
		fi
	done
}

### main
case "$1" in
	start)
		start_loopback 					# ALWAYS setup loopback - do it before exit check
		[ -f $WPAGUI_ACTIVE_FLAG ] || exit 		# leave if we are not the active network manager

		start_wired_autodhcp
		start_wireless
		touch $UP_FLAG		  			# indicate startup
		;;

	stop) #called at shutdown and if quit is selected on wpa_gui
		stop_wired
		stop_wireless
		rm -f $UP_FLAG
		;;

	restart) #called from wpa_gui right click menu
		touch $WPAGUI_ACTIVE_FLAG # If restart called assume we don't want wpa disabled.

		stop_wired
		stop_wireless
		killall wpa_gui
		sleep 2

		start_wired_autodhcp
		start_wireless
		exec wpa_gui -t &
		touch $UP_FLAG		  			# indicate startup
		;;

	status)
		[ -e $UP_FLAG ] && pidof wpa_gui >/dev/null && echo "Wpagui is running." || echo "Wpagui is stopped."
		;;

esac
