Forum Discussion
bloosqr
Oct 24, 2026Tutor
Patch file against latest firmware : 5 ghz / 6 ghz direct communication bug
Hi all in that other thread, while resetting the firmware fixed the problem. I realized it did not fix the actual underlying issue. I realized today someone on reddit actually had a similar issue...
bloosqr
Oct 24, 2026Tutor
Here is my firmware analysis : Orbi RBE970/RBE971 — 5 GHz ↔ 6 GHz client isolation: firmware analysis
Comparison of V9.12.5.3 and V12.1.11.15 (RBE970 .chk, board U12H487T00_NETGEAR). Extraction: CHK → FIT → UBI (128 KB PEBs) → squashfs (xz) → rootfs.
1. Hardware / radio topology (confirmed)
From /lib/wifi/select_bdf_files.sh and /ntgr/ntgr_wireless_vap.sh:
netdev Band Silicon ini file
wifi0 2.4 GHz FH/BH IPQ9574 (SoC-internal) QCA9574_i.ini
wifi1 5 GHz fronthaul QCN9224 QCN9224_i.ini
wifi2 6 GHz fronthaul + backhaul QCN9224 QCN9224_i.ini
wifi3 5 GHz backhaul QCN9224 QCN9224_i.ini
RBE970 links three QCN9224 BDFs (bdwlan.b0011, b0012, b0004) plus the IPQ9574 internal radio. The 5 GHz and 6 GHz fronthaul radios are separate PCIe SoCs — separate psoc_id.
2. 5 GHz and 6 GHz clients share one netdev
/lib/wifi/qcawificfg80211.sh:1716 (V12):
echo "MLD Single Netdev is ENABLED" > /dev/console
mld_netdev=1
Hardcoded — not conditional. With an AP MLD on a single netdev, a 5 GHz client and a 6 GHz client on the same node are on the same bridge port. The Linux bridge will never forward between them (same-port traffic is dropped by definition). All such traffic must be relayed by the Wi-Fi datapath's intra-BSS forwarding path.
This confirms the architectural claim in the r/orbi thread. Intra-BSS forwarding is gated by ap_bridge, set per-VAP at qcawifi.sh:3541:
iwpriv "$ifname" ap_bridge "$((isolate^1))"
With isolate=0 (default) this is ap_bridge=1, i.e. forwarding is permitted. So plain AP isolation is not the cause.
3. The V9 → V12 delta: PPE Direct Switching turned on
ini/internal/QCN9224_i.ini:
-dp_ppe2tcl_ring=0x2000
+ppe_ds_enable=1
+dp_fse_3_tuple_enable=1
ini/global.ini:
+# PPEDS per WLAN SoC configuration
+ppeds_wifi_soc_cfg=0xff
ppe_ds_enable across every radio ini:
ini V9 V12
QCN9224_i.ini (5 GHz, 6 GHz) (absent) 1
QCA9574_i.ini (2.4 GHz) (absent) 0
QCN6432_i.ini (absent) 0
QCA5332_i.ini (absent) 0
QCN9000_i.ini 0 0
V9's qcawificfg80211.sh contains zero references to ppe_ds_enable; V12's contains three.
QCN9224 is the only chip in V12 with PPE Direct Switching enabled — and it is exactly the 5 GHz and 6 GHz radios. 2.4 GHz is on the ordinary path. This matches the symptom's band selectivity: 2.4 GHz pairs, wired peers and internet traffic are unaffected.
4. The guard that was supposed to prevent this never fires
qcawificfg80211.sh:1893-1903 (V12):
mldev_mode="$(grep "mldev_mode_ap" $ini_p/global.ini | awk -F '=' '{print $2}')"
# Disable PPE for unified non-bond and hybrid non-bond mlo models
if [ ! -z $mldev_mode ] && [ $mldev_mode -eq 0 -o $mldev_mode -eq 2 ]; then
update_internal_ini QCN9224_i.ini ppe_ds_enable 0
else
config_get ppe_ds_enable qcawifi ppe_ds_enable 1
[ -n "$ppe_ds_enable" ] && update_internal_ini QCN9224_i.ini ppe_ds_enable $ppe_ds_enable
fi
mldev_mode_ap is written to global.ini earlier only if the UCI option is non-empty:
config_get mldev_mode_ap qcawifi mldev_mode_ap # no default supplied
[ -n "$mldev_mode_ap" ] && update_ini_file mldev_mode_ap "$mldev_mode_ap"
Shipped /ntgr/wireless.default defines config qcawifi 'qcawifi' with no mldev_mode_ap and no ppe_ds_enable, and global.ini has no mldev_mode_ap line. Therefore:
mldev_mode is the empty string → [ ! -z $mldev_mode ] is false
the else branch runs → ppe_ds_enable defaults to 1
The branch intended to disable PPE-DS for non-bonded MLO models is unreachable as shipped. /ntgr/wireless.default is byte-identical between V9 and V12, so the entire behavioural change comes from the Qualcomm ini defaults and new script logic, not from Netgear's own config.
5. Why it is per-association ("luck of the draw")
umac.ko (6.3 MB) contains the MLO primary-UMAC machinery:
mlo_peer_allocate_primary_umac
mlo_peer_assign_primary_umac
mlo_peer_free_primary_umac
osifp_peer_primary_umac_update
osif_process_primary_umac_update_event
with these log strings:
MLD ID %d Assoc peer %pM primary umac soc %d
MLD ID %d ML Peer %pM avg RSSI %d primary umac soc %d
MLD ID %d ML Peer %pM center primary umac soc %d
Central LINK %d Force central as primary umac!!
peer %pM primary umac migration already in progress
New primary link id not found for ml peer %pM
Unable to fetch new primary link id for ml peer %pM
Each ML peer is assigned a primary UMAC — the SoC that owns its datapath — at association time, chosen by assoc link, average RSSI, or a forced "central" link, and migratable at runtime. Because 5 GHz FH and 6 GHz FH are different QCN9224 SoCs, two clients that land on different bands get primary UMACs on different chips, and the intra-BSS relay between them has to cross chips through the PPE direct-switch path. The assignment is re-rolled on every join, which is precisely the observed "half the time it works, a reset re-rolls it" behaviour.
The driver also exports gDisableIntraBssFwd / WLAN_INTRA_BSS, neither of which is set anywhere in the shipped configuration.
Confidence
Items 1–4 are facts read directly from the two images. Item 5 is the best-supported mechanism, but static analysis cannot prove the frame is dropped there — that needs the live device. The V9→V12 delta is however a directly testable prediction: V9 does not configure PPE-DS on these radios at all.
6. What to do
Workarounds that need no shell (and why they work)
Action Why it works
Wire one of the two devices Traffic goes via EDMA/bridge, never the Wi-Fi↔Wi-Fi DS relay
Put both devices on the same band Intra-BSS stays within one UMAC/SoC
Separate 6 GHz SSID (/etc/separate_6g_enable_group → wireless.FhA1_6G.ifdown) Splits the AP MLD, so the two clients land on distinct netdevs and the bridge forwards normally
IoT SSID with 5 GHz enabled Same reason — separate VAP, ordinary bridge path
There is genuinely no GUI setting for the underlying behaviour; that part of the thread is correct.