Skip to content

J1939: the self-traffic guard is bounded by the arbitration window, not by the transmission it exists for #121

Description

@dborgards

What

#119 stops a J1939 node raising its own application PGNs as peer traffic. During a re-claim the
address store is -1, so a second marker, _vacatedAddressStore, covers the address being given
up — gated on ClaimState == Claiming, because an unbounded marker has a strictly worse failure
mode (below).

That gate is a proxy for the thing actually wanted: has the echo of what this node transmitted
under the old address drained yet?
The two coincide as long as the echo arrives within the
arbitration window. When it does not — an RX-reader backlog, or an adapter delivering late — the
claim completes, WriteAddress(B) clears the marker, ClaimState leaves Claiming, and the
still-queued frame carrying the old source address passes both guards and is raised through
MessageReceived.

Default ClaimAnnounceTimeout is 250 ms (J1939NodeOptions), so the echo has to be more than a
quarter second late for the two to come apart. It is a residual window, not a common one — but it
is the case the guard was written for, arriving slightly too late to be caught.

Not a regression, which is why it is a ticket

Before #119 every echo surfaced as peer traffic, delayed or not. #119 narrows that to "only an
echo arriving after the arbitration window closes". Nothing got worse, so by causality it does not
belong in that pull request — but the narrowing is incomplete and the reason is structural rather
than an oversight.

Raised by Codex on #119 (483324d,
discussion_r4009573748).

Why the obvious fix is the wrong one

Codex's first suggestion — keep the address until a peer claim establishes new ownership — was
considered and rejected during #119, and there is a test pinning the rejection
(A_Vacated_Address_Stops_Being_Ours_Once_The_Claim_Is_Over). An unbounded marker makes a node
that loses an address go permanently deaf to whoever holds it, because the clearing event
never has to arrive: a device with a static address that claimed once at power-up, before this
node started listening, simply never re-claims. Trading "one own broadcast is heard once, 250 ms
after a re-claim" for "a peer is never heard again" is the wrong direction.

The direction that does work

Codex's second suggestion, and the same thing the very first review comment on #119 asked for:
classify against the address associated with the transmission, not against the address current
when the frame is processed.
Then the marker is not a timer at all — it lives exactly as long as
there is an outstanding transmission under the old address, which is the property wanted.

Sketch, not a decision:

  • count transmissions issued under an address, decrement as their echoes are classified, and keep
    the marker while the count is above zero. Needs a way to tell an echo of our frame from a
    peer's frame with the same SA, which on a flagging adapter is IsEcho and on an unflagged one
    is not available — so the count alone would over-drop on a busy segment;
  • or tag outgoing frames and match the tag on the way back, which is adapter-independent but
    touches the send path;
  • or keep the current window and simply extend it by a bounded drain interval after the claim
    completes. Cheapest, and the worst of the three: it is another clock, which is what Three wall-clock-dependent tests fail intermittently across all three CI legs #92 is a
    list of.

Whatever shape it takes, it should keep A_Vacated_Address_Stops_Being_Ours_Once_The_Claim_Is_Over
green — that test is the boundary this must not cross.

Acceptance

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions