LAPB conformance — C# LapbLayer vs the authoritative ND LAPB spec¶
This document records how the C# LAPB implementation satisfies the authoritative ND LAPB
Layer-2 spec (canonical copy at WSL /home/ronny/repos/os/x25emu/docs/lapb-nd-spec.md). It
walks the spec section 8.1 validator checklist (12 items) and maps each to the code and the
unit test that proves it.
Implementation: SINTRAN/XMSG/SRC/Xmsg.Live/LapbLayer.cs (state machine),
SINTRAN/XMSG/SRC/Xmsg.Live/LapbOptions.cs (timers/window),
SINTRAN/XMSG/SRC/Xmsg.Hdlc/LapbFrame.cs (control-byte decode),
SINTRAN/XMSG/SRC/Xmsg.Live/Seam/LapbLayerAdapter.cs (live clock wiring).
Tests: all under SINTRAN/XMSG/SRC/Xmsg.Live.Tests/ —
LapbFrameDecodeTests, LapbLayerTests, LapbFrmrTests, LapbTimerTests,
LapbConformanceVectorsTests (byte vectors S1-S8).
Section 8.1 validator checklist¶
Each item answers YES with the code location and the proving test.
-
S-frame subtype via
ctrl & 0x0F; RR/RNR/REJ distinguished; REJ0x9not conflated with data address0x09.LapbFrame.DecodeSupervisorydecodes the low nibble by field position. Test:LapbFrameDecodeTests.SupervisoryFrame_DecodesSubtype_NrAndPollFinal,.RejControlByte_NotConfusedWithDataAddress. -
Retransmit queue covers the whole window (not one buffer); go-back-N triggerable by REJ.
LapbLayer._txInfo[8]stores a payload per N(S);GoBackNreplays them. Test:LapbLayerTests.Rej_GoBackN_RetransmitsAllOutstanding,LapbConformanceVectorsTests.S2. -
T1 ticked in the LIVE runner; T1/N2 values.
LapbLayerAdapterinjects a monotonic millisecond clock (CurrentMillis) intoTickfrom the pump loop; defaults T1=3000, N2=10 (LapbOptions). Test:LapbTimerTests(all). -
RNR handled: busy blocks new I-frames; RR(P=1) probe.
HandleSupervisorysets/clears_peerBusy;TransmitPendinggates on!_peerBusy;OnT1Expirypolls RR(P=1). Test:LapbLayerTests.Rnr_HoldsSends_ThenRrResumes,LapbConformanceVectorsTests.S3. -
P=1 answered with F=1 and current N(R).
HandleSupervisory/HandleInformationemit RR(F=1) whenframe.PollFinal. Test:LapbLayerTests.ReceivedPoll_AnsweredWithFinal,LapbConformanceVectorsTests.S6. -
On SABM (sent/received/mid-session) V(S)/V(R)/V(A) reset to 0 and queue cleared; NO adopt-peer-sequence path.
Resetis called on UA-accepted and on every received SABM; sequence adoption was removed. Test:LapbLayerTests.MidSessionSabm_ResetsButStaysConnected,.RxUa_Connects_ResetsVariables_EmitsRr_LearnsPeer,LapbConformanceVectorsTests.S7. -
Constructed with the 16-bit node number; stamped on SABM/UA/RR; peer node kept OUT of routing.
LapbLayer(ushort ownNode, ...);SendUnnumbered/EmitSupervisorystamp the node;PeerNodeis read-only and never a routing key. Test:LapbLayerTests.MultipleTrunks_KeepIndependentSequenceAndIdentity. -
Two I-frames outstanding and the FIRST retransmitted on REJ(0) (depth-1-buffer regression). Test:
LapbConformanceVectorsTests.S2,LapbLayerTests.Rej_GoBackN_RetransmitsAllOutstanding. -
No code path sends an I-frame while peer-busy.
TransmitPendingrequires!_peerBusy. Test:LapbLayerTests.Rnr_HoldsSends_ThenRrResumes(held send asserts empty output). -
LAPB module free of X.25/XMSG types (payload independence).
LapbLayerreferences onlySystem,System.Collections.GenericandNDInsight.Sintran.Xmsg.Hdlc(LapbFrame); the information field is opaqueReadOnlyMemory<byte>/ReadOnlySpan<byte>. -
Bad N(R) -> FRMR reason Z; over-long I-field -> FRMR reason Y.
AcknowledgeThroughsends FRMR(Z);HandleInformationsends FRMR(Y) for info > 312 bytes. Test:LapbFrmrTests.BadReceiveSequence_SendsFrmrReasonZ_EntersFrmrSent,.OverlongInformation_SendsFrmrReasonY_NotDelivered. -
Mid-session SABM -> UA + reset (NOT DM + disconnect).
HandleUnnumberedSABM case sends UA, resets, stays CONNECTED. Test:LapbConformanceVectorsTests.S7,LapbLayerTests.MidSessionSabm_ResetsButStaysConnected.
Byte-level vectors (section 8.2)¶
S1-S7 are asserted frame-for-frame in LapbConformanceVectorsTests (local node 100, peer 102).
S8 is a framing-layer vector (byte-stuffing / FCS) covered by the HDLC tests
(HdlcEncoderTests), not the LAPB layer.
Our implementation emits one spec-permitted extra RR keepalive on entering CONNECTED (spec 3.4, live-necessary so the ND peer advances to RUN); the vectors account for it and otherwise assert the required frames exactly.
Deviation from prior behaviour (live re-verification pending)¶
The previous LapbLayer ADOPTED the peer's sequence from its first I-frame — a live-verified
workaround for the epoch-1 reconnect (the ND kernel appearing to keep its sequence across our TCP
reconnect). The spec forbids adoption (section 3.2) and this implementation removes it, hard-zeroing
on every SABM. The offline gates (S1-S7, SeamParityTests) pass, but they cannot prove the LIVE
reconnect. Live re-verification against machine 100 — bring-up, reachability/list-route, connect-to,
and a reconnect after a simulated machine restart — remains the operator's gate. If the live
reconnect regresses, the documented fallback is a default-OFF LapbOptions.AdoptPeerSequenceOnReconnect
flag, not yet implemented.