#!/bin/sh
# The DHCP client, hung off wpa_supplicant's own association events.
# Exec'd by s6-supervise, never by hand.
#
# WPA_SUPPLICANT ASSOCIATES AND NOTHING MORE; it never asks for an address.
# Stock firmwareExe watched for that and ran udhcpc itself (it is full of
# "udhcpc -i wlan0" strings) and FlashForge shipped an action script at
# /usr/prog/wifi/bin/wifi_reconnect for the same hook. Ours is
# $MODDIR/bin/wifi-action.sh, which has shipped since the s6 migration and,
# until this service existed, was invoked by nothing at all.
#
# WHY A SERVICE AND NOT TWO LINES IN wifi/run. The old wifi oneshot ran udhcpc
# ONCE, straight after association, which covers exactly one story: a printer
# booting in range of a network it already knows. It does not cover the owner
# who joins a network from the HelixScreen panel an hour later -- associated,
# no address, which the panel reports as a connection timeout -- and it does
# not cover a lease lost to an AP reboot. `wpa_cli -a` fires on every
# association change for as long as it runs, so all three become one path.
MODDIR=/usr/data/anvil
IFACE=wlan0
ACTION=$MODDIR/bin/wifi-action.sh
CTRL=/var/run/wpa_supplicant/$IFACE

[ -f $MODDIR/anvil-env.sh ] && . $MODDIR/anvil-env.sh

mkdir -p /usr/data/logs
exec >>/usr/data/logs/anvil-wifi.log 2>&1

if [ ! -x "$ACTION" ]; then
    echo "wifi-dhcp: !! no $ACTION -- nothing will ask for an address"
    sleep 5
    exit 1
fi

# wpa_cli attaches to the control socket and exits at once if it is not there.
# `dependencies.d/wifi` only says the supplicant was exec'd, not that it has
# created the socket -- wifi has no notification-fd and nothing it could
# honestly send one on -- so the wait belongs here.
n=0
while [ $n -lt 30 ] && [ ! -e "$CTRL" ]; do
    sleep 1
    n=$((n + 1))
done
if [ ! -e "$CTRL" ]; then
    echo "wifi-dhcp: !! $CTRL never appeared -- is wpa_supplicant up?"
    sleep 5
    exit 1
fi

killall wpa_cli 2>/dev/null

# THE RESTART CASE, and it is the one that bites. wpa_cli runs the action
# script on CHANGES; restarted while the printer is already associated there
# is no change left to fire on, and the lease `finish` just dropped would
# never come back. The action script replaces any previous client before it
# starts one, so calling it here is idempotent with an event that may also
# arrive a moment later.
if /usr/sbin/wpa_cli -i $IFACE status 2>/dev/null | grep -q '^wpa_state=COMPLETED'; then
    echo "wifi-dhcp: already associated -- asking for a lease now"
    "$ACTION" "$IFACE" CONNECTED
fi

# NO -B, for the reason wifi/run has none. wpa_cli exits when the supplicant
# goes away, which is correct here rather than a fault: s6 restarts this, it
# waits for the new control socket, and the printer comes back without anyone
# typing anything.
#
# And `exec`, so a stop signals wpa_cli rather than a shell that ignores it.
exec /usr/sbin/wpa_cli -i $IFACE -a "$ACTION"
