Repository navigation
IPv6 Port Service: align rule limits and errors with FLWRT (ref FWDEV#204 IPv6 row) #1687
Description
Ref linksys/FWDEV#204, the IPv6 port services row. FW's GUI guide is in its comments of 2026-10-14 (1, 2). The firmware is linksys/feed_usp#50 (open), together with linksys/targets#272 (merged) and linksys/feed_uspapi#41 (open).
The rest of #204 (single and range forwarding, triggering, Firewall, DMZ) is done on the GUI side in PR #1680.
Unblocked: FW's local build 2.0.3.26101472 (linked on linksys/FWDEV#204) carries the fix. FW will post the Jenkins image after the PRs merge.
What changes, and why
On FLWRT today, IPv6 port services is a firmware defect, not a page defect. linksys/feed_usp#50 records three causes:
- A rule the page saves names no interface, so FLWRT does not open it from WAN to LAN. A saved rule opens nothing.
Protocol255 (Both) is not a protocol fw4 knows.- A firmware update clears FW's mapping table, so
CreationDatereads back as0001-01-01T00:00:00Z. The page treats that date as the marker of a system rule (usp_ipv6_port_service_service.dart,buildRuleUIModels). After an update, every user rule disappears from the page.
All three are fixed in the firmware, and rules saved by an older build are converted on upgrade. The page's requests stay as they are:
Device.Firewall.Chain.1.Rule.withIPVersion6,TargetAccept, andProtocol6 / 17 / 255.Targetis sent last, because FW runs its checks whenTargetis written.- One rule has one port range.
What the fix adds is checking. FW now refuses a request that breaks a rule, so the page has to deal with refusals.
To do
1. A refused save must not read as saved
saveBatch logs a UspPartialSuccess from a delete, an add or an update as a warning and carries on, so the whole save reports success. Until now FW refused nothing, so this could not be seen. With linksys/feed_usp#50 it will: a 16th rule, a duplicate description or an overlap is refused, and the page still says "saved".
Do it the way PR #1680 did for port forwarding:
- throw when any step fails or partly fails, with the router's message
- re-read the router after a partial failure, so a retry does not add the saved rules again
2. Description limit: 64 bytes, not 32 characters
FW checks bytes. validateRule checks description.length > 32, so for Latin text the page is stricter than FW, but 22 CJK characters (66 bytes) pass the page and are refused by FW. Count bytes as port_rule_limits.dart does (utf8.encode), with a 64-byte limit.
3. At most 15 rules
Disable Add at 15 rules, with the reason shown, as #1680 does on the port forwarding tabs. FW keeps rules past 15 that a previous build saved editable, so the page must not block editing them.
4. The description must be unique across every firewall rule
FLWRT finds a rule by its description, so a duplicate would take over the other rule, and FW refuses it with ErrorDescriptionInUse.
The check has to include the system rules the page hides. fetch already reads all of Device.Firewall.Chain.1.Rule, but buildRuleUIModels drops the system rules, so their descriptions have to be kept for the dialog to check against.
5. Overlap
A new or edited rule overlaps another when all three hold:
- same LAN host (
DestIP) - overlapping port range
- a shared protocol:
Bothcounts as TCP and as UDP
Disabled rules count. The same port to a different host is allowed. #1680's forwardingOverlaps and othersThan (port_rule_limits.dart) do this for forwarding rules and can be adapted.
Not in this issue
- The router's error name. A refused save shows the generic text, because the batch localiser maps by fault code only. The same goes for fix(firewall, port-forwarding): FWDEV#204's rules in the UI, and no silent saves (#1611, #1080) #1680; it is a shared change.
required: trueon Add and Set. FW asks for it, so that a refused request saves nothing. It needs a usp-client change in linksys/usp_framework.
Measure on 2.0.3.26101472 first
- Which of the seven errors each refusal returns, and whether the error name comes through to the app.
- Whether a refused Add leaves a rule behind, and whether a refused Set still changes the port.
- A WAN-side IPv6 host reaches the LAN device through an accepted rule, for TCP, UDP and
Both. - After a firmware update, the rules are still listed (
CreationDateis not the zero date) and still pass traffic.
Post-merge recheck
linksys/feed_usp#50 and linksys/feed_uspapi#41 are not merged. Once they are, re-run the measurements above on the Jenkins image, and re-check the limits and error names against the merged code.
Activity
AustinChangLinksys commentedon Oct 15, 2026
Classification: enhancement/task (not a bug) — 2.x line (USP/TR-181
Device.Firewall.Chain.1.Rule,lib/page/ipv6_port_service). (author=Austin — self-filed tracking item, may already be in progress)Codebase findings (checked on
origin/dev-2.7.3@ d215304, after PR #1680 merged):lib/page/ipv6_port_service/services/usp_ipv6_port_service_service.dart:59-62, 93, 136— eachUspPartialSuccesscase only callslogger.w(...)andbreaks, sosaveBatchreturns normally. Confirmed. OnlyUspFailurethrows (L63-67).port_forwarding/services/usp_port_forwarding_service.dart:72, 120, 154, 379, 511already handleUspPartialSuccess(the fix(firewall, port-forwarding): FWDEV#204's rules in the UI, and no silent saves (#1611, #1080) #1680 pattern to reuse).lib/page/ipv6_port_service/models/ipv6_port_service_ui_model.dart:98still usesdescription.length > 32.lib/page/port_forwarding/models/port_rule_limits.dart:34already has theutf8.encode(description).length > kMaxRuleDescriptionBytescheck to reuse.lib/page/ipv6_port_service/(grep for>= 15/canAdd→ no hits).usp_ipv6_port_service_service.dart:195-200buildRuleUIModelsfilters outcreationDate == 0001-01-01T00:00:00Z, so hidden system-rule descriptions are not available to the dialog (views/dialogs/ipv6_port_service_rule_dialog.dart). Confirmed gap.port_rule_limits.darthasothersThan(L22) andforwardingOverlaps(L39) to adapt; no overlap check exists in the IPv6 dialog/model.Blockers / open questions:
ErrorDescriptionInUse) surface through the batch localiser — issue already scopes this out as a shared change.Suggested roles:
2x-dev, 2x-verifyAutomated triage by gate.py. Dispatch requires Austin's authorization.
test(golden): the IPv6 port services states #1687 added, and a valida…
fix(ipv6-port-service): FWDEV#204's rules in the dialog, and no silen…