Flint 3: main Wi-Fi VAPs are not attached to br-lan after boot

Summary

On a GL.iNet Flint 3 (GL-BE9300), the main 2.4, 5, and 6 GHz Wi-Fi networks advertise normally and accept client associations after a reboot, but the corresponding interfaces (wlan0, wlan1, and wlan2) are not attached to br-lan. DHCP broadcasts therefore do not reach the LAN DHCP server.

Guest, IoT, VPN, and MLO interfaces are attached to their respective bridges and continue to work.

A manual wifi reload restores bridge membership for all three main interfaces, but the problem returns after every reboot.

My investigation found that the qsdk-wifi setup handler throws a Lua exception during its first boot-time request and never replies to netifd. All three netifd workers wait for their explicit 600-second ubus timeout. The wireless driver then incorrectly marks each radio up despite the failed setup.

Device and firmware

Field Value
Device GL.iNet Flint 3 / GL-BE9300
Firmware base OpenWrt 23.05-SNAPSHOT
OpenWrt revision r0-3601c2a49
Target ipq53xx/generic
Architecture aarch64_cortex-a53_neon-vfpv4
Wireless stack Qualcomm/QSDK, Wi-Fi 7/MLO
gl-sdk4-qsdk-wifi git-2026.239.24451-38e5a78-1
netifd 2024-01-04-c18cc79d-1
qca-wifi-scripts 1

Network layout

Interface Purpose Expected bridge State after boot
wlan0 Main 2.4 GHz AP br-lan No bridge master
wlan1 Main 5 GHz AP br-lan No bridge master
wlan2 Main 6 GHz AP br-lan No bridge master
mld0 Main MLO aggregate br-lan Correctly attached
wlan01 Guest AP br-guest Correctly attached
wlan06 IoT AP br-iot Correctly attached
ath12 VPN AP br-vpnwifi Correctly attached
eth1.1 Wired LAN br-lan Correctly attached

The main SSID is shared by the conventional and MLO APs. Credentials and unrelated private configuration have been omitted from this report.

Steps to reproduce

  1. Configure the main AP interfaces on all three radios with network='lan'.

  2. Reboot the router.

  3. Wait for the main SSID to appear.

  4. Connect a non-MLO client to the main SSID.

  5. Observe that the client associates but does not obtain a DHCP lease.

  6. Inspect bridge membership:

bridge link show dev wlan0
bridge link show dev wlan1
bridge link show dev wlan2
ubus call network.device status '{"name":"br-lan"}'
  1. Run wifi reload.

  2. Repeat the bridge queries and DHCP test.

Actual result

Immediately after boot, all three conventional main AP interfaces exist and are up, but none has a bridge master:

wlan0  UP  <BROADCAST,MULTICAST,UP,LOWER_UP>
wlan1  UP  <BROADCAST,MULTICAST,UP,LOWER_UP>
wlan2  UP  <BROADCAST,MULTICAST,UP,LOWER_UP>

bridge link contains no entry for those interfaces.

Netifd's own bridge state confirms the same result:

{
  "bridge-members": [
    "eth1.1",
    "mld0"
  ]
}

DHCP requests are visible on the affected wireless interface but do not reach br-lan. Manually attaching an affected VAP immediately restores connectivity:

ip link set wlan1 master br-lan

Running wifi reload restores the expected state for all three VAPs:

wlan0 master br-lan state forwarding
wlan1 master br-lan state forwarding
wlan2 master br-lan state forwarding

The failure returns after reboot.

Expected result

Every enabled AP VAP configured with network='lan' should be registered with netifd and attached to br-lan after boot:

wlan0 master br-lan state forwarding
wlan1 master br-lan state forwarding
wlan2 master br-lan state forwarding
mld0  master br-lan state forwarding

Clients connecting to any advertised main AP should receive DHCP service without requiring a wireless reload.

Relevant persistent configuration

The affected wireless sections contain the correct network assignment. For example:

wireless.wifi5g.device='wifi1'
wireless.wifi5g.network='lan'
wireless.wifi5g.mode='ap'
wireless.wifi5g.ifname='wlan1'

The LAN bridge is also configured correctly:

network.@device[0].name='br-lan'
network.@device[0].type='bridge'
network.@device[0].ports='eth1.1'
network.lan.device='br-lan'
network.lan.proto='static'
network.lan.ipaddr='192.168.1.1'

The netifd-generated QSDK setup request includes both:

"bridge": "br-lan",
"bridge_ifname": "br-lan"

and the VAP configuration contains:

"network": ["lan"]

This indicates that UCI-to-netifd translation recognizes the intended network.

Boot log evidence

At boot, the three netifd wireless workers report an MLO data warning:

12:09:57 netifd: wifi0 (...): WARNING: Variable 'mld' does not exist or is not an array/object
12:09:57 netifd: wifi1 (...): WARNING: Variable 'mld' does not exist or is not an array/object
12:09:57 netifd: wifi2 (...): WARNING: Variable 'mld' does not exist or is not an array/object

The QSDK configurator then enters its first-setup path and throws immediately:

12:09:58 qsdk-wifi: first setup
12:09:58 qsdk-wifi: .../gl-sdk4-qsdk-wifi/usr/sbin/qca-wifi-configurator:1316: table index is nil

Exactly one configured ubus timeout later, all three workers fail:

12:20:27 netifd: wifi0 (...): Command failed: ubus call qsdk-wifi setup { ... }
12:20:27 netifd: Wireless device 'wifi0' is now up
12:20:27 netifd: wifi1 (...): Command failed: ubus call qsdk-wifi setup { ... }
12:20:27 netifd: Wireless device 'wifi1' is now up
12:20:27 netifd: wifi2 (...): Command failed: ubus call qsdk-wifi setup { ... }
12:20:27 netifd: Wireless device 'wifi2' is now up

The ten-minute duration comes from /lib/netifd/wireless/qcawificfg80211.sh:

ubus -t 600 call qsdk-wifi setup "$(json_dump)"
echo "$(json_dump)" > /tmp/qcawificfg80211_${1}_bak
wireless_set_up

The Lua exception occurs almost immediately. The apparent 600-second “hang” is the ubus client waiting because the exception path does not return a success response or error response. The driver subsequently calls wireless_set_up without checking whether ubus ... setup succeeded.

The configurator process remains alive under procd after the exception, so it is not restarted:

/usr/bin/lua /usr/sbin/qca-wifi-configurator

Conflicting initialization paths

Two Qualcomm initialization paths run during boot:

Component Startup order Role
/etc/init.d/qca-wifi-configurator START=15 Provides the qsdk-wifi ubus service
/etc/init.d/network START=20 Starts netifd and its qcawificfg80211 workers
/etc/init.d/qcawifi-legacy START=22 Runs /sbin/wifi reload_legacy

qcawifi-legacy contains bridge-attachment code:

add_bridge_iface() {
    config_get ifname "$1" ifname
    config_get mld "$1" mld
    config_get disabled "$1" disabled
    config_get network "$1" network

    [ "$disabled" = "1" ] && return

    if [ -n "$mld" ]; then
        brctl addif br-$network $mld
    else
        brctl addif br-$network $ifname
    fi
}

However, that code is called only from the service's reload() function. Its boot-time start() function performs wifi reload_legacy but never runs add_bridge_iface:

start() {
    config_load wireless
    config_foreach wait_for_mldphy_create wifi-iface
    ubus -t 30 wait_for network.interface
    /sbin/wifi reload_legacy "" "network_reload_legacy"
    echo "Bringup wifi " > /dev/kmsg
}

The boot log also records:

procd: /etc/rc.d/S22qcawifi-legacy: sh: 1: unknown operand

The conventional APs are brought up through this overlapping initialization sequence, but their bridge attachment is omitted. MLO follows separate QSDK code that explicitly removes and re-adds mld0 through netifd, which explains why mld0 is attached correctly.

Suspected root cause

There appear to be three related defects:

  1. Invalid or incomplete MLO setup data: all three workers report that mld is missing or not an object immediately before the configurator exception.
  2. Unanswered ubus request after Lua exception: qca-wifi-configurator throws table index is nil in its first-setup handler and does not reply with an error, leaving clients blocked until -t 600 expires.
  3. Incorrect success state after setup failure: qcawificfg80211.sh calls wireless_set_up unconditionally after the failed ubus request.

Additionally, the netifd setup path and qcawifi-legacy run concurrently and appear to have overlapping ownership of VAP creation and bridge attachment.

The immediate demonstrated cause of the ten-minute delay is the unanswered ubus request following the Lua exception. The exact nil table key cannot be identified from the device because /usr/sbin/qca-wifi-configurator is installed as compiled Lua 5.1 bytecode and its matching source is not included.

Requested fixes

Please consider the following changes in gl-sdk4-qsdk-wifi:

  1. Fix the mld table construction or validation leading to the exception at qca-wifi-configurator:1316.

  2. Wrap every qsdk-wifi ubus request handler so all failure paths return an explicit ubus error.

  3. Check the return status of:

ubus -t 600 call qsdk-wifi setup ...

and do not call wireless_set_up after failure.

  1. Register each successfully created, non-MLO AP VAP with netifd, preferably through the standard wireless_add_vif <section> <ifname> API.

  2. Register an MLO aggregate such as mld0 once rather than adding each MLO link VAP independently.

  3. Remove the overlapping ownership between qcawifi-legacy and the newer qca-wifi-configurator, or serialize them with an explicit completion dependency.

  4. Avoid a fixed-delay workaround. Bridge registration should occur in response to successful VAP creation.

Equivalent explicit netifd device registration would be:

ubus call network.interface.<network> add_device '{"name":"<ifname>"}'

but using netifd's wireless-driver notification API is preferable because it preserves ownership and teardown semantics.

AI assistance disclosure

This report was prepared with the help of an AI assistant. The assistant helped organize the investigation, analyze the collected read-only diagnostics, and draft the report. The router observations, configuration excerpts, runtime state, and log messages cited above came from the affected device and were reviewed before submission.

Hi,

Thanks for the detailed report. We tested this on a Flint 3 in our lab but could not reproduce the issue, including after creating a VPN AP using ath12 and rebooting the router.

Could you please confirm the exact firmware version installed on your BE9300? You can find it under SYSTEM → Upgrade in the Admin Panel.

Please follow the guide below to export a configuration backup. Do not upload the backup publicly, as it may contain sensitive settings. Please send it to us in a private message so we can inspect the configuration and try to reproduce the issue locally.

To send a private message, click the Technical Support avatar and then the Message button.