Repository navigation
WiFi Advanced: MLO switch, on FLWRT 2.0's X_LINKSYS_Mesh (ref FWDEV#201) #1692
Copy link
Copy link
Open
Copy link
Labels
2.xLabeled for 2.x versionLabeled for 2.x versionFLWRT-2.0Labeled belonging on FLWRT-2.0Labeled belonging on FLWRT-2.0enhancementNew feature or requestNew feature or requestfeature:wifiWiFi configuration and managementWiFi configuration and managementtriagedAutomated diagnosis complete; root cause investigated (bug lane entry)Automated diagnosis complete; root cause investigated (bug lane entry)
Milestone
Description
Ref linksys/FWDEV#201 (FW's contract of 2026-10-09). Parity row: linksys/Architecture#210, WiFi — MLO (fronthaul + backhaul, SLO fallback).
This is the MLO part of #856, split out the way steering was (#1661). The MLO client display, MLO (<bands>) on a device, is a different change and lives in #1686.
FW contract
| Leaf | Access | Meaning |
|---|---|---|
Device.X_LINKSYS_Mesh.MLOEnabled |
writable bool, default off | one switch for the whole mesh, set on the controller only |
Device.X_LINKSYS_Mesh.MLOStatus |
read-only | Disabled / Active / Inactive (on, but the bands' SSID, password or security are not compatible) |
A change restarts Wi-Fi for about 60 s. Read MLOStatus again after that.
Measured on the bench
FW 2.0.3.26101472 (HW1, single node), 2026-10-15, through the app's WASM client and usp-bridge.
- Read:
MLOEnabledisxsd:boolean, writable, and reads0.MLOStatusisxsd:string, read-only, and readsDisabled. Both are served by dm-reflector, like the steering leaves. - MLO + DFS in one Set (
{MLOEnabled: 1, Radio.1/2.IEEE80211hEnabled: 1},allowPartial: true): accepted, all three applied, and Wi-Fi reloaded once. The reply came after 19.9 s.MLOStatusreadInactive10 s later and stayed there, which is expected: the bench's two main bands share an SSID but are WPA2-Personal. - The same leaves in two Sets (MLO, then DFS) also reloaded once. But the MLO Set was answered in 166 ms, and its reload started 71 s later.
Not measured: Active (needs the same password and WPA3 on both bands), MLO together with steering, and why the reload after the MLO-only Set came 71 s late.
To do
- A definition of its own (
wifi/mesh_mlo.yaml, linksys/usp_framework branchfeat/mlo-switch-definition), not inmesh_steering.yaml. Its two leaves are required, and its header says a write does not restart Wi-Fi. With MLO in it, firmware without MLO would make the steering switches fail to read too. In PrivacyGUI, generate only this definition with the vendored 0.17.0, as feat(advanced, wifi): UPnP switch and client/node steering switches (#1660, #1661) #1674 did for steering. - One Set for the whole tab. Steering, MLO and DFS go out in one Set with
allowPartial: true. Today steering and DFS are two Sets (feat(advanced, wifi): UPnP switch and client/node steering switches (#1660, #1661) #1674), and DFS usesallowPartial: false.- Until [USP] Migrate to usp-codegen 0.18.0: multi-instance tables are lists, no fixed-instance reads #1654 vendors 0.18.1, build the map by hand in
usp_wifi_advanced_service.dart: one function per part, each returning aMap<String, dynamic>, merged into oneset(). Then [USP] Migrate to usp-codegen 0.18.0: multi-instance tables are lists, no fixed-instance reads #1654 step 13 swaps each function's body forMeshSteering.updateParams(),MeshMlo.updateParams()andWiFiRadios.updateParams(), and nothing else changes. - With
allowPartial: truea part can fail on its own, so the save reads back every changed value throughwifiWriteConfirmProvider(fix(wifi): save in one SET, read the router back, and run each write under one recovery (#1499, #1460) #1673) before it reports success.
- Until [USP] Migrate to usp-codegen 0.18.0: multi-instance tables are lists, no fixed-instance reads #1654 vendors 0.18.1, build the map by hand in
- A save that restarts Wi-Fi waits for the restart. feat(advanced, wifi): UPnP switch and client/node steering switches (#1660, #1661) #1674's
changesDfsgrows into "does this save restart Wi-Fi?", true when MLO or DFS changes. Such a save goes the DFS way (Wi-Fi restart, then reconnect), not the steering way (applies at once). Because the reload can start long after the reply (71 s above), the read-back must not finish before it. - Show
MLOStatus. OnInactive, say why. FW suggests: "Use the same Wi-Fi name, password and WPA3 security on 2.4 GHz and 5 GHz."
Depends on
- FW: linksys/FWDEV#201's PRs merged on 2026-10-14 (linksys/targets#269, linksys/feed_core#36, linksys/feed_premium#55, linksys/feed_usp#49, linksys/feed_uspapi#40). Local build
2.0.3.26101472carries them. - linksys/usp_framework: the
mesh_mlo.yamlPR. - One node is enough to verify. Switching restarts Wi-Fi, so measure over a cable.
Acceptance criteria
- The switch turns MLO on and off, and the status is right after the restart.
-
Inactiveshows its hint. With the same SSID, password and WPA3 on both bands, the status readsActive. - A save that changes MLO, DFS and steering together sends one Set and restarts Wi-Fi once.
- A part refused within that Set shows as a failed save, not as saved.
- On firmware without MLO, steering and DFS still read and write.
Post-merge recheck
- The 60 s restart, and what the switch reads on an agent.
- Once [USP] Migrate to usp-codegen 0.18.0: multi-instance tables are lists, no fixed-instance reads #1654 vendors 0.18.1: the hand-built map is replaced by the three
updateParams()builders ([USP] Migrate to usp-codegen 0.18.0: multi-instance tables are lists, no fixed-instance reads #1654 step 13).
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
2.xLabeled for 2.x versionLabeled for 2.x versionFLWRT-2.0Labeled belonging on FLWRT-2.0Labeled belonging on FLWRT-2.0enhancementNew feature or requestNew feature or requestfeature:wifiWiFi configuration and managementWiFi configuration and managementtriagedAutomated diagnosis complete; root cause investigated (bug lane entry)Automated diagnosis complete; root cause investigated (bug lane entry)
Activity
AustinChangLinksys commentedon Oct 15, 2026
Automated triage
Classification: enhancement (feature:wifi), USP/TR-181 protocol-layer change → 2.x line. The line is decidable here because the ticket reads/writes
Device.X_LINKSYS_Mesh.*(TR-181 / generated USP code, which 1.x does not have). (author=Austin — self-filed tracking item, may already be in progress)Codebase findings (checked on
origin/dev-2.7.3, the newest line):grep MLOoverlib/page/wifi_settingsandlib/generated/mesh_steering.g.dartreturns nothing. The onlyMLOhit in generated code is the unrelatedDevice.WiFi.Templates.APMLDTemplate.{i}.MLOEnable(lib/generated/tr181_paths.g.dart:18825).lib/generated/mesh_steering.g.dartexists underlib/generated/mesh*, somesh_mlo.g.darthas to be generated (To-do 1).usp_wifi_advanced_provider.dart:109:if (!state.changesDfs) return;, withchangesDfsatwifi_advanced_feature_state.dart:44. This is the flag the ticket wants widened to "does this save restart Wi-Fi?" (To-do 3).usp_wifi_advanced_service.dart:65: the comment says the DFS write is notallowPartial, which matches the ticket's "DFS usesallowPartial: false". Moving to one Set withallowPartial: true(To-do 2) changes that contract.wifiWriteConfirmProviderexists (wifi_write_confirm_provider.dart:114) and is used inusp_wifi_advanced_provider.dart:256, so the read-back mentioned in To-do 2 is reachable.usp-definitions/wifi/mesh_steering.yaml:7says a write does not restart Wi-Fi, which supports keeping MLO in its own definition.feat/mlo-switch-definitionbranch in usp_framework, and anything aboutMLOStatuson firmware without MLO.Blockers / open questions:
mesh_mlo.yamlPR in linksys/usp_framework (To-do 1). It is not in the local clone, so I cannot confirm its state.Suggested roles:
2x-dev, 2x-verifyAutomated triage by gate.py. Dispatch requires Austin's authorization.
AustinChangLinksys commentedon Oct 18, 2026
Implemented on
feat/1692-mlo-switch(PR to follow). The definition is linksys/usp_framework#86. Bench results and the ticket corrections below.Bench, 2026-10-16 (FW 2.0.3.26101472, single node, Mac on Ethernet)
MLOStatusInactiveat onceDisabledat onceActiveat 9.8 sDisabledlsmeshlogs "-> wifi reload", but the MLO hook finds the grouping unchanged and returns. That reload came from the DFS Set sent 70 s after the MLO one.Decided: every MLO change is treated as restarting Wi-Fi. The save enters recovery even when the router will not restart (WPA2 bands): the app cannot tell the two apart without the firmware's grouping rule. If nothing drops, recovery's first probe, sent as soon as the write settles, finds the router and ends it.
Corrections to the description
These lines attribute the 71 s reload to the MLO Set. Per the bench above, it was the DFS Set's:
MLOEnabledsetter only schedules the restart and returns, so the answer comes before the restart ends.Post-merge recheck (additions)
lib/generated/mesh_mlo.g.dartfrom merged main and diff it. PrivacyGUI generated it contract-first from [Screenshot testing] #86's branch with the vendored 0.17.0. Format the regenerated file from the repo root before diffing: the package's language version picks the short style, a temp directory picks the tall one.MLOEnabledandMLOStatusare still bothrequiredin the merged definition. The app relies on that: a router that offers MLO but answers without one of them must fail the read, not show "off".feat(wifi): MLO switch on the Advanced tab, and one Set for the tab (#…