fix: push_mac_acl() must never set macfilter='disable'

OpenWrt's wifi-scripts validator rejects any macfilter value other than
"allow"/"deny" outright — confirmed on real hardware, setting
macfilter='disable' puts netifd in a permanent restart crash loop with the
radio stuck down. The only way to disable filtering is to delete the option
entirely. Also guards against pushing an empty whitelist (macfilter='allow'
with zero MACs blocks every client outright) by treating it as equivalent
to "off".
This commit is contained in:
Christian Manivong
2026-07-16 12:05:07 +02:00
parent af032a3c4d
commit 6b78ebcacb
2 changed files with 38 additions and 5 deletions
+16 -3
View File
@@ -570,14 +570,22 @@ class OpenWrtWirelessMixin:
Full-rebuild, not diff — always deletes the existing maclist before
re-adding, so the result is idempotent regardless of prior state.
OpenWrt's wifi-scripts validator rejects any ``macfilter`` value other
than ``"allow"``/``"deny"`` outright (confirmed on real hardware:
setting ``macfilter='disable'`` puts netifd in a permanent restart
crash loop with the radio stuck down) — there is no "off" value; the
only way to disable filtering is to omit the option entirely.
A whitelist ("allow") with zero MACs blocks every client outright, so
it is treated as equivalent to "off" instead of being pushed as-is.
:param ssid_name: SSID name to match against ``option ssid`` on each wifi-iface section.
:param mode: ``"off"`` | ``"whitelist"`` | ``"blacklist"`` — mapped to UCI
``macfilter`` ``"disable"``/``"allow"``/``"deny"``.
:param mode: ``"off"`` | ``"whitelist"`` | ``"blacklist"``.
:param macs: MAC addresses to set as the maclist. Only the entries for the
active mode's list are ever passed in — the caller resolves whitelist
vs. blacklist before calling.
"""
uci_mode = {"off": "disable", "whitelist": "allow", "blacklist": "deny"}[mode]
effective_mode = "off" if (mode == "whitelist" and not macs) else mode
sections = self._send_command(
"uci show wireless | grep -oE '^wireless\\.[^.]+' | sort -u"
).split()
@@ -585,6 +593,11 @@ class OpenWrtWirelessMixin:
ssid_val = self._send_command(f"uci -q get {sec}.ssid 2>/dev/null || true").strip()
if ssid_val != ssid_name:
continue
if effective_mode == "off":
self._send_command(f"uci -q delete {sec}.macfilter || true")
self._send_command(f"uci -q delete {sec}.maclist || true")
continue
uci_mode = "allow" if effective_mode == "whitelist" else "deny"
self._send_command(f"uci set {sec}.macfilter='{uci_mode}'")
self._send_command(f"uci delete {sec}.maclist 2>/dev/null || true")
for mac in macs: