Hardware / firmware: Two GL-BE9300 (Flint 3), one as Mesh main router and one as mesh node, both on 4.10.1. Clients affected: two Pixel 9s.
Symptom
After some days of uptime, my Pixel 9 could no longer connect to the mesh SSID on any band. Android reported "check password." Enabling randomized MAC on the phone made it connect instantly; switching back to the device MAC made it fail again. Rebooting the main router fixed it. A second Pixel 9 on the same network showed an early stage of the same thing: stuck on 2.4 GHz at -67 dBm with the 6 GHz BSS refusing it.
Root cause (traced on the router)
Steering blocks added during a client-steer are never removed, because prplMesh's release path depends on data-model objects that GL.iNet's wld.lua doesn't implement.
-
The controller steers a client and, as part of that, blocks it on the band it should leave. prplMesh's whm HAL does this through the Ambiorix data model:
WiFi.AccessPoint.N.MACFiltering.addEntry(mac=…)plusMode="BlackList". This works; the MAC lands in hostapd'sdeny_acl. -
~25 s later the HAL releases the block. Before calling
delEntryit resolvesDevice.WiFi.AccessPoint.[Alias=='wlanX'].MACFiltering.Entry.[MACAddress==…]to find the entry. -
wld.lua'sMACFilteringobject exposes onlyMode,addEntryanddelEntry. There is noEntrytable, so the lookup always fails, prplMesh treats it as "nothing to remove," anddelEntryis never called. -
The deny entry lives only in hostapd's memory, so nothing ever cleans it up until reboot. Each steer attempt leaks one more block; once a client is blocked on every band it can use, it's locked out. Android shows the association reject as a password error.
Evidence (6 GHz BSS = wlan2 = WiFi.AccessPoint.3, client MAC redacted to aa:bb:cc:11:22:33)
Agent log, /tmp/beerocks/logs/beerocks_agent.*.log:
ERROR 12:08:51:168 ambiorix_client.cpp[71] --> AmbiorixClient::resolve_path failed to resolve path: Device.WiFi.AccessPoint.[Alias == 'wlan2'].MACFiltering.Entry.[MACAddress == 'aa:bb:cc:11:22:33' || MACAddress == 'AA:BB:CC:11:22:33'].
WARNING 12:08:51:168 ap_wlan_hal_whm.cpp[349] --> change MACFiltering mode to BlackList
ERROR 12:09:16:485 ambiorix_client.cpp[71] --> AmbiorixClient::resolve_path failed to resolve path: Device.WiFi.AccessPoint.[Alias == 'wlan2'].MACFiltering.Entry.[MACAddress == 'aa:bb:cc:11:22:33' || MACAddress == 'AA:BB:CC:11:22:33'].
Controller log at the same time: client_steering_task.cpp[508] --> Client Steer attempt: result= Success, sta_mac= aa:bb:cc:11:22:33, source= 2a:81:b2:3c:a9:b8, dest= 0a:f7:40:c8:a9:ea, trigger= [optimal_path_task], type= 11v (BTM).
State afterwards (still present >20 min later, no further steering attempts logged):
# hostapd_cli -p /var/run/hostapd-wifi2 -i wlan2 deny_acl SHOW
aa:bb:cc:11:22:33 VLAN_ID=0
# ubus call WiFi.AccessPoint.3.MACFiltering _get '{"depth":3}'
{ "WiFi.AccessPoint.3.MACFiltering.": { "Mode": "BlackList" } } <- no entries
# ubus -v list WiFi.AccessPoint.3.MACFiltering
"addEntry":{} "delEntry":{} <- no Entry object
Confirmation that the RPC itself works and only the call is missing:
# ubus-cli 'WiFi.AccessPoint.3.MACFiltering.delEntry(mac="aa:bb:cc:11:22:33")'
# hostapd_cli -p /var/run/hostapd-wifi2 -i wlan2 deny_acl SHOW
(empty)
After that, the phone reconnected on 6 GHz by itself.
Suggested fix
Have wld.lua keep MACFiltering.Entry.{i}.MACAddress instances in sync with addEntry/delEntry (which is what prplMesh's whm HAL expects from pwhm), or alternatively resync hostapd's ACL from the model whenever Mode changes. Either way, prplMesh's sta_allow must end up calling delEntry.