Two more issues found deploying the previous two commits live:
1. The nodogsplash package's own uci-defaults populate an anonymous
@nodogsplash[0] section pointed at br-lan (see install_and_stop's
doc comment). NoDogSplash runs one gateway instance per config
section, so this ran alongside our own nodogsplash.main instead of
being superseded by it — silently re-gating br-lan. configure() now
deletes it.
2. After `network restart` + `wifi down/up`, netifd intermittently
loses the race to claim br-tollgate as the wifi vif attaches
(reports up:false, DEVICE_CLAIM_FAILED) even though the bridge
device and member interface both exist correctly. NoDogSplash
refuses to start against an interface netifd hasn't brought up.
restart_services() now explicitly cycles just the tollgate
interface (ifdown/ifup) after the wifi restart.
Deploying the previous commit's fix live exposed a real bug: nodogsplash's
OpenWrt package postinst auto-enables and starts the service immediately
on install, using its stock default config — gatewayinterface=br-lan.
Since NoDogSplash only touches IPv4 iptables, this silently cut IPv4
(not IPv6) connectivity for anything on br-lan, including the admin
management box plugged into this router's LAN port, for the window
between install and our own configure step.
Split nodogsplash provisioning into install_and_stop() (runs first,
closes that window immediately) and configure() (runs after
wifi::provision_ssid has created br-tollgate, so gatewayinterface is
pointed at the isolated tollgate bridge instead of br-lan).
tollgate-wrt has no firewall/netfilter code of its own (confirmed via
strings on the binary and the upstream Go source) — it delegates all
MAC authorization and gate open/close to NoDogSplash via ndsctl.
Upstream's package declares +nodogsplash as a hard dependency, but
neither of our install paths pull it in: the opkg fast path only
resolves deps against a real feed, and the raw .ipk-extraction
fallback (used whenever the package isn't in a feed, and always on
ApkNative) skips dependency resolution entirely. Result: tollgate-wrt
ran, accepted payments, and tracked balances, but never actually
blocked unpaid clients — the static firewall zone just forwarded
everyone to WAN unconditionally.
Also fixes the config.json mismatch: tollgate-wrt reads
/etc/tollgate/config.json exclusively, never the tollgate.main.* UCI
keys we were writing — so mint/price changes through this project's
UI silently had no effect on what the daemon actually advertised.
- tollgate/nodogsplash.rs: install nodogsplash, configure it to gate
the dedicated br-tollgate bridge, open the pre-auth walled-garden
ports (2121 payment, 2050 portal).
- tollgate/wifi.rs: bind network.tollgate to a stable br-tollgate
bridge device (NoDogSplash needs a known interface name — the
driver-assigned name of a bare wifi vif isn't guaranteed); disable
IPv6 RA/DHCPv6 on it (NoDogSplash only manages IPv4 iptables, so
IPv6 would let clients bypass the portal entirely).
- tollgate/config.rs: apply_daemon_config() merges pricing/mint into
the real config.json instead of (only) UCI.
- opkg.rs: generic install_package() for standard feed packages under
either PkgManager mode.
- router.rs: upload_file() (SCP) for non-UCI config files.