#!/bin/sh
# Aurora Wi-Fi controller (B8F). Pronto/WCNSS remoteproc -> wcn36xx wlan0 -> minimal hostapd AP (WPA2-PSK/CCMP).
# No DHCP/NAT/DNS/firewall. Everything proven in B8B..B8E; order = B8C..B8E: WCNSS is started after the modem reached
# START OK (or FAIL/rollback, or WAIT_MODEM s elapsed), from the RO modem FAT (/firmware/image/wcnss.mdt), NV from initramfs.
#   aurora-wifi start | stop | status
D=/run/aurora-wifi; LOG=$D/wifi.log; CONF=/etc/aurora/wifi.conf; X=/usr/libexec/aurora/wifi
ML=/run/aurora-modem/lifecycle.log; RPNAME=a204000.remoteproc
mkdir -p $D
now() { cut -d' ' -f1 /proc/uptime; }
log() { m="[$(now)] $*"; echo "$m" >> $LOG; echo "$m"; echo "<5>[aurora-wifi] $*" > /dev/kmsg 2>/dev/null; }
rp() { for r in /sys/class/remoteproc/remoteproc*; do [ "$(cat $r/name 2>/dev/null)" = $RPNAME ] && echo $r && return; done; }
hpid() { ps w | grep "[h]ostapd -t .*$D/hostapd.conf" | awk '{print $1}'; }
WAIT_MODEM=300; SSID=; PSK=; CHANNEL=6
[ -f $CONF ] && . $CONF
case "$1" in
start)
	T0=$(now); log "=== WIFI START (wait for modem START OK/FAIL up to ${WAIT_MODEM}s)"
	i=0; while [ $i -lt $WAIT_MODEM ]; do
		grep -qE "=== START OK|FAIL in|rollback" $ML 2>/dev/null && break; sleep 1; i=$((i+1)); done
	log "modem gate after ${i}s: $(grep -E '=== START OK|FAIL in|rollback' $ML 2>/dev/null | tail -1 | cut -c1-80)"
	[ "$(cat /sys/module/firmware_class/parameters/path)" = /firmware/image ] && [ -f /firmware/image/wcnss.mdt ] || { log "FAIL: /firmware/image/wcnss.mdt not available"; exit 1; }
	[ -f /lib/firmware/wlan/prima/WCNSS_qcom_wlan_nv.bin ] || { log "FAIL: NV missing"; exit 1; }
	R=$(rp); [ -n "$R" ] || { log "FAIL: remoteproc $RPNAME not found"; exit 1; }
	if [ "$(cat $R/state)" = offline ]; then echo start > $R/state || { log "FAIL: WCNSS start write"; exit 1; }; fi
	log "WCNSS $R state=$(cat $R/state)"
	i=0; while [ ! -e /sys/class/net/wlan0 ] && [ $i -lt 30 ]; do sleep 1; i=$((i+1)); done
	[ -e /sys/class/net/wlan0 ] || { log "FAIL: wlan0 did not appear in 30 s"; exit 1; }
	ip link set wlan0 up || { log "FAIL: wlan0 up"; exit 1; }
	log "wlan0 up addr=$(cat /sys/class/net/wlan0/address) ($(dmesg | grep -o "wcn36xx: firmware WLAN version.*XO'" | tail -1))"
	[ -n "$SSID" ] && [ ${#PSK} -ge 8 ] || { log "AP not configured (SSID/PSK) - wlan0 left up, managed"; exit 0; }
	umask 077; cat > $D/hostapd.conf <<C
interface=wlan0
driver=nl80211
ctrl_interface=$D/ctrl
ssid=$SSID
hw_mode=g
channel=$CHANNEL
ieee80211n=1
wmm_enabled=1
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=$PSK
logger_stdout=-1
logger_stdout_level=2
C
	printf 'trap "" HUP\nexport LD_LIBRARY_PATH=%s/lib\nexec %s/hostapd -t %s/hostapd.conf >> %s/hostapd.log 2>&1\n' $X $X $D $D > $D/hostapd.run
	setsid sh $D/hostapd.run < /dev/null > /dev/null 2>&1 &
	i=0; while ! grep -q "AP-ENABLED" $D/hostapd.log 2>/dev/null && [ $i -lt 20 ]; do sleep 1; i=$((i+1)); done
	if grep -q "AP-ENABLED" $D/hostapd.log; then log "=== AP ENABLED ssid=$SSID ch=$CHANNEL pid=$(hpid) in $(awk "BEGIN{print $(now)-$T0}")s"
	else log "FAIL: hostapd did not reach AP-ENABLED: $(tail -3 $D/hostapd.log | tr '\n' ' ')"; exit 1; fi;;
stop)
	P=$(hpid); [ -n "$P" ] && kill $P; sleep 1
	[ -e /sys/class/net/wlan0 ] && ip link set wlan0 down
	R=$(rp); [ -n "$R" ] && [ "$(cat $R/state)" = running ] && echo stop > $R/state
	log "=== WIFI STOP (hostapd=${P:-none}, WCNSS $(cat $R/state 2>/dev/null))";;
status)
	R=$(rp); echo "remoteproc: $RPNAME $(cat $R/state 2>/dev/null) ($R)"
	echo "crash=$(dmesg | grep -cE 'crash detected in a204000') watchdog=$(dmesg | grep -cE 'Watchdog startup') fatal=$(dmesg | grep -cE 'qcom-wcnss-pil.*fatal')"
	echo "wlan0: $(ip -o link show wlan0 2>/dev/null | cut -d' ' -f2-3) $(iw dev wlan0 info 2>/dev/null | grep -E 'ssid|type|channel' | tr -s '\t\n' '  ')"
	echo "hostapd: pid=$(hpid) $(grep -cE 'AP-STA-CONNECTED' $D/hostapd.log 2>/dev/null) connects, $(grep -cE 'AP-STA-DISCONNECTED' $D/hostapd.log 2>/dev/null) disconnects"
	iw dev wlan0 station dump 2>/dev/null | grep -E "^Station|authorized|signal:|connected time"
	tail -3 $LOG;;
*)	echo "usage: $0 start|stop|status"; exit 2;;
esac
