Skip to content

IPv6 Port Service: align rule limits and errors with FLWRT (ref FWDEV#204 IPv6 row) #1687

Description

@AustinChangLinksys

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.
  • Protocol 255 (Both) is not a protocol fw4 knows.
  • A firmware update clears FW's mapping table, so CreationDate reads back as 0001-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. with IPVersion 6, Target Accept, and Protocol 6 / 17 / 255.
  • Target is sent last, because FW runs its checks when Target is 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: Both counts 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

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 (CreationDate is 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

  1. added
    usp:investigationRequires technical investigation or TR-181 path validation
    blocked:fw-supportBlocked — requires firmware team support
    2.xLabeled for 2.x version
    and removed
    blocked:fw-supportBlocked — requires firmware team support
    on Oct 14, 2026
  2. AustinChangLinksys commented on Oct 15, 2026

    @AustinChangLinksys
    CollaboratorAuthor

    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):

    • To-do 1 (refused save reads as saved): lib/page/ipv6_port_service/services/usp_ipv6_port_service_service.dart:59-62, 93, 136 — each UspPartialSuccess case only calls logger.w(...) and breaks, so saveBatch returns normally. Confirmed. Only UspFailure throws (L63-67). port_forwarding/services/usp_port_forwarding_service.dart:72, 120, 154, 379, 511 already handle UspPartialSuccess (the fix(firewall, port-forwarding): FWDEV#204's rules in the UI, and no silent saves (#1611, #1080) #1680 pattern to reuse).
    • To-do 2 (64 bytes): lib/page/ipv6_port_service/models/ipv6_port_service_ui_model.dart:98 still uses description.length > 32. lib/page/port_forwarding/models/port_rule_limits.dart:34 already has the utf8.encode(description).length > kMaxRuleDescriptionBytes check to reuse.
    • To-do 3 (max 15): no rule-count cap or Add-disable logic found under lib/page/ipv6_port_service/ (grep for >= 15 / canAdd → no hits).
    • To-do 4 (unique description incl. system rules): usp_ipv6_port_service_service.dart:195-200 buildRuleUIModels filters out creationDate == 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.
    • To-do 5 (overlap): port_rule_limits.dart has othersThan (L22) and forwardingOverlaps (L39) to adapt; no overlap check exists in the IPv6 dialog/model.
    • Unblock premise (FW build 2.0.3.26101472 carries the fix) was not verifiable from the codebase.

    Blockers / open questions:

    • Whether FW's refusal error names (e.g. ErrorDescriptionInUse) surface through the batch localiser — issue already scopes this out as a shared change.
    • Line: this touches TR-181 paths only, so 2.x is code-supported.

    Suggested roles: 2x-dev, 2x-verify

    Automated triage by gate.py. Dispatch requires Austin's authorization.

  3. added
    triagedAutomated diagnosis complete; root cause investigated (bug lane entry)
    on Oct 15, 2026
  4. added a commit that references this issue on Oct 19, 2026
  5. added this to the 2.7.3 milestone on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

2.xLabeled for 2.x versiontriagedAutomated diagnosis complete; root cause investigated (bug lane entry)usp:investigationRequires technical investigation or TR-181 path validation

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions