Forum Discussion

bloosqr's avatar
bloosqr
Tutor
Oct 24, 2026

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 and had somehow figured out what it was that was going on.

This was the text from that post

"Each Orbi node bundles its 5 and 6 GHz clients into one Wi-Fi 7 "multi-link" access point. Traffic between two Wi-Fi clients on that node never goes through the router's normal switching; the Wi-Fi chip relays it directly as a shortcut. Each time a device joins, the chip sets up that relay, and roughly half the time it gets it wrong. Then the device reaches the internet and anything wired, but not its Wi-Fi neighbors on the same node, until it rejoins.

 

That's why a wire or the IoT SSID fixes it instantly (the traffic takes the normal path), and why a reset only seems to work: everyone rejoins, a fresh roll of the dice.

 

Test: on the 6 GHz device, turn Wi-Fi off and on ten times and ping the 5 GHz device after each. A mix of pass and fail means it's this.

 

Best I can figure the real fix has to be a Netgear firmware update; there's no setting for it. Until then: wire one device, put one on the IoT SSID, or toggle Wi-Fi until a ping work"

We live in a modern era and decompiling firmware is actually pretty simple and so that is exactly what I did. Once decompiled, it turned out the original posters intuition was pretty much exactly right and super easy to find. I also confirmed this bug is not in the latest v9 version of the firmware.


Here is the parse through the firmware/OS which shows the author's intuition is exactly right:

 

  1. RBE970 = IPQ9574 + three QCN9224s. Per select_bdf_files.sh and ntgr_wireless_vap.sh: wifi0=2.4 GHz (SoC-internal), wifi1=5 GHz fronthaul, wifi2=6 GHz, wifi3=5 GHz backhaul. The 5 GHz and 6 GHz fronthaul radios are separate PCIe chips.
  2. 5 and 6 GHz clients sit on one netdev. qcawificfg80211.sh:1716 hardcodes MLD Single Netdev is ENABLED. Same bridge port ⇒ the Linux bridge can never forward between them; it has to be the Wi-Fi datapath’s intra-BSS relay. That part of the thread is correct. And it’s not AP isolation — qcawifi.sh:3541 sets ap_bridge=1 by default.
  3. The actual V9→V12 delta. V12 added to QCN9224_i.ini:-dp_ppe2tcl_ring=0x2000 +ppe_ds_enable=1
  4. plus ppeds_wifi_soc_cfg=0xff in global.ini. QCN9224 is the only chip with PPE Direct Switching on — every other radio ini says 0. V9’s config script never mentions ppe_ds_enable at all. So V12 moved Wi-Fi↔Wi-Fi forwarding onto the hardware shortcut path on precisely the two affected bands, and left 2.4 GHz alone.
  5. The safety guard is dead code. qcawificfg80211.sh:1893 disables PPE-DS for “unified non-bond and hybrid non-bond mlo models” by reading mldev_mode_ap from global.ini — but that key is only written if the UCI option is non-empty, and shipped /ntgr/wireless.default never sets it. Empty string ⇒ the if is false ⇒ else ⇒ ppe_ds_enable defaults to 1. The guard cannot fire as shipped.
  6. Why it’s per-join. umac.ko has mlo_peer_assign_primary_umac and logs like MLD ID %d ML Peer %pM avg RSSI %d primary umac soc %d and Central LINK %d Force central as primary umac!!. Each client is assigned a primary UMAC — the chip owning its datapath — at association, by assoc link or RSSI, and it can migrate at runtime. Two clients on different bands get primary UMACs on different chips, so the relay must cross chips via the DS path. Re-rolled on every join: your “luck of the draw.”

I am adding the patch file as an attachment here. That patch file has a longer discussion on why this patch fixes the problem.  I hope someone at Netgear reads this and can confirm this. 

Please fix and update. I can make an unofficial firmware update but it would be better for Netgear to roll this out for obvious reasons.

If someone @ Netgear needs my contact info, please let me know.

1 Reply

  • 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.